This commit is contained in:
daylinmorgan 2023-06-01 20:57:00 +00:00
parent 42e813d394
commit 7442fdca53
3 changed files with 313 additions and 283 deletions

Binary file not shown.

View file

@ -1,4 +1,4 @@
<svg class="rich-terminal shadow" viewBox="0 0 890.3333333333334 277.5333333333333" xmlns="http://www.w3.org/2000/svg">
<svg class="rich-terminal shadow" viewBox="0 0 890.3333333333334 301.93333333333334" xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io & yartsu https://github.com/daylinmorgan/yartsu -->
<style>
@ -19,14 +19,14 @@
font-weight: 700;
}
.terminal-3499396704-matrix {
.terminal-1773455935-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
.terminal-3499396704-title {
.terminal-1773455935-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
@ -36,56 +36,60 @@
-webkit-filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
}
.terminal-3499396704-r1 { fill: #94e2d5;font-weight: bold }
.terminal-3499396704-r2 { fill: #c6d0f5 }
.terminal-3499396704-r3 { fill: #f9e2af;font-weight: bold }
.terminal-1773455935-r1 { fill: #94e2d5;font-weight: bold }
.terminal-1773455935-r2 { fill: #c6d0f5 }
.terminal-1773455935-r3 { fill: #f9e2af;font-weight: bold }
</style>
<defs>
<clipPath id="terminal-3499396704-clip-terminal">
<rect x="0" y="0" width="853.0" height="194.2" />
<clipPath id="terminal-1773455935-clip-terminal">
<rect x="0" y="0" width="853.0" height="218.6" />
</clipPath>
<clipPath id="terminal-3499396704-line-0">
<clipPath id="terminal-1773455935-line-0">
<rect x="0" y="1.5" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-1">
<clipPath id="terminal-1773455935-line-1">
<rect x="0" y="25.9" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-2">
<clipPath id="terminal-1773455935-line-2">
<rect x="0" y="50.3" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-3">
<clipPath id="terminal-1773455935-line-3">
<rect x="0" y="74.7" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-4">
<clipPath id="terminal-1773455935-line-4">
<rect x="0" y="99.1" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-5">
<clipPath id="terminal-1773455935-line-5">
<rect x="0" y="123.5" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-3499396704-line-6">
<clipPath id="terminal-1773455935-line-6">
<rect x="0" y="147.9" width="854" height="24.65"/>
</clipPath>
<clipPath id="terminal-1773455935-line-7">
<rect x="0" y="172.3" width="854" height="24.65"/>
</clipPath>
</defs>
<rect fill="#1e1e2e" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="10.1667" y="1" width="870" height="243.2" rx="8"/><text class="terminal-3499396704-title" fill="#c6d0f5" text-anchor="middle" x="435" y="27">viv&#160;list&#160;--help</text>
<rect fill="#1e1e2e" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="10.1667" y="1" width="870" height="267.6" rx="8"/><text class="terminal-1773455935-title" fill="#c6d0f5" text-anchor="middle" x="435" y="27">viv&#160;list&#160;--help</text>
<g transform="translate(32,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
<circle cx="44" cy="0" r="7" fill="#28c840"/>
</g>
<g transform="translate(18.166666666666664, 41) scale(.95)" clip-path="url(#terminal-3499396704-clip-terminal)">
<g transform="translate(18.166666666666664, 41) scale(.95)" clip-path="url(#terminal-1773455935-clip-terminal)">
<g class="terminal-3499396704-matrix">
<text class="terminal-3499396704-r1" x="0" y="20" textLength="61" clip-path="url(#terminal-3499396704-line-0)">usage</text><text class="terminal-3499396704-r2" x="61" y="20" textLength="305" clip-path="url(#terminal-3499396704-line-0)">:&#160;viv&#160;list&#160;[-h]&#160;[-v]&#160;[-q]</text><text class="terminal-3499396704-r2" x="854" y="20" textLength="12.2" clip-path="url(#terminal-3499396704-line-0)">
</text><text class="terminal-3499396704-r2" x="854" y="44.4" textLength="12.2" clip-path="url(#terminal-3499396704-line-1)">
</text><text class="terminal-3499396704-r2" x="0" y="68.8" textLength="195.2" clip-path="url(#terminal-3499396704-line-2)">list&#160;all&#160;vivenvs</text><text class="terminal-3499396704-r2" x="854" y="68.8" textLength="12.2" clip-path="url(#terminal-3499396704-line-2)">
</text><text class="terminal-3499396704-r2" x="854" y="93.2" textLength="12.2" clip-path="url(#terminal-3499396704-line-3)">
</text><text class="terminal-3499396704-r1" x="0" y="117.6" textLength="85.4" clip-path="url(#terminal-3499396704-line-4)">options</text><text class="terminal-3499396704-r2" x="85.4" y="117.6" textLength="12.2" clip-path="url(#terminal-3499396704-line-4)">:</text><text class="terminal-3499396704-r2" x="854" y="117.6" textLength="12.2" clip-path="url(#terminal-3499396704-line-4)">
</text><text class="terminal-3499396704-r3" x="24.4" y="142" textLength="24.4" clip-path="url(#terminal-3499396704-line-5)">-h</text><text class="terminal-3499396704-r2" x="48.8" y="142" textLength="24.4" clip-path="url(#terminal-3499396704-line-5)">,&#160;</text><text class="terminal-3499396704-r3" x="73.2" y="142" textLength="73.2" clip-path="url(#terminal-3499396704-line-5)">--help</text><text class="terminal-3499396704-r2" x="146.4" y="142" textLength="463.6" clip-path="url(#terminal-3499396704-line-5)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;show&#160;this&#160;help&#160;message&#160;and&#160;exit</text><text class="terminal-3499396704-r2" x="854" y="142" textLength="12.2" clip-path="url(#terminal-3499396704-line-5)">
</text><text class="terminal-3499396704-r3" x="24.4" y="166.4" textLength="24.4" clip-path="url(#terminal-3499396704-line-6)">-v</text><text class="terminal-3499396704-r2" x="48.8" y="166.4" textLength="24.4" clip-path="url(#terminal-3499396704-line-6)">,&#160;</text><text class="terminal-3499396704-r3" x="73.2" y="166.4" textLength="109.8" clip-path="url(#terminal-3499396704-line-6)">--verbose</text><text class="terminal-3499396704-r2" x="183" y="166.4" textLength="414.8" clip-path="url(#terminal-3499396704-line-6)">&#160;&#160;&#160;&#160;show&#160;full&#160;metadata&#160;for&#160;vivenvs</text><text class="terminal-3499396704-r2" x="854" y="166.4" textLength="12.2" clip-path="url(#terminal-3499396704-line-6)">
</text><text class="terminal-3499396704-r3" x="24.4" y="190.8" textLength="24.4" clip-path="url(#terminal-3499396704-line-7)">-q</text><text class="terminal-3499396704-r2" x="48.8" y="190.8" textLength="24.4" clip-path="url(#terminal-3499396704-line-7)">,&#160;</text><text class="terminal-3499396704-r3" x="73.2" y="190.8" textLength="85.4" clip-path="url(#terminal-3499396704-line-7)">--quiet</text><text class="terminal-3499396704-r2" x="158.6" y="190.8" textLength="427" clip-path="url(#terminal-3499396704-line-7)">&#160;&#160;&#160;&#160;&#160;&#160;suppress&#160;non-essential&#160;output</text><text class="terminal-3499396704-r2" x="854" y="190.8" textLength="12.2" clip-path="url(#terminal-3499396704-line-7)">
<g class="terminal-1773455935-matrix">
<text class="terminal-1773455935-r1" x="0" y="20" textLength="61" clip-path="url(#terminal-1773455935-line-0)">usage</text><text class="terminal-1773455935-r2" x="61" y="20" textLength="414.8" clip-path="url(#terminal-1773455935-line-0)">:&#160;viv&#160;list&#160;[-h]&#160;[-f]&#160;[-q]&#160;[--json]</text><text class="terminal-1773455935-r2" x="854" y="20" textLength="12.2" clip-path="url(#terminal-1773455935-line-0)">
</text><text class="terminal-1773455935-r2" x="854" y="44.4" textLength="12.2" clip-path="url(#terminal-1773455935-line-1)">
</text><text class="terminal-1773455935-r2" x="0" y="68.8" textLength="195.2" clip-path="url(#terminal-1773455935-line-2)">list&#160;all&#160;vivenvs</text><text class="terminal-1773455935-r2" x="854" y="68.8" textLength="12.2" clip-path="url(#terminal-1773455935-line-2)">
</text><text class="terminal-1773455935-r2" x="854" y="93.2" textLength="12.2" clip-path="url(#terminal-1773455935-line-3)">
</text><text class="terminal-1773455935-r1" x="0" y="117.6" textLength="85.4" clip-path="url(#terminal-1773455935-line-4)">options</text><text class="terminal-1773455935-r2" x="85.4" y="117.6" textLength="12.2" clip-path="url(#terminal-1773455935-line-4)">:</text><text class="terminal-1773455935-r2" x="854" y="117.6" textLength="12.2" clip-path="url(#terminal-1773455935-line-4)">
</text><text class="terminal-1773455935-r3" x="24.4" y="142" textLength="24.4" clip-path="url(#terminal-1773455935-line-5)">-h</text><text class="terminal-1773455935-r2" x="48.8" y="142" textLength="24.4" clip-path="url(#terminal-1773455935-line-5)">,&#160;</text><text class="terminal-1773455935-r3" x="73.2" y="142" textLength="73.2" clip-path="url(#terminal-1773455935-line-5)">--help</text><text class="terminal-1773455935-r2" x="146.4" y="142" textLength="439.2" clip-path="url(#terminal-1773455935-line-5)">&#160;&#160;&#160;&#160;&#160;show&#160;this&#160;help&#160;message&#160;and&#160;exit</text><text class="terminal-1773455935-r2" x="854" y="142" textLength="12.2" clip-path="url(#terminal-1773455935-line-5)">
</text><text class="terminal-1773455935-r3" x="24.4" y="166.4" textLength="24.4" clip-path="url(#terminal-1773455935-line-6)">-f</text><text class="terminal-1773455935-r2" x="48.8" y="166.4" textLength="24.4" clip-path="url(#terminal-1773455935-line-6)">,&#160;</text><text class="terminal-1773455935-r3" x="73.2" y="166.4" textLength="73.2" clip-path="url(#terminal-1773455935-line-6)">--full</text><text class="terminal-1773455935-r2" x="146.4" y="166.4" textLength="427" clip-path="url(#terminal-1773455935-line-6)">&#160;&#160;&#160;&#160;&#160;show&#160;full&#160;metadata&#160;for&#160;vivenvs</text><text class="terminal-1773455935-r2" x="854" y="166.4" textLength="12.2" clip-path="url(#terminal-1773455935-line-6)">
</text><text class="terminal-1773455935-r3" x="24.4" y="190.8" textLength="24.4" clip-path="url(#terminal-1773455935-line-7)">-q</text><text class="terminal-1773455935-r2" x="48.8" y="190.8" textLength="24.4" clip-path="url(#terminal-1773455935-line-7)">,&#160;</text><text class="terminal-1773455935-r3" x="73.2" y="190.8" textLength="85.4" clip-path="url(#terminal-1773455935-line-7)">--quiet</text><text class="terminal-1773455935-r2" x="158.6" y="190.8" textLength="402.6" clip-path="url(#terminal-1773455935-line-7)">&#160;&#160;&#160;&#160;suppress&#160;non-essential&#160;output</text><text class="terminal-1773455935-r2" x="854" y="190.8" textLength="12.2" clip-path="url(#terminal-1773455935-line-7)">
</text><text class="terminal-1773455935-r3" x="24.4" y="215.2" textLength="73.2" clip-path="url(#terminal-1773455935-line-8)">--json</text><text class="terminal-1773455935-r2" x="97.6" y="215.2" textLength="475.8" clip-path="url(#terminal-1773455935-line-8)">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;name:metadata&#160;json&#160;for&#160;vivenvs</text><text class="terminal-1773455935-r2" x="854" y="215.2" textLength="12.2" clip-path="url(#terminal-1773455935-line-8)">
</text>
</g>
</g>

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

540
viv.py
View file

@ -50,7 +50,7 @@ from typing import (
from urllib.error import HTTPError
from urllib.request import urlopen
__version__ = "23.5a4-21-gf5c91fe-dev"
__version__ = "23.5a4-29-g0ccf72c-dev"
class Config:
@ -746,20 +746,20 @@ class ViVenv:
verbose=bool(os.getenv("VIV_VERBOSE")),
)
def show(self, verbose: bool = False) -> None:
if not verbose:
_id = (
self.meta.id[:8]
if self.meta.id == self.name
else (self.name[:5] + "..." if len(self.name) > 8 else self.name)
)
def touch(self) -> None:
self.meta.accessed = str(datetime.today())
sys.stdout.write(
f"""{a.bold}{a.cyan}{_id}{a.end} """
f"""{a.style(", ".join(self.meta.spec),'dim')}\n"""
)
else:
self.tree()
def show(self) -> None:
_id = (
self.meta.id[:8]
if self.meta.id == self.name
else (self.name[:5] + "..." if len(self.name) > 8 else self.name)
)
sys.stdout.write(
f"""{a.bold}{a.cyan}{_id}{a.end} """
f"""{a.style(", ".join(self.meta.spec),'dim')}\n"""
)
def _tree_leaves(self, items: List[str], indent: str = "") -> str:
tree_chars = [""] * (len(items) - 1) + [""]
@ -981,6 +981,9 @@ class Viv:
else:
echo("re-using existing vivenv")
vivenv.touch()
vivenv.meta.write()
echo("see below for import statements\n")
if args.standalone:
@ -999,9 +1002,16 @@ class Viv:
sys.stdout.write("\n".join(self.vivenvs) + "\n")
elif len(self.vivenvs) == 0:
echo("no vivenvs setup")
elif args.full:
for _, vivenv in self.vivenvs.items():
vivenv.tree()
elif args.json:
sys.stdout.write(
json.dumps({k: v.meta.__dict__ for k, v in self.vivenvs.items()})
)
else:
for _, vivenv in self.vivenvs.items():
vivenv.show(args.verbose)
vivenv.show()
def exe(self, args: Namespace) -> None:
"""run python/pip in existing vivenv"""
@ -1014,7 +1024,7 @@ class Viv:
cmd = (
f"{pip_path} {' '.join(args.cmd)}"
if args.exe == "pip"
if args.subcmd == "pip"
else f"{python_path} {' '.join(args.cmd)}"
) + " ".join(args.rest)
@ -1028,8 +1038,10 @@ class Viv:
if not metadata_file.is_file():
error(f"Unable to find metadata for vivenv: {args.vivenv}", code=1)
vivenv.show(verbose=True)
if args.json:
sys.stdout.write(json.dumps(vivenv.meta.__dict__))
else:
vivenv.tree()
def _install_local_src(self, sha256: str, src: Path, cli: Path) -> None:
echo("updating local source copy of viv")
@ -1058,7 +1070,7 @@ class Viv:
def manage(self, args: Namespace) -> None:
"""manage viv itself"""
if args.cmd == "show":
if args.subcmd == "show":
if args.pythonpath:
if self.local and self.local_source:
sys.stdout.write(str(self.local_source.parent) + "\n")
@ -1074,7 +1086,7 @@ class Viv:
)
)
elif args.cmd == "update":
elif args.subcmd == "update":
sha256, next_version = self._get_new_version(args.ref)
if self.local_version == next_version:
@ -1093,7 +1105,7 @@ class Viv:
args.cli,
)
elif args.cmd == "install":
elif args.subcmd == "install":
sha256, downloaded_version = self._get_new_version(args.ref)
echo(f"Downloaded version: {downloaded_version}")
@ -1107,7 +1119,7 @@ class Viv:
):
self._install_local_src(sha256, args.src, args.cli)
elif args.cmd == "purge":
elif args.subcmd == "purge":
to_remove = []
if c._cache.is_dir():
to_remove.append(c._cache)
@ -1206,10 +1218,223 @@ class Viv:
else:
vivenv.create()
vivenv.install_pkgs()
vivenv.meta.write()
vivenv.touch()
vivenv.meta.write()
sys.exit(subprocess.run([vivenv.path / "bin" / bin, *args.rest]).returncode)
class Arg:
def __init__(self, *args: str, **kwargs: Any) -> None:
self.args = args
self.kwargs = kwargs
class Cli:
args = {
"list": [
Arg(
"-f",
"--full",
help="show full metadata for vivenvs",
action="store_true",
),
Arg(
"-q",
"--quiet",
help="suppress non-essential output",
action="store_true",
),
],
"shim": [
Arg(
"-f",
"--freeze",
help="freeze/resolve all dependencies",
action="store_true",
),
Arg(
"-o",
"--output",
help="path/to/output file",
type=Path,
metavar="<path>",
),
],
"remove": [Arg("vivenv", help="name/hash of vivenv", nargs="*")],
("exe|pip", "exe|python"): [Arg("vivenv", help="name/hash of vivenv")],
("list", "info"): [
Arg(
"--json",
help="name:metadata json for vivenvs ",
action="store_true",
default=False,
)
],
("freeze", "shim"): [
Arg(
"-p",
"--path",
help="generate line to add viv to sys.path",
choices=["abs", "rel"],
),
Arg(
"-s",
"--standalone",
help="generate standalone activation function",
action="store_true",
),
],
("run", "freeze", "shim"): [
Arg(
"-k",
"--keep",
help="preserve environment",
action="store_true",
),
Arg("reqs", help="requirements specifiers", nargs="*"),
Arg(
"-r",
"--requirements",
help="path/to/requirements.txt file",
metavar="<path>",
),
],
("run", "shim"): [
Arg("-b", "--bin", help="console_script/script to invoke", metavar="<bin>"),
],
("manage|purge", "manage|update", "manage|install"): [
Arg(
"-r",
"--ref",
help="git reference (branch/tag/commit)",
default="latest",
metavar="<ref>",
),
Arg(
"-s",
"--src",
help="path/to/source_file",
default=c.srcdefault,
metavar="<src>",
),
Arg(
"-c",
"--cli",
help="path/to/cli (symlink to src)",
default=Path.home() / ".local" / "bin" / "viv",
metavar="<cli>",
),
],
"manage|show": [
Arg(
"-p",
"--pythonpath",
help="show the path/to/install",
action="store_true",
)
],
("exe|python", "exe|pip"): [
Arg(
"cmd",
help="command to to execute",
nargs="*",
)
],
}
cmds = (
"list",
(
"exe",
dict(
pip=dict(help="run cmd with pip"),
python=dict(help="run cmd with python"),
),
),
"remove",
"freeze",
"info",
(
"manage",
dict(
show=dict(help="show current installation", aliases=["s"]),
install=dict(help="install fresh viv", aliases=["i"]),
update=dict(help="update viv version", aliases=["u"]),
purge=dict(help="remove traces of viv", aliases=["p"]),
),
),
"shim",
"run",
)
def __init__(self, viv: Viv) -> None:
self.viv = viv
self.parser = ArgumentParser(prog=viv.name, description=t.description)
self._cmd_arg_group_map()
self._make_parsers()
self._add_args()
def _cmd_arg_group_map(self) -> None:
self.cmd_arg_group_map = {}
for grp in self.args:
if isinstance(grp, str):
self.cmd_arg_group_map.setdefault(grp, []).append(grp)
else:
for cmd in grp:
self.cmd_arg_group_map.setdefault(cmd, []).append(grp)
def _make_parsers(self) -> None:
self.parsers = {**{grp: ArgumentParser(add_help=False) for grp in self.args}}
def _add_args(self) -> None:
for grp, args in self.args.items():
for arg in args:
self.parsers.get(grp).add_argument(*arg.args, **arg.kwargs)
def _validate_args(self, args: Namespace) -> None:
if args.func.__name__ in ("freeze", "shim", "run"):
if not args.reqs:
error("must specify a requirement", code=1)
if args.func.__name__ in ("freeze", "shim"):
if not self.viv.local_source and not (args.standalone or args.path):
warn(
"failed to find local copy of `viv` "
"make sure to add it to your PYTHONPATH "
"or consider using --path/--standalone"
)
if args.path and not self.viv.local_source:
error("No local viv found to import from", code=1)
if args.path and args.standalone:
error("-p/--path and -s/--standalone are mutually exclusive", code=1)
if args.func.__name__ == "manage":
if args.cmd == "install" and self.viv.local_source:
error(f"found existing viv installation at {self.viv.local_source}")
echo(
"use "
+ a.style("viv manage update", "bold")
+ " to modify current installation.",
style="red",
)
sys.exit(1)
if args.cmd == "update":
if not self.viv.local_source:
error(
a.style("viv manage update", "bold")
+ " should be used with an exisiting installation",
1,
)
if self.viv.git:
error(
a.style("viv manage update", "bold")
+ " shouldn't be used with a git-based installation",
1,
)
def _get_subcmd_parser(
self,
subparsers: _SubParsersAction[ArgumentParser],
@ -1217,8 +1442,13 @@ class Viv:
attr: Optional[str] = None,
**kwargs: Any,
) -> ArgumentParser:
aliases = kwargs.pop("aliases", [name[0]])
cmd = getattr(self, attr if attr else name)
# override for remove
if name == "remove":
aliases = ["rm"]
else:
aliases = kwargs.pop("aliases", [name[0]])
cmd = getattr(self.viv, attr if attr else name)
parser: ArgumentParser = subparsers.add_parser(
name,
help=cmd.__doc__.splitlines()[0],
@ -1230,252 +1460,48 @@ class Viv:
return parser
def _validate_args(self, args: Namespace) -> None:
if args.func.__name__ in ("freeze", "shim", "run"):
if not args.reqs:
error("must specify a requirement", code=1)
if args.func.__name__ in ("freeze", "shim"):
if not self.local_source and not (args.standalone or args.path):
warn(
"failed to find local copy of `viv` "
"make sure to add it to your PYTHONPATH "
"or consider using --path/--standalone"
)
if args.path and not self.local_source:
error("No local viv found to import from", code=1)
if args.path and args.standalone:
error("-p/--path and -s/--standalone are mutually exclusive", code=1)
if args.func.__name__ == "manage":
if args.cmd == "install" and self.local_source:
error(f"found existing viv installation at {self.local_source}")
echo(
"use "
+ a.style("viv manage update", "bold")
+ " to modify current installation.",
style="red",
)
sys.exit(1)
if args.cmd == "update":
if not self.local_source:
error(
a.style("viv manage update", "bold")
+ " should be used with an exisiting installation",
1,
)
if self.git:
error(
a.style("viv manage update", "bold")
+ " shouldn't be used with a git-based installation",
1,
)
def cli(self) -> None:
"""cli entrypoint"""
parser = ArgumentParser(prog=self.name, description=t.description)
parser.add_argument(
def run(self):
self.parser.add_argument(
"-V",
"--version",
action="version",
version=f"{a.bold}viv{a.end}, version {a.cyan}{__version__}{a.end}",
)
subparsers = parser.add_subparsers(
cmd_p = self.parser.add_subparsers(
metavar="<sub-cmd>", title="subcommands", required=True
)
p_vivenv_arg = ArgumentParser(add_help=False)
p_vivenv_arg.add_argument("vivenv", help="name/hash of vivenv")
p_list = self._get_subcmd_parser(subparsers, "list")
p_list.add_argument(
"-v",
"--verbose",
help="show full metadata for vivenvs",
default=False,
action="store_true",
)
p_list.add_argument(
"-q",
"--quiet",
help="suppress non-essential output",
action="store_true",
default=False,
)
for cmd in self.cmds:
if isinstance(cmd, tuple):
cmd, subcmds = cmd
subcmd_p = self._get_subcmd_parser(cmd_p, cmd)
subcmd_cmd_p = subcmd_p.add_subparsers(
title="subcommand", metavar="<sub-cmd>", required=True
)
for subcmd, kwargs in subcmds.items():
subcmd_cmd_p.add_parser(
subcmd,
parents=[
self.parsers.get(k)
for k in self.cmd_arg_group_map[f"{cmd}|{subcmd}"]
],
**kwargs,
).set_defaults(func=getattr(self.viv, cmd), subcmd=subcmd)
p_exe = self._get_subcmd_parser(
subparsers,
"exe",
)
p_exe_sub = p_exe.add_subparsers(
title="subcommand", metavar="<sub-cmd>", required=True
)
p_exe_shared = ArgumentParser(add_help=False)
p_exe_shared.add_argument(
"cmd",
help="command to to execute",
nargs="*",
)
p_exe_sub.add_parser(
"python",
help="run command with python",
parents=[p_vivenv_arg, p_exe_shared],
).set_defaults(func=self.exe, exe="python")
p_exe_sub.add_parser(
"pip", help="run command with pip", parents=[p_vivenv_arg, p_exe_shared]
).set_defaults(func=self.exe, exe="pip")
p_remove = self._get_subcmd_parser(
subparsers,
"remove",
aliases=["rm"],
)
p_remove.add_argument("vivenv", help="name/hash of vivenv", nargs="*")
p_freeze_shim_shared = ArgumentParser(add_help=False)
p_freeze_shim_shared.add_argument(
"-p",
"--path",
help="generate line to add viv to sys.path",
choices=["abs", "rel"],
)
p_freeze_shim_shared.add_argument(
"-r",
"--requirements",
help="path/to/requirements.txt file",
metavar="<path>",
)
p_freeze_shim_shared.add_argument(
"-k",
"--keep",
help="preserve environment",
action="store_true",
)
p_freeze_shim_shared.add_argument(
"-s",
"--standalone",
help="generate standalone activation function",
action="store_true",
)
p_freeze_shim_shared.add_argument(
"reqs", help="requirements specifiers", nargs="*"
)
self._get_subcmd_parser(subparsers, "freeze", parents=[p_freeze_shim_shared])
self._get_subcmd_parser(
subparsers,
"info",
parents=[p_vivenv_arg],
)
p_manage_shared = ArgumentParser(add_help=False)
p_manage_shared.add_argument(
"-r",
"--ref",
help="git reference (branch/tag/commit)",
default="latest",
metavar="<ref>",
)
p_manage_shared.add_argument(
"-s",
"--src",
help="path/to/source_file",
default=c.srcdefault,
metavar="<src>",
)
p_manage_shared.add_argument(
"-c",
"--cli",
help="path/to/cli (symlink to src)",
default=Path.home() / ".local" / "bin" / "viv",
metavar="<cli>",
)
p_manage_sub = self._get_subcmd_parser(
subparsers,
name="manage",
).add_subparsers(title="subcommand", metavar="<sub-cmd>", required=True)
p_manage_sub.add_parser(
"install", help="install viv", aliases="i", parents=[p_manage_shared]
).set_defaults(func=self.manage, cmd="install")
p_manage_sub.add_parser(
"update",
help="update viv version",
aliases="u",
parents=[p_manage_shared],
).set_defaults(func=self.manage, cmd="update")
(
p_manage_show := p_manage_sub.add_parser(
"show", help="show current installation info", aliases="s"
)
).set_defaults(func=self.manage, cmd="show")
p_manage_show.add_argument(
"-p", "--pythonpath", help="show the path/to/install", action="store_true"
)
p_manage_sub.add_parser(
"purge", help="remove traces of viv", aliases="p", parents=[p_manage_shared]
).set_defaults(func=self.manage, cmd="purge")
p_shim = self._get_subcmd_parser(
subparsers, "shim", parents=[p_freeze_shim_shared]
)
p_shim.add_argument(
"-f",
"--freeze",
help="freeze/resolve all dependencies",
action="store_true",
)
p_shim.add_argument(
"-o",
"--output",
help="path/to/output file",
type=Path,
metavar="<path>",
)
p_shim.add_argument(
"-b", "--bin", help="console_script/script to invoke", metavar="<bin>"
)
p_run = self._get_subcmd_parser(subparsers, "run")
p_run.add_argument(
"-r",
"--requirements",
help="path/to/requirements.txt file",
metavar="<path>",
)
p_run.add_argument(
"-k",
"--keep",
help="preserve environment",
action="store_true",
)
p_run.add_argument("reqs", help="requirements specifiers", nargs="*")
p_run.add_argument(
"-b", "--bin", help="console_script/script to invoke", metavar="<bin>"
)
else:
self._get_subcmd_parser(
cmd_p,
cmd,
parents=[self.parsers.get(k) for k in self.cmd_arg_group_map[cmd]],
)
if "--" in sys.argv:
i = sys.argv.index("--")
args = parser.parse_args(sys.argv[1:i])
args = self.parser.parse_args(sys.argv[1:i])
args.rest = sys.argv[i + 1 :]
else:
args = parser.parse_args()
args = self.parser.parse_args()
args.rest = []
self._validate_args(args)
@ -1486,7 +1512,7 @@ class Viv:
def main() -> None:
viv = Viv()
viv.cli()
Cli(viv).run()
if __name__ == "__main__":