dpack — DarkForge Package Manager
A source-based package manager for DarkForge Linux, positioned between CRUX's pkgutils and Gentoo's emerge in complexity. Written in Rust.
Features
- TOML package definitions — clean, readable package recipes
- Dependency resolution — topological sort with circular dependency detection
- Build sandboxing — bubblewrap (bwrap) isolation with PID/network namespaces
- Installed package database — file-based TOML tracking in
/var/lib/dpack/db/ - Full build orchestration — download → checksum → extract → sandbox build → stage → commit → register
- CRUX Pkgfile converter — convert CRUX ports to dpack format
- Gentoo ebuild converter — best-effort conversion of Gentoo ebuilds (handles ~80% of cases)
- Shared library conflict detection — ELF binary scanning via readelf/objdump
- Reverse dependency tracking — warns before removing packages that others depend on
Requirements
Build-time (compiling dpack itself):
dpack is written in Rust and can be built on any platform with a Rust toolchain:
- Rust 1.75+ with Cargo (install via https://rustup.rs)
- A C linker (gcc or clang) — needed by some Rust dependencies
- Works on Linux and macOS for development, but runtime features require Linux
# macOS (Homebrew)
brew install rustup && rustup-init
# Arch Linux
sudo pacman -S rust
# Ubuntu / Debian
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Runtime (using dpack to build/install packages):
dpack must run on a Linux system (it uses Linux-specific features):
- Linux kernel 5.4+ (for namespace support)
bash(build scripts are bash)curlorwget(source tarball downloads)git(for git-source packages)tar(source extraction)readelforobjdump(shared library scanning — part of binutils)- bubblewrap (
bwrap) for sandboxed builds (optional — falls back to direct execution) - A C/C++ compiler (gcc or clang) and make (for building packages)
On the DarkForge system itself, all runtime dependencies are provided by the base system. On another Linux distro for testing:
# Arch Linux
sudo pacman -S base-devel bubblewrap curl git
# Ubuntu / Debian
sudo apt install build-essential bubblewrap curl git binutils
Building
cd src/dpack
cargo build --release
The binary is at target/release/dpack. Install it:
# On Linux
sudo install -m755 target/release/dpack /usr/local/bin/
# For development/testing (from the repo root)
cargo run --release -- install zlib
Usage
# Install a package (resolves deps, builds in sandbox, installs, updates db)
dpack install zlib
# Install multiple packages
dpack install openssl curl git
# Remove a package (warns about reverse deps, removes files)
dpack remove zlib
# Upgrade packages (compares installed vs repo versions)
dpack upgrade # upgrade all outdated packages
dpack upgrade openssl git # upgrade specific packages
# Search for packages
dpack search compression
# Show package info
dpack info zlib
# List installed packages
dpack list
# Check for file conflicts and shared library issues
dpack check
# Check for available updates (compares installed vs repo + upstream)
dpack check-updates
# Convert foreign package formats
dpack convert /path/to/Pkgfile # CRUX → dpack TOML (stdout)
dpack convert /path/to/curl-8.19.0.ebuild -o curl.toml # Gentoo → dpack TOML (file)
Configuration
dpack reads its configuration from /etc/dpack.conf (TOML format). If the file doesn't exist, sensible defaults are used.
Example /etc/dpack.conf:
[flags]
cflags = "-march=znver5 -O2 -pipe -fomit-frame-pointer"
cxxflags = "-march=znver5 -O2 -pipe -fomit-frame-pointer"
ldflags = "-Wl,-O1,--as-needed"
makeflags = "-j32"
[paths]
db_dir = "/var/lib/dpack/db"
repo_dir = "/var/lib/dpack/repos"
source_dir = "/var/cache/dpack/sources"
build_dir = "/var/tmp/dpack/build"
[sandbox]
enabled = true
allow_network = false
bwrap_path = "/usr/bin/bwrap"
[[repos]]
name = "core"
path = "/var/lib/dpack/repos/core"
priority = 0
[[repos]]
name = "extra"
path = "/var/lib/dpack/repos/extra"
priority = 10
[[repos]]
name = "desktop"
path = "/var/lib/dpack/repos/desktop"
priority = 20
[[repos]]
name = "gaming"
path = "/var/lib/dpack/repos/gaming"
priority = 30
Package Definition Format
Package definitions are TOML files stored at <repo>/<name>/<name>.toml:
[package]
name = "zlib"
version = "1.3.1"
description = "Compression library implementing the deflate algorithm"
url = "https://zlib.net/"
license = "zlib"
[source]
url = "https://zlib.net/zlib-${version}.tar.xz"
sha256 = "38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32"
[dependencies]
run = []
build = ["gcc", "make"]
[dependencies.optional]
static = { description = "Build static library", default = true }
minizip = { description = "Build minizip utility", deps = [] }
[build]
system = "autotools"
configure = "./configure --prefix=/usr"
make = "make"
install = "make DESTDIR=${PKG} install"
[build.flags]
cflags = "" # empty = use global defaults
ldflags = ""
Variables available in build commands
${PKG}— staging directory (DESTDIR)${version}— package version (expanded in source URL)
Build systems
The system field is a hint: autotools, cmake, meson, cargo, or custom.
Git sources
Instead of downloading a tarball, dpack can clone a git repository directly. This is useful for building from the latest development branch or a specific commit:
[source]
url = "" # can be empty for git sources
sha256 = "SKIP" # integrity verified by git
git = "https://github.com/FreeCAD/FreeCAD.git" # clone URL
branch = "main" # checkout this branch
# Or pin to a tag (supports ${version} expansion):
# tag = "v${version}"
# Or pin to a specific commit:
# commit = "abc123def456"
When git is set, dpack clones the repository (with --depth 1 for branches/tags) into the build directory. The branch, tag, and commit fields control what gets checked out (in priority order: commit > tag > branch > default).
Upstream update checking
Packages can specify an update_check URL in the [source] section. When you run dpack check-updates, it queries these URLs and compares the result against your installed version.
[source]
url = "https://example.com/foo-${version}.tar.xz"
sha256 = "..."
update_check = "https://api.github.com/repos/owner/repo/releases/latest"
Supported URL patterns:
- GitHub releases API — parses
tag_namefrom the JSON response - GitHub/Gitea tags API — parses the first tag name
- Plain URL — the response body is treated as the version string
Running Tests
cargo test
Tests cover: TOML parsing, dependency resolution (simple, diamond, circular), database operations (register, unregister, persistence, file ownership, conflicts), and converter parsing.
Architecture
src/
├── main.rs # CLI (clap) — install, remove, upgrade, search, info, list, convert, check
├── lib.rs # Library re-exports
├── config/
│ ├── mod.rs # Module root
│ ├── package.rs # PackageDefinition TOML structs + parsing + validation
│ └── global.rs # DpackConfig (flags, paths, sandbox, repos)
├── resolver/
│ ├── mod.rs # DependencyGraph, topological sort, reverse deps
│ └── solib.rs # Shared library conflict detection (ELF scanning)
├── sandbox/
│ └── mod.rs # BuildSandbox (bubblewrap + direct backends)
├── converter/
│ ├── mod.rs # Format auto-detection
│ ├── crux.rs # CRUX Pkgfile parser
│ └── gentoo.rs # Gentoo ebuild parser
├── db/
│ └── mod.rs # PackageDb (file-based TOML, installed tracking)
└── build/
└── mod.rs # BuildOrchestrator (download → build → install pipeline)
Repository
git@git.dannyhaslund.dk:danny8632/dpack.git