CLI package manager frontend for NurOS.
Note
Repository Mirrors
- git.nuros.org (core/tulpar): primary, self-hosted Forgejo instance, accounts restricted to the core team.
- GitHub (NurOS-Linux/tulpar): mirror for external contributors. Issues and Pull Requests opened here are welcome and are reviewed and processed by the core team.
tulpar is the command-line package manager for NurOS. It resolves, downloads, installs, removes, and upgrades packages, backed by libapg for local package database and transaction handling, and by a Tulpar Server instance for remote repository operations over HTTP.
libapg has no networking and no logging of its own; everything network-related, repository-related, configuration, caching, and logging is tulpar's responsibility, built on top of libapg's package, database, transaction, dependency graph, signature, and journal APIs.
| Dependency | Description |
|---|---|
| Meson | Build system |
| Ninja | Build tool |
| pkg-config | Helper tool for compiling |
| libapg | Packaging backend library, pulled in as a meson subproject |
| libcurl | HTTP(S) client used for all Tulpar Server communication |
| yyjson | JSON library, same one libapg uses internally |
Everything else (terminal color output, progress bars, argument parsing) is hand-written with no external dependency.
tulpar consumes libapg as a meson subproject, wired up through
subprojects/libapg.wrap, a wrap-git pointing at
https://git.nuros.org/core/libapg.git, pinned to a specific commit.
Meson fetches and builds it automatically as part of a normal
meson setup.
Manual mirror override: if git.nuros.org is unreachable from your
network, libapg is also mirrored read-only at
github.com/nuros-linux/libapg.git.
meson's .wrap format does not support a fallback URL list in a single
file, so this is a manual override, not something the wrap file itself
encodes: edit subprojects/libapg.wrap and change the url to the
GitHub mirror before running meson setup, or drop a working checkout
directly at subprojects/libapg/ (meson prefers an existing directory
over fetching the wrap).
The pinned revision is only the latest one known when this wrap was
written; it does not track main automatically and will be bumped by
the maintainer as libapg evolves.
tulpar verifies package signatures against libapg's libsodium
(Ed25519) backend via the unsuffixed sign_verify / keyring_load /
keyring_add_key functions. require_signature defaults to false,
matching Tulpar Server's own default; when a package's signature is
missing or fails verification, tulpar always prints a loud warning
before proceeding, regardless of require_signature. Set
require_signature = true (or pass --require-signature) to reject
unsigned or unverifiable packages outright instead of just warning.
Lifecycle scripts (pre-install, post-install, pre-remove, post-remove)
are executed by libapg's run_script(), isolated using the strongest
primitive available on the host:
- Linux:
unshare()with isolated network, mount, UTS, and IPC namespaces. - FreeBSD:
chroot()into the alternate install root, when one is given (via--dest). - Other POSIX platforms: no sandbox primitive is available; scripts run without isolation.
tulpar does not reimplement any of this. It only resolves where the
package database lives under --dest, makes sure the target root's
directory structure exists before committing, and passes the resolved
root path into trans_commit(), which threads it through to every
script invocation libapg triggers internally.
meson setup build --buildtype=release
meson compile -C buildmeson test -C buildsudo meson install -C buildGlobal settings are read from two locations, in order, with later values overriding earlier ones:
/etc/apg/tulpar.conf(system-wide)~/.config/apg/tulpar.conf(per-user override)
The format is plain key = value lines; # starts a comment; there
are no sections. See tulpar.conf(5) for the full list of keys
(cache_dir, db_dir, log_file, repodata_ttl,
max_parallel_downloads, require_signature, color_theme,
verbose, quiet, journald).
The repository list is a plain text file, one URL per line, # for
comments, no key/value syntax, no sections:
/etc/apg/repos(system-wide)~/.config/apg/repos(per-user addition, for managing personal repositories without root)
Manage it with tulpar repo add|remove|list|update rather than
editing it by hand if you'd rather not deal with the raw format.
/var/cache/apg/pkgs/: downloaded.apgarchives./var/cache/apg/repodata/: cachedrepodata.jsonper configured repository, refreshed automatically oncerepodata_ttl(default 900 seconds) has elapsed, or on demand withtulpar repo update.
Plain syslog-style text lines, one per event, written to
/var/log/tulpar.log by default. Override the path with log_file in
tulpar.conf or a CLI flag. --verbose and --quiet control both log
and terminal output verbosity. On Linux, log lines can additionally be
mirrored to syslog/journald by setting journald = true.
Every command has a full name, a single-letter short alias usable as
the first word, and the same letter usable as a leading flag:
tulpar install pkg, tulpar i pkg, and tulpar -i pkg are
identical.
| Command | Alias | Description |
|---|---|---|
install |
i |
Install one or more packages |
remove, uninstall |
r |
Remove an installed package |
upgrade |
u |
Upgrade one named package, or all installed packages |
search |
s |
Search the local database and remote repository indexes |
list |
l |
List installed packages |
info, show |
n |
Show full metadata for a package |
verify |
v |
Verify installed package files |
orphans, autoremove |
o |
List and remove orphaned packages |
hold |
g |
Block a package from upgrade or removal |
unhold |
x |
Release a held package |
history, audit, log |
a |
Show past install/remove operations |
repo add|remove|list|update |
e |
Manage configured repositories |
download |
w |
Fetch a package without installing it |
key add|list |
k |
Manage the trusted signing keyring |
-h/-V/-y/-j/-d/-q are reserved globally for help, version,
--yes, --json, --dest, and --quiet, so no command alias reuses
those letters; see tulpar(1) for the full rationale behind each
letter choice.
Every install/remove/upgrade-family command accepts --dest <path> to
operate against an alternate filesystem root instead of the live
system. The package database then lives under
<dest>/var/lib/apg/db, dependency resolution runs against that
database, and root privileges are not required (the destination may be
user-owned). Without --dest, tulpar operates on the live root and
requires geteuid() == 0 before any write operation.
Full documentation for every command is available as a man page:
tulpar(1), tulpar-install(1), tulpar-remove(1),
tulpar-upgrade(1), tulpar-search(1), tulpar-list(1),
tulpar-info(1), tulpar-verify(1), tulpar-orphans(1),
tulpar-hold(1), tulpar-unhold(1), tulpar-history(1),
tulpar-repo(1), tulpar-download(1), tulpar-key(1), and
tulpar.conf(5).
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
See the LICENSE file for details.