diff options
| author | James O'Doherty <james@theodohertyfamily.com> | 2026-05-22 09:18:55 -0400 |
|---|---|---|
| committer | James O'Doherty <james@theodohertyfamily.com> | 2026-05-22 09:18:55 -0400 |
| commit | 96d75d9f1fab87365d7e6b5070eed3a5757c3484 (patch) | |
| tree | e01144dbb5338826d36f1b07444ebd78407c3bf4 /internal/cli/cli.go | |
| parent | 756ba94292b408cc4f23d137b2c4c52009b2b38d (diff) | |
Refactor CLI for testability and implement hermetic config path injection
Diffstat (limited to 'internal/cli/cli.go')
| -rw-r--r-- | internal/cli/cli.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go new file mode 100644 index 0000000..cb95202 --- /dev/null +++ b/internal/cli/cli.go @@ -0,0 +1,114 @@ +package cli + +import ( + "flag" + "fmt" + + "git.theodohertyfamily.com/tools/wg-wrap/internal/config" +) + +type App struct { + Args []string + ConfigDir string // Optional override for profile storage location +} + +func NewApp(args []string) *App { + return &App{Args: args} +} + +func (a *App) Run() error { + // Handle subcommands first (profile list, import, configure, delete, stop) + if len(a.Args) > 1 && a.Args[1] == "profile" { + return a.handleProfileCmd() + } + + cfg := &config.Config{} + + fs := flag.NewFlagSet("wg-wrap", flag.ExitOnError) + fs.StringVar(&cfg.Profile, "profile", "", "WireGuard profile to use (filename without extension in ~/.config/wg-wrap/profiles/)") + fs.StringVar(&cfg.DNSServer, "dns-server", "", "Override DNS server to use") + + args := a.Args[1:] + sepIdx := -1 + for i, arg := range args { + if arg == "--" { + sepIdx = i + break + } + } + + var flagsToParse []string + if sepIdx != -1 { + flagsToParse = args[:sepIdx] + cfg.Command = args[sepIdx+1:] + } else { + flagsToParse = args + } + + err := fs.Parse(flagsToParse) + if err != nil { + return fmt.Errorf("error parsing flags: %w", err) + } + + if sepIdx == -1 { + cfg.Command = fs.Args() + } + + if len(cfg.Command) == 0 { + return fmt.Errorf("no command provided. use --help for usage") + } + + if cfg.Profile == "" { + cfg.Profile = "default" + } + + profilesDir := a.ConfigDir + if profilesDir == "" { + profilesDir = config.GetDefaultProfilesDir() + } + + fmt.Printf("Profile: %s\n", cfg.Profile) + fmt.Printf("Profiles Directory: %s\n", profilesDir) + fmt.Printf("DNS Server: %s\n", cfg.DNSServer) + fmt.Printf("Command: %v\n", cfg.Command) + return nil +} + +func (a *App) handleProfileCmd() error { + if len(a.Args) < 3 { + return fmt.Errorf("usage: wg-wrap profile <list|import|configure|delete|stop> [args]") + } + + subCmd := a.Args[2] + switch subCmd { + case "list": + fmt.Println("Listing profiles...") + return fmt.Errorf("profile list not yet implemented") + case "import": + if len(a.Args) < 4 { + return fmt.Errorf("usage: wg-wrap profile import <path>") + } + fmt.Printf("Importing profile from %s...\n", a.Args[3]) + return fmt.Errorf("profile import not yet implemented") + case "configure": + if len(a.Args) < 4 { + return fmt.Errorf("usage: wg-wrap profile configure <name>") + } + fmt.Printf("Configuring profile %s...\n", a.Args[3]) + return fmt.Errorf("profile configure not yet implemented") + case "delete": + if len(a.Args) < 4 { + return fmt.Errorf("usage: wg-wrap profile delete <name>") + } + fmt.Printf("Deleting profile %s...\n", a.Args[3]) + return fmt.Errorf("profile delete not yet implemented") + case "stop": + if len(a.Args) < 4 { + return fmt.Errorf("usage: wg-wrap profile stop <name>") + } + fmt.Printf("Stopping profile %s and unpinning namespace...\n", a.Args[3]) + return fmt.Errorf("profile stop not yet implemented") + default: + return fmt.Errorf("unknown profile subcommand: %s", subCmd) + } +} |
