Compare commits

..

12 commits

6 changed files with 547 additions and 525 deletions

View file

@ -1,10 +1,5 @@
# See https://pre-commit.com for more information # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
default_install_hook_types:
- pre-commit
- post-commit
default_stages:
- pre-commit
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 23.3.0 rev: 23.3.0
@ -22,5 +17,4 @@ repos:
language: script language: script
name: sets __version__ in viv.py name: sets __version__ in viv.py
entry: ./scripts/bump-dev.sh entry: ./scripts/bump-dev.sh
stages: [post-commit] files: viv.py$
always_run: true

View file

@ -10,16 +10,18 @@ types: ## run mypy
bump-version: ## update version and tag commit bump-version: ## update version and tag commit
@echo "bumping to version => $(VERSION)" @echo "bumping to version => $(VERSION)"
@sed -i 's/__version__ = ".*"/__version__ = "$(VERSION)"/g' src/viv/viv.py @sed -i 's/__version__ = ".*"/__version__ = "$(VERSION)"/g' src/viv/viv.py
@sed -i 's/install -r .*/install -r v$(VERSION)/g' README.md @git add src/viv/viv.py && git commit -m "chore: bump version" --no-verify
@git add src/viv/viv.py README.md && git commit -m "chore: bump version" --no-verify
@git tag v$(VERSION) @git tag v$(VERSION)
@git tag -d latest || true
@git tag latest
venv: ## generate environment venv: ## generate environment
pdm install pdm install
# TAPES = demo freeze list-info-remove # TAPES = demo freeze list-info-remove
# GIFS := $(foreach n, $(TAPES), docs/$(n).gif) # GIFS := $(foreach n, $(TAPES), docs/$(n).gif)
# docs: $(GIFS) ## generate usage examples # docs: $(GIFS) # generate usage examples
# docs/%.gif: docs/%.tape # docs/%.gif: docs/%.tape
# viv rm $$(viv l -q) # viv rm $$(viv l -q)

View file

@ -9,16 +9,9 @@
</p> </p>
</div> </div>
<br /> <br />
--- ---
Python is a great choice to quickly prototype or accomplish small tasks in scripts.
However, leveraging it's vast ecosystem can be tedious for one-off or rarely used scripts.
This is were `viv` comes in handy.
`Viv` is a standalone dependency-free `venv` creator. `Viv` is a standalone dependency-free `venv` creator.
It is meant to be invoked in any script that has third-party dependencies,
prior to loading of any of the external modules.
These `venvs` can be identified by name or by their specification. 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). In any case they will be re-used across scripts (and generated on-demand, if needed).
@ -26,12 +19,16 @@ In any case they will be re-used across scripts (and generated on-demand, if nee
**Importantly**, `viv` will also remove your user site directory. **Importantly**, `viv` will also remove your user site directory.
(view with: `python -m 'import site;print(site.USER_SITE)'`). (view with: `python -m 'import site;print(site.USER_SITE)'`).
`Viv`'s uncompromising insistence on portability means that it will always (1) only use the standard library (2) never exceed a single script.
For that reason any usage of the `CLI` can be accomplished using a remote copy as seen in the below install command.
## Setup ## Setup
Run the below command to install `viv`. Run the below command to install `viv`.
```sh ```sh
python3 <(curl -fsSL gh.dayl.in/viv/viv.py) manage install -r v23.5a1 python3 <(curl -fsSL gh.dayl.in/viv/viv.py) manage install
``` ```
To access `viv` from within scripts you should add it's location to your `PYTHONPATH`. To access `viv` from within scripts you should add it's location to your `PYTHONPATH`.
@ -43,9 +40,22 @@ export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
Advanced users may recognize that principally, Advanced users may recognize that principally,
the module just needs to be recognized at run time the module just needs to be recognized at run time
and the single script at `./src/viv/viv.py` can be invoked directly for the CLI. and the single script [`viv.py`](https://github.com/daylinmorgan/viv/blob/main/src/viv/viv.py) can be invoked directly for the CLI.
How you accomplish these options is ultimately up to you but the above instructions can get you started. How you accomplish these options is ultimately up to you but the above instructions can get you started.
## Additional Features
An experimental feature of `viv` is generating shim's that leverage the principles of `viv`.
These shims would operate similar to `pipx` in which you can specify a command line app to "install".
*Note* that `--standalone` will auto-generate a code-golfed minified version of `viv` to accomplish the same basic task as using a local copy of `viv`.
After generating this a standalone `shim` you can freely use this script across unix machines which have `python>3.8`.
See [examples/black](https://github.com/daylinmorgan/viv/blob/dev/examples/black) for output of below command.
```sh
python3 <(curl -fsSL gh.dayl.in/viv/viv.py) shim black -o ./black --standalone --freeze
```
### Pypi (Not Recommended) ### Pypi (Not Recommended)
```sh ```sh
@ -70,43 +80,10 @@ To remove all `vivenvs` you can use the below command:
viv remove $(viv list -q) viv remove $(viv list -q)
``` ```
# Standalone Viv To remove `viv` all together you can use the included `purge` command:
Supposing you want to increase the portability of your script while still employing the principles of `viv`. ```sh
python3 <(curl -fsSL gh.dayl.in/viv/viv.py) manage purge
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`).
It can be auto-generated with for example: `viv freeze <spec> --standalone`.
The only part necessary to modify if copied verbatim from below is the call to `_viv_use`.
Output of `viv freeze rich --standalone`:
```python
# <<<<< auto-generated by daylinmorgan/viv (v22.12a3-35-g0d0c66d-dev)
# fmt: off
def _viv_use(*pkgs: str, track_exe: bool = False, name: str = "") -> None: # noqa
i,s,m,e,spec=__import__,str,map,lambda x: True if x else False,[*pkgs] # noqa
if not {*m(type,pkgs)}=={s}: raise ValueError(f"spec: {pkgs} is invalid") # noqa
ge,sys,P,ew=i("os").getenv,i("sys"),i("pathlib").Path,i("sys").stderr.write # noqa
(cache:=(P(ge("XDG_CACHE_HOME",P.home()/".cache"))/"viv"/"venvs")).mkdir(parents=True,exist_ok=True) # noqa
((sha256:=i("hashlib").sha256()).update((s(spec)+ # noqa
(((exe:=("N/A",s(P(i("sys").executable).resolve()))[e(track_exe)])))).encode())) # noqa
if (env:=cache/(name if name else (_id:=sha256.hexdigest()))) not in cache.glob("*/") or ge("VIV_FORCE"): # noqa
v=e(ge("VIV_VERBOSE"));ew(f"generating new vivenv -> {env.name}\n") # noqa
i("venv").EnvBuilder(with_pip=True,clear=True).create(env) # noqa
with (env/"pip.conf").open("w") as f:f.write("[global]\ndisable-pip-version-check=true") # noqa
if (p:=i("subprocess").run([env/"bin"/"pip","install","--force-reinstall",*spec],text=True, # noqa
stdout=(-1,None)[v],stderr=(-2,None)[v])).returncode!=0: # noqa
if env.is_dir():i("shutil").rmtree(env) # noqa
ew(f"pip had non zero exit ({p.returncode})\n{p.stdout}\n");sys.exit(p.returncode) # noqa
with (env/"viv-info.json").open("w") as f: # noqa
i("json").dump({"created":s(i("datetime").datetime.today()),"id":_id,"spec":spec,"exe":exe},f) # noqa
sys.path = [p for p in (*sys.path,s(*(env/"lib").glob("py*/si*"))) if p!=i("site").USER_SITE] # noqa
_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 ## Alternatives

View file

@ -1,20 +1,38 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""
Proof of concept output for a 'shim generator'
that would essentially emulate pipx
A possible cli signature
viv shim black -o ~/bin/black # <<<<< auto-generated by viv (v23.5a2-2-gebb657c-dev)
""" # see `python3 <(curl -fsSL gh.dayl.in/viv/viv.py) --help`
# fmt: off
def _viv_use(*pkgs, track_exe=False, name=""): # noqa
T,F=True,False;i,s,m,e,spec=__import__,str,map,lambda x: T if x else F,[*pkgs] # noqa
if not {*m(type,pkgs)}=={s}: raise ValueError(f"spec: {pkgs} is invalid") # noqa
ge,sys,P,ew=i("os").getenv,i("sys"),i("pathlib").Path,i("sys").stderr.write # noqa
(cache:=(P(ge("XDG_CACHE_HOME",P.home()/".cache"))/"viv"/"venvs")).mkdir(parents=T,exist_ok=T) # noqa
((sha256:=i("hashlib").sha256()).update((s(spec)+ # noqa
(((exe:=("N/A",s(P(i("sys").executable).resolve()))[e(track_exe)])))).encode())) # noqa
if ((env:=cache/(name if name else (_id:=sha256.hexdigest()))) # noqa
not in cache.glob("*/")) or ge("VIV_FORCE"): # noqa
v=e(ge("VIV_VERBOSE"));ew(f"generating new vivenv -> {env.name}\n") # noqa
i("venv").EnvBuilder(with_pip=T,clear=T).create(env) # noqa
with (env/"pip.conf").open("w") as f:f.write("[global]\ndisable-pip-version-check=true") # noqa
if (p:=i("subprocess").run([env/"bin"/"pip","install","--force-reinstall",*spec],text=True, # noqa
stdout=(-1,None)[v],stderr=(-2,None)[v])).returncode!=0: # noqa
if env.is_dir():i("shutil").rmtree(env) # noqa
ew(f"pip had non zero exit ({p.returncode})\n{p.stdout}\n");sys.exit(p.returncode) # noqa
with (env/"viv-info.json").open("w") as f: # noqa
i("json").dump({"created":s(i("datetime").datetime.today()), # noqa
"id":_id,"spec":spec,"exe":exe},f) # noqa
sys.path = [p for p in (*sys.path,s(*(env/"lib").glob("py*/si*"))) if p!=i("site").USER_SITE] # noqa
return env # noqa
# fmt: on
# >>>>> code golfed with <3
import subprocess import subprocess
import sys import sys
import viv
if __name__ == "__main__": if __name__ == "__main__":
vivenv = viv.use( vivenv = _viv_use(
"black==23.3.0", "black==23.3.0",
"click==8.1.3", "click==8.1.3",
"mypy-extensions==1.0.0", "mypy-extensions==1.0.0",
@ -22,11 +40,4 @@ if __name__ == "__main__":
"pathspec==0.11.1", "pathspec==0.11.1",
"platformdirs==3.5.1", "platformdirs==3.5.1",
) )
sys.exit( sys.exit(subprocess.run([vivenv / "bin" / "black", *sys.argv[1:]]).returncode)
subprocess.run(
[
vivenv.path / "bin" / "black",
*sys.argv[1:],
]
).returncode
)

View file

@ -1,6 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env sh
TAG=$(git describe --tags --always --dirty=-dev) TAG=$(git describe --tags --always --dirty=-dev --exclude 'latest')
VERSION="${TAG#v}" VERSION="${TAG#v}"
if [[ "$(git diff --name-only HEAD HEAD~1)" == *"src/viv/viv.py"* ]]; then sed -i "s/__version__ = \".*\"/__version__ = \"$VERSION\"/g" src/viv/viv.py
sed -i "s/__version__ = \".*\"/__version__ = \"$VERSION\"/g" src/viv/viv.py git add src/viv/viv.py
fi

File diff suppressed because it is too large Load diff