Skip to content

Commit 9191d77

Browse files
committed
add cargo, gem, nix, docker binproviders and rename packages override to install_args
1 parent 3175a61 commit 9191d77

16 files changed

Lines changed: 1596 additions & 204 deletions

.github/workflows/tests.yml

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,57 @@ jobs:
4545
source .venv/bin/activate \
4646
&& python tests.py
4747
48-
- name: Run live package lifecycle tests on macOS
48+
live-integration:
49+
runs-on: ${{ matrix.os }}
50+
strategy:
51+
fail-fast: true
52+
matrix:
53+
os: [ubuntu-latest, macos-15-intel]
54+
55+
steps:
56+
- uses: actions/checkout@v4
57+
58+
- name: Setup Python
59+
uses: actions/setup-python@v5
60+
with:
61+
python-version: '3.12'
62+
63+
- name: Install uv
64+
uses: astral-sh/setup-uv@v3
65+
with:
66+
enable-cache: true
67+
cache-dependency-glob: "uv.lock"
68+
69+
- name: Install Nix
70+
uses: DeterminateSystems/nix-installer-action@v16
71+
72+
- name: Setup Docker on macOS
73+
if: runner.os == 'macOS'
74+
uses: docker/setup-docker-action@v4
75+
76+
- name: Setup venv and install pip dependencies
77+
run: |
78+
uv venv --python "3.12" \
79+
&& uv sync --all-extras \
80+
&& uv pip install pip \
81+
&& echo "/home/linuxbrew/.linuxbrew/bin" >> "$GITHUB_PATH" \
82+
&& echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
83+
84+
- name: Run non-root live package lifecycle tests on macOS
4985
if: runner.os == 'macOS'
5086
env:
5187
ABX_PKG_LIVE_PKG_TESTS: "1"
5288
run: |
5389
source .venv/bin/activate \
54-
&& python -m unittest tests.LiveUpdateAndUninstallTest
90+
&& python -m unittest \
91+
tests.LiveUpdateAndUninstallTest.test_brew_provider_live_update_and_uninstall \
92+
tests.LiveUpdateAndUninstallTest.test_pip_provider_live_update_and_uninstall \
93+
tests.LiveUpdateAndUninstallTest.test_npm_provider_live_update_and_uninstall \
94+
tests.LiveUpdateAndUninstallTest.test_cargo_provider_live_update_and_uninstall \
95+
tests.LiveUpdateAndUninstallTest.test_gem_provider_live_update_and_uninstall \
96+
tests.LiveUpdateAndUninstallTest.test_go_get_provider_live_update_and_uninstall \
97+
tests.LiveUpdateAndUninstallTest.test_nix_provider_live_update_and_uninstall \
98+
tests.LiveUpdateAndUninstallTest.test_docker_provider_live_update_and_uninstall
5599
56100
- name: Run non-root live package lifecycle tests on Linux
57101
if: runner.os == 'Linux'
@@ -60,13 +104,18 @@ jobs:
60104
run: |
61105
source .venv/bin/activate \
62106
&& python -m unittest \
107+
tests.LiveUpdateAndUninstallTest.test_pip_provider_live_update_and_uninstall \
63108
tests.LiveUpdateAndUninstallTest.test_npm_provider_live_update_and_uninstall \
64-
tests.LiveUpdateAndUninstallTest.test_pip_provider_live_update_and_uninstall
109+
tests.LiveUpdateAndUninstallTest.test_cargo_provider_live_update_and_uninstall \
110+
tests.LiveUpdateAndUninstallTest.test_gem_provider_live_update_and_uninstall \
111+
tests.LiveUpdateAndUninstallTest.test_go_get_provider_live_update_and_uninstall \
112+
tests.LiveUpdateAndUninstallTest.test_nix_provider_live_update_and_uninstall \
113+
tests.LiveUpdateAndUninstallTest.test_docker_provider_live_update_and_uninstall
65114
66115
- name: Run root-required live package lifecycle tests on Linux
67116
if: runner.os == 'Linux'
68117
run: |
69-
sudo env "PATH=$PATH" "ABX_PKG_LIVE_PKG_TESTS=1" ./.venv/bin/python -m unittest \
118+
sudo env "PATH=$PATH:/nix/var/nix/profiles/default/bin" "ABX_PKG_LIVE_PKG_TESTS=1" ./.venv/bin/python -m unittest \
70119
tests.LiveUpdateAndUninstallTest.test_apt_provider_live_update_and_uninstall \
71120
tests.LiveUpdateAndUninstallTest.test_pyinfra_provider_live_update_and_uninstall \
72121
tests.LiveUpdateAndUninstallTest.test_ansible_provider_live_update_and_uninstall

