mirror of
https://github.com/gogrlx/snack.git
synced 2026-04-02 05:08:42 -07:00
e46b2b4ce4a90e9b94c8b52a272afd08f3f5db4b
Run with: go test -tags containertest -v -count=1 -timeout 10m . Spins up Debian, Alpine, Arch, and Fedora containers locally via Docker, copies the module source in, and runs the full integration test suite in each. All four distros pass. Requires Docker. Use build tag 'containertest' (separate from 'integration' which runs directly on the host).
snack πΏ
Idiomatic Go wrappers for system package managers.
snack provides thin, context-aware Go bindings for system package managers. Think taigrr/systemctl but for package management.
Part of the grlx ecosystem.
Supported Package Managers
| Package | Manager | Platform | Status |
|---|---|---|---|
pacman |
pacman | Arch Linux | π§ |
aur |
AUR (makepkg) | Arch Linux | π§ |
apk |
apk-tools | Alpine Linux | π§ |
apt |
APT (apt-get/apt-cache) | Debian/Ubuntu | π§ |
dpkg |
dpkg | Debian/Ubuntu | π§ |
dnf |
DNF | Fedora/RHEL | π§ |
rpm |
RPM | Fedora/RHEL | π§ |
flatpak |
Flatpak | Cross-distro | π§ |
snap |
snapd | Cross-distro | π§ |
pkg |
pkg(8) | FreeBSD | π§ |
ports |
ports/packages | OpenBSD | π§ |
detect |
Auto-detection | All | π§ |
Install
go get github.com/gogrlx/snack
Usage
package main
import (
"context"
"fmt"
"log"
"github.com/gogrlx/snack"
"github.com/gogrlx/snack/apt"
)
func main() {
ctx := context.Background()
mgr := apt.New()
// Install a package
err := mgr.Install(ctx, []string{"nginx"}, snack.WithSudo(), snack.WithAssumeYes())
if err != nil {
log.Fatal(err)
}
// Check if installed
installed, err := mgr.IsInstalled(ctx, "nginx")
if err != nil {
log.Fatal(err)
}
fmt.Println("nginx installed:", installed)
}
Auto-detection
import "github.com/gogrlx/snack/detect"
mgr, err := detect.Default()
if err != nil {
log.Fatal(err)
}
fmt.Println("Detected:", mgr.Name())
Interfaces
snack uses a layered interface design. Every provider implements Manager (the base). Extended capabilities are optional β use type assertions to check support:
// Base β every provider
snack.Manager // Install, Remove, Purge, Upgrade, Update, List, Search, Info, IsInstalled, Version
// Optional capabilities β type-assert to check
snack.VersionQuerier // LatestVersion, ListUpgrades, UpgradeAvailable, VersionCmp
snack.Holder // Hold, Unhold, ListHeld (version pinning)
snack.Cleaner // Autoremove, Clean (orphan/cache cleanup)
snack.FileOwner // FileList, Owner (file-to-package queries)
snack.RepoManager // ListRepos, AddRepo, RemoveRepo
snack.KeyManager // AddKey, RemoveKey, ListKeys (GPG keys)
snack.Grouper // GroupList, GroupInfo, GroupInstall
snack.NameNormalizer // NormalizeName, ParseArch
Check capabilities at runtime:
caps := snack.GetCapabilities(mgr)
if caps.Hold {
mgr.(snack.Holder).Hold(ctx, []string{"nginx"})
}
Design
- Thin CLI wrappers β each sub-package wraps a package manager's CLI tools. No FFI, no library bindings.
- Common interface β all managers implement
snack.Manager, making them interchangeable. - Capability interfaces β extended features via type assertion, so providers aren't forced to stub unsupported operations.
- Per-provider mutex β each provider serializes mutating operations independently; apt + snap can run in parallel.
- Context-aware β all operations accept
context.Contextfor cancellation and timeouts. - Platform-safe β build tags ensure packages compile everywhere but only run where appropriate.
- No root assumption β use
snack.WithSudo()when elevated privileges are needed.
Implementation Priority
- pacman + AUR (Arch Linux)
- apk (Alpine Linux)
- apt + dpkg (Debian/Ubuntu)
- dnf + rpm (Fedora/RHEL)
- flatpak + snap (cross-distro)
- pkg + ports (BSD)
CLI
A companion CLI tool is planned for direct terminal usage:
snack install nginx
snack remove nginx
snack search redis
snack list
snack upgrade
License
0BSD β see LICENSE.
Languages
Go
99.8%
Shell
0.2%