- Python 80.1%
- Shell 19.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| installer | ||
| manager | ||
| .gitignore | ||
| README.md | ||
Spin
Spin is a small Python package manager prototype for installing versioned .spin archives from local files or HTTPS URLs.
The CLI lives in manager/spin.py, and the system installer lives in installer/install.sh.
Status
This project is an early implementation. The current code supports:
- Installing a package from a local
.spinarchive or a configured HTTPS URL - Removing and reinstalling packages
- Installing a specific version when the repo URL can be versioned
- Basic dependency resolution from package manifests
- SHA-256 verification when hashes are present in repo metadata
- Atomic install with rollback on failure
- A local package database, cache, and generated lock file
- Scaffolding a simple HTTPS package repository directory
Requirements
- Python 3.10+ for the installer script
tomlopensslif you want to use the generated local repoactivatescript- Root privileges for most
spincommands
The Python package metadata in pyproject.toml currently declares requires-python = ">=3.14", but the installer itself checks for Python 3.10 or newer.
Repository Layout
spin/
├── installer/
│ └── install.sh
├── manager/
│ └── spin.py
├── info/
│ └── README.md
├── pyproject.toml
└── uv.lock
Installation
Install system-wide with:
sudo ./installer/install.sh
Useful installer options:
./installer/install.sh --help
./installer/install.sh --dry-run
sudo ./installer/install.sh --prefix /usr/local
sudo ./installer/install.sh --uninstall
By default, the installer writes:
/usr/local/bin/spin/usr/local/lib/spin/spin.py
Runtime Storage
Spin separates package payloads from its internal state.
State storage:
- Linux:
/var/lib/spin - macOS:
/usr/local/var/spin - Windows:
%PROGRAMDATA%\Spin
Installed package contents:
- Linux:
/usr/local/spin - macOS:
/Applications/Spin - Windows:
%ProgramFiles%\Spin
State storage contains:
cache/for downloaded archivesdb.tomlfor installed package metadatarepos.tomlfor configured package sourcesspin.lockfor installed version pins.spin.mutexfor a file-based lock
Usage
Spin uses subcommands such as spin help. It does not currently expose standard --help or --version flags.
Only spin help works without root. All other commands currently exit unless run as root.
spin help
sudo spin up <package|file.spin>
sudo spin down <name>
sudo spin redo <name>
sudo spin lift <name>
sudo spin drop <name> <version>
sudo spin ls
sudo spin info <name>
sudo spin status
sudo spin clean
sudo spin search <query>
sudo spin repo add <name> <https-url>
sudo spin repo make <directory>
sudo spin repo pull
Examples:
sudo spin up ./example.spin
sudo spin repo add hello https://packages.example.com/hello.spin
sudo spin up hello
sudo spin drop hello 1.2.3
sudo spin ls
Create a local repo scaffold:
sudo spin repo make /srv/spin-repo
cd /srv/spin-repo
./activate 8000
sudo spin repo add local https://localhost:8000
Package Format
A .spin file is a ZIP archive. Spin expects the archive to contain:
manifest.tomlfiles/
At minimum, the manifest must define:
name = "hello"
version = "1.0.0"
Dependencies are optional and are expressed as a table:
name = "hello"
version = "1.0.0"
[dependencies]
libfoo = ">=1.2.0"
libbar = "==2.0.0"
Supported dependency operators are:
>=<===
If no operator is used, Spin treats the dependency string as an exact value to compare.
Repository Metadata
Configured package sources are stored in repos.toml under a repos table.
For package installation, the current implementation uses a simple name-to-URL map:
Example:
[repos]
hello = "https://packages.example.com/hello.spin"
"hello.sha256" = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
For versioned installs with spin drop, Spin supports either:
- A URL template containing
{version} - A fallback convention where
hello.spinbecomeshello-<version>.spin
Example template:
[repos]
hello = "https://packages.example.com/hello-{version}.spin"
"hello-1.2.3.sha256" = "..."
Repository Scaffolding
spin repo make <dir> creates a minimal repository directory with:
packages/for.spinarchivesindex.tomlas a repository index templateactivateas a small HTTPS file server launcher
The generated activate script:
- Generates a self-signed TLS certificate on first run using
openssl - Serves the repo over HTTPS with Python’s built-in HTTP server
- Listens on port
8000by default, or a custom port passed as the first argument
The generated index.toml template looks like this:
# Spin repository index
#
# Register packages like:
#
# [packages.mypkg]
# version = "1.0.0"
# file = "packages/mypkg-1.0.0.spin"
# sha256 = "<hex digest>"
#
# Versioned URL templates are also supported:
# url = "https://example.com/pkgs/mypkg-{version}.spin"
At the moment, this scaffold is only partially integrated with the rest of the CLI:
repo makecreates the repo layout successfullyrepo pulldownloads<repo>/index.tomlinto the cacheup,drop, and dependency resolution do not currently read package entries out of those downloaded index files- In practice, installs still depend on direct name-to-URL entries in
repos.toml
Notes And Current Limitations
- Package and repo URLs must use HTTPS.
- All commands except
helpcurrently require root becausespin.pyexits ifos.geteuid() != 0. spin helpworks, butspin --helpandspin --versiondo not.repo addstores a single name-to-string entry inrepos.toml. That string is treated as a package URL byup, but as a repo base URL byrepo pull.repo pulldownloadsindex.tomlfiles into the cache, but does not merge them back intorepos.tomlor use them for install resolution.- Version comparison is string-based, not semantic-version aware.
searchmatches raw keys inrepos.toml, so hash keys likefoo.sha256can also appear in results.statuscounts rawrepos.tomlentries, so package URLs and hash entries both contribute to the displayed repo count.- The
info/README.mdfile exists but is currently empty.
Development
Run the CLI directly during development:
python3 manager/spin.py help
sudo python3 manager/spin.py status
sudo python3 manager/spin.py repo make /tmp/my-repo
If toml is missing:
python3 -m pip install toml