Files
ax/src/cmd/root.go
T

123 lines
3.2 KiB
Go
Raw Normal View History

2026-03-26 12:48:47 +00:00
package cmd
import (
2026-04-01 22:39:44 +02:00
"axolotl/models"
2026-03-29 18:58:34 +02:00
"axolotl/service"
"axolotl/store"
2026-03-29 18:58:34 +02:00
"fmt"
2026-03-26 12:48:47 +00:00
"os"
"strings"
2026-03-26 12:48:47 +00:00
"github.com/spf13/cobra"
)
func getNodeService() (service.NodeService, error) {
user := cfg.User
if user == "" {
return nil, fmt.Errorf("no user configured: run 'ax user set <username>' first")
}
if cfg.Remote.Host != "" {
base := fmt.Sprintf("http://%s:%d", cfg.Remote.Host, cfg.Remote.Port)
return service.NewRemoteNodeService(base, user), nil
}
st, err := store.FindAndOpenSQLiteStore()
if err != nil {
return nil, err
}
return service.NewLocalNodeService(st, user), nil
}
2026-03-26 12:48:47 +00:00
var jsonFlag bool
var cfg *store.Config
var rootCmd = &cobra.Command{Use: "ax", Short: "The axolotl issue tracker"}
2026-03-26 12:48:47 +00:00
func Execute() {
2026-03-29 18:58:34 +02:00
var err error
cfg, err = store.LoadConfig()
2026-03-29 18:58:34 +02:00
if err != nil {
fmt.Fprintln(os.Stderr, "failed to load config:", err)
os.Exit(1)
}
RegisterAliasCommands()
2026-03-26 12:48:47 +00:00
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().BoolVar(&jsonFlag, "json", false, "")
}
func RegisterAliasCommands() {
2026-03-29 18:58:34 +02:00
rootCmd.AddGroup(&cobra.Group{ID: "aliases", Title: "Aliases:"})
aliases := cfg.Aliases
2026-03-29 18:58:34 +02:00
for _, a := range aliases {
rootCmd.AddCommand(&cobra.Command{
Use: a.Name,
Short: a.Description,
GroupID: "aliases",
DisableFlagParsing: true,
Run: func(ccmd *cobra.Command, args []string) {
acmd := a.Command
acmd = strings.ReplaceAll(acmd, "$me", cfg.User)
parts := strings.Fields(acmd)
var expanded []string
usedArgs := make([]bool, len(args))
for _, part := range parts {
if part == "$@" {
expanded = append(expanded, args...)
for i := range usedArgs {
usedArgs[i] = true
}
continue
}
hasCatchAll := strings.Contains(part, "$@")
replaced := part
if hasCatchAll {
replaced = strings.ReplaceAll(replaced, "$@", strings.Join(args, " "))
for i := range usedArgs {
usedArgs[i] = true
}
}
for i := len(args) - 1; i >= 0; i-- {
placeholder := fmt.Sprintf("$%d", i+1)
if strings.Contains(replaced, placeholder) {
replaced = strings.ReplaceAll(replaced, placeholder, args[i])
usedArgs[i] = true
}
}
expanded = append(expanded, replaced)
}
// Forward any unconsumed args (e.g. --json flag).
for i, arg := range args {
if !usedArgs[i] {
expanded = append(expanded, arg)
}
}
rootCmd.SetArgs(expanded)
2026-03-29 18:58:34 +02:00
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
},
})
}
}
2026-04-01 22:39:44 +02:00
// parseRelInput parses a rel string into a RelInput.
// Formats:
// - "prefix::value" → property rel with no target (tag)
// - "relname:target" → edge rel with a target node
// - "tagname" → simple label rel with no target (alias for --tag)
func parseRelInput(s string) (service.RelInput, error) {
if strings.Contains(s, "::") {
// Property: name::value — no target node.
return service.RelInput{Type: models.RelType(s), Target: ""}, nil
}
if idx := strings.Index(s, ":"); idx >= 0 {
// Edge rel: relname:target.
return service.RelInput{Type: models.RelType(s[:idx]), Target: s[idx+1:]}, nil
}
// Simple label tag — no target node.
return service.RelInput{Type: models.RelType(s), Target: ""}, nil
}