diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/colors.py | 2 | ||||
| -rw-r--r-- | src/options.py | 5 | ||||
| -rw-r--r-- | src/util.py | 20 | ||||
| -rw-r--r-- | src/verbs/install.py | 115 | ||||
| -rw-r--r-- | src/verbs/sync.py | 2 | 
5 files changed, 114 insertions, 30 deletions
| diff --git a/src/colors.py b/src/colors.py index c05d49b..df22d30 100644 --- a/src/colors.py +++ b/src/colors.py @@ -29,3 +29,5 @@ BG_MAGENTA         = esc(45)  BG_CYAN            = esc(46)  BG_WHITE           = esc(47)  BG_DEFAULT         = esc(49) + +CLEAR_LINE         = "\033[K" diff --git a/src/options.py b/src/options.py index 910b8a3..499f9e7 100644 --- a/src/options.py +++ b/src/options.py @@ -27,6 +27,11 @@ options = {                  "flag" : True,                  "desc" : "skip any checksum or signature verification"                  }, +        "n": { +                "name" : "no-deps", +                "flag" : True, +                "desc" : "do not resolve dependencies" +                },          "v": {                  "name" : "verbose",                  "flag" : True, diff --git a/src/util.py b/src/util.py index 16df7bc..2411f1d 100644 --- a/src/util.py +++ b/src/util.py @@ -3,6 +3,7 @@ import requests  import colors  import time  import os +import hashlib  DEFAULT_BAR_COLOR = colors.BLACK + colors.BG_CYAN  DEFAULT_BAR_COLOR_RESET = colors.BG_BLACK + colors.CYAN @@ -25,8 +26,8 @@ def loading_bar(completed, total, text,      print(color + info, end="\r") - - +def print_reset(text): +    print(colors.RESET + text)  def curl(url):      r = requests.get(url) @@ -36,6 +37,21 @@ def mkdir(path):      if not os.path.exists(path):          os.makedirs(path) +def md5sum(data): +    return hashlib.md5(data) + +def ask_confirmation(text, default=True, no_confirm=False): +    yes = "Y" if default else "y" +    no = "n" if default else "N" + +    if no_confirm: +        reponse = "y" if default else "n" +        print(f"{text} [{yes},{no}] {colors.RESET} {reponse}") +    else: +        reponse = input(f"{text} [{yes},{no}] " + colors.RESET) + +    return reponse.lower() == "y" or len(reponse) == 0  +  if __name__ == "__main__":      for i in range(1000):          loading_bar(i, 1000, "it is loading...") diff --git a/src/verbs/install.py b/src/verbs/install.py index 11a2183..0847b1d 100644 --- a/src/verbs/install.py +++ b/src/verbs/install.py @@ -4,11 +4,8 @@ import util  import colors  import time -def find_package(query, repos, packages_dir): -    sources = [] -    checksum = None -    requested_repo = None +def find_package(query, repos, packages_dir, sources):      for repo in repos:          repo_dir = os.path.join(packages_dir, repo)          files = os.listdir(repo_dir) @@ -17,13 +14,21 @@ def find_package(query, repos, packages_dir):              requested_repo = repo              with open(os.path.join(repo_dir, query)) as file:                  checksum = file.readline().strip().split("=")[-1] -                sources = file.readline().strip().split("=")[-1].split() -                return checksum, sources, requested_repo +                listed_sources = file.readline().strip().split("=")[-1].split() +                found_sources = { +                            source: util.add_path(url, repo)  +                            for source, url in sources.items()  +                            if source in listed_sources +                        } +                return checksum, found_sources, requested_repo      return None, [], None  def retrieve_package_info(sources, checksum, package_name,                               verbose=False, skip_verification=False): +     +    # TODO we may potentially do this a few times while resolving deps, might want to cache things here +    # TODO actually use the ping times we made earlier to decide which source to pick      for source,url in sources.items():          package_info_url = util.add_path(url, package_name + ".xipkg.info")          status, response = util.curl(package_info_url) @@ -43,14 +48,18 @@ def retrieve_package_info(sources, checksum, package_name,  def retrieve_package(sources, checksum, package_name,                               verbose=False, skip_verification=False): + +    # TODO actually use the ping times we made earlier to decide which source to pick +    # TODO actually save tar file, and add loading bar      for source,url in sources.items(): -        package_info_url = util.add_path(url, package_name + ".xipkg.info") +        package_info_url = util.add_path(url, package_name + ".xipkg")          status, response = util.curl(package_info_url)          if status == 200: -            info = parse_package_info(response) -            if info["CHECKSUM"] == checksum or skip_verification: -                return info +            downloaded_checksum = util.md5sum(response) +            print(downloaded_checksum, "compared to requested", checksum) +            if downloaded_checksum == checksum or skip_verification: +                return reponse              else:                  if verbose:                      print(colors.RED  @@ -67,11 +76,63 @@ def parse_package_info(packageinfo):          split = line.split("=")          if len(split) > 1:              info[split[0]] = "=".join(split[1:]) +      return info -def resolve_dependencies(package_info): -    getpkgs = lambda deps: re.findall("[\(\s](\w)[\)\s]") -    package_info[""] +def resolve_dependencies(package_info, config): +    getpkgs = lambda deps: re.findall("\w*", deps) +    deps = getpkgs(package_info["DEPS"]) + +    deps = [ +                dep for dep in deps if len(dep) > 0 +            ] + +    return deps + +def find_all_dependencies(package_names, options, config): +    # this is all assuming that the order of deps installed doesn't matter +    to_check = [p for p in package_names] +    all_deps = [] + +    while len(to_check) > 0: +        util.loading_bar(len(all_deps), len(all_deps) + len(to_check), "Resolving dependencies...") +        dep = to_check.pop() + +        dep_checksum, dep_sources, dep_repo = find_package(dep, config["repos"], config["dir"]["packages"], config["sources"]) +        if dep_checksum is not None: +            info = retrieve_package_info( +                        dep_sources, dep_checksum, dep, +                        verbose=options["v"], skip_verification=options["u"] +                    ) + +            if len(info) > 0: +                all_deps.append(dep) +                deps = resolve_dependencies(info, config) +                for dep in deps: +                    if not dep in all_deps: + +                        if is_installed(dep, config): +                            print(colors.YELLOW + f"Package {query} has already been installed") +                        else: +                            to_check.append(dep) +            else: +                if options["v"]: +                    util.print_reset(colors.CLEAR_LINE + colors.RED + f"Failed to retrieve info for {query}") +        else: +            util.print_reset(colors.CLEAR_LINE + colors.RED + f"Failed to find package {dep}") + +    if len(all_deps) > 0: +        util.loading_bar(len(all_deps), len(all_deps) + len(to_check), "Resolved dependencies") +        print(colors.RESET) + +    # assuming that the latter packages are core dependencies +    # we can reverse the array to reflect the more important packages to install +    all_deps.reverse() +    return all_deps + +def is_installed(package_name, config): +    # TODO actually find out if its installed +    return False  def install(args, options, config):      sources = config["sources"] @@ -81,23 +142,21 @@ def install(args, options, config):      unsafe = options["u"]      packages_dir = config["dir"]["packages"] -    for query in args: -        # TODO FIRST CHECK IF ALREADY INSTALLED -        checksum, listed_sources, repo = find_package(query, repos, packages_dir) +    to_install = args if options["n"] else find_all_dependencies(args, options, config) -        if checksum is not None: -            info = retrieve_package_info( -                        { -                        source: util.add_path(url, repo)  -                        for source, url in sources.items()  -                        if source in listed_sources -                    }, checksum, query, -                        verbose=v, skip_verification=unsafe -                    ) +    if len(to_install) > 0: +        print(colors.BLUE + "The following packages will be installed:") +        print(end="\t") +        for d in to_install: +            print(colors.BLUE if d in args else colors.LIGHT_BLUE, d, end="") +        print() -            print(info) +        if util.ask_confirmation(colors.BLUE + "Continue?", no_confirm=options["y"]): +            print("installed")          else: -            print(colors.RED + "Package not found") -        print(colors.RESET, end="") +            print(colors.RED + "Action cancelled by user") +    else: +        print(colors.LIGHT_RED + "Nothing to do") + diff --git a/src/verbs/sync.py b/src/verbs/sync.py index bd828ef..c534f4d 100644 --- a/src/verbs/sync.py +++ b/src/verbs/sync.py @@ -24,6 +24,7 @@ def sync_packages(repo, sources, verbose=False):          listed = list_packages(url + repo if url[-1] == "/" else f"/{repo}")          if len(listed) == 0 and verbose:              print(colors.BG_RED + f"No packages found in {source}/{repo}" + colors.RESET) +          total += len(listed)          for p in listed:              if not p in packages: @@ -67,6 +68,7 @@ def save_package_list(validated, location):          with open(package_file, "w") as file:              file.write("checksum=" + info["checksum"] + "\n")              file.write("sources=" + " ".join([source for source in info["sources"]])) +            file.write("deps=" + " ".join([source for source in info["sources"]]))  ###### !!! ####### | 
