package cmd import ( "fmt" "sort" "strings" "forgejo.zerova.net/public/fgj-sid/internal/config" "github.com/spf13/cobra" ) var loginsCmd = &cobra.Command{ Use: "logins", Short: "Manage configured Forgejo/Gitea logins", Long: `Manage configured Forgejo/Gitea logins. This is a complementary command to 'fgj auth' using the noun vocabulary familiar to users of tea. Use 'fgj auth login' to add a new login and 'fgj auth logout' to remove one.`, } var loginsListCmd = &cobra.Command{ Use: "list", Aliases: []string{"ls"}, Short: "List all configured logins", Long: "List all configured Forgejo/Gitea logins with their hostname, user, protocol, default flag, and match_dirs.", RunE: runLoginsList, } var loginsDefaultCmd = &cobra.Command{ Use: "default [hostname]", Short: "Get or set the default login", Long: `Get or set the default login. With no argument, prints the currently-configured default hostname (or "no default set" if none is configured). With a hostname argument, marks that login as the default and unsets the default flag on all other logins.`, Args: cobra.MaximumNArgs(1), RunE: runLoginsDefault, } func init() { rootCmd.AddCommand(loginsCmd) loginsCmd.AddCommand(loginsListCmd) loginsCmd.AddCommand(loginsDefaultCmd) addJSONFlags(loginsListCmd, "Output logins as JSON") } // loginEntry is the JSON representation of a configured login. type loginEntry struct { Hostname string `json:"hostname"` User string `json:"user"` GitProtocol string `json:"git_protocol"` Default bool `json:"default"` MatchDirs []string `json:"match_dirs"` } func runLoginsList(cmd *cobra.Command, args []string) error { cfg, err := config.Load() if err != nil { return fmt.Errorf("failed to load config: %w", err) } hostnames := make([]string, 0, len(cfg.Hosts)) for hostname := range cfg.Hosts { hostnames = append(hostnames, hostname) } // Sort by config-file order; fall back to alphabetical when Order is // equal (e.g., both zero because the config was constructed in-memory // rather than loaded from disk). sort.Slice(hostnames, func(i, j int) bool { a, b := cfg.Hosts[hostnames[i]], cfg.Hosts[hostnames[j]] if a.Order != b.Order { return a.Order < b.Order } return hostnames[i] < hostnames[j] }) if wantJSON(cmd) { entries := make([]loginEntry, 0, len(hostnames)) for _, hostname := range hostnames { h := cfg.Hosts[hostname] dirs := h.MatchDirs if dirs == nil { dirs = []string{} } entries = append(entries, loginEntry{ Hostname: hostname, User: h.User, GitProtocol: h.GitProtocol, Default: h.Default, MatchDirs: dirs, }) } return outputJSON(cmd, entries) } if len(hostnames) == 0 { fmt.Fprintln(ios.Out, "No logins configured") fmt.Fprintln(ios.Out, "Run 'fgj auth login' to add a login") return nil } tp := ios.NewTablePrinter() tp.AddHeader("HOSTNAME", "USER", "PROTOCOL", "DEFAULT", "MATCH_DIRS") for _, hostname := range hostnames { h := cfg.Hosts[hostname] defaultMark := "" if h.Default { defaultMark = "*" } tp.AddRow( hostname, h.User, h.GitProtocol, defaultMark, strings.Join(h.MatchDirs, ", "), ) } return tp.Render() } func runLoginsDefault(cmd *cobra.Command, args []string) error { cfg, err := config.Load() if err != nil { return fmt.Errorf("failed to load config: %w", err) } if len(args) == 0 { current := cfg.DefaultHost() if current == "" { fmt.Fprintln(ios.Out, "no default set") return nil } fmt.Fprintln(ios.Out, current) return nil } target := args[0] if _, ok := cfg.Hosts[target]; !ok { return fmt.Errorf("no configuration found for host %s", target) } for hostname, h := range cfg.Hosts { h.Default = (hostname == target) cfg.Hosts[hostname] = h } if err := cfg.Save(); err != nil { return fmt.Errorf("failed to save config: %w", err) } cs := ios.ColorScheme() fmt.Fprintf(ios.Out, "%s Default host set to %s\n", cs.SuccessIcon(), target) return nil }