Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

sower-activator: extract simple activation tool

we will use this as a lightweight stable interface to activating across boundaries

+199 -3
+1
.gitignore
··· 43 43 /sower 44 44 dev-server.json 45 45 .erlang-history/ 46 + sower-activator
+72
cmd/sower-activator/activate.go
··· 1 + package main 2 + 3 + import ( 4 + "fmt" 5 + "log/slog" 6 + "os" 7 + "os/exec" 8 + ) 9 + 10 + // Seed type constants 11 + const ( 12 + SeedTypeHomeManager = "home-manager" 13 + SeedTypeNixOS = "nixos" 14 + ) 15 + 16 + // activate activates a seed based on its type 17 + func activate(seedType, storePath, mode string) error { 18 + var err error 19 + 20 + switch seedType { 21 + case SeedTypeHomeManager: 22 + cmd := exec.Command(fmt.Sprintf("%s/activate", storePath)) 23 + err = runCommand(cmd) 24 + if err != nil { 25 + return fmt.Errorf("failed to activate home-manager generation: %v", err) 26 + } 27 + 28 + case SeedTypeNixOS: 29 + err = setProfile("/nix/var/nix/profiles/system", storePath) 30 + if err != nil { 31 + return fmt.Errorf("failed to set nixos profile: %v", err) 32 + } 33 + 34 + switchCmd := exec.Command(fmt.Sprintf("%s/bin/switch-to-configuration", storePath), mode) 35 + err = runCommand(switchCmd) 36 + if err != nil { 37 + return fmt.Errorf("failed to run switch-to-configuration: %v", err) 38 + } 39 + 40 + default: 41 + return fmt.Errorf("unsupported seed type: %s", seedType) 42 + } 43 + 44 + return nil 45 + } 46 + 47 + // setProfile sets a nix profile to point to the given store path 48 + func setProfile(profile, storePath string) error { 49 + profileCmd := exec.Command("nix-env", "--set", "--profile", profile, storePath) 50 + err := runCommand(profileCmd) 51 + if err != nil { 52 + return fmt.Errorf("failed to set profile: %v", err) 53 + } 54 + 55 + return nil 56 + } 57 + 58 + // runCommand executes a command with stdout and stderr attached 59 + func runCommand(cmd *exec.Cmd) error { 60 + // Directly attach streams for real-time output 61 + cmd.Stdout = os.Stdout 62 + cmd.Stderr = os.Stderr 63 + 64 + slog.Debug("Running command", "cmd", cmd.String()) 65 + 66 + err := cmd.Run() 67 + if err != nil { 68 + return fmt.Errorf("failed to run command: %v", err) 69 + } 70 + 71 + return nil 72 + }
+83
cmd/sower-activator/main.go
··· 1 + package main 2 + 3 + import ( 4 + "flag" 5 + "log/slog" 6 + "os" 7 + "time" 8 + ) 9 + 10 + func main() { 11 + // Define command-line flags 12 + var ( 13 + seedType = flag.String("type", "", "Seed type (nixos, home-manager)") 14 + path = flag.String("path", "", "Nix store path to activate") 15 + mode = flag.String("mode", "switch", "Activation mode for NixOS (switch, boot, test, etc.)") 16 + debug = flag.Bool("debug", false, "Enable debug logging") 17 + ) 18 + 19 + flag.Parse() 20 + 21 + // Setup logger 22 + initLogger(*debug) 23 + 24 + // Validate required arguments 25 + if *seedType == "" { 26 + slog.Error("Missing required flag: --type") 27 + flag.Usage() 28 + os.Exit(1) 29 + } 30 + 31 + if *path == "" { 32 + slog.Error("Missing required flag: --path") 33 + flag.Usage() 34 + os.Exit(1) 35 + } 36 + 37 + // Validate seed type 38 + if *seedType != SeedTypeNixOS && *seedType != SeedTypeHomeManager { 39 + slog.Error("Invalid seed type. Must be 'nixos' or 'home-manager'", "type", *seedType) 40 + os.Exit(1) 41 + } 42 + 43 + // Check if running as root for NixOS 44 + if *seedType == SeedTypeNixOS && os.Getuid() != 0 { 45 + slog.Error("NixOS activation must be run as root") 46 + os.Exit(1) 47 + } 48 + 49 + // Log what we're about to do 50 + slog.Info("Activating seed", "type", *seedType, "path", *path, "mode", *mode) 51 + 52 + // Perform activation 53 + err := activate(*seedType, *path, *mode) 54 + if err != nil { 55 + slog.Error("Activation failed", "error", err) 56 + os.Exit(1) 57 + } 58 + 59 + slog.Info("Activation complete", "type", *seedType, "path", *path) 60 + } 61 + 62 + func initLogger(debug bool) { 63 + logLevel := slog.LevelInfo 64 + if debug { 65 + logLevel = slog.LevelDebug 66 + } 67 + 68 + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ 69 + Level: logLevel, 70 + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { 71 + // Format time more compactly 72 + if a.Key == slog.TimeKey { 73 + return slog.Attr{ 74 + Key: a.Key, 75 + Value: slog.StringValue(time.Now().Format(time.DateTime)), 76 + } 77 + } 78 + return a 79 + }, 80 + })) 81 + 82 + slog.SetDefault(logger) 83 + }
+4
flake.nix
··· 120 120 }; 121 121 122 122 packages = rec { 123 + activator = pkgs.callPackage ./nix/packages/activator.nix { 124 + inherit version; 125 + }; 126 + 123 127 cli = pkgs.callPackage ./nix/packages/cli.nix { 124 128 inherit beamPackages version; 125 129 };
+3 -2
justfile
··· 118 118 set -eou pipefail 119 119 120 120 setKV() { 121 - sed -i "s|$1 = \".*\"|$1 = \"${2:-}\"|" ./nix/packages/cli.nix 121 + sed -i "s|$1 = \".*\"|$1 = \"${2:-}\"|" ./nix/packages/activator.nix 122 + sed -i "s|$1 = \".*\"|$1 = \"${2:-}\"|" ./nix/packages/go-cli.nix 122 123 } 123 124 124 125 setKV vendorHash "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" # Necessary to force clean build. 125 126 126 127 set +e 127 - VENDOR_HASH=$(nix build --no-link .#cli 2>&1 >/dev/null | grep "got:" | cut -d':' -f2 | sed 's| ||g') 128 + VENDOR_HASH=$(nix build --no-link .#activator 2>&1 >/dev/null | grep "got:" | cut -d':' -f2 | sed 's| ||g') 128 129 set -e 129 130 130 131 if [ -n "${VENDOR_HASH:-}" ]; then
+35
nix/packages/activator.nix
··· 1 + { 2 + lib, 3 + buildGoModule, 4 + version, 5 + }: 6 + let 7 + nixpkgsref = lib.elemAt (lib.splitString "." lib.version) 3; 8 + in 9 + 10 + buildGoModule rec { 11 + pname = "sower-activator"; 12 + inherit version; 13 + 14 + src = 15 + with lib.fileset; 16 + toSource { 17 + root = ../..; 18 + fileset = unions [ 19 + ../../cmd/sower-activator 20 + ../../go.mod 21 + ../../go.sum 22 + ]; 23 + }; 24 + 25 + env.CGO_ENABLED = 0; 26 + 27 + ldflags = [ 28 + "-X main.version=${version}" 29 + "-X main.nixpkgsref=${nixpkgsref}" 30 + ]; 31 + 32 + vendorHash = "sha256-Ct7urD4IrXEcvNEqGUtaKqyr4M6S7ZEpuQQIUb91dIM="; 33 + 34 + meta.mainProgram = "sower"; 35 + }
+1 -1
nix/packages/go-cli.nix
··· 52 52 # disable checks for now until better fleshed out 53 53 doCheck = false; 54 54 55 - vendorHash = "sha256-DJdtdiMwVJ0yREdx6OqDlYX/jp0dPHsBmz4Ltigqlgw="; 55 + vendorHash = "sha256-Ct7urD4IrXEcvNEqGUtaKqyr4M6S7ZEpuQQIUb91dIM="; 56 56 57 57 meta.mainProgram = "sower"; 58 58 }