banger/internal/paths/paths.go
Thales Maciel 238bb8a020
Switch to fetched runtime bundles
Stop treating Firecracker, kernels, modules, and guest images as tracked source files. Source checkouts now resolve runtime assets from ./runtime, while installed binaries keep using ../lib/banger.

Add a small runtimebundle helper plus runtime-bundle.toml so make can bootstrap, package, and install a runtime bundle with checksum validation. Update the shell helpers and daemon path hints to fail clearly when the bundle is missing instead of assuming repo-root artifacts.

This removes the tracked runtime blobs from HEAD in favor of an ignored local runtime/ tree. Verified with go test ./..., make build, bash -n on the shell helpers, make -n install, and a temporary package/fetch smoke test. The manifest URL/SHA still need a published bundle before fresh clones can bootstrap, and history rewrite remains a separate rollout step.
2026-03-16 15:05:10 -03:00

155 lines
3.9 KiB
Go

package paths
import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
)
type Layout struct {
ConfigHome string
StateHome string
CacheHome string
RuntimeHome string
ConfigDir string
StateDir string
CacheDir string
RuntimeDir string
SocketPath string
DBPath string
DaemonLog string
VMsDir string
ImagesDir string
}
func Resolve() (Layout, error) {
home, err := os.UserHomeDir()
if err != nil {
return Layout{}, err
}
configHome := getenvDefault("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
stateHome := getenvDefault("XDG_STATE_HOME", filepath.Join(home, ".local", "state"))
cacheHome := getenvDefault("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
runtimeHome := os.Getenv("XDG_RUNTIME_DIR")
if runtimeHome == "" {
runtimeHome = filepath.Join(os.TempDir(), fmt.Sprintf("banger-runtime-%d", os.Getuid()))
}
layout := Layout{
ConfigHome: configHome,
StateHome: stateHome,
CacheHome: cacheHome,
RuntimeHome: runtimeHome,
ConfigDir: filepath.Join(configHome, "banger"),
StateDir: filepath.Join(stateHome, "banger"),
CacheDir: filepath.Join(cacheHome, "banger"),
RuntimeDir: filepath.Join(runtimeHome, "banger"),
}
layout.SocketPath = filepath.Join(layout.RuntimeDir, "bangerd.sock")
layout.DBPath = filepath.Join(layout.StateDir, "state.db")
layout.DaemonLog = filepath.Join(layout.StateDir, "bangerd.log")
layout.VMsDir = filepath.Join(layout.StateDir, "vms")
layout.ImagesDir = filepath.Join(layout.StateDir, "images")
return layout, nil
}
func Ensure(layout Layout) error {
for _, dir := range []string{layout.ConfigDir, layout.StateDir, layout.CacheDir, layout.RuntimeDir, layout.VMsDir, layout.ImagesDir} {
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
}
return nil
}
var executablePath = os.Executable
func ResolveRuntimeDir(configuredRuntimeDir, deprecatedRepoRoot string) string {
for _, candidate := range []string{
os.Getenv("BANGER_RUNTIME_DIR"),
os.Getenv("BANGER_REPO_ROOT"),
configuredRuntimeDir,
deprecatedRepoRoot,
} {
if candidate = strings.TrimSpace(candidate); candidate != "" {
return filepath.Clean(candidate)
}
}
exe, err := executablePath()
if err != nil {
return ""
}
exeDir := filepath.Dir(exe)
if filepath.Base(exeDir) == "bin" {
installRuntimeDir := filepath.Clean(filepath.Join(exeDir, "..", "lib", "banger"))
if HasRuntimeBundle(installRuntimeDir) {
return installRuntimeDir
}
}
sourceRuntimeDir := filepath.Join(exeDir, "runtime")
if HasRuntimeBundle(sourceRuntimeDir) {
return sourceRuntimeDir
}
return ""
}
func HasRuntimeBundle(dir string) bool {
if strings.TrimSpace(dir) == "" {
return false
}
required := []string{
"firecracker",
"customize.sh",
"packages.apt",
"wtf/root/boot/vmlinux-6.8.0-94-generic",
}
for _, name := range required {
if _, err := os.Stat(filepath.Join(dir, name)); err != nil {
return false
}
}
for _, name := range []string{"rootfs-docker.ext4", "rootfs.ext4"} {
if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
return true
}
}
return false
}
func BangerdPath() (string, error) {
if env := os.Getenv("BANGER_DAEMON_BIN"); env != "" {
return env, nil
}
exe, err := executablePath()
if err != nil {
return "", err
}
dir := filepath.Dir(exe)
for _, candidate := range []string{
filepath.Join(dir, "bangerd"),
filepath.Join(dir, "bangerd.exe"),
} {
if _, err := os.Stat(candidate); err == nil {
return candidate, nil
}
}
return "", errors.New("bangerd binary not found next to banger; build ./cmd/bangerd")
}
func RuntimeBundleHint() string {
return "run `make runtime-bundle` or set runtime_dir in ~/.config/banger/config.toml"
}
func getenvDefault(key, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
return fallback
}
func RuntimeFallbackLabel() string {
return strconv.Itoa(os.Getuid())
}