diff --git a/cmd/dev.go b/cmd/dev.go index dd549894..b96f7c44 100644 --- a/cmd/dev.go +++ b/cmd/dev.go @@ -4,7 +4,9 @@ import ( "encoding/json" "fmt" + "github.com/charmbracelet/lipgloss/table" "github.com/opentdf/platform/protocol/go/common" + "github.com/opentdf/tructl/internal/config" "github.com/opentdf/tructl/pkg/cli" "github.com/spf13/cobra" ) @@ -75,6 +77,19 @@ func unMarshalMetadata(m string) *common.MetadataMutable { return nil } +// HandleSuccess prints a success message according to the configured format (styled table or JSON) +func HandleSuccess(command *cobra.Command, id string, t *table.Table, policyObject interface{}) { + if TructlCfg.Output.Format == config.OutputJSON || configFlagOverrides.OutputFormatJSON { + if output, err := json.MarshalIndent(policyObject, "", " "); err != nil { + cli.ExitWithError("Error marshalling policy object", err) + } else { + fmt.Println(string(output)) + } + return + } + cli.PrintSuccessTable(command, id, t) +} + func init() { rootCmd.AddCommand(devCmd) devCmd.AddCommand(designCmd) diff --git a/cmd/policy-attributes.go b/cmd/policy-attributes.go index eb98fd6e..b75eb25c 100644 --- a/cmd/policy-attributes.go +++ b/cmd/policy-attributes.go @@ -82,7 +82,7 @@ used to define the access controls based on subject encodings and entity entitle cli.ErrorMessage(value, err) } } - cli.HandleSuccess(cmd, a.Id, t, a) + HandleSuccess(cmd, a.Id, t, a) }, } @@ -113,7 +113,7 @@ used to define the access controls based on subject encodings and entity entitle {"Values", cli.CommaSeparated(a.Values)}, {"Namespace", a.Namespace}, }...) - cli.HandleSuccess(cmd, a.Id, t, a) + HandleSuccess(cmd, a.Id, t, a) }, } @@ -142,7 +142,7 @@ used to define the access controls based on subject encodings and entity entitle cli.CommaSeparated(a.Values), ) } - cli.HandleSuccess(cmd, "", t, attrs) + HandleSuccess(cmd, "", t, attrs) }, } @@ -180,7 +180,7 @@ used to define the access controls based on subject encodings and entity entitle {"Values", cli.CommaSeparated(a.Values)}, {"Namespace", a.Namespace}, }...) - cli.HandleSuccess(cmd, a.Id, t, a) + HandleSuccess(cmd, a.Id, t, a) }, } @@ -198,7 +198,7 @@ used to define the access controls based on subject encodings and entity entitle if a, err := h.UpdateAttribute(id); err != nil { cli.ExitWithError("Could not update attribute", err) } else { - cli.HandleSuccess(cmd, id, nil, a) + HandleSuccess(cmd, id, nil, a) } }, } diff --git a/cmd/policy-namespaces.go b/cmd/policy-namespaces.go index f79d6aaf..dfc0d268 100644 --- a/cmd/policy-namespaces.go +++ b/cmd/policy-namespaces.go @@ -51,7 +51,7 @@ or different attributes tied to each. {"Id", ns.Id}, {"Name", ns.Name}, }...) - cli.HandleSuccess(cmd, ns.Id, t, ns) + HandleSuccess(cmd, ns.Id, t, ns) }, } @@ -75,7 +75,7 @@ or different attributes tied to each. ns.Name, ) } - cli.HandleSuccess(cmd, "", t, list) + HandleSuccess(cmd, "", t, list) }, } @@ -98,7 +98,7 @@ or different attributes tied to each. {"Name", name}, {"Id", created.Id}, }...) - cli.HandleSuccess(cmd, created.Id, t, created) + HandleSuccess(cmd, created.Id, t, created) }, } @@ -132,7 +132,7 @@ or different attributes tied to each. {"Id", ns.Id}, {"Name", ns.Name}, }...) - cli.HandleSuccess(cmd, ns.Id, t, ns) + HandleSuccess(cmd, ns.Id, t, ns) }, } @@ -160,7 +160,7 @@ or different attributes tied to each. {"Id", ns.Id}, {"Name", ns.Name}, }...) - cli.HandleSuccess(cmd, id, t, ns) + HandleSuccess(cmd, id, t, ns) }, } ) diff --git a/cmd/policy-subject_mappings.go b/cmd/policy-subject_mappings.go index f28567cd..96b92054 100644 --- a/cmd/policy-subject_mappings.go +++ b/cmd/policy-subject_mappings.go @@ -52,7 +52,7 @@ var ( // rows = append(rows, mdRows...) // } -// cli.HandleSuccess(cmd, id, cli.NewTabular().Rows(rows...), mapping) +// HandleSuccess(cmd, id, cli.NewTabular().Rows(rows...), mapping) // }, // } @@ -80,7 +80,7 @@ var ( // } // t.Row(rowCells...) // } -// cli.HandleSuccess(cmd, "", t, list) +// HandleSuccess(cmd, "", t, list) // }, // } @@ -117,7 +117,7 @@ var ( // rows = append(rows, mdRows...) // } -// cli.HandleSuccess(cmd, mapping.Id, +// HandleSuccess(cmd, mapping.Id, // cli.NewTabular(). // Rows(rows...), mapping) // }, diff --git a/cmd/root.go b/cmd/root.go index 07ab9f57..25df22ef 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,14 +6,17 @@ package cmd import ( "fmt" "os" - "strings" "github.com/opentdf/tructl/internal/config" - "github.com/opentdf/tructl/pkg/cli" "github.com/spf13/cobra" ) -var cfgFile string +var ( + cfgFile string + TructlCfg config.Config + + configFlagOverrides = config.ConfigFlagOverrides{} +) // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ @@ -33,16 +36,14 @@ func Execute() { } func init() { - singleOutputJSON := rootCmd.PersistentFlags().Bool("json", false, "Output a single command result in JSON format") + rootCmd.PersistentFlags().BoolVar(&configFlagOverrides.OutputFormatJSON, "json", false, "output single command in JSON (overrides configured output format)") rootCmd.PersistentFlags().String("host", "localhost:9000", "host:port of the Virtru Data Security Platform gRPC server") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config-file", "", "config file (default is $HOME/.tructl.yaml)") cfg, err := config.LoadConfig("tructl") if err != nil { fmt.Println("Error loading config:", err) os.Exit(1) } - if strings.ToLower(cfg.Output.Format) == cli.OutputJSON || singleOutputJSON { - cli.OutputFormat = cli.OutputJSON - } - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.tructl.yaml)") + TructlCfg = *cfg } diff --git a/go.mod b/go.mod index e9230cb7..4ff3ddcf 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/catppuccin/go v0.2.0 // indirect github.com/containerd/console v1.0.4 // indirect github.com/coreos/go-oidc/v3 v3.9.0 // indirect + github.com/creasty/defaults v1.7.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect diff --git a/go.sum b/go.sum index bb4cf5cc..2c6abdd0 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,8 @@ github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= +github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/config/config.go b/internal/config/config.go index 5a74c6f7..b5b8eed6 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/creasty/defaults" - "github.com/opentdf/tructl/pkg/cli" "github.com/spf13/viper" ) @@ -20,6 +19,11 @@ type Config struct { Output Output `yaml:"output"` } +// captures all CLI flags that will override pre-specified config values +type ConfigFlagOverrides struct { + OutputFormatJSON bool +} + type Error string func (e Error) Error() string { @@ -27,6 +31,9 @@ func (e Error) Error() string { } const ( + OutputJSON = "json" + OutputStyled = "styled" + ErrLoadingConfig Error = "error loading config" ) @@ -34,9 +41,9 @@ const ( func LoadConfig(key string) (*Config, error) { if key == "" { key = "tructl" - slog.Info("LoadConfig: key not provided, using default", "config", key) + slog.Debug("LoadConfig: key not provided, using default", "config file", key) } else { - slog.Info("LoadConfig", "config", key) + slog.Debug("LoadConfig", "config file", key) } config := &Config{} @@ -73,10 +80,10 @@ func LoadConfig(key string) (*Config, error) { func UpdateOutputFormat(format string) { v := viper.GetViper() format = strings.ToLower(format) - if format == cli.OutputJSON { - v.Set("output.format", cli.OutputJSON) + if format == OutputJSON { + v.Set("output.format", OutputJSON) } else { - v.Set("output.format", cli.OutputStyled) + v.Set("output.format", OutputStyled) } viper.WriteConfig() } diff --git a/pkg/cli/tabular.go b/pkg/cli/tabular.go index 3dbc3dd3..e4cad33b 100644 --- a/pkg/cli/tabular.go +++ b/pkg/cli/tabular.go @@ -1,7 +1,6 @@ package cli import ( - "encoding/json" "fmt" "github.com/charmbracelet/lipgloss" @@ -9,13 +8,6 @@ import ( "github.com/spf13/cobra" ) -const ( - OutputJSON = "json" - OutputStyled = "styled" -) - -var OutputFormat string - func NewTabular() *table.Table { t := NewTable() t.Headers("Property", "Value") @@ -67,16 +59,3 @@ func PrintSuccessTable(cmd *cobra.Command, id string, t *table.Table) { fmt.Println(lipgloss.JoinVertical(lipgloss.Top, successMessage, t.Render(), jsonDirections)) } - -// HandleSuccess prints a success message according to the configured format (styled table or JSON) -func HandleSuccess(command *cobra.Command, id string, t *table.Table, policyObject interface{}) { - if OutputFormat == OutputJSON { - if output, err := json.MarshalIndent(policyObject, "", " "); err != nil { - ExitWithError("Error marshalling policy object", err) - } else { - fmt.Println(string(output)) - } - return - } - PrintSuccessTable(command, id, t) -}