// Copyright 2024 Matthew Rich . All rights reserved. package main import ( "context" "decl/internal/data" _ "decl/internal/config" "decl/internal/folio" _ "decl/internal/resource" _ "decl/internal/fan" "decl/internal/builtin" _ "errors" "flag" "fmt" _ "gopkg.in/yaml.v3" "io" "log/slog" "os" "decl/internal/client" ) const ( FormatYaml = "yaml" FormatJson = "json" ) var ( version string commit string date string ) var Client *client.App = client.NewClient() var GlobalOformat *string var GlobalOutput string var GlobalQuiet *bool var ImportMerge *bool var ImportResource *string var ApplyDelete *bool var ConfigPath string var ConfigDoc data.Document = folio.DocumentRegistry.NewDocument("") var ctx context.Context = context.Background() type RunCommand func(cmd *flag.FlagSet, output io.Writer) error type SubCommand struct { Name string Run RunCommand } var jxSubCommands = []SubCommand{ { Name: "diff", Run: DiffSubCommand, }, { Name: "apply", Run: ApplySubCommand, }, { Name: "import", Run: ImportSubCommand, }, { Name: "config", Run: ConfigSubCommand, }, } func VersionUsage() { fmt.Println("jx") fmt.Printf("version: %s\n", version) fmt.Printf("commit: %s\n", commit) fmt.Printf("date: %s\n", date) } func LoggerConfig() { var programLevel = new(slog.LevelVar) logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})) slog.SetDefault(logger) if debugLogging, ok := os.LookupEnv("JX_DEBUG"); ok && debugLogging != "" { programLevel.Set(slog.LevelDebug) } else { programLevel.Set(slog.LevelError) } } func ConfigSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { if err = cmd.Parse(os.Args[2:]); err != nil { return } if err = Client.SetOutput(GlobalOutput); err == nil { if configErr := Client.SystemConfiguration(ConfigPath); configErr != nil { slog.Info("Main.Import - SystemConfiguration", "config", ConfigPath, "error", configErr) } err = Client.ConfigCmd(cmd.Args(), true) } return } func ImportSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { ImportResource = cmd.String("resource", "", "(uri) Add a resource to the document.") ImportMerge = cmd.Bool("merge", false, "Merge resources into a single document.") e := cmd.Parse(os.Args[2:]) if e != nil { // returns ErrHelp return e } if err = Client.SetOutput(GlobalOutput); err == nil { if configErr := Client.SystemConfiguration(ConfigPath); configErr != nil { slog.Info("Main.Import - SystemConfiguration", "config", ConfigPath, "error", configErr) } err = Client.ImportCmd(ctx, cmd.Args(), *ImportResource, *GlobalQuiet, *ImportMerge) } return } func ApplySubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { ApplyDelete = cmd.Bool("delete", false, "Delete resources defined in the available documents.") if e := cmd.Parse(os.Args[2:]); e != nil { return e } if err = Client.SetOutput(GlobalOutput); err == nil { if configErr := Client.SystemConfiguration(ConfigPath); configErr != nil { slog.Info("Main.Import - SystemConfiguration", "config", ConfigPath, "error", configErr) } err = Client.ApplyCmd(ctx, cmd.Args(), *GlobalQuiet, *ApplyDelete) } return } func DiffSubCommand(cmd *flag.FlagSet, output io.Writer) (err error) { if e := cmd.Parse(os.Args[2:]); e != nil { return e } return Client.DiffCmd(cmd.Args()) } func main() { LoggerConfig() if len(os.Args) < 2 { fmt.Println("expected subcommands: diff, apply, import") os.Exit(1) } DefaultConfigurations, configErr := builtin.BuiltInDocuments() if configErr != nil { slog.Warn("Failed loading default configuration", "error", configErr) } ConfigDoc.AppendConfigurations(DefaultConfigurations) for _, subCmd := range jxSubCommands { cmdFlagSet := flag.NewFlagSet(subCmd.Name, flag.ExitOnError) cmdFlagSet.StringVar(&ConfigPath, "config", "/etc/jx/conf.d", "Config file path") cmdFlagSet.StringVar(&ConfigPath, "c", "/etc/jx/conf.d", "Config file path") GlobalOformat = cmdFlagSet.String("oformat", "yaml", "Output serialization format") cmdFlagSet.StringVar(&GlobalOutput, "output", "-", "Output target (default stdout)") cmdFlagSet.StringVar(&GlobalOutput, "o", "-", "Output target (default stdout)") GlobalQuiet = cmdFlagSet.Bool("quiet", false, "Generate terse output.") switch subCmd.Name { case "diff": cmdFlagSet.Usage = func() { fmt.Println("jx diff source [source2]") cmdFlagSet.PrintDefaults() VersionUsage() } case "apply": cmdFlagSet.Usage = func() { fmt.Println("jx diff source [source2]") cmdFlagSet.PrintDefaults() VersionUsage() } case "import": cmdFlagSet.Usage = func() { fmt.Println("jx import source...") cmdFlagSet.PrintDefaults() VersionUsage() } case "config": cmdFlagSet.Usage = func() { fmt.Println("jx config source...") cmdFlagSet.PrintDefaults() VersionUsage() } } slog.Info("CLI", "cmd", subCmd.Name) if os.Args[1] == subCmd.Name { if e := subCmd.Run(cmdFlagSet, os.Stdout); e != nil { slog.Error("Failed running command", "command", os.Args[1], "error", e) os.Exit(1) } return } } flag.PrintDefaults() VersionUsage() os.Exit(1) }