October 2019, Gentoo Forums:
Me: "I'd rather rewrite Portage on Golang."
Reply: "We look forward to you having some work to show another 5 years from now."
6 years and ~60,000 lines of code later — here it is.
If you've ever used Gentoo Linux, you know Portage. It's powerful, flexible, and... Python-based. For years — literally years — I had this persistent idea: what if Portage was written in Go? Fast compilation, single binary, no runtime dependencies, native concurrency. The idea kept coming back.
Last spring, I finally decided to stop thinking and start coding. What began as "let's see how hard this is" turned into 8 months of intensive development and a complete reimplementation of a package manager.
Today, I'm releasing GRPM v0.1.0 (Go Resource Package Manager) — a drop-in replacement for Portage with modern architecture and guaranteed conflict-free dependency resolution.
The Problem with Traditional Package Managers
Traditional dependency resolution algorithms work with heuristics. When they encounter conflicts, they often give up or make suboptimal choices. Portage's resolver is sophisticated, but it can still fail on complex dependency graphs with circular dependencies and slot conflicts.
I wanted something mathematically guaranteed to find a solution if one exists.
The Solution: SAT-Based Dependency Resolution
GRPM uses a Boolean Satisfiability (SAT) solver at its core. Every package version becomes a Boolean variable, and every dependency becomes a logical clause:
// internal/solver/gophersat_adapter.go
type GophersatAdapter struct {
clauses [][]int
vars map[string]int // name@version -> var ID
packages map[string][]*pkg.Package // name -> []versions
}
func (g *GophersatAdapter) AddPackage(p *pkg.Package) {
key := p.Name + "@" + p.Version
g.packages[p.Name] = append(g.packages[p.Name], p)
g.getVarID(key)
}
This approach transforms dependency resolution into a well-studied mathematical problem. If a valid installation exists, the SAT solver will find it.
Why SAT Solvers?
- Completeness: If a solution exists, it finds it
- Conflict handling: Multiple slot versions, blockers, USE flag constraints — all become SAT clauses
- Speed: Modern SAT solvers handle millions of variables
GRPM uses gophersat, a pure Go SAT solver. No external dependencies, no CGO.
Architecture: Clean Design with DDD
GRPM follows Domain-Driven Design with a layered architecture:
┌─────────────────────────────────────┐
│ CLI / Daemon Layer │
├─────────────────────────────────────┤
│ Application Layer │ ← Use cases
├─────────────────────────────────────┤
│ Domain Layer │ ← Business logic
│ (pkg, solver) │
├─────────────────────────────────────┤
│ Infrastructure Layer │ ← Repository, sync, install
└─────────────────────────────────────┘
The domain layer knows nothing about Portage file formats or filesystem details. This makes the codebase testable and the architecture extensible.
Key Features in v0.1.0
1. Full Binary Package Support
GRPM supports both modern GPKG (.gpkg.tar) and legacy TBZ2 (.tbz2) formats:
# Install from binary package
sudo grpm install --binpkg www-servers/nginx
# Build binary package from installed
sudo grpm build app-misc/hello-2.10
The binary package subsystem handles:
- Multiple compression formats (zstd, xz, gzip, bzip2)
- Package signing (GPG, SSH, RSA)
- Remote binhost support
2. Source Building (Emerge Command)
The emerge command executes full ebuild phases:
# Build from source with 8 parallel jobs
sudo grpm emerge --jobs 8 dev-lang/go
# Show build plan first
grpm emerge --pretend app-misc/hello
Output:
*** Dependency resolution (--pretend mode):
[ebuild N ] sys-libs/zlib-1.2.13 [0]
[ebuild N ] app-misc/hello-2.10 [0]
Total: 2 package(s)
GRPM implements all PMS phases: pkg_setup, src_unpack, src_prepare, src_configure, src_compile, src_install.
3. Native Repository Sync
No external rsync binary required. GRPM uses gokrazy/rsync, a pure Go rsync implementation:
# Auto-select best method
sudo grpm sync
# Use Git with GPG verification
sudo grpm sync --method git
# Native Go rsync (faster, no GPG)
sudo grpm sync --method rsync
4. Daemon Architecture
GRPM can run as a background service with gRPC and REST APIs:
# Start daemon
sudo grpm daemon
# CLI auto-connects to daemon if running
grpm status
The daemon provides:
-
gRPC on Unix socket (
/var/run/grpm.sock) -
REST API on HTTP (
127.0.0.1:8080) - Job queue with conflict detection
- Parallel operation support
5. Transactional Updates
On Btrfs or ZFS, GRPM automatically creates snapshots before package operations:
# Snapshot created automatically
sudo grpm install --snapshot-dir /.snapshots sys-libs/zlib
If installation fails, you can roll back to the snapshot.
Performance Optimization: 120x Faster Regex
GRPM uses coregex instead of Go's standard regexp package. The performance difference is dramatic:
| Benchmark | stdlib regexp | coregex | Speedup |
|---|---|---|---|
| Compile | 5,100 ns | 23 ns | 221x |
| Match | 185 ns | 1.5 ns | 123x |
All regex patterns are precompiled at package initialization:
// internal/repo/ebuild_parser.go
var (
ebuildVarRe = coregex.MustCompile(`(?m)^([A-Z_][A-Z0-9_]*)="([^"]*)"`)
ebuildAtomVersionRe = coregex.MustCompile(`^(.+?)-(\d.*)$`)
)
For a package manager parsing thousands of ebuilds, this optimization matters.
CLI Reference
GRPM provides a familiar interface for Portage users:
| Command | Description |
|---|---|
grpm resolve |
Resolve dependencies with SAT solver |
grpm install |
Install packages (binary or source) |
grpm emerge |
Build packages from source |
grpm remove |
Remove installed packages |
grpm search |
Search for packages |
grpm info |
Display package information |
grpm sync |
Synchronize repository |
grpm update |
Update @world/@system packages |
grpm depclean |
Remove orphaned packages |
grpm status |
Show daemon status |
Pretend and Ask Modes
Like Portage, GRPM supports dry-run and confirmation modes:
# Show what would happen (dry-run)
grpm install --pretend app-misc/hello
# Ask for confirmation
sudo grpm install --ask app-misc/hello
Output with --ask:
*** Installation plan:
[ebuild N ] sys-libs/zlib-1.2.13 to / USE="..."
[ebuild N ] app-misc/hello-2.10 to / USE="..."
Total: 2 package(s)
Would you like to merge these packages? [Yes/No]
Quick Start
Installation
# Download
wget https://github.com/grpmsoft/grpm/releases/download/v0.1.0/grpm_0.1.0_linux_x86_64.tar.gz
# Extract and install
tar -xzf grpm_0.1.0_linux_x86_64.tar.gz
sudo install -m 0755 grpm /usr/bin/grpm
# Verify
grpm -V
Basic Workflow
# Sync repository
sudo grpm sync
# Search for packages
grpm search firefox
# Show package info
grpm info dev-lang/go
# Build from source
sudo grpm emerge --pretend app-misc/hello
sudo grpm emerge app-misc/hello
# Install from binary
sudo grpm install --binpkg app-misc/hello
Technical Details
- Language: Go 1.25+
- License: Apache-2.0
- Platforms: Linux (x86_64, arm64, armv7, armv6, i386)
- Codebase: ~60,000 lines of Go
- Test Coverage: ~70%
Dependencies
GRPM uses carefully selected dependencies:
| Dependency | Purpose |
|---|---|
| gophersat | SAT solver for dependency resolution |
| cobra | CLI framework |
| grpc | Daemon communication |
| gokrazy/rsync | Native rsync implementation |
| modernc.org/sqlite | Pure Go SQLite for caching |
| coregex | High-performance regex |
All dependencies are pure Go — no CGO required.
Known Limitations
GRPM v0.1.0 is a foundation release. Current limitations:
- Ebuild execution limited to autotools workflow (./configure && make)
- Limited eclass support (toolchain-funcs, eutils, multilib)
- No EAPI 8 features
- CMake/Meson build systems not supported
These will be addressed in future releases.
What's Next
Development continues with iterative v0.x.x releases:
- Full EAPI 8 support
- CMake/Meson build system support
- Extended eclass support
- Performance optimization for large dependency graphs
- Community testing on real Gentoo systems
v1.0.0 will come after community validation and API stabilization — no fixed timeline, quality over deadlines.
Why Build This?
Three reasons:
Learning: Package managers are fascinating systems. Building one from scratch teaches you about dependency graphs, constraint solving, filesystem operations, and system integration.
Performance: Go's performance characteristics — fast compilation, efficient memory usage, excellent concurrency — make it ideal for system tools.
Community: Gentoo deserves modern tooling. If GRPM helps even a few users, the effort is worthwhile.
Try It Out
- Repository: github.com/grpmsoft/grpm
- Releases: github.com/grpmsoft/grpm/releases
- Documentation: CLI Reference
Contributions are welcome! Whether it's bug reports, feature requests, or code contributions — every bit helps.
Have you tried building your own package manager? Or have experience with SAT solvers in other domains? I'd love to hear about it in the comments.
Top comments (0)