feat(cli): add the prx command-line interface
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"prx/internal/config"
|
||||
"prx/internal/engine"
|
||||
"prx/internal/proto"
|
||||
"prx/internal/version"
|
||||
)
|
||||
|
||||
func (a *app) newLogsCmd() *cobra.Command {
|
||||
var follow bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "logs",
|
||||
Short: "Show proxy engine journal logs",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
if _, err := exec.LookPath("journalctl"); err != nil {
|
||||
return errors.New("journalctl not found; install systemd to use 'prx logs'")
|
||||
}
|
||||
cfg, err := a.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cfg.Engine.ServiceName == "" {
|
||||
return errors.New("engine.service_name is not configured; cannot read logs")
|
||||
}
|
||||
args := []string{"-u", cfg.Engine.ServiceName, "--no-pager"}
|
||||
if follow {
|
||||
args = append(args, "-f")
|
||||
} else {
|
||||
args = append(args, "-n", "100")
|
||||
}
|
||||
c := exec.CommandContext(cmd.Context(), "journalctl", args...)
|
||||
c.Stdout = a.out
|
||||
c.Stderr = a.errOut
|
||||
if err := c.Run(); err != nil {
|
||||
return fmt.Errorf("journalctl: %w (you may need to be in the systemd-journal group)", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolVarP(&follow, "follow", "f", false, "follow log output")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (a *app) newVersionCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
fmt.Fprintf(a.out, "prx %s (commit %s, built %s)\n", version.Version, version.Commit, version.Date)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *app) newInitCmd() *cobra.Command {
|
||||
var (
|
||||
force bool
|
||||
withEngine bool
|
||||
engineConfig string
|
||||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Write a default configuration file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
if config.Exists(a.configPath) && !force {
|
||||
fmt.Fprintf(a.out, "config already exists at %s (use --force to overwrite)\n", a.configPath)
|
||||
} else {
|
||||
if err := config.Save(a.configPath, config.Default()); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(a.out, "wrote default config to %s\n", a.configPath)
|
||||
}
|
||||
|
||||
if !withEngine {
|
||||
return nil
|
||||
}
|
||||
cfg, err := a.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := engineConfig
|
||||
if path == "" {
|
||||
path = cfg.Engine.ConfigPath
|
||||
}
|
||||
body, err := engine.Template(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.dispatch(cmd.Context(), cfg, proto.ActionInitEngine, func(p *proto.Plan) {
|
||||
p.EngineConfig = path
|
||||
p.EngineConfigBody = body
|
||||
})
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolVar(&force, "force", false, "overwrite an existing config file")
|
||||
cmd.Flags().BoolVar(&withEngine, "engine-config", false, "also generate a baseline engine configuration")
|
||||
cmd.Flags().StringVar(&engineConfig, "engine-config-path", "", "engine config path (defaults to engine.config_path)")
|
||||
return cmd
|
||||
}
|
||||
Reference in New Issue
Block a user