almost working impl
This commit is contained in:
parent
dd9396cfdf
commit
89aa834bc7
1
TODO.md
1
TODO.md
|
@ -36,6 +36,7 @@
|
|||
- [ ] existence of `.local`, `.local/programs`, `.local/bin`
|
||||
- [ ] that permissions are ok
|
||||
- [ ] that `.local/bin` are in `PATH`
|
||||
- [ ] UI, add some progress to install
|
||||
- [ ] allow to list versions
|
||||
- [ ] allow to force installation of a given version
|
||||
- [-] improve search algorithm, fuzzing
|
||||
|
|
82
cliget.py
82
cliget.py
|
@ -1,15 +1,17 @@
|
|||
"""Cliget - install cli tools in you user profile
|
||||
|
||||
Usage:
|
||||
cliget [-v] [-c URL] list
|
||||
cliget [-v] [-c URL] search PAT
|
||||
cliget [-v] [-c URL] info TOOL
|
||||
cliget [-v] [-c URL] list
|
||||
cliget [-v] [-c URL] versions TOOLS ...
|
||||
cliget [-v] [-c URL] allversions TOOL
|
||||
cliget [-v] [-c URL] install TOOLS ...
|
||||
cliget [-v] [-c URL] update [--all] [TOOLS ...]
|
||||
|
||||
list list all installed tools
|
||||
search search catalog for tools with the given pattern
|
||||
info show details of an entry in the catalog
|
||||
list list all installed tools
|
||||
versions TOOLS list current and latest versions of some tools
|
||||
allversions TOOL list all versions of a tool
|
||||
install TOOLS install some tools
|
||||
|
@ -25,7 +27,7 @@ Options:
|
|||
"""
|
||||
|
||||
import logging
|
||||
import sys, os
|
||||
import sys, os, shutil
|
||||
from docopt import docopt
|
||||
from yaml import load, SafeLoader
|
||||
from semver import VersionInfo
|
||||
|
@ -39,7 +41,7 @@ def trace(*mess):
|
|||
print("TRACE", mess)
|
||||
|
||||
def warn(*mess):
|
||||
print(f"WARN {mess[0]}")
|
||||
print("WARN", mess)
|
||||
|
||||
class DotDict(dict):
|
||||
def __getattr__(self, name):
|
||||
|
@ -62,11 +64,11 @@ def _find_semver(s:str) -> VersionInfo:
|
|||
trace("parse error", e)
|
||||
return ver
|
||||
|
||||
|
||||
def _local_version(cmd):
|
||||
ver = VersionInfo(0)
|
||||
try:
|
||||
first_line = run([cmd, '--version'], input='', text=True, capture_output=True, check=True, timeout=0.1).stdout.split('\n')[0]
|
||||
trace(cmd, '=>', first_line)
|
||||
ver = _find_semver(first_line)
|
||||
except Exception as e:
|
||||
trace("run error", e)
|
||||
|
@ -92,6 +94,16 @@ def dolist(options):
|
|||
for (cli, _, ver) in _internal_list(options):
|
||||
print(cli, ver)
|
||||
|
||||
def doinfo(options):
|
||||
tool = options.TOOL
|
||||
ctl = _load_catalog(options)
|
||||
if tool in ctl:
|
||||
print(tool)
|
||||
for (k,v) in ctl[tool].items():
|
||||
print(f' {k}: {v}')
|
||||
else:
|
||||
warn(f'{tool} not in catalog')
|
||||
|
||||
def dosearch(options):
|
||||
pat = options.PAT
|
||||
ctl = _load_catalog(options)
|
||||
|
@ -100,7 +112,7 @@ def dosearch(options):
|
|||
trace(cli, props)
|
||||
rtitle = fuzz.ratio(cli, pat)
|
||||
rdesc = fuzz.partial_token_set_ratio(props['desc'], pat)
|
||||
score = 0.2 * rtitle + rdesc
|
||||
score = rtitle + rdesc if rtitle>60 else rdesc
|
||||
L.append((cli, props['desc'], score))
|
||||
L = sorted(L, key=lambda x: -x[-1])
|
||||
# TODO format a as table
|
||||
|
@ -114,7 +126,6 @@ def dolistupdate(options):
|
|||
pass
|
||||
pass
|
||||
|
||||
|
||||
def _gh_versions(repo:str) -> [VersionInfo|None]:
|
||||
[owner, repo] = repo.split("/")
|
||||
url = f'https://api.github.com/repos/{owner}/{repo}/releases'
|
||||
|
@ -153,7 +164,6 @@ def doallversions(options):
|
|||
else:
|
||||
warn(f'{tool} not in catalog')
|
||||
|
||||
|
||||
def doinstall(options):
|
||||
tools = options.TOOLS
|
||||
ctl = _load_catalog(options)
|
||||
|
@ -161,18 +171,52 @@ def doinstall(options):
|
|||
if tool in ctl:
|
||||
props = ctl[tool]
|
||||
if props.github:
|
||||
vers = _gh_version(props.github)
|
||||
trace(vers)
|
||||
rver = _gh_version(props.github)
|
||||
lver = _local_version(tool)
|
||||
trace(lver,rver)
|
||||
if rver > lver:
|
||||
_perform_install(tool, props.github)
|
||||
else:
|
||||
warn(f'{tool} not in catalog')
|
||||
|
||||
def perform_install(cli, repo):
|
||||
# get arch and os
|
||||
# dl asset
|
||||
# mkdirs
|
||||
# unpack
|
||||
# symlink
|
||||
def _match_arch_machine(name:str) -> bool:
|
||||
sysname = os.uname().sysname.lower() # os
|
||||
machine = os.uname().machine.lower() # arch
|
||||
return name.lower().find(sysname)>0 and name.lower().find(machine)>0
|
||||
|
||||
def _perform_install(cli, repo, version=None):
|
||||
# get asset list
|
||||
[owner, repo] = repo.split("/")
|
||||
url = f'https://api.github.com/repos/{owner}/{repo}/releases/latest'
|
||||
r = requests.get(url)
|
||||
assets = r.json()['assets']
|
||||
trace(assets)
|
||||
# select right asset
|
||||
asset = DotDict(next(filter(lambda x: _match_arch_machine(x['name']),assets)))
|
||||
trace(asset.name, asset.url)
|
||||
# mkdirs
|
||||
p = os.path
|
||||
home = os.environ["HOME"]
|
||||
assetshome = p.join(home, '.cache/cliget/assets')
|
||||
os.makedirs(assetshome, exist_ok=True)
|
||||
location = p.join(assetshome, asset.name)
|
||||
trace(f"will dl {location}")
|
||||
# dl asset if not already there
|
||||
if not p.exists(location):
|
||||
dlurl = requests.get(asset.url).json()['browser_download_url']
|
||||
r = requests.get(dlurl, allow_redirects=True, stream=True)
|
||||
with open(location, 'wb') as fd:
|
||||
shutil.copyfileobj(r.raw, fd)
|
||||
trace("downloaded")
|
||||
# unpack asset
|
||||
if not asset.name.endswith('.tar.gz'):
|
||||
raise ValueError('package type not handled')
|
||||
progloc = p.join(home, '.local/program/'+cli)
|
||||
trace("process tgz")
|
||||
os.makedirs(progloc, exist_ok=True)
|
||||
run(["tar", "xfz", location, "-C", progloc])
|
||||
# symlink
|
||||
os.symlink(p.join(progloc, cli), p.join(home, '.local/bin', cli))
|
||||
|
||||
if __name__ == '__main__':
|
||||
if "DEBUG" in os.environ:
|
||||
|
@ -183,13 +227,15 @@ if __name__ == '__main__':
|
|||
options = docopt(__doc__, version='Cliget 0.1.0')
|
||||
options = DotDict({k.replace('-','_'):v for (k,v) in options.items() if v is not None})
|
||||
trace(options)
|
||||
if options.list:
|
||||
if options.info:
|
||||
doinfo(options)
|
||||
elif options.list:
|
||||
dolist(options)
|
||||
elif options.search:
|
||||
dosearch(options)
|
||||
elif options.versions:
|
||||
doversions(options)
|
||||
elif options.allversions(options):
|
||||
elif options.allversions:
|
||||
doallversions(options)
|
||||
elif options.install or options.update:
|
||||
if not options.__all and len(options.TOOLS)==0:
|
||||
|
|
Loading…
Reference in New Issue