mirror of
https://github.com/daylinmorgan/viv.git
synced 2024-11-12 20:23:15 -06:00
Compare commits
13 commits
d4d304793c
...
cca5bf4866
Author | SHA1 | Date | |
---|---|---|---|
cca5bf4866 | |||
80ae99c754 | |||
3a85fe4f3a | |||
ca67431a79 | |||
0b26c8cb48 | |||
c5d9d8cb65 | |||
b349cef943 | |||
85689a0788 | |||
c999b3a123 | |||
aaa63467b9 | |||
e3ebca86d2 | |||
034403b7a8 | |||
9aea8acc53 |
15 changed files with 687 additions and 178 deletions
27
.github/workflows/docs.yml
vendored
Normal file
27
.github/workflows/docs.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*.*.*"]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-docs:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Add Source to Docs
|
||||
run: cp ./src/viv/viv.py docs/viv.py
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# publish_dir: ./site
|
||||
publish_dir: ./docs
|
22
Makefile
22
Makefile
|
@ -10,26 +10,20 @@ types: ## run mypy
|
|||
bump-version: ## update version and tag commit
|
||||
@echo "bumping to version => $(VERSION)"
|
||||
@sed -i 's/__version__ = ".*"/__version__ = "$(VERSION)"/g' src/viv/viv.py
|
||||
@sed 's/--branch .* g/--branch $(VERSION) g/g' README.md
|
||||
@git add src/viv/viv.py && git commit -m "chore: bump version"
|
||||
@sed -i 's/install -r .*/install -r v$(VERSION)/g' README.md
|
||||
@git add src/viv/viv.py README.md && git commit -m "chore: bump version" --no-verify
|
||||
@git tag v$(VERSION)
|
||||
|
||||
venv: ## generate environment
|
||||
pdm install
|
||||
|
||||
install: ## symlink to $PREFIX
|
||||
ln -sf $(shell pwd)/src/viv/viv.py $(PREFIX)/viv
|
||||
# TAPES = demo freeze list-info-remove
|
||||
# GIFS := $(foreach n, $(TAPES), docs/$(n).gif)
|
||||
# docs: $(GIFS) ## generate usage examples
|
||||
|
||||
uninstall: ## delete $(PREFIX)/viv
|
||||
rm $(PREFIX)/viv
|
||||
|
||||
TAPES = demo freeze list-info-remove
|
||||
GIFS := $(foreach n, $(TAPES), docs/$(n).gif)
|
||||
docs: $(GIFS) ## generate usage examples
|
||||
|
||||
docs/%.gif: docs/%.tape
|
||||
viv rm $$(viv l -q)
|
||||
cd docs; vhs < $*.tape
|
||||
# docs/%.gif: docs/%.tape
|
||||
# viv rm $$(viv l -q)
|
||||
# cd docs; vhs < $*.tape
|
||||
|
||||
clean: ## remove build artifacts
|
||||
rm -rf {build,dist}
|
||||
|
|
34
README.md
34
README.md
|
@ -1,9 +1,8 @@
|
|||
# Viv
|
||||
# viv
|
||||
|
||||
<!-- PROJECT DEMO -->
|
||||
<div align="center">
|
||||
<a href="https://github.com/daylinmorgan/viv">
|
||||
<img src="https://raw.githubusercontent.com/daylinmorgan/viv/main/docs/demo.gif" alt="Logo" width=600 >
|
||||
<img src="https://raw.githubusercontent.com/daylinmorgan/viv/main/assets/logo.svg" alt="Logo" width=500 >
|
||||
</a>
|
||||
<p align="center">
|
||||
viv isn't venv
|
||||
|
@ -11,8 +10,6 @@
|
|||
</div>
|
||||
<br />
|
||||
|
||||
See [usage](https://github.com/daylinmorgan/viv/blob/main/docs/usage.md) for more demo gifs.
|
||||
|
||||
---
|
||||
|
||||
Python is a great choice to quickly prototype or accomplish small tasks in scripts.
|
||||
|
@ -26,27 +23,22 @@ prior to loading of any of the external modules.
|
|||
These `venvs` can be identified by name or by their specification.
|
||||
In any case they will be re-used across scripts (and generated on-demand, if needed).
|
||||
|
||||
**Importantly**, `viv` will remove your user site directory (`python -m 'import site;print(site.USER_SITE)'`),
|
||||
to ensure the script isn't using anything outside the standard library and the `viv`-managed `venv`.
|
||||
**Importantly**, `viv` will also remove your user site directory.
|
||||
(view with: `python -m 'import site;print(site.USER_SITE)'`).
|
||||
|
||||
## Setup
|
||||
|
||||
### Manual (Recommended)
|
||||
|
||||
Start by cloning the repo and symlinking the script for access to the CLI.
|
||||
By default it will symlink `./src/viv/viv.py` to `~/bin/viv`.
|
||||
You can set `PREFIX` to symlink to a different location.
|
||||
Run the below command to install `viv`.
|
||||
|
||||
```sh
|
||||
git clone --depth 1 --branch v22.12a3 git@github.com:daylinmorgan/viv.git ~/.viv
|
||||
cd ~/.viv
|
||||
make install # or PREFIX=~/.local/bin make install
|
||||
python3 <(curl -fsSL gh.dayl.in/viv/viv.py) manage install -r v23.5a1
|
||||
```
|
||||
|
||||
Place this directory on the python path in your rc file.
|
||||
To access `viv` from within scripts you should add it's location to your `PYTHONPATH`.
|
||||
By default `viv` will be installed to `$XDG_DATA_HOME/viv` or `~/.local/share/viv` you can customize this with `--src`.
|
||||
|
||||
```sh
|
||||
export PYTHONPATH="$PYTHONPATH:$HOME/.viv/src"
|
||||
export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
|
||||
```
|
||||
|
||||
Advanced users may recognize that principally,
|
||||
|
@ -72,7 +64,7 @@ to automate `vivenv` creation and installation of dependencies.
|
|||
__import__("viv").use("click")
|
||||
```
|
||||
|
||||
To remove all `vivenvs`:
|
||||
To remove all `vivenvs` you can use the below command:
|
||||
|
||||
```sh
|
||||
viv remove $(viv list -q)
|
||||
|
@ -80,9 +72,7 @@ viv remove $(viv list -q)
|
|||
|
||||
# Standalone Viv
|
||||
|
||||
*Requires* `python>=3.8`
|
||||
|
||||
Supposing you want to increase the portability of your script while still employing `viv`.
|
||||
Supposing you want to increase the portability of your script while still employing the principles of `viv`.
|
||||
|
||||
The below function can be freely pasted at the top of your scripts and requires
|
||||
no modification of your PYTHONPATH or import of additional modules (including downloading/installing `viv`).
|
||||
|
@ -117,8 +107,6 @@ def _viv_use(*pkgs: str, track_exe: bool = False, name: str = "") -> None:
|
|||
_viv_use("markdown-it-py==2.2.0", "mdurl==0.1.2", "Pygments==2.14.0", "rich==13.3.2") # noqa
|
||||
# fmt: on
|
||||
# >>>>> code golfed with <3
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Alternatives
|
||||
|
|
323
assets/logo.svg
Normal file
323
assets/logo.svg
Normal file
|
@ -0,0 +1,323 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
id="svg2233"
|
||||
viewBox="0 0 286.80808 184.19898"
|
||||
version="1.0"
|
||||
xml:space="preserve"
|
||||
width="286.80807"
|
||||
height="184.19897"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
|
||||
id="defs2235"><linearGradient
|
||||
id="linearGradient7463"><stop
|
||||
id="stop7465"
|
||||
style="stop-color:#d1e3e2;stop-opacity:.54680"
|
||||
offset="0" /><stop
|
||||
id="stop3853"
|
||||
style="stop-color:#eeeeee;stop-opacity:.61569"
|
||||
offset=".5" /><stop
|
||||
id="stop7467"
|
||||
style="stop-color:#d1e3e2;stop-opacity:.54510"
|
||||
offset="1" /></linearGradient><filter
|
||||
id="filter3662"
|
||||
x="-0.0066908929"
|
||||
y="-0.044310786"
|
||||
width="1.0133818"
|
||||
height="1.0886216"><feGaussianBlur
|
||||
id="feGaussianBlur3664"
|
||||
stdDeviation="0.98997704" /></filter><radialGradient
|
||||
id="radialGradient2603"
|
||||
fx="272.03"
|
||||
fy="553.58002"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cy="707.21997"
|
||||
cx="271.98999"
|
||||
gradientTransform="matrix(0.56638235,-0.00114952,1.732559e-4,0.0853702,23.42315,270.93592)"
|
||||
r="210"><stop
|
||||
id="stop11688"
|
||||
style="stop-color:#000000;stop-opacity:.48768"
|
||||
offset="0" /><stop
|
||||
id="stop11690"
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1" /></radialGradient><linearGradient
|
||||
id="linearGradient2605"
|
||||
y2="782.23999"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="287.59"
|
||||
gradientTransform="matrix(1.157,0,0,1.2361,-49.276,-172.53)"
|
||||
y1="739.82001"
|
||||
x1="287.59"><stop
|
||||
id="stop3673"
|
||||
style="stop-color:#000000;stop-opacity:.10345"
|
||||
offset="0" /><stop
|
||||
id="stop3675"
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
id="linearGradient2669"
|
||||
y2="775.28003"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="255.53"
|
||||
gradientTransform="matrix(0.49986408,0,0,0.49986408,22.394217,-45.390032)"
|
||||
y1="488.28"
|
||||
x1="292.42001"><stop
|
||||
id="stop3879"
|
||||
style="stop-color:#ffffff;stop-opacity:.43429"
|
||||
offset="0" /><stop
|
||||
id="stop3881"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
id="linearGradient2672"
|
||||
y2="460.76001"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="128.5"
|
||||
gradientTransform="matrix(0.49986408,0,0,0.49986408,22.394217,-45.318973)"
|
||||
y1="405.76001"
|
||||
x1="440.75" /><linearGradient
|
||||
id="linearGradient2675"
|
||||
y2="226.81"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="371.47"
|
||||
gradientTransform="matrix(-0.68684145,0,0,-0.68684145,349.40033,489.25029)"
|
||||
y1="401.95999"
|
||||
x1="181.42" /><linearGradient
|
||||
id="linearGradient2678"
|
||||
y2="460.76001"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="128.5"
|
||||
gradientTransform="matrix(0.49986408,0,0,0.49986408,19.707478,97.509558)"
|
||||
y1="405.76001"
|
||||
x1="440.75" /><linearGradient
|
||||
id="linearGradient2683"
|
||||
y2="226.81"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="371.47"
|
||||
gradientTransform="matrix(-0.50539246,0.71869007,0,-0.68010507,280.36657,219.24055)"
|
||||
y1="401.95999"
|
||||
x1="181.42" /><linearGradient
|
||||
id="linearGradient2686"
|
||||
y2="226.81"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="371.47"
|
||||
gradientTransform="matrix(-0.13654685,-0.11142041,0,-0.68684145,286.98927,501.88457)"
|
||||
y1="401.95999"
|
||||
x1="181.42" /><linearGradient
|
||||
id="linearGradient2689"
|
||||
y2="226.81"
|
||||
xlink:href="#linearGradient7463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="371.47"
|
||||
gradientTransform="matrix(-0.68684145,0,0,-0.68684145,364.94802,462.39001)"
|
||||
y1="401.95999"
|
||||
x1="181.42" /><linearGradient
|
||||
id="linearGradient2795"><stop
|
||||
style="stop-color:#b8b8b8;stop-opacity:0.49803922"
|
||||
offset="0"
|
||||
id="stop2797" /><stop
|
||||
style="stop-color:#7f7f7f;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop2799" /></linearGradient><linearGradient
|
||||
id="linearGradient2787"><stop
|
||||
style="stop-color:#7f7f7f;stop-opacity:0.5"
|
||||
offset="0"
|
||||
id="stop2789" /><stop
|
||||
style="stop-color:#7f7f7f;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop2791" /></linearGradient><linearGradient
|
||||
id="linearGradient3676"><stop
|
||||
style="stop-color:#b2b2b2;stop-opacity:0.5"
|
||||
offset="0"
|
||||
id="stop3678" /><stop
|
||||
style="stop-color:#b3b3b3;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop3680" /></linearGradient><linearGradient
|
||||
id="linearGradient3236"><stop
|
||||
style="stop-color:#f4f4f4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3244" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3240" /></linearGradient><linearGradient
|
||||
id="linearGradient4671"><stop
|
||||
style="stop-color:#ffd43b;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4673" /><stop
|
||||
style="stop-color:#ffe873;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4675" /></linearGradient><linearGradient
|
||||
id="linearGradient4689"><stop
|
||||
style="stop-color:#5a9fd4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4691" /><stop
|
||||
style="stop-color:#306998;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4693" /></linearGradient><linearGradient
|
||||
x1="224.23996"
|
||||
y1="144.75717"
|
||||
x2="-65.308502"
|
||||
y2="144.75717"
|
||||
id="linearGradient2987"
|
||||
xlink:href="#linearGradient4671"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(100.2702,99.61116)" /><linearGradient
|
||||
x1="172.94208"
|
||||
y1="77.475983"
|
||||
x2="26.670298"
|
||||
y2="76.313133"
|
||||
id="linearGradient2990"
|
||||
xlink:href="#linearGradient4689"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(100.2702,99.61116)" /><linearGradient
|
||||
x1="224.23996"
|
||||
y1="144.75717"
|
||||
x2="-65.308502"
|
||||
y2="144.75717"
|
||||
id="linearGradient2255"
|
||||
xlink:href="#linearGradient4671"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)" /><linearGradient
|
||||
x1="172.94208"
|
||||
y1="76.176224"
|
||||
x2="26.670298"
|
||||
y2="76.313133"
|
||||
id="linearGradient2258"
|
||||
xlink:href="#linearGradient4689"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)" /><radialGradient
|
||||
cx="61.518883"
|
||||
cy="132.28575"
|
||||
r="29.036913"
|
||||
fx="61.518883"
|
||||
fy="132.28575"
|
||||
id="radialGradient2801"
|
||||
xlink:href="#linearGradient2795"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.177966,0,108.7434)" /><linearGradient
|
||||
x1="150.96111"
|
||||
y1="192.35176"
|
||||
x2="112.03144"
|
||||
y2="137.27299"
|
||||
id="linearGradient1475"
|
||||
xlink:href="#linearGradient4671"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)" /><linearGradient
|
||||
x1="26.648937"
|
||||
y1="20.603781"
|
||||
x2="135.66525"
|
||||
y2="114.39767"
|
||||
id="linearGradient1478"
|
||||
xlink:href="#linearGradient4689"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.562541,0,0,0.567972,-9.399749,-5.305317)" /><radialGradient
|
||||
cx="61.518883"
|
||||
cy="132.28575"
|
||||
r="29.036913"
|
||||
fx="61.518883"
|
||||
fy="132.28575"
|
||||
id="radialGradient1480"
|
||||
xlink:href="#linearGradient2795"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.382716e-8,-0.296405,1.43676,4.683673e-7,-128.544,150.5202)" /></defs><g
|
||||
id="layer4"
|
||||
transform="translate(-34.19,-165.32103)"><path
|
||||
id="path1648"
|
||||
style="display:none;fill:none;stroke:#ffffff;stroke-width:1px"
|
||||
d="m 255.17,667.94 c 105.62,-29.82 164.49,-18.7 304.85,-6.95 82.52,6.91 180.3,-11.42 237.14,-8.54 95.12,4.81 189.98,28.25 321.14,20.54" /><path
|
||||
id="path11576"
|
||||
style="fill:url(#radialGradient2603);fill-rule:evenodd;stroke-width:0.710589"
|
||||
d="M 177.59404,304.59654 C 98.434384,304.59654 34.19,318.7799 34.19,329.71587 34.1914,340.64474 98.434384,349.52 177.59404,349.52 c 79.15965,0 143.40404,-8.87526 143.40404,-19.80413 0,-10.93597 -64.24439,-25.11933 -143.40404,-25.11933 z m -60.86198,3.58848 h 115.25759 c 1.96834,0.22028 5.15888,0.90955 6.95667,2.70734 l 24.96301,19.31382 c 1.83332,1.83332 0.98061,4.78227 -1.91859,4.78227 H 97.503511 c -2.657604,0 -4.37723,-2.55812 -3.538734,-4.12142 L 111.16104,311.0629 c 1.5633,-1.86174 2.83525,-2.74998 5.57102,-2.87788 z" /><path
|
||||
id="path3669"
|
||||
style="fill:url(#linearGradient2605);filter:url(#filter3662)"
|
||||
transform="matrix(0.49986408,0,0,0.49986408,22.394217,-45.390034)"
|
||||
d="m 169.09,708.78 c -6.32,0.32 -9.29,2.55 -12.9,7.16 l -39.85,48.94 c -1.93,3.85 2.1,10.21 8.25,10.21 h 380.72 c 6.71,0 8.64,-7.31 4.41,-11.84 l -57.78,-47.78 c -4.16,-4.46 -11.54,-6.14 -16.1,-6.69 h -9.75 c 2.65,0.85 5.26,2.09 7.13,3.97 l 49.94,38.66 c 3.66,3.66 1.98,9.56 -3.82,9.56 H 150.28 c -5.32,0 -8.79,-5.13 -7.12,-8.25 l 34.43,-39.6 c 1.66,-1.97 3.15,-3.39 5,-4.34 z" /><path
|
||||
id="path3660"
|
||||
style="fill:#000000;fill-opacity:0.068571;filter:url(#filter3662)"
|
||||
transform="matrix(0.49986408,0,0,0.49986408,22.394217,-45.390034)"
|
||||
d="m 176.84,714 c -1.54,0.96 -2.86,2.27 -4.31,4 l -35.72,41.06 c -1.73,3.24 1.86,8.57 7.38,8.56 H 485.5 c 6.01,0 7.77,-6.1 3.97,-9.9 l -4.66,-3.6 c 1.04,3.31 -0.96,6.85 -5.47,6.85 H 150.28 c -5.32,0 -8.79,-5.13 -7.12,-8.25 z" /><path
|
||||
id="path3873"
|
||||
d="m 266.56693,326.90194 h -6.3882 l 5.96185,-130.62764 h 6.3882 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3871"
|
||||
d="M 99.500268,329.10477 H 93.119175 V 196.01138 h 6.381093 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3867"
|
||||
d="m 114.54344,310.55128 c -2.65049,-0.0995 -4.74673,-0.52584 -5.39337,-4.1001 l -15.83193,19.39909 c -0.390824,6.17502 0.483201,8.12914 4.213795,7.54646 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3869"
|
||||
d="m 234.71832,310.56549 c 2.60075,-0.0924 5.30099,-2.416 5.08782,-5.50707 l 26.83185,20.10968 c -0.44767,6.8714 -1.76937,9.05291 -3.90824,8.73315 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3863"
|
||||
d="m 111.01892,169.85601 c 0.0782,-1.26911 -2.01097,-1.64359 -2.94894,-0.0185 L 95.002237,190.6109 c -1.009037,1.65568 -1.819109,2.40179 -1.819109,5.72735 l 3.389511,-2.99158 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3865"
|
||||
d="m 241.19178,170.08553 c -0.46898,-1.181 1.98966,-1.58248 3.34688,-0.73901 l 25.21882,20.3193 c 1.48513,1.25774 2.48706,2.8992 2.59365,6.30293 l -3.78034,-2.6434 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3857"
|
||||
d="m 115.53827,306.08878 h -6.38109 V 170.07487 h 6.38109 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3859"
|
||||
d="m 239.8843,305.9893 c 0,1.94701 -2.54391,4.76805 -5.89789,4.76805 H 114.72109 c -3.26871,0 -5.53549,-1.06588 -5.53549,-4.76805 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3861"
|
||||
d="m 239.95536,306.08878 h -6.38109 V 170.07487 h 6.38109 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3855"
|
||||
d="m 245.44822,170.0834 c -1.81201,-1.53914 -6.69376,-4.76237 -10.04063,-4.76237 H 114.76373 c -3.07685,0 -5.08782,2.03939 -6.85719,4.76237 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3849"
|
||||
d="M 230.37661,307.51706 H 117.73399 c -2.37337,0 -5.09493,-3.05553 -5.09493,-5.22283 V 171.24024 c 0,-1.09147 2.13888,-3.62046 3.69507,-3.61832 l 116.2311,0.16556 c 2.0465,0 3.3753,2.2341 3.3753,3.62969 V 303.2386 c 0,2.27389 -1.9257,4.24933 -5.56392,4.27775 z"
|
||||
style="fill:url(#linearGradient2689);stroke-width:0.710589" /><path
|
||||
id="path3845"
|
||||
style="fill:url(#linearGradient2686);stroke-width:0.710589"
|
||||
d="m 262.15417,327.49884 -24.10319,-19.1646 c -1.208,-0.95929 -0.81718,-5.03808 -0.81718,-5.03808 V 172.29191 c 0,-3.14365 5.68472,-4.25501 7.5962,-2.71232 l 25.33962,20.47705 c 1.52777,1.23643 2.36626,4.13563 2.36626,6.90693 l -5.80551,127.2026 c 0,5.40759 -2.23125,5.63498 -4.5762,3.33267 z" /><path
|
||||
id="path3837"
|
||||
style="fill:url(#linearGradient2683);stroke-width:0.710589"
|
||||
d="m 108.77346,312.39881 -12.001856,12.85456 c -2.138874,2.2881 -3.496099,8.60524 -3.496099,3.83008 l -0.1208,-131.33112 c -0.0071,-0.93798 0.774542,-4.15695 1.840426,-5.83394 l 13.259599,-20.81317 c 0.67506,-1.05238 3.22607,-1.03959 3.22607,1.69121 v 133.21418 c 0,2.24547 -1.71252,5.11625 -2.70734,6.3882 z" /><path
|
||||
id="path7416"
|
||||
d="m 272.53588,196.45195 c 0,-2.11045 -0.87402,-4.87465 -2.38758,-6.3882 H 95.371743 c -1.094307,1.49934 -2.238356,3.98641 -2.238356,6.3882 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3835"
|
||||
d="m 265.72844,329.05503 c 0,3.82297 -1.50645,5.94763 -3.6098,5.94763 H 97.801959 c -3.403723,0 -4.668572,-2.62208 -4.668572,-6.0329 z"
|
||||
style="fill:#9ab7c1;stroke-width:0.710589" /><path
|
||||
id="path3831"
|
||||
d="m 116.73917,308.18502 h 115.25048 c 1.96834,0.22028 5.15888,0.90245 6.95667,2.70024 l 24.96301,19.32803 c 1.82621,1.83332 0.98061,4.78226 -1.91149,4.78226 H 97.510617 c -2.66471,0 -4.391442,-2.57233 -3.552946,-4.12852 l 17.203369,-19.78991 c 1.5633,-1.86885 2.84236,-2.7642 5.57813,-2.8921 z"
|
||||
style="fill:url(#linearGradient2678);stroke-width:0.710589" /><path
|
||||
id="rect7391"
|
||||
d="M 262.18259,332.01108 H 98.56229 c -2.373369,0 -3.474782,-0.68927 -3.474782,-2.84947 V 196.72908 c 0,-1.09431 0.696377,-2.24547 2.259674,-2.24547 l 171.657068,0.16344 c 0.98062,0.007 2.50128,0.3624 2.50128,1.75516 l -5.7842,131.33112 c 0,2.26678 0.10659,4.24222 -3.53874,4.27775 z"
|
||||
style="fill:url(#linearGradient2675);stroke-width:0.710589" /><g
|
||||
id="g2303"
|
||||
transform="matrix(1.0141096,0,0,1.0141096,120.25928,195.81719)"><path
|
||||
id="path1948"
|
||||
style="fill:url(#linearGradient1478);fill-opacity:1"
|
||||
d="m 60.510156,6.3979729 c -4.583653,0.021298 -8.960939,0.4122177 -12.8125,1.09375 C 36.35144,9.4962267 34.291407,13.691825 34.291406,21.429223 v 10.21875 h 26.8125 v 3.40625 h -26.8125 -10.0625 c -7.792459,0 -14.6157592,4.683717 -16.7500002,13.59375 -2.46182,10.212966 -2.5710151,16.586023 0,27.25 1.9059283,7.937852 6.4575432,13.593748 14.2500002,13.59375 h 9.21875 v -12.25 c 0,-8.849902 7.657144,-16.656248 16.75,-16.65625 h 26.78125 c 7.454951,0 13.406253,-6.138164 13.40625,-13.625 v -25.53125 c 0,-7.266339 -6.12998,-12.7247775 -13.40625,-13.9375001 -4.605987,-0.7667253 -9.385097,-1.1150483 -13.96875,-1.09375 z m -14.5,8.2187501 c 2.769547,0 5.03125,2.298646 5.03125,5.125 -2e-6,2.816336 -2.261703,5.09375 -5.03125,5.09375 -2.779476,-1e-6 -5.03125,-2.277415 -5.03125,-5.09375 -1e-6,-2.826353 2.251774,-5.125 5.03125,-5.125 z" /><path
|
||||
id="path1950"
|
||||
style="fill:url(#linearGradient1475);fill-opacity:1"
|
||||
d="m 91.228906,35.054223 v 11.90625 c 0,9.230755 -7.825895,16.999999 -16.75,17 h -26.78125 c -7.335833,0 -13.406249,6.278483 -13.40625,13.625 v 25.531247 c 0,7.26634 6.318588,11.54032 13.40625,13.625 8.487331,2.49561 16.626237,2.94663 26.78125,0 6.750155,-1.95439 13.406253,-5.88761 13.40625,-13.625 V 92.897973 h -26.78125 v -3.40625 h 26.78125 13.406254 c 7.79246,0 10.69625,-5.435408 13.40624,-13.59375 2.79933,-8.398886 2.68022,-16.475776 0,-27.25 -1.92578,-7.757441 -5.60387,-13.59375 -13.40624,-13.59375 z m -15.0625,64.65625 c 2.779478,3e-6 5.03125,2.277417 5.03125,5.093747 -2e-6,2.82635 -2.251775,5.125 -5.03125,5.125 -2.76955,0 -5.03125,-2.29865 -5.03125,-5.125 2e-6,-2.81633 2.261697,-5.093747 5.03125,-5.093747 z" /><path
|
||||
id="path1894"
|
||||
style="opacity:0.44382;fill:url(#radialGradient1480);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
transform="matrix(0.73406,0,0,0.809524,16.24958,27.00935)"
|
||||
d="m 110.46717,132.28575 a 48.948285,8.6066792 0 1 1 -97.896571,0 48.948285,8.6066792 0 1 1 97.896571,0 z" /></g><path
|
||||
id="rect7393"
|
||||
style="fill:url(#linearGradient2672);stroke-width:0.710589"
|
||||
d="m 115.10481,165.35798 c -2.95605,0 -4.89596,1.63364 -5.74867,2.88997 l -13.749902,21.88686 c -0.753225,1.30748 -0.09238,2.24546 1.129837,2.24546 l 170.733305,0.24871 c 2.26678,-0.17765 3.29003,-0.86692 0.0426,-3.33977 l -24.7285,-20.29159 c -1.7978,-1.80135 -4.60462,-3.63964 -8.10783,-3.63964 z" /><path
|
||||
id="path3875"
|
||||
d="M 262.18259,332.01108 H 98.56229 c -2.373369,0 -3.474782,-0.68927 -3.474782,-2.84947 v -76.63706 c 48.163742,12.18661 119.151622,17.80737 173.504602,-1.47802 l -2.87078,76.6868 c 0,2.26678 0.10659,4.24222 -3.53874,4.27775 z"
|
||||
style="fill:url(#linearGradient2669);stroke-width:0.710589" /></g><metadata
|
||||
id="metadata49"><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
|
||||
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" /><dc:publisher><cc:Agent
|
||||
rdf:about="http://openclipart.org/"><dc:title>Openclipart</dc:title></cc:Agent></dc:publisher><dc:date>2007-10-31T17:22:52</dc:date><dc:description>A strip of Poll box by BenBois</dc:description><dc:source>https://openclipart.org/detail/7782/transparent-cube-by-molumen</dc:source><dc:creator><cc:Agent><dc:title>molumen</dc:title></cc:Agent></dc:creator><dc:subject><rdf:Bag><rdf:li>box</rdf:li><rdf:li>cube</rdf:li><rdf:li>glass</rdf:li><rdf:li>plexiglass</rdf:li><rdf:li>remix</rdf:li><rdf:li>shape</rdf:li><rdf:li>transparent</rdf:li></rdf:Bag></dc:subject></cc:Work><cc:License
|
||||
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/"><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /></cc:License></rdf:RDF></metadata></svg>
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/demo.gif
BIN
docs/demo.gif
Binary file not shown.
Before Width: | Height: | Size: 757 KiB |
11
docs/demo.py
11
docs/demo.py
|
@ -1,11 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
__import__("viv").use("pyfiglet==0.8.post1") # noqa
|
||||
|
||||
from pyfiglet import Figlet
|
||||
|
||||
if __name__ == "__main__":
|
||||
f = Figlet(font="slant")
|
||||
figtxt = f.renderText("viv").splitlines()
|
||||
figtxt[-2] += " isn't venv!"
|
||||
print("\n".join(figtxt))
|
|
@ -1,23 +0,0 @@
|
|||
Set Height 750
|
||||
Set Width 1500
|
||||
Set Theme "Catppuccin Mocha"
|
||||
Output ./demo.gif
|
||||
|
||||
Type "viv list"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "python ../examples/cli.py --help"
|
||||
Enter
|
||||
Sleep 10s
|
||||
Type "viv list"
|
||||
Enter
|
||||
Sleep 3s
|
||||
Type "viv info 841"
|
||||
Enter
|
||||
Sleep 3s
|
||||
Type "python ../examples/cli.py hello 'prospective viv user!'"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "python ../examples/cli.py goodbye 'prospective viv user!'"
|
||||
Enter
|
||||
Sleep 2s
|
|
@ -1,23 +0,0 @@
|
|||
Set Height 750
|
||||
Set Width 1500
|
||||
Set Theme "Catppuccin Mocha"
|
||||
Output ./freeze.gif
|
||||
|
||||
Type "viv freeze --help"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "viv list"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "viv freeze requests bs4"
|
||||
Enter
|
||||
Sleep 7s
|
||||
Type "viv list"
|
||||
Enter
|
||||
Sleep 3s
|
||||
Type "viv freeze requests bs4 --keep --path relative"
|
||||
Enter
|
||||
Sleep 7s
|
||||
Type "viv list"
|
||||
Enter
|
||||
Sleep 5s
|
9
docs/index.html
Normal file
9
docs/index.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="canonical" href="https://github.com/daylinmorgan/viv"/>
|
||||
<meta name="robots" content="noindex">
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="refresh" content="0; url=https://github.com/daylinmorgan/viv"/>
|
||||
</head>
|
||||
</html>
|
|
@ -1,30 +0,0 @@
|
|||
Set Height 750
|
||||
Set Width 1500
|
||||
Set Theme "Catppuccin Mocha"
|
||||
Output ./list-info-remove.gif
|
||||
|
||||
Type "cat demo.py"
|
||||
Enter
|
||||
Sleep 500ms
|
||||
Type "python demo.py"
|
||||
Enter
|
||||
Sleep 3s
|
||||
Type "viv list -h"
|
||||
Enter
|
||||
Sleep 500ms
|
||||
Type "viv list -q"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Type "viv info -h"
|
||||
Enter
|
||||
Sleep 500ms
|
||||
Type "viv info "
|
||||
Sleep 1s
|
||||
Type "f8"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Type "viv remove -h"
|
||||
Enter
|
||||
Type "viv rm f8"
|
||||
Enter
|
||||
Sleep 2s
|
|
@ -1,18 +0,0 @@
|
|||
# Usage
|
||||
|
||||
*NOTE*: these demo gif's are a work in progress. If you'd like to see them you can run `vhs` locally with `make docs`.
|
||||
|
||||
<div align="center">
|
||||
# Demo
|
||||
|
||||
<img src="https://raw.githubusercontent.com/daylinmorgan/viv/main/docs/demo.gif" alt="demo" width=600 >
|
||||
|
||||
# Freeze
|
||||
|
||||
<img src="https://raw.githubusercontent.com/daylinmorgan/viv/main/docs/freeze.gif" alt="demo" width=600 >
|
||||
|
||||
# List | Info | Remove
|
||||
|
||||
<img src="https://raw.githubusercontent.com/daylinmorgan/viv/main/docs/list-info-remove.gif" alt="demo" width=600 >
|
||||
|
||||
</div>
|
|
@ -8,10 +8,9 @@ A possible cli signature
|
|||
viv shim black -o ~/bin/black
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
sys.path.append("/home/daylin/.viv/src") # noqa
|
||||
import subprocess
|
||||
import viv
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -17,7 +17,7 @@ homepage = "https://github.com/daylinmorgan/viv"
|
|||
repository = "https://github.com/daylinmorgan/viv"
|
||||
|
||||
[project.scripts]
|
||||
viv = "viv.viv:main"
|
||||
viv = "viv:main"
|
||||
|
||||
[tool.pdm]
|
||||
version = { source = "scm" }
|
||||
|
@ -29,6 +29,7 @@ dev = [
|
|||
]
|
||||
|
||||
[tool.ruff]
|
||||
select = ["E","F","I"]
|
||||
ignore = ["E402"]
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
@ -1 +1 @@
|
|||
from .viv import use # noqa
|
||||
from .viv import __version__, use, main # noqa
|
||||
|
|
337
src/viv/viv.py
337
src/viv/viv.py
|
@ -22,14 +22,15 @@ import tempfile
|
|||
import threading
|
||||
import time
|
||||
import venv
|
||||
from argparse import SUPPRESS, Action
|
||||
from argparse import ArgumentParser as StdArgParser
|
||||
from argparse import (
|
||||
SUPPRESS,
|
||||
Action,
|
||||
HelpFormatter,
|
||||
Namespace,
|
||||
RawDescriptionHelpFormatter,
|
||||
_SubParsersAction,
|
||||
)
|
||||
from argparse import ArgumentParser as StdArgParser
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from itertools import zip_longest
|
||||
|
@ -39,6 +40,7 @@ from types import TracebackType
|
|||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Generator,
|
||||
List,
|
||||
NoReturn,
|
||||
Optional,
|
||||
|
@ -46,10 +48,11 @@ from typing import (
|
|||
TextIO,
|
||||
Tuple,
|
||||
Type,
|
||||
Generator,
|
||||
)
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import urlopen
|
||||
|
||||
__version__ = "22.12a3-41-g5c40210-dev"
|
||||
__version__ = "23.5a1-3-g3a85fe4-dev"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -59,9 +62,21 @@ class Config:
|
|||
venvcache: Path = (
|
||||
Path(os.getenv("XDG_CACHE_HOME", Path.home() / ".cache")) / "viv" / "venvs"
|
||||
)
|
||||
srccache: Path = (
|
||||
Path(os.getenv("XDG_CACHE_HOME", Path.home() / ".cache")) / "viv" / "src"
|
||||
)
|
||||
share: Path = (
|
||||
Path(os.getenv("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "viv"
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.venvcache.mkdir(parents=True, exist_ok=True)
|
||||
self.srccache.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
self.share.mkdir(parents=True, exist_ok=True)
|
||||
self.srcdefault = self.share / "viv.py"
|
||||
|
||||
|
||||
c = Config()
|
||||
|
@ -235,6 +250,9 @@ class Ansi:
|
|||
else:
|
||||
return (row,)
|
||||
|
||||
def viv_preamble(self, style: str = "magenta", sep: str = "::") -> str:
|
||||
return f"{self.cyan}Viv{self.end}{self.__dict__[style]}{sep}{self.end}"
|
||||
|
||||
def table(
|
||||
self, rows: Tuple[Tuple[str, Sequence[str]], ...], header_style: str = "cyan"
|
||||
) -> None:
|
||||
|
@ -299,12 +317,27 @@ def echo(
|
|||
msg: str, style: str = "magenta", newline: bool = True, fd: TextIO = sys.stderr
|
||||
) -> None:
|
||||
"""output general message to stdout"""
|
||||
output = f"{a.cyan}Viv{a.end}{a.__dict__[style]}::{a.end} {msg}"
|
||||
output = f"{a.viv_preamble(style)} {msg}"
|
||||
if newline:
|
||||
output += "\n"
|
||||
fd.write(output)
|
||||
|
||||
|
||||
def confirm(question: str, context: str = "") -> bool:
|
||||
sys.stderr.write(context)
|
||||
sys.stderr.write(
|
||||
a.viv_preamble(sep="?? ") + question + a.style(" (Y)es/(n)o: ", "yellow")
|
||||
)
|
||||
while True:
|
||||
ans = input().strip().lower()
|
||||
if ans in ("y", "yes"):
|
||||
return True
|
||||
elif ans in ("n", "no"):
|
||||
return False
|
||||
sys.stdout.write("Please select (Y)es or (n)o. ")
|
||||
sys.stdout.write("\n")
|
||||
|
||||
|
||||
def run(
|
||||
command: List[str],
|
||||
spinmsg: str = "",
|
||||
|
@ -433,12 +466,14 @@ class ViVenv:
|
|||
def dump_info(self, write: bool = False) -> None:
|
||||
# TODO: include associated files in 'info'
|
||||
# means it needs to be loaded first
|
||||
# or keep a seperate file hash in c.share?
|
||||
info = {
|
||||
"created": str(datetime.today()),
|
||||
"id": self.id,
|
||||
"spec": self.spec,
|
||||
"exe": self.exe,
|
||||
}
|
||||
|
||||
# save metadata to json file
|
||||
if write:
|
||||
with (self.path / "viv-info.json").open("w") as f:
|
||||
|
@ -448,7 +483,7 @@ class ViVenv:
|
|||
a.table((("key", "value"), *((k, v) for k, v in info.items())))
|
||||
|
||||
|
||||
def use(*packages: str, track_exe: bool = False, name: str = "") -> None:
|
||||
def use(*packages: str, track_exe: bool = False, name: str = "") -> ViVenv:
|
||||
"""create a vivenv and append to sys.path
|
||||
|
||||
Args:
|
||||
|
@ -467,6 +502,7 @@ def use(*packages: str, track_exe: bool = False, name: str = "") -> None:
|
|||
vivenv.dump_info(write=True)
|
||||
|
||||
modify_sys_path(vivenv.path)
|
||||
return vivenv
|
||||
|
||||
|
||||
def validate_spec(spec: Tuple[str, ...]) -> None:
|
||||
|
@ -515,8 +551,7 @@ STANDALONE_TEMPLATE = r"""
|
|||
# >>>>> code golfed with <3
|
||||
""" # noqa
|
||||
|
||||
STANDALONE_TEMPLATE_USE = r"""
|
||||
def _viv_use(*pkgs: str, track_exe: bool = False, name: str = "") -> None:
|
||||
STANDALONE_TEMPLATE_USE = r"""def _viv_use(*pkgs: str, track_exe: bool = False, name: str = "") -> None:
|
||||
i,s,m,e,spec=__import__,str,map,lambda x: True if x else False,[*pkgs]
|
||||
if not {{*m(type,pkgs)}}=={{s}}: raise ValueError(f"spec: {{pkgs}} is invalid")
|
||||
ge,sys,P,ew=i("os").getenv,i("sys"),i("pathlib").Path,i("sys").stderr.write
|
||||
|
@ -535,9 +570,27 @@ def _viv_use(*pkgs: str, track_exe: bool = False, name: str = "") -> None:
|
|||
i("json").dump({{"created":s(i("datetime").datetime.today()),"id":_id,"spec":spec,"exe":exe}},f)
|
||||
sys.path = [p for p in (*sys.path,s(*(env/"lib").glob("py*/si*"))) if p!=i("site").USER_SITE]
|
||||
_viv_use({spec})
|
||||
"""[ # noqa
|
||||
1:
|
||||
]
|
||||
""" # noqa
|
||||
|
||||
SHOW_TEMPLATE = f"""
|
||||
{a.style('Version', 'bold')}: {{version}}
|
||||
{a.style('CLI', 'bold')}: {{cli}}
|
||||
{a.style('Running Source', 'bold')}: {{running_src}}
|
||||
{a.style('Local Source', 'bold')}: {{local_src}}
|
||||
"""
|
||||
|
||||
INSTALL_TEMPLATE = f"""
|
||||
Install viv.py to {a.green}{{src_location}}{a.end}
|
||||
Symlink {a.bold}{{src_location}}{a.end} to {a.bold}{{cli_location}}{a.end}
|
||||
|
||||
"""
|
||||
|
||||
UPDATE_TEMPLATE = f"""
|
||||
Update source at {a.green}{{src_location}}{a.end}
|
||||
Symlink {a.bold}{{src_location}}{a.end} to {a.bold}{{cli_location}}{a.end}
|
||||
Version {a.bold}{{local_version}}{a.end} -> {a.bold}{{next_version}}{a.end}
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def noqa(txt: str) -> str:
|
||||
|
@ -691,7 +744,7 @@ class CustomHelpFormatter(RawDescriptionHelpFormatter, HelpFormatter):
|
|||
# determine the required width and the entry label
|
||||
help_position = min(self._action_max_length + 2, self._max_help_position)
|
||||
help_width = max(self._width - help_position, 11)
|
||||
action_width = help_position - self._current_indent - 2
|
||||
action_width = help_position - self._current_indent
|
||||
action_header = self._format_action_invocation(action)
|
||||
action_header_len = len(a.escape(action_header))
|
||||
|
||||
|
@ -763,7 +816,8 @@ class ArgumentParser(StdArgParser):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.formatter_class = lambda prog: CustomHelpFormatter(
|
||||
prog, max_help_position=35
|
||||
prog,
|
||||
max_help_position=35,
|
||||
)
|
||||
|
||||
def error(self, message: str) -> NoReturn:
|
||||
|
@ -776,18 +830,76 @@ class ArgumentParser(StdArgParser):
|
|||
description = f"""
|
||||
|
||||
{a.tagline()}
|
||||
|
||||
{a.style('create/activate a vivenv','underline')}
|
||||
from command line:
|
||||
`{a.style("viv -h","bold")}`
|
||||
within python script:
|
||||
{a.style('__import__("viv").use("typer", "rich-click")','bold')}
|
||||
to create/activate a vivenv:
|
||||
- from command line: `{a.style("viv -h","bold")}`
|
||||
- within python script: {a.style('__import__("viv").use("typer", "rich-click")','bold')}
|
||||
"""
|
||||
|
||||
|
||||
def fetch_source(reference: str) -> str:
|
||||
try:
|
||||
r = urlopen(
|
||||
"https://raw.githubusercontent.com/daylinmorgan/viv/"
|
||||
+ reference
|
||||
+ "/src/viv/viv.py"
|
||||
)
|
||||
except HTTPError as e:
|
||||
error(
|
||||
"Issue updating viv see below:"
|
||||
+ a.style("-> ", "red").join(["\n"] + repr(e).splitlines())
|
||||
)
|
||||
if "404" in repr(e):
|
||||
echo("Please check your reference is valid.", style="red")
|
||||
sys.exit(1)
|
||||
|
||||
src = r.read()
|
||||
(hash := hashlib.sha256()).update(src)
|
||||
sha256 = hash.hexdigest()
|
||||
|
||||
cached_src_file = c.srccache / f"{sha256}.py"
|
||||
|
||||
if not cached_src_file.is_file():
|
||||
with cached_src_file.open("w") as f:
|
||||
f.write(src.decode())
|
||||
|
||||
return sha256
|
||||
|
||||
|
||||
def make_executable(path: Path) -> None:
|
||||
"""apply an executable bit for all users with read access"""
|
||||
mode = os.stat(path).st_mode
|
||||
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
||||
os.chmod(path, mode)
|
||||
|
||||
|
||||
class Viv:
|
||||
def __init__(self) -> None:
|
||||
self.vivenvs = get_venvs()
|
||||
self._get_sources()
|
||||
self.name = (
|
||||
"viv" if self.local else "python3 <(curl -fsSL gh.dayl.in/viv/viv.py)"
|
||||
)
|
||||
|
||||
def _get_sources(self) -> None:
|
||||
self.local_source: Path | str
|
||||
self.running_source = Path(__file__).resolve()
|
||||
self.local = not str(self.running_source).startswith("/proc/")
|
||||
if self.local:
|
||||
self.local_source = self.running_source
|
||||
self.local_version = __version__
|
||||
else:
|
||||
try:
|
||||
_local_viv = __import__("viv")
|
||||
self.local_source = (
|
||||
_local_viv.__file__ if _local_viv.__file__ else "Not Found"
|
||||
)
|
||||
self.local_version = _local_viv.__version__
|
||||
except ImportError:
|
||||
self.local_source = self.local_version = "Not Found"
|
||||
|
||||
self.git = self.local_source != "Not Found" and str(self.local_source).endswith(
|
||||
"src/viv/__init__.py"
|
||||
)
|
||||
|
||||
def _match_vivenv(self, name_id: str) -> ViVenv: # type: ignore[return]
|
||||
# TODO: improve matching algorithm to favor names over id's
|
||||
|
@ -895,11 +1007,125 @@ class Viv:
|
|||
|
||||
vivenv.dump_info()
|
||||
|
||||
def _install_local_src(self, sha256: str, src: Path, cli: Path) -> None:
|
||||
echo("updating local source copy of viv")
|
||||
shutil.copy(c.srccache / f"{sha256}.py", src)
|
||||
make_executable(src)
|
||||
echo("symlinking cli")
|
||||
|
||||
if not cli.is_file():
|
||||
cli.symlink_to(src)
|
||||
else:
|
||||
cli.unlink()
|
||||
cli.symlink_to(src)
|
||||
|
||||
echo("Remember to include the following line in your shell rc file:")
|
||||
sys.stderr.write(
|
||||
' export PYTHONPATH="$PYTHONPATH:$HOME/'
|
||||
f'{src.relative_to(Path.home())}"\n'
|
||||
)
|
||||
|
||||
def manage(self, args: Namespace) -> None:
|
||||
"""manage viv itself"""
|
||||
|
||||
if args.cmd == "show":
|
||||
if args.pythonpath:
|
||||
if not self.local:
|
||||
error("expected to find a local installation", exit=1)
|
||||
else:
|
||||
sys.stdout.write(str(self.local_source.parent) + "\n")
|
||||
else:
|
||||
echo("Current:")
|
||||
sys.stderr.write(
|
||||
SHOW_TEMPLATE.format(
|
||||
version=__version__,
|
||||
cli=shutil.which("viv"),
|
||||
running_src=self.running_source,
|
||||
local_src=self.local_source,
|
||||
)
|
||||
)
|
||||
|
||||
elif args.cmd == "update":
|
||||
if self.local_source == "Not Found":
|
||||
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,
|
||||
)
|
||||
sha256 = fetch_source(args.reference)
|
||||
sys.path.append(str(c.srccache))
|
||||
next_version = __import__(sha256).__version__
|
||||
|
||||
if self.local_version == next_version:
|
||||
echo(f"no change between {args.reference} and local version")
|
||||
sys.exit(0)
|
||||
|
||||
if confirm(
|
||||
"Would you like to perform the above installation steps?",
|
||||
UPDATE_TEMPLATE.format(
|
||||
src_location=self.local_source,
|
||||
local_version=self.local_version,
|
||||
cli_location=args.cli,
|
||||
next_version=next_version,
|
||||
),
|
||||
):
|
||||
self._install_local_src(
|
||||
sha256,
|
||||
Path(
|
||||
args.src
|
||||
if self.local_source == "Not Found"
|
||||
else self.local_source,
|
||||
),
|
||||
args.cli,
|
||||
)
|
||||
|
||||
elif args.cmd == "install":
|
||||
if not self.local_source == "Not Found":
|
||||
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)
|
||||
|
||||
sha256 = fetch_source(args.reference)
|
||||
sys.path.append(str(c.srccache))
|
||||
downloaded_version = __import__(sha256).__version__
|
||||
echo(f"Downloaded version: {downloaded_version}")
|
||||
|
||||
# TODO: see if file is actually where
|
||||
# we are about to install and give more instructions
|
||||
|
||||
if confirm(
|
||||
"Would you like to perform the above installation steps?",
|
||||
INSTALL_TEMPLATE.format(
|
||||
src_location=args.src,
|
||||
cli_location=args.cli,
|
||||
),
|
||||
):
|
||||
self._install_local_src(sha256, args.src, args.cli)
|
||||
def shim(self, args):
|
||||
"""generate viv-powered cli apps"""
|
||||
echo("not implemented.")
|
||||
|
||||
def _get_subcmd_parser(
|
||||
self, subparsers: _SubParsersAction[ArgumentParser], name: str, **kwargs: Any
|
||||
self,
|
||||
subparsers: _SubParsersAction[ArgumentParser],
|
||||
name: str,
|
||||
attr: Optional[str] = None,
|
||||
**kwargs: Any,
|
||||
) -> ArgumentParser:
|
||||
aliases = kwargs.pop("aliases", [name[0]])
|
||||
cmd = getattr(self, name)
|
||||
cmd = getattr(self, attr if attr else name)
|
||||
parser: ArgumentParser = subparsers.add_parser(
|
||||
name,
|
||||
help=cmd.__doc__.splitlines()[0],
|
||||
|
@ -914,7 +1140,7 @@ class Viv:
|
|||
def cli(self) -> None:
|
||||
"""cli entrypoint"""
|
||||
|
||||
parser = ArgumentParser(description=description)
|
||||
parser = ArgumentParser(prog=self.name, description=description)
|
||||
parser.add_argument(
|
||||
"-V",
|
||||
"--version",
|
||||
|
@ -927,10 +1153,7 @@ class Viv:
|
|||
)
|
||||
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 = self._get_subcmd_parser(subparsers, "list")
|
||||
|
||||
p_list.add_argument(
|
||||
"-q",
|
||||
|
@ -955,16 +1178,15 @@ class Viv:
|
|||
nargs="*",
|
||||
)
|
||||
|
||||
p_exe_python = p_exe_sub.add_parser(
|
||||
p_exe_sub.add_parser(
|
||||
"python",
|
||||
help="run command with python",
|
||||
parents=[p_vivenv_arg, p_exe_shared],
|
||||
)
|
||||
p_exe_pip = p_exe_sub.add_parser(
|
||||
).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]
|
||||
)
|
||||
p_exe_python.set_defaults(func=self.exe, exe="python")
|
||||
p_exe_pip.set_defaults(func=self.exe, exe="pip")
|
||||
).set_defaults(func=self.exe, exe="pip")
|
||||
|
||||
p_remove = self._get_subcmd_parser(
|
||||
subparsers,
|
||||
|
@ -1008,6 +1230,57 @@ class Viv:
|
|||
"info",
|
||||
parents=[p_vivenv_arg],
|
||||
)
|
||||
p_manage_shared = ArgumentParser(add_help=False)
|
||||
p_manage_shared.add_argument(
|
||||
"-r",
|
||||
"--reference",
|
||||
help="git reference (branch/tag/commit)",
|
||||
default="main",
|
||||
)
|
||||
|
||||
p_manage_shared.add_argument(
|
||||
"-s",
|
||||
"--src",
|
||||
help="path/to/source_file",
|
||||
default=c.srcdefault,
|
||||
)
|
||||
p_manage_shared.add_argument(
|
||||
"-c",
|
||||
"--cli",
|
||||
help="path/to/cli (symlink to src)",
|
||||
default=Path.home() / "bin" / "viv",
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
self._get_subcmd_parser(
|
||||
subparsers,
|
||||
"shim",
|
||||
).set_defaults(func =self.shim, cmd="shim")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
|
Loading…
Reference in a new issue