diff --git a/bpm/command.py b/bpm/command.py index a669314..c7b828a 100644 --- a/bpm/command.py +++ b/bpm/command.py @@ -166,7 +166,7 @@ def cli_alias(args): file = list(BIN_PATH.glob(args.old_name + "*")) if not file: - log.error(f"Lnk `{args.old_name}` not found.") + log.error(f"Script `{args.old_name}` not found.") exit(1) if len(file) > 1: name = file[0].with_suffix("") diff --git a/bpm/install/__init__.py b/bpm/install/__init__.py index 3ddba3c..906d7f7 100644 --- a/bpm/install/__init__.py +++ b/bpm/install/__init__.py @@ -163,7 +163,10 @@ def extract(buffer: io.BytesIO, to_dir: Path) -> Path: with zipfile.ZipFile(buffer, "r") as file: file.extractall(path=to_dir) except zipfile.BadZipFile: - import py7zr + try: + import py7zr + except ImportError: + utils.error_exit("cannot extract 7z file without py7zr module.") with py7zr.SevenZipFile(buffer, "r") as file: file.extractall(path=to_dir) diff --git a/bpm/search.py b/bpm/search.py index 66d9cd3..2c382c7 100644 --- a/bpm/search.py +++ b/bpm/search.py @@ -2,6 +2,7 @@ import platform import posixpath import sys +from enum import Enum from functools import reduce from pprint import pprint from typing import Optional @@ -14,6 +15,73 @@ from .utils.exceptions import AssetNotFoundError, InvalidAssetError, RepoNotFoundError +class Combination(Enum): + """ + Enum for the different ways of combining the select_list and prompt. + """ + + ALL = 0 + ANY = 1 + + +def select_list( + select_list: list[str], + prompts: list[str], + combination: Combination = Combination.ALL, + case_sensitive=False, +) -> list[str]: + """ + Selects items from the given list and return. + if no item were found, return the origin list, so the return list will not be empty. + + :param combination: ALL => every prompt should in the word, ANY => one or more prompt in the word. + + >>> select_list(["12", "13", "23"], ["1"]) + ['12', '13'] + >>> select_list(["12", "13", "23", "34"], ["1", "2"], Combination.ANY) + ['12', '13', '23'] + >>> select_list(["12", "13", "23", "34", "21"], ["1", "2"], Combination.ALL) + ['12', '21'] + """ + comb_func = any if combination == Combination.ANY else all + is_valid = lambda s: comb_func( # noqa: E731 + map( + (lambda x: x in s) + if case_sensitive + else (lambda x: x.lower() in s.lower()), + prompts, + ) + ) + return list(filter(is_valid, select_list)) or select_list + + +def sort_list( + sort_list: list[str], + prompts: list[str], + combination: Combination = Combination.ALL, + case_sensitive=False, +) -> list[str]: + """ + Sort items from the given list and return. + + :param combination: ALL => every prompt should in the word, ANY => one or more prompt in the word. + + + >>> sort_list(["12", "13", "23"], ["2"]) + ['12', '23', '13'] + """ + comb_func = any if combination == Combination.ANY else all + is_valid = lambda s: comb_func( # noqa: E731 + map( + (lambda x: x not in s) + if case_sensitive + else (lambda x: x.lower() not in s.lower()), + prompts, + ) + ) + return sorted(sort_list, key=is_valid) + + class RepoHandler: def __init__(self, name: str, **kwargs): self.name = name @@ -181,7 +249,6 @@ def get_asset(self, interactive: bool = False): log.error(f"repo {self.repo_owner}/{self.repo_name} not found.") raise RepoNotFoundError - r = r[:25] # only gets the front 25 results. r = list(filter(lambda x: bool(x["assets"]), r)) if len(r) == 0: raise AssetNotFoundError @@ -196,21 +263,19 @@ def get_asset(self, interactive: bool = False): # select # 1. platform - temp = [x for x in assets if platform.system().lower() in x.lower()] - if temp: - assets = temp - # windows maybe use `win` instead of `windows` - elif WINDOWS and "win" not in self.name.lower(): - assets = [x for x in assets if "win" in x.lower()] - if not assets: - raise InvalidAssetError + if WINDOWS and "win" not in self.name.lower(): + pltfm = [platform.system().lower(), "win"] + assets = select_list(assets, pltfm, Combination.ANY) # 2. architecture - temp = [x for x in assets if platform.machine().lower() in x.lower()] - if temp: - assets = temp + arch = ( + [platform.machine().lower()] + if platform.machine().lower() != "amd64" + else ["amd64", "x86_64"] + ) + assets = select_list(assets, arch, Combination.ANY) # 3. musl or gnu if not self.prefer_gnu: - assets = sorted(assets, key=lambda x: "musl" not in x) + assets = sort_list(assets, ["musl"]) # 4. tar, zip, 7z, other assets = sorted(assets, key=lambda x: not x.endswith(".7z")) if WINDOWS: @@ -269,4 +334,7 @@ def test_parse_url(self): if __name__ == "__main__": + import doctest + unittest.main() + doctest.testmod() diff --git a/pyproject.toml b/pyproject.toml index 8b3a886..9b287c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bin-package-manager" -version = "2.2.0" +version = "2.2.1" description = "Bin package manager, a package manager based on Github release" authors = ["lxl66566 "] license = "MIT"