From 3d5e1a091d91d78476a4125c0dc92bd5756e003c Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Wed, 26 Feb 2025 06:43:25 +0100 Subject: [PATCH] feat(config): CLI integration --- config/service.go | 8 +++---- main.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/config/service.go b/config/service.go index 8b13d08..09b2a26 100644 --- a/config/service.go +++ b/config/service.go @@ -40,7 +40,7 @@ func NewService(configDirFunc ConfigDirFunc) (*Service, error) { // ReadOrCreateConfig reads the configuration from the file at the given path or // creates it with default values. func (s *Service) ReadOrCreateConfig() (cfg Config, _ error) { - if _, err := os.Stat(s.path()); os.IsNotExist(err) { + if _, err := os.Stat(s.Path()); os.IsNotExist(err) { return s.createConfig() } else if err != nil { return cfg, fmt.Errorf("stat: %w", err) @@ -50,7 +50,7 @@ func (s *Service) ReadOrCreateConfig() (cfg Config, _ error) { } func (s *Service) readConfig() (cfg Config, _ error) { - contents, err := os.ReadFile(s.path()) + contents, err := os.ReadFile(s.Path()) if err != nil { return cfg, fmt.Errorf("read file: %w", err) } @@ -80,14 +80,14 @@ func (s *Service) createConfig() (cfg Config, _ error) { return cfg, fmt.Errorf("marshal: %w", err) } - if err = os.WriteFile(s.path(), yamlBytes, 0644); err != nil { + if err = os.WriteFile(s.Path(), yamlBytes, 0644); err != nil { return cfg, fmt.Errorf("write file: %w", err) } return cfg, nil } -func (s *Service) path() string { +func (s *Service) Path() string { return filepath.Join(s.configDir, "config.yaml") } diff --git a/main.go b/main.go index 2afd8cf..1583d77 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,16 @@ package main import ( "context" + "flag" "fmt" "log/slog" "os" + "os/exec" + "syscall" "git.netflux.io/rob/octoplex/app" "git.netflux.io/rob/octoplex/config" + "git.netflux.io/rob/octoplex/domain" dockerclient "github.com/docker/docker/client" "golang.design/x/clipboard" ) @@ -27,6 +31,25 @@ func run(ctx context.Context) error { return fmt.Errorf("build config service: %w", err) } + flag.Parse() + if narg := flag.NArg(); narg > 1 { + flag.Usage() + return fmt.Errorf("too many arguments") + } else if narg == 1 { + switch flag.Arg(0) { + case "edit-config": + return editConfigFile(configService.Path()) + case "print-config": + return printConfigPath(configService.Path()) + case "version": + return printVersion() + case "help", "-h", "--help": + // TODO: improve help message + flag.Usage() + return nil + } + } + cfg, err := configService.ReadOrCreateConfig() if err != nil { return fmt.Errorf("read or create config: %w", err) @@ -58,3 +81,36 @@ func run(ctx context.Context) error { logger, ) } + +// editConfigFile opens the config file in the user's editor. +func editConfigFile(configPath string) error { + editor := os.Getenv("EDITOR") + if editor == "" { + editor = "vi" + } + binary, err := exec.LookPath(editor) + if err != nil { + return fmt.Errorf("look path: %w", err) + } + + fmt.Fprintf(os.Stderr, "Editing config file: %s\n", configPath) + fmt.Println(binary) + + if err := syscall.Exec(binary, []string{"--", configPath}, os.Environ()); err != nil { + return fmt.Errorf("exec: %w", err) + } + + return nil +} + +// printConfigPath prints the path to the config file to stderr. +func printConfigPath(configPath string) error { + fmt.Fprintln(os.Stderr, configPath) + return nil +} + +// printVersion prints the version of the application to stderr. +func printVersion() error { + fmt.Fprintf(os.Stderr, "%s version %s\n", domain.AppName, "0.0.0") + return nil +}