Files
sjnetPKG/README.md
T
jhkaktus f1250881f4 Implement sjnetpkg 0.1.0, a Git-based package manager
Packages are ordinary Git repositories carrying a sjnetpkg.toml, so sjnetpkg
only needs to resolve, clone, track and run them instead of inventing an
archive format or build system. This adds the v0.1 CLI (install from registry
or Git URL, remove, list/inspect, registry update, run) on top of the Python
standard library, together with a test suite.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-09-24 16:51:29 +02:00

5.2 KiB

sjnetPKG

A simple, Git-based package manager.

A package is not a pre-compiled file or a special archive format - it is an ordinary Git repository. sjnetpkg finds packages, clones them, keeps track of what is installed, updates them and runs them.

Git repository  ->  ~/.sjnetpkg/pkg/<name>  ->  sjnetpkg.toml  ->  run command

The repository (including .git) is kept completely intact, and sjnetpkg never modifies the package code itself.

Installation

Requires Python 3.11 or newer and the git executable on PATH.

pip install .
# or, for development
pip install -e .

You can also run it straight from the checkout:

PYTHONPATH=src python3 -m sjnetpkg --help

Package format

Every package must contain a sjnetpkg.toml in its root directory:

name = "cool-tool"
version = "1.0.0"

[run]
command = "cargo run"

name and version are required. version is treated as an opaque string; v0.1 performs no semantic-version resolution.

The optional [run] section defines how the package is started. The command is language-agnostic, for example:

Language command
Rust cargo run
Python python main.py
Go go run .
Node.js npm start
Bash bash main.sh

The command string is passed to the platform shell (/bin/sh on POSIX, cmd.exe on Windows), so multi-argument commands such as cargo run --release work as written. The process runs with the package directory as its working directory, and STDIN, STDOUT and STDERR are passed through directly.

Registry

The registry is a plain TOML file mapping package names to Git repositories:

[packages.cool-tool]
repo = "https://github.com/example/cool-tool.git"

The registry URL is configured in ~/.sjnetpkg/config.toml:

registry = "https://pkg.serverjonas.de/registry.toml"

A downloaded copy is kept at ~/.sjnetpkg/registry.toml so packages can be resolved even when the remote registry is unreachable. A failed or invalid download never destroys the existing local copy.

The default registry is https://pkg.serverjonas.de/registry.toml, defined by DEFAULT_REGISTRY_URL in src/sjnetpkg/config.py. It is written into config.toml on first start; afterwards the file in the home directory wins.

CLI

Usage:
    sjnetpkg -S <package>     install a package from the registry
    sjnetpkg -U <url>         install a package directly from a Git URL
    sjnetpkg -R <package>     remove an installed package
    sjnetpkg -Q               list installed packages
    sjnetpkg -Q <package>     show information about an installed package
    sjnetpkg -Sy              update the local copy of the registry
    sjnetpkg run <package>    run an installed package
    sjnetpkg --help           show the help
    sjnetpkg --version        show the version

With -U, the directory name is derived from the repository name in the URL, while the name in sjnetpkg.toml is the final package identity. The two are allowed to differ.

Installation never starts a package automatically - use sjnetpkg run <name>. Packages are installed into ~/.sjnetpkg/pkg/ and are never copied to /usr/bin, /usr/local/bin or ~/.local/bin.

Exit codes: 0 on success, 1 on errors, 2 on command line usage errors. Errors are reported as short messages, never as Python tracebacks.

Directory layout

~/.sjnetpkg/
|-- config.toml
|-- registry.toml
`-- pkg/
    `-- cool-tool/
        |-- .git/
        |-- sjnetpkg.toml
        `-- ...

The home directory can be overridden with the SJNETPKG_HOME environment variable (useful for testing and custom setups). It defaults to pathlib.Path.home() / ".sjnetpkg".

Updating packages

Updates run git pull inside a package directory. sjnetpkg -Su, which updates all installed packages, is planned; the update concept is defined but v0.1 does not implement it yet. An update will never start a package.

Development

Modules and responsibilities:

  • cli.py - arguments, options, command dispatch, exit codes, error messages
  • config.py - the ~/.sjnetpkg/ layout, config.toml, registry configuration
  • registry.py - downloading, reading and searching the registry
  • package.py - package paths, sjnetpkg.toml, metadata, install state
  • git.py - git clone, git pull, git availability and errors
  • runner.py - run command lookup, working directory, process, exit code

Run the tests (standard library unittest, no extra dependencies):

PYTHONPATH=src python3 -m unittest discover -s tests -t tests

They also run under pytest, which picks up tests/conftest.py.

Scope of v0.1

Deliberately not included: dependency resolver, version constraints, automatic dependency installation, sandbox, signatures, checksums, binary packages, build system, automatic compiler installation, global executables, daemon, package hooks, an own Git implementation, remote package cache.

Security

A package is potentially executable foreign code: its [run] command may start arbitrary commands. v0.1 provides no sandbox - only install and run packages you trust.

License

To be determined.