README.md

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1><a href="https://github.com/ArchiveBox/abx-pkg"><code>abx-pkg</code></a> &nbsp; &nbsp; &nbsp; &nbsp; 📦 <small><code>apt</code>&nbsp; <code>brew</code>&nbsp; <code>pip</code>&nbsp; <code>npm</code> &nbsp;₊₊₊</small><br/><sub>Simple Python interfaces for package managers + installed binaries.</sub></h1>
1+
<h1><a href="https://github.com/ArchiveBox/abx-pkg"><code>abx-pkg</code></a> &nbsp; &nbsp; &nbsp; &nbsp; 📦 <small><code>apt</code>&nbsp; <code>brew</code>&nbsp; <code>pip</code>&nbsp; <code>npm</code>&nbsp; <code>cargo</code>&nbsp; <code>gem</code>&nbsp; <code>go_get</code>&nbsp; <code>nix</code>&nbsp; <code>docker</code> &nbsp;₊₊₊</small><br/><sub>Simple Python interfaces for package managers + installed binaries.</sub></h1>
22
<br/>
33

44
[![PyPI][pypi-badge]][pypi]
@@ -47,7 +47,18 @@ python
4747
```python
4848
from abx_pkg import *
4949

50-
apt, brew, pip, npm, env = AptProvider(), BrewProvider(), PipProvider(), NpmProvider(), EnvProvider()
50+
apt, brew, pip, npm, cargo, gem, go_get, nix, docker, env = (
51+
AptProvider(),
52+
BrewProvider(),
53+
PipProvider(),
54+
NpmProvider(),
55+
CargoProvider(),
56+
GemProvider(),
57+
GoGetProvider(),
58+
NixProvider(),
59+
DockerProvider(),
60+
EnvProvider(),
61+
)
5162

5263
dependencies = [
5364
Binary(name='curl', binproviders=[env, apt, brew]),
@@ -108,10 +119,17 @@ print(ffmpeg.model_json_schema()) # ... OpenAPI-ready JSON schema showing all
108119
- `brew` (macOS/Linux)
109120
- `pip` (Linux/macOS/Windows)
110121
- `npm` (Linux/macOS/Windows)
122+
- `cargo` (Linux/macOS)
123+
- `gem` (Linux/macOS)
124+
- `go get` / `go install` (`GoGetProvider`) (Linux/macOS)
125+
- `nix` (Linux/macOS)
126+
- `docker` (Linux/macOS, using local wrapper scripts that run `docker run`)
111127
- `env` (looks for existing version of binary in user's `$PATH` at runtime)
112128
- `vendor` (you can bundle vendored copies of packages you depend on within your source)
113129

114-
*Planned:* `docker`, `cargo`, `nix`, `apk`, `go get`, `gem`, `pkg`, *and more using `ansible`/[`pyinfra`](https://github.com/pyinfra-dev/pyinfra)...*
130+
*Planned:* `apk`, `pkg`, *and more using `ansible`/[`pyinfra`](https://github.com/pyinfra-dev/pyinfra)...*
131+
132+
`DockerProvider` expects image refs as install args, typically via overrides on a `Binary`. It writes a local wrapper script for the binary and executes it via `docker run ...`; the binary version is parsed from the image tag, so semver-like tags work best.
115133

116134
---
117135

@@ -131,7 +149,7 @@ This type represents a "provider of binaries", e.g. a package manager like `apt`
131149
`BinProvider`s implement the following interface:
132150
* `.INSTALLER_BIN -> /opt/homebrew/bin/brew` provider's pkg manager location
133151
* `.PATH -> PATHStr('/opt/homebrew/bin:/usr/local/bin:...')` where provider stores bins
134-
* `get_packages(bin_name: str) -> InstallArgs(['curl', 'libcurl4', '...])` find pkg dependencies for a bin
152+
* `get_install_args(bin_name: str) -> InstallArgs(['curl', 'libcurl4', '...])` find installer args for a bin
135153
- `install(bin_name: str)` install a bin using binprovider to install needed packages
136154
- `update(bin_name: str)` update a bin using the binprovider's package manager
137155
- `uninstall(bin_name: str)` remove a bin using the binprovider's package manager
@@ -216,9 +234,9 @@ class YtdlpBinary(Binary):
216234

217235
# customize installed package names for specific package managers
218236
overrides: dict[BinProviderName, ProviderLookupDict] = {
219-
'pip': {'packages': ['yt-dlp[default,curl-cffi]']}, # can use literal values (packages -> list[str], version -> SemVer, abspath -> Path, install -> str log)
220-
'apt': {'packages': lambda: ['yt-dlp', 'ffmpeg']}, # also accepts any pure Callable that returns a list of packages
221-
'brew': {'packages': 'self.get_macos_packages'}, # also accepts string reference to function on self (where self is the BinProvider)
237+
'pip': {'install_args': ['yt-dlp[default,curl-cffi]']}, # can use literal values (install_args -> list[str], version -> SemVer, abspath -> Path, install -> str log)
238+
'apt': {'install_args': lambda: ['yt-dlp', 'ffmpeg']}, # also accepts any pure Callable that returns a list of packages
239+
'brew': {'install_args': 'self.get_macos_packages'}, # also accepts string reference to function on self (where self is the BinProvider)
222240
}
223241

224242

@@ -253,7 +271,7 @@ class DockerBinary(Binary):
253271
},
254272
'apt': {
255273
# example: vary installed package name based on your CPU architecture
256-
'packages': {
274+
'install_args': {
257275
'amd64': ['docker'],
258276
'armv7l': ['docker-ce'],
259277
'arm64': ['docker-ce'],
@@ -486,11 +504,11 @@ class CargoProvider(BinProvider):
486504
sys.path.append('~/.cargo/bin')
487505

488506
def on_install(self, bin_name: BinName, **context):
489-
packages = self.on_get_packages(bin_name)
490-
installer_process = run(['cargo', 'install', *packages.split(' ')], capture_output = True, text=True)
507+
install_args = self.on_get_install_args(bin_name)
508+
installer_process = run(['cargo', 'install', *install_args.split(' ')], capture_output = True, text=True)
491509
assert installer_process.returncode == 0
492510

493-
def on_get_packages(self, bin_name: BinName, **context) -> InstallArgs:
511+
def on_get_install_args(self, bin_name: BinName, **context) -> InstallArgs:
494512
# optionally remap bin_names to strings passed to installer
495513
# e.g. 'yt-dlp' -> ['yt-dlp, 'ffmpeg', 'libcffi', 'libaac']
496514
return [bin_name]
@@ -523,7 +541,7 @@ print(rg.version) # SemVer(14, 1, 0)
523541
- [x] Implement initial basic support for `apt`, `brew`, and `pip`
524542
- [x] Provide editability and actions via Django Admin UI using [`django-pydantic-field`](https://github.com/surenkov/django-pydantic-field) and [`django-jsonform`](https://django-jsonform.readthedocs.io/en/latest/)
525543
- [ ] Add `preinstall` and `postinstall` hooks for things like adding `apt` sources and running cleanup scripts
526-
- [ ] Implement more package managers (`cargo`, `gem`, `go get`, `ppm`, `nix`, `docker`, etc.)
544+
- [ ] Implement more package managers (`apk`, `ppm`, `pkg`, etc.)
527545

528546

529547
### Other Packages We Like

abx_pkg/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434

3535
from .binprovider_apt import AptProvider
3636
from .binprovider_brew import BrewProvider
37+
from .binprovider_cargo import CargoProvider
38+
from .binprovider_gem import GemProvider
39+
from .binprovider_go_get import GoGetProvider
40+
from .binprovider_nix import NixProvider
41+
from .binprovider_docker import DockerProvider
3742
from .binprovider_pip import PipProvider
3843
from .binprovider_npm import NpmProvider
3944
from .binprovider_ansible import AnsibleProvider
@@ -43,6 +48,11 @@
4348
EnvProvider,
4449
AptProvider,
4550
BrewProvider,
51+
CargoProvider,
52+
GemProvider,
53+
GoGetProvider,
54+
NixProvider,
55+
DockerProvider,
4656
PipProvider,
4757
NpmProvider,
4858
AnsibleProvider,

0 commit comments

Comments
 (0)