diff --git a/catalog.yaml b/catalog.yaml index f632218..6cf199f 100644 --- a/catalog.yaml +++ b/catalog.yaml @@ -1,6 +1,6 @@ ab: name: Apache Benchmark - desc: + desc: a tool for benchmarking your Apache Hypertext Transfer Protocol (HTTP) server arc: desc: Easily create & extract archives, and compress & decompress files of various formats @@ -69,7 +69,7 @@ gron: github: tomnomnom/gron grype: - decs: A vulnerability scanner for container images and filesystems + desc: A vulnerability scanner for container images and filesystems github: anchore/grype hey: @@ -200,9 +200,9 @@ terminews: desc: RSS client in the terminal github: antavelos/terminews -tldr: - desc: Collaborative cheatsheets for console commands ; must choose a client - website: https://tldr.sh/ +#tldr: +# desc: Collaborative cheatsheets for console commands ; must choose a client +# website: https://tldr.sh/ tmux: desc: terminal multiplexer diff --git a/cliget.py b/cliget.py index 7f779f6..a899965 100644 --- a/cliget.py +++ b/cliget.py @@ -1,12 +1,12 @@ """Cliget - install cli tools in you user profile Usage: - cliget [-c URL] list - cliget [-c URL] search PAT - cliget [-c URL] update [--all] [TOOL ...] + cliget [-v] [-c URL] list + cliget [-v] [-c URL] search PAT + cliget [-v] [-c URL] update [--all] [TOOL ...] list list all installed tools -search search for tools in the catalog with the given pattenr +search search for tools in the catalog with the given pattern update list all updatable tools update TOOL update tools update --all update all updatable tools @@ -15,49 +15,95 @@ update --all update all updatable tools Options: -h, --help -c, --catalog URL + -v, --verbose """ -from yaml import load, SafeLoader -import semver +import sys, os from docopt import docopt +from yaml import load, SafeLoader +from semver import VersionInfo +import re from subprocess import run, CalledProcessError, TimeoutExpired +from fuzzywuzzy import fuzz + +def debug(*mess): + #print("DEBUG", mess) + pass class DotDict(dict): def __getattr__(self, name): return self[name] if name in self else None def loadcatalog(options)->dict: - catalog=options.get('--catalog', 'catalog.yaml') - return load(open(catalog),SafeLoader) + catalog=options.get('__catalog', 'catalog.yaml') + return load(open(catalog), SafeLoader) -ver = semver.VersionInfo.parse('1.2.3-pre.2+build.4') -#print(ver.major, ver.minor, ver.patch) +def find_semver(s:str) -> VersionInfo: + ver = VersionInfo(0,0,0) + try: + ver = VersionInfo.parse(s) + except ValueError: + try: + ver = VersionInfo(*list(i.group(0) for i in re.finditer('\d+', s))[:3]) + except Exception as e: + debug("parse error", e) + return ver + _version = lambda cmd: run([cmd, '--version'], input='', text=True, capture_output=True, check=True, timeout=0.1).stdout.split('\n')[0] -def debug(mess): - #print(mess) - pass - -def dolist(options): +def _internal_list(options) -> tuple[str,VersionInfo]: + """list installed tools and their version""" ctl = loadcatalog(options) - for cli,_ in ctl.items(): + for cli, props in ctl.items(): # search in path try: - debug(cli, _version(cli)) + vers = _version(cli) + debug(cli, vers) + yield cli, props, find_semver(vers) except CalledProcessError: debug(cli, "call error") except TimeoutExpired: debug(cli, "timeout") except FileNotFoundError: debug(cli, "not found") - +def dolist(options): + for (cli, _, ver) in _internal_list(options): + print(cli, ver) + +def dosearch(options): + pat = options.PAT + ctl = loadcatalog(options) + L = [] + for cli, props in ctl.items(): + debug(cli, props) + rtitle = fuzz.ratio(cli, pat) + rdesc = fuzz.partial_ratio(props['desc'], pat) + score = 2 * rtitle + rdesc + L.append((cli, props['desc'], score)) + L = sorted(L, key=lambda x: -x[-1]) + # TODO format a as table + print("\n".join("|".join(map(str,l)) for l in L[:10])) + +def dolistupdate(options): + print("look for updatables") + for (cli, props, ver) in _internal_list(options): + # get last version online + if props.github: + pass + pass + if __name__ == '__main__': options = docopt(__doc__, version='Cliget 0.1.0') - print(options) - options = DotDict(options) + options = DotDict({k.replace('-','_'):v for (k,v) in options.items() if v is not None}) + debug(options) if options.list: dolist(options) elif options.search: dosearch(options) + elif options.update: + if not options.__all and len(options.TOOL)==0: + dolistupdate(options) + else: + print("not implemented") diff --git a/cmd.txt b/cmd.txt new file mode 100644 index 0000000..3cba195 --- /dev/null +++ b/cmd.txt @@ -0,0 +1,4 @@ + +. ./venv/bin/activate + + diff --git a/requirements.txt b/requirements.txt index 276d4f5..16a50f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ pyyaml docopt semver +fuzzywuzzy +python-Levenshtein