package cli import ( "errors" "fmt" "path/filepath" "strings" "banger/internal/api" "banger/internal/rpc" "github.com/spf13/cobra" ) func (d *deps) newKernelCommand() *cobra.Command { cmd := &cobra.Command{ Use: "kernel", Short: "Manage the local kernel catalog", RunE: helpNoArgs, } cmd.AddCommand( d.newKernelListCommand(), d.newKernelShowCommand(), d.newKernelRmCommand(), d.newKernelImportCommand(), d.newKernelPullCommand(), ) return cmd } func (d *deps) newKernelPullCommand() *cobra.Command { var force bool cmd := &cobra.Command{ Use: "pull ", Short: "Download a cataloged kernel bundle", Args: exactArgsUsage(1, "usage: banger kernel pull [--force]"), RunE: func(cmd *cobra.Command, args []string) error { layout, _, err := d.ensureDaemon(cmd.Context()) if err != nil { return err } var result api.KernelShowResult err = withHeartbeat(cmd.ErrOrStderr(), "kernel pull", func() error { var callErr error result, callErr = rpc.Call[api.KernelShowResult](cmd.Context(), layout.SocketPath, "kernel.pull", api.KernelPullParams{Name: args[0], Force: force}) return callErr }) if err != nil { return err } return printJSON(cmd.OutOrStdout(), result.Entry) }, } cmd.Flags().BoolVar(&force, "force", false, "re-pull even if already present") return cmd } func (d *deps) newKernelImportCommand() *cobra.Command { var params api.KernelImportParams cmd := &cobra.Command{ Use: "import ", Short: "Import a kernel bundle produced by scripts/make-*-kernel.sh", Long: "Copy the kernel, optional initrd, and optional modules directory from into the local kernel catalog keyed by . is usually build/manual/void-kernel or build/manual/alpine-kernel.", Args: exactArgsUsage(1, "usage: banger kernel import --from "), RunE: func(cmd *cobra.Command, args []string) error { params.Name = args[0] if strings.TrimSpace(params.FromDir) == "" { return errors.New("--from is required") } abs, err := filepath.Abs(params.FromDir) if err != nil { return err } params.FromDir = abs layout, _, err := d.ensureDaemon(cmd.Context()) if err != nil { return err } result, err := rpc.Call[api.KernelShowResult](cmd.Context(), layout.SocketPath, "kernel.import", params) if err != nil { return err } return printJSON(cmd.OutOrStdout(), result.Entry) }, } cmd.Flags().StringVar(¶ms.FromDir, "from", "", "directory produced by make-*-kernel.sh (e.g. build/manual/void-kernel)") cmd.Flags().StringVar(¶ms.Distro, "distro", "", "distribution label stored in the manifest (e.g. void, alpine)") cmd.Flags().StringVar(¶ms.Arch, "arch", "", "architecture label stored in the manifest (e.g. x86_64)") return cmd } func (d *deps) newKernelListCommand() *cobra.Command { var available bool cmd := &cobra.Command{ Use: "list", Aliases: []string{"ls"}, Short: "List kernels (local by default, or --available for the catalog)", Args: noArgsUsage("usage: banger kernel list [--available]"), RunE: func(cmd *cobra.Command, args []string) error { layout, _, err := d.ensureDaemon(cmd.Context()) if err != nil { return err } if available { result, err := rpc.Call[api.KernelCatalogResult](cmd.Context(), layout.SocketPath, "kernel.catalog", api.Empty{}) if err != nil { return err } return printKernelCatalogTable(cmd.OutOrStdout(), result.Entries) } result, err := rpc.Call[api.KernelListResult](cmd.Context(), layout.SocketPath, "kernel.list", api.Empty{}) if err != nil { return err } return printKernelListTable(cmd.OutOrStdout(), result.Entries) }, } cmd.Flags().BoolVar(&available, "available", false, "show the built-in catalog (with pulled/available status) instead of local entries") return cmd } func (d *deps) newKernelShowCommand() *cobra.Command { return &cobra.Command{ Use: "show ", Short: "Show kernel catalog entry details", Args: exactArgsUsage(1, "usage: banger kernel show "), ValidArgsFunction: d.completeKernelNameOnlyAtPos0, RunE: func(cmd *cobra.Command, args []string) error { layout, _, err := d.ensureDaemon(cmd.Context()) if err != nil { return err } result, err := rpc.Call[api.KernelShowResult](cmd.Context(), layout.SocketPath, "kernel.show", api.KernelRefParams{Name: args[0]}) if err != nil { return err } return printJSON(cmd.OutOrStdout(), result.Entry) }, } } func (d *deps) newKernelRmCommand() *cobra.Command { return &cobra.Command{ Use: "rm ", Aliases: []string{"remove", "delete"}, Short: "Remove a kernel catalog entry", Args: exactArgsUsage(1, "usage: banger kernel rm "), ValidArgsFunction: d.completeKernelNameOnlyAtPos0, RunE: func(cmd *cobra.Command, args []string) error { layout, _, err := d.ensureDaemon(cmd.Context()) if err != nil { return err } if _, err := rpc.Call[api.Empty](cmd.Context(), layout.SocketPath, "kernel.delete", api.KernelRefParams{Name: args[0]}); err != nil { return err } _, err = fmt.Fprintf(cmd.OutOrStdout(), "removed %s\n", args[0]) return err }, } }