diff --git a/adr/0000-use-adr-in-directory.md b/adr/0000-use-adr-in-directory.md new file mode 100644 index 00000000..9e1a8857 --- /dev/null +++ b/adr/0000-use-adr-in-directory.md @@ -0,0 +1,43 @@ +--- +status: accepted +date: 2024-08-29 +decision: Use ADRs in the `adr` directory of the repo to document architectural decisions +author: '@jakedoublev' +deciders: ['@ryanulit', '@jrschumacher'] +--- + +# Use a ADR storage format that make diffs easier to read + +## Context and Problem Statement + +We've been using Github Issues to document ADR decisions, but it's hard to read the diffs when changes are made. We need a better way to store and manage ADRs. ADRs sometimes get updated and it's hard to track the changes and decision using the edit history dropdown or the comments section. + +## Decision Drivers + +- **Low barrier of entry**: A primary goal of our ADR process is to ensure decisions are captured. +- **Ease of management**: Make it easy to manage the ADRs. +- **Ensure appropriate tracking and review**: Make it easy to track and review the changes in the ADRs. + +## Considered Options + +1. Use Github Issues +2. Use Github Discussions +3. Use a shared ADR repository +4. Use an `adr` directory in the repo + +## Decision Outcome + +It was decided to use an `adr` directory in the repo to store ADRs. This approach provides a low barrier of entry for developers to document decisions and ensures that the decisions are tracked and reviewed appropriately. + +Additionally, this change does not impact other teams or repositories, and it is easy to manage and maintain. We can experiment with this decision and if it works promote it to other repositories. + +### Consequences + +- **Positive**: + - Low barrier of entry for developers to document decisions. + - Easy to manage and maintain. + - Ensures appropriate tracking and review of decisions via git history and code review. +- **Negative**: + - Requires developers to be aware of the ADR process and where to find the ADRs. + - May require additional tooling to manage and maintain the ADRs. + - May require additional training for developers to understand the ADR process and how to use it effectively. diff --git a/adr/0001-printing-with-json.md b/adr/0001-printing-with-json.md new file mode 100644 index 00000000..7f8d8359 --- /dev/null +++ b/adr/0001-printing-with-json.md @@ -0,0 +1,39 @@ +--- +status: accepted +date: 2024-08-29 +decision: Encapsulate printing to ensure consistent output format +author: '@jrschumacher' +deciders: ['@jakedoublev', '@ryanulit', '@suchak1'] +--- + +# Consistent output format for printing JSON and pretty-print + +## Context and Problem Statement + +We need to develop a printer that can globally determine when to print in pretty-print format versus JSON format. This decision is crucial to ensure consistent and appropriate output formatting across different use cases and environments. + +## Decision Drivers + +- **Consistency**: Ensure uniform output format across the application. +- **Flexibility**: Ability to switch between pretty-print and JSON formats based on context. +- **Ease of Implementation**: Simplicity in implementing and maintaining the solution. + +## Considered Options + +1. Keep existing code as is +2. Move the printing into a global function that has context about the CLI flags to drive output format + +## Decision Outcome + +It was decided to encapsulate printing to ensure there is consistent output format. This function will have context about the CLI flags to drive the output format. This approach provides the flexibility to switch between pretty-print and JSON formats based on the context. + +### Consequences + +- **Positive**: + - Provides flexibility to switch formats without changing the code. + - Ensures consistent output format across different environments. + - Simplifies the implementation and maintenance process. + +- **Negative**: + - Requires careful management of configuration settings. + - Potential for misconfiguration leading to incorrect output format when developers use `fmt` directly. diff --git a/cmd/auth-clientCredentials.go b/cmd/auth-clientCredentials.go index 759bd620..d35da9ec 100644 --- a/cmd/auth-clientCredentials.go +++ b/cmd/auth-clientCredentials.go @@ -1,8 +1,6 @@ package cmd import ( - "fmt" - "github.com/opentdf/otdfctl/pkg/auth" "github.com/opentdf/otdfctl/pkg/cli" "github.com/opentdf/otdfctl/pkg/man" @@ -16,9 +14,8 @@ var clientCredentialsCmd = man.Docs.GetCommand("auth/client-credentials", ) func auth_clientCredentials(cmd *cobra.Command, args []string) { - cp := InitProfile(cmd, false) - - p := cli.NewPrinter(true) + c := cli.New(cmd, args) + cp := InitProfile(c, false) var clientId string var clientSecret string @@ -45,20 +42,20 @@ func auth_clientCredentials(cmd *cobra.Command, args []string) { }) // Validate the client credentials - p.Printf("Validating client credentials for %s... ", cp.GetEndpoint()) + c.Printf("Validating client credentials for %s... ", cp.GetEndpoint()) if err := auth.ValidateProfileAuthCredentials(cmd.Context(), cp); err != nil { - fmt.Println("failed") - cli.ExitWithError("An error occurred during login. Please check your credentials and try again", err) + c.Println("failed") + c.ExitWithError("An error occurred during login. Please check your credentials and try again", err) } - p.Println("ok") + c.Println("ok") // Save the client credentials - p.Print("Storing client ID and secret in keyring... ") + c.Print("Storing client ID and secret in keyring... ") if err := cp.Save(); err != nil { - p.Println("failed") - cli.ExitWithError("An error occurred while storing client credentials", err) + c.Println("failed") + c.ExitWithError("An error occurred while storing client credentials", err) } - p.Println("ok") + c.Println("ok") } func init() { diff --git a/cmd/auth-login.go b/cmd/auth-login.go index 0e7a093d..2ebc9910 100644 --- a/cmd/auth-login.go +++ b/cmd/auth-login.go @@ -9,19 +9,21 @@ import ( ) func auth_codeLogin(cmd *cobra.Command, args []string) { - fh := cli.NewFlagHelper(cmd) - clientID := fh.GetOptionalString("client-id") - tlsNoVerify := fh.GetOptionalBool("tls-no-verify") - - cp := InitProfile(cmd, false) - printer := cli.NewPrinter(true) - - printer.Println("Initiating login...") - tok, publicClientID, err := auth.LoginWithPKCE(cmd.Context(), cp.GetEndpoint(), clientID, tlsNoVerify) + c := cli.New(cmd, args) + cp := InitProfile(c, false) + + c.Print("Initiating login...") + tok, publicClientID, err := auth.LoginWithPKCE( + cmd.Context(), + cp.GetEndpoint(), + c.FlagHelper.GetOptionalString("client-id"), + c.FlagHelper.GetOptionalBool("tls-no-verify"), + ) if err != nil { - cli.ExitWithError("could not authenticate", err) + c.Println("failed") + c.ExitWithError("could not authenticate", err) } - printer.Println("ok") + c.Println("ok") // Set the auth credentials to profile if err := cp.SetAuthCredentials(profiles.AuthCredentials{ @@ -33,15 +35,15 @@ func auth_codeLogin(cmd *cobra.Command, args []string) { RefreshToken: tok.RefreshToken, }, }); err != nil { - cli.ExitWithError("failed to set auth credentials", err) + c.ExitWithError("failed to set auth credentials", err) } - printer.Println("Storing credentials to profile in keyring...") + c.Print("Storing credentials to profile in keyring...") if err := cp.Save(); err != nil { - printer.Println("failed") - cli.ExitWithError("An error occurred while storing authentication credentials", err) + c.Println("failed") + c.ExitWithError("An error occurred while storing authentication credentials", err) } - printer.Println("ok") + c.Println("ok") } var codeLoginCmd *man.Doc diff --git a/cmd/auth-logout.go b/cmd/auth-logout.go index d161b6da..5ece0e74 100644 --- a/cmd/auth-logout.go +++ b/cmd/auth-logout.go @@ -9,33 +9,31 @@ import ( ) func auth_logout(cmd *cobra.Command, args []string) { - fh := cli.NewFlagHelper(cmd) - tlsNoVerify := fh.GetOptionalBool("tls-no-verify") - cp := InitProfile(cmd, false) - printer := cli.NewPrinter(true) - printer.Println("Initiating logout...") + c := cli.New(cmd, args) + cp := InitProfile(c, false) + c.Println("Initiating logout...") // we can only revoke access tokens stored for the code login flow, not client credentials creds := cp.GetAuthCredentials() if creds.AuthType == profiles.PROFILE_AUTH_TYPE_ACCESS_TOKEN { - printer.Println("Revoking access token...") + c.Println("Revoking access token...") if err := auth.RevokeAccessToken( cmd.Context(), cp.GetEndpoint(), creds.AccessToken.PublicClientID, creds.AccessToken.RefreshToken, - tlsNoVerify, + c.FlagHelper.GetOptionalBool("tls-no-verify"), ); err != nil { - printer.Println("failed") - cli.ExitWithError("An error occurred while revoking the access token", err) + c.Println("failed") + c.ExitWithError("An error occurred while revoking the access token", err) } } if err := cp.SetAuthCredentials(profiles.AuthCredentials{}); err != nil { - printer.Println("failed") - cli.ExitWithError("An error occurred while logging out", err) + c.Println("failed") + c.ExitWithError("An error occurred while logging out", err) } - printer.Println("ok") + c.Println("ok") } var codeLogoutCmd *man.Doc diff --git a/cmd/auth-printAccessToken.go b/cmd/auth-printAccessToken.go index e093d629..07259000 100644 --- a/cmd/auth-printAccessToken.go +++ b/cmd/auth-printAccessToken.go @@ -1,9 +1,6 @@ package cmd import ( - "encoding/json" - "fmt" - "github.com/opentdf/otdfctl/pkg/auth" "github.com/opentdf/otdfctl/pkg/cli" "github.com/opentdf/otdfctl/pkg/man" @@ -15,40 +12,27 @@ var auth_printAccessTokenCmd = man.Docs.GetCommand("auth/print-access-token", man.WithRun(auth_printAccessToken)) func auth_printAccessToken(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - jsonOut := flagHelper.GetOptionalBool("json") - - cp := InitProfile(cmd, false) - - printEnabled := !jsonOut - p := cli.NewPrinter(printEnabled) + c := cli.New(cmd, args) + cp := InitProfile(c, false) ac := cp.GetAuthCredentials() switch ac.AuthType { case profiles.PROFILE_AUTH_TYPE_CLIENT_CREDENTIALS: - p.Printf("Getting access token for %s... ", ac.ClientId) + c.Printf("Getting access token for %s... ", ac.ClientId) case profiles.PROFILE_AUTH_TYPE_ACCESS_TOKEN: - p.Printf("Getting profile's stored access token... ") + c.Printf("Getting profile's stored access token... ") default: - cli.ExitWithError("Invalid auth type", nil) + c.ExitWithError("Invalid auth type", nil) } tok, err := auth.GetTokenWithProfile(cmd.Context(), cp) if err != nil { - p.Println("failed") + c.Println("failed") cli.ExitWithError("Failed to get token", err) } - p.Println("ok") - p.Printf("Access Token: %s\n", tok.AccessToken) + c.Println("ok") + c.Printf("Access Token: %s\n", tok.AccessToken) - if jsonOut { - d, err := json.MarshalIndent(tok, "", " ") - if err != nil { - cli.ExitWithError("Failed to marshal token to json", err) - } - - fmt.Println(string(d)) - return - } + c.PrintIfJson(tok) } func init() { diff --git a/cmd/config.go b/cmd/config.go index 293d1dd1..3a8f4d40 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -10,11 +10,11 @@ import ( ) func config_updateOutput(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - format := flagHelper.GetRequiredString("format") + format := c.Flags.GetRequiredString("format") config.UpdateOutputFormat(cfgKey, format) fmt.Println(cli.SuccessMessage(fmt.Sprintf("Output format updated to %s", format))) diff --git a/cmd/dev-selectors.go b/cmd/dev-selectors.go index 3f341fe4..5571c9d8 100644 --- a/cmd/dev-selectors.go +++ b/cmd/dev-selectors.go @@ -15,16 +15,16 @@ import ( var ( selectors []string - dev_selectorsCmd *cobra.Command + // dev_selectorsCmd *cobra.Command ) func dev_selectorsGen(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - subject := flagHelper.GetRequiredString("subject") - contextType := flagHelper.GetRequiredString("type") + subject := c.Flags.GetRequiredString("subject") + contextType := c.Flags.GetRequiredString("type") var value any if contextType == "json" || contextType == "" { @@ -62,13 +62,13 @@ func dev_selectorsGen(cmd *cobra.Command, args []string) { } func dev_selectorsTest(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - subject := flagHelper.GetRequiredString("subject") - contextType := flagHelper.GetRequiredString("type") - selectors := flagHelper.GetStringSlice("selectors", selectors, cli.FlagHelperStringSliceOptions{Min: 1}) + subject := c.Flags.GetRequiredString("subject") + contextType := c.Flags.GetRequiredString("type") + selectors := c.Flags.GetStringSlice("selectors", selectors, cli.FlagsStringSliceOptions{Min: 1}) var value any if contextType == "json" || contextType == "" { diff --git a/cmd/dev.go b/cmd/dev.go index 6dac6a7f..54065559 100644 --- a/cmd/dev.go +++ b/cmd/dev.go @@ -1,7 +1,6 @@ package cmd import ( - "encoding/json" "fmt" "io" "os" @@ -72,16 +71,17 @@ func getMetadataRows(m *common.Metadata) [][]string { return nil } -func unMarshalMetadata(m string) *common.MetadataMutable { - if m != "" { - metadata := &common.MetadataMutable{} - if err := json.Unmarshal([]byte(m), metadata); err != nil { - cli.ExitWithError("Failed to unmarshal metadata", err) - } - return metadata - } - return nil -} +// TODO can we use it or remove it? +// func unMarshalMetadata(m string) *common.MetadataMutable { +// if m != "" { +// metadata := &common.MetadataMutable{} +// if err := json.Unmarshal([]byte(m), metadata); err != nil { +// cli.ExitWithError("Failed to unmarshal metadata", err) +// } +// return metadata +// } +// return nil +// } func getMetadataMutable(labels []string) *common.MetadataMutable { metadata := common.MetadataMutable{} @@ -108,13 +108,9 @@ func getMetadataUpdateBehavior() common.MetadataUpdateEnum { // HandleSuccess prints a success message according to the configured format (styled table or JSON) func HandleSuccess(command *cobra.Command, id string, t table.Model, policyObject interface{}) { + c := cli.New(command, []string{}) if OtdfctlCfg.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 + c.ExitWithJson(policyObject) } cli.PrintSuccessTable(command, id, t) } diff --git a/cmd/interactive.go b/cmd/interactive.go index c63d8636..299e6420 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -1,6 +1,7 @@ package cmd import ( + "github.com/opentdf/otdfctl/pkg/cli" "github.com/opentdf/otdfctl/pkg/man" "github.com/opentdf/otdfctl/tui" "github.com/spf13/cobra" @@ -9,7 +10,8 @@ import ( func init() { cmd := man.Docs.GetCommand("interactive", man.WithRun(func(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) tui.StartTea(h) }), ) diff --git a/cmd/kas-grants.go b/cmd/kas-grants.go index a391599f..c0c4514a 100644 --- a/cmd/kas-grants.go +++ b/cmd/kas-grants.go @@ -12,14 +12,14 @@ import ( var forceFlagValue = false func policy_assignKasGrant(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - nsID := flagHelper.GetOptionalString("namespace-id") - attrID := flagHelper.GetOptionalString("attribute-id") - valID := flagHelper.GetOptionalString("value-id") - kasID := flagHelper.GetRequiredString("kas-id") + nsID := c.Flags.GetOptionalString("namespace-id") + attrID := c.Flags.GetOptionalString("attribute-id") + valID := c.Flags.GetOptionalString("value-id") + kasID := c.Flags.GetRequiredString("kas-id") count := 0 for _, v := range []string{nsID, attrID, valID} { @@ -69,15 +69,15 @@ func policy_assignKasGrant(cmd *cobra.Command, args []string) { } func policy_unassignKasGrant(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - nsID := flagHelper.GetOptionalString("namespace-id") - attrID := flagHelper.GetOptionalString("attribute-id") - valID := flagHelper.GetOptionalString("value-id") - kasID := flagHelper.GetRequiredString("kas-id") - force := flagHelper.GetOptionalBool("force") + nsID := c.Flags.GetOptionalString("namespace-id") + attrID := c.Flags.GetOptionalString("attribute-id") + valID := c.Flags.GetOptionalString("value-id") + kasID := c.Flags.GetRequiredString("kas-id") + force := c.Flags.GetOptionalBool("force") count := 0 for _, v := range []string{nsID, attrID, valID} { diff --git a/cmd/kas-registry.go b/cmd/kas-registry.go index 3fb0fe53..172ef057 100644 --- a/cmd/kas-registry.go +++ b/cmd/kas-registry.go @@ -14,11 +14,11 @@ import ( var policy_kasRegistryCmd *cobra.Command func policy_getKeyAccessRegistry(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.FlagHelper.GetRequiredString("id") kas, err := h.GetKasRegistryEntry(id) if err != nil { @@ -49,7 +49,8 @@ func policy_getKeyAccessRegistry(cmd *cobra.Command, args []string) { } func policy_listKeyAccessRegistries(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() list, err := h.ListKasRegistryEntries() @@ -85,14 +86,14 @@ func policy_listKeyAccessRegistries(cmd *cobra.Command, args []string) { } func policy_createKeyAccessRegistry(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - uri := flagHelper.GetRequiredString("uri") - cachedJSON := flagHelper.GetOptionalString("public-keys") - remote := flagHelper.GetOptionalString("public-key-remote") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + uri := c.Flags.GetRequiredString("uri") + cachedJSON := c.Flags.GetOptionalString("public-keys") + remote := c.Flags.GetOptionalString("public-key-remote") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) if cachedJSON == "" && remote == "" { e := fmt.Errorf("a public key is required. Please pass either a cached or remote public key") @@ -141,16 +142,15 @@ func policy_createKeyAccessRegistry(cmd *cobra.Command, args []string) { } func policy_updateKeyAccessRegistry(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - - id := flagHelper.GetRequiredString("id") - uri := flagHelper.GetOptionalString("uri") - cachedJSON := flagHelper.GetOptionalString("public-keys") - remote := flagHelper.GetOptionalString("public-key-remote") - labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + id := c.Flags.GetRequiredString("id") + uri := c.Flags.GetOptionalString("uri") + cachedJSON := c.Flags.GetOptionalString("public-keys") + remote := c.Flags.GetOptionalString("public-key-remote") + labels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) if cachedJSON == "" && remote == "" && len(labels) == 0 && uri == "" { cli.ExitWithError("No values were passed to update. Please pass at least one value to update (E.G. 'uri', 'public-keys', 'public-key-remote', 'label')", nil) @@ -193,12 +193,12 @@ func policy_updateKeyAccessRegistry(cmd *cobra.Command, args []string) { } func policy_deleteKeyAccessRegistry(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - force := flagHelper.GetOptionalBool("force") + id := c.Flags.GetRequiredString("id") + force := c.Flags.GetOptionalBool("force") kas, err := h.GetKasRegistryEntry(id) if err != nil { diff --git a/cmd/policy-attributeNamespaces.go b/cmd/policy-attributeNamespaces.go index bbbdd0c1..8e8b5b89 100644 --- a/cmd/policy-attributeNamespaces.go +++ b/cmd/policy-attributeNamespaces.go @@ -17,11 +17,11 @@ var ( ) func policy_getAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") ns, err := h.GetNamespace(id) if err != nil { @@ -40,7 +40,8 @@ func policy_getAttributeNamespace(cmd *cobra.Command, args []string) { } func policy_listAttributeNamespaces(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() state := cli.GetState(cmd) @@ -75,12 +76,12 @@ func policy_listAttributeNamespaces(cmd *cobra.Command, args []string) { } func policy_createAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - name := flagHelper.GetRequiredString("name") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + name := c.Flags.GetRequiredString("name") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) created, err := h.CreateNamespace(name, getMetadataMutable(metadataLabels)) if err != nil { @@ -99,11 +100,11 @@ func policy_createAttributeNamespace(cmd *cobra.Command, args []string) { } func policy_deactivateAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") ns, err := h.GetNamespace(id) if err != nil { @@ -130,12 +131,12 @@ func policy_deactivateAttributeNamespace(cmd *cobra.Command, args []string) { } func policy_updateAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + id := c.Flags.GetRequiredString("id") + labels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) ns, err := h.UpdateNamespace( id, @@ -158,11 +159,11 @@ func policy_updateAttributeNamespace(cmd *cobra.Command, args []string) { } func policy_unsafeDeleteAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") ns, err := h.GetNamespace(id) if err != nil { @@ -191,11 +192,11 @@ func policy_unsafeDeleteAttributeNamespace(cmd *cobra.Command, args []string) { } func policy_unsafeReactivateAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") ns, err := h.GetNamespace(id) if err != nil { @@ -225,12 +226,12 @@ func policy_unsafeReactivateAttributeNamespace(cmd *cobra.Command, args []string } func policy_unsafeUpdateAttributeNamespace(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - name := flagHelper.GetRequiredString("name") + id := c.Flags.GetRequiredString("id") + name := c.Flags.GetRequiredString("name") ns, err := h.GetNamespace(id) if err != nil { diff --git a/cmd/policy-attributeValues.go b/cmd/policy-attributeValues.go index 3aadc12c..31847bb8 100644 --- a/cmd/policy-attributeValues.go +++ b/cmd/policy-attributeValues.go @@ -13,14 +13,14 @@ import ( var policy_attributeValuesCmd *cobra.Command func policy_createAttributeValue(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - attrId := flagHelper.GetRequiredString("attribute-id") - value := flagHelper.GetRequiredString("value") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + attrId := c.FlagHelper.GetRequiredString("attribute-id") + value := c.FlagHelper.GetRequiredString("value") + metadataLabels := c.FlagHelper.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) + attr, err := h.GetAttribute(attrId) if err != nil { cli.ExitWithError(fmt.Sprintf("Failed to get parent attribute (%s)", attrId), err) @@ -35,12 +35,12 @@ func policy_createAttributeValue(cmd *cobra.Command, args []string) { } func policy_getAttributeValue(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + id := c.FlagHelper.GetRequiredString("id") + v, err := h.GetAttributeValue(id) if err != nil { cli.ExitWithError("Failed to find attribute value", err) @@ -50,10 +50,10 @@ func policy_getAttributeValue(cmd *cobra.Command, args []string) { } func policy_listAttributeValue(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - attrId := flagHelper.GetRequiredString("attribute-id") + attrId := c.FlagHelper.GetRequiredString("attribute-id") state := cli.GetState(cmd) vals, err := h.ListAttributeValues(attrId, state) if err != nil { @@ -84,13 +84,13 @@ func policy_listAttributeValue(cmd *cobra.Command, args []string) { } func policy_updateAttributeValue(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + id := c.Flags.GetRequiredString("id") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) + _, err := h.GetAttributeValue(id) if err != nil { cli.ExitWithError(fmt.Sprintf("Failed to get attribute value (%s)", id), err) @@ -105,12 +105,12 @@ func policy_updateAttributeValue(cmd *cobra.Command, args []string) { } func policy_deactivateAttributeValue(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + id := c.Flags.GetRequiredString("id") + value, err := h.GetAttributeValue(id) if err != nil { cli.ExitWithError(fmt.Sprintf("Failed to get attribute value (%s)", id), err) @@ -127,11 +127,11 @@ func policy_deactivateAttributeValue(cmd *cobra.Command, args []string) { } func policy_unsafeReactivateAttributeValue(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") v, err := h.GetAttributeValue(id) if err != nil { @@ -158,12 +158,12 @@ func policy_unsafeReactivateAttributeValue(cmd *cobra.Command, args []string) { } func policy_unsafeUpdateAttributeValue(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - value := flagHelper.GetOptionalString("value") + id := c.Flags.GetRequiredString("id") + value := c.Flags.GetOptionalString("value") v, err := h.GetAttributeValue(id) if err != nil { @@ -190,11 +190,11 @@ func policy_unsafeUpdateAttributeValue(cmd *cobra.Command, args []string) { } func policy_unsafeDeleteAttributeValue(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") v, err := h.GetAttributeValue(id) if err != nil { diff --git a/cmd/policy-attributes.go b/cmd/policy-attributes.go index 7553e22d..efda0de2 100644 --- a/cmd/policy-attributes.go +++ b/cmd/policy-attributes.go @@ -20,15 +20,15 @@ var ( ) func policy_createAttribute(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - name := flagHelper.GetRequiredString("name") - rule := flagHelper.GetRequiredString("rule") - values := flagHelper.GetStringSlice("value", attrValues, cli.FlagHelperStringSliceOptions{}) - namespace := flagHelper.GetRequiredString("namespace") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + name := c.Flags.GetRequiredString("name") + rule := c.Flags.GetRequiredString("rule") + values := c.Flags.GetStringSlice("value", attrValues, cli.FlagsStringSliceOptions{}) + namespace := c.Flags.GetRequiredString("namespace") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) attr, err := h.CreateAttribute(name, rule, namespace, values, getMetadataMutable(metadataLabels)) if err != nil { @@ -58,12 +58,12 @@ func policy_createAttribute(cmd *cobra.Command, args []string) { } func policy_getAttribute(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + id := c.Flags.GetRequiredString("id") + attr, err := h.GetAttribute(id) if err != nil { errMsg := fmt.Sprintf("Failed to get attribute (%s)", id) @@ -86,7 +86,8 @@ func policy_getAttribute(cmd *cobra.Command, args []string) { } func policy_listAttributes(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() state := cli.GetState(cmd) @@ -126,12 +127,12 @@ func policy_listAttributes(cmd *cobra.Command, args []string) { } func policy_deactivateAttribute(cmd *cobra.Command, args []string) { - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() + id := c.Flags.GetRequiredString("id") + attr, err := h.GetAttribute(id) if err != nil { errMsg := fmt.Sprintf("Failed to get attribute (%s)", id) @@ -161,12 +162,12 @@ func policy_deactivateAttribute(cmd *cobra.Command, args []string) { } func policy_updateAttribute(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + id := c.Flags.GetRequiredString("id") + labels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) if a, err := h.UpdateAttribute(id, getMetadataMutable(labels), getMetadataUpdateBehavior()); err != nil { cli.ExitWithError(fmt.Sprintf("Failed to update attribute (%s)", id), err) @@ -184,11 +185,11 @@ func policy_updateAttribute(cmd *cobra.Command, args []string) { } func policy_unsafeReactivateAttribute(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") a, err := h.GetAttribute(id) if err != nil { @@ -216,14 +217,14 @@ func policy_unsafeReactivateAttribute(cmd *cobra.Command, args []string) { } func policy_unsafeUpdateAttribute(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - name := flagHelper.GetOptionalString("name") - rule := flagHelper.GetOptionalString("rule") - valuesOrder := flagHelper.GetStringSlice("values-order", attrValues, cli.FlagHelperStringSliceOptions{}) + id := c.Flags.GetRequiredString("id") + name := c.Flags.GetOptionalString("name") + rule := c.Flags.GetOptionalString("rule") + valuesOrder := c.Flags.GetStringSlice("values-order", attrValues, cli.FlagsStringSliceOptions{}) a, err := h.GetAttribute(id) if err != nil { @@ -262,11 +263,11 @@ func policy_unsafeUpdateAttribute(cmd *cobra.Command, args []string) { } func policy_unsafeDeleteAttribute(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") a, err := h.GetAttribute(id) if err != nil { diff --git a/cmd/policy-resourceMappings.go b/cmd/policy-resourceMappings.go index edffba26..8a7a997e 100644 --- a/cmd/policy-resourceMappings.go +++ b/cmd/policy-resourceMappings.go @@ -17,15 +17,15 @@ var ( ) func policy_createResourceMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - attrId := flagHelper.GetRequiredString("attribute-value-id") - terms := flagHelper.GetStringSlice("terms", policy_resource_mappingsTerms, cli.FlagHelperStringSliceOptions{ + attrId := c.Flags.GetRequiredString("attribute-value-id") + terms := c.Flags.GetStringSlice("terms", policy_resource_mappingsTerms, cli.FlagsStringSliceOptions{ Min: 1, }) - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) resourceMapping, err := h.CreateResourceMapping(attrId, terms, getMetadataMutable(metadataLabels)) if err != nil { @@ -45,11 +45,11 @@ func policy_createResourceMapping(cmd *cobra.Command, args []string) { } func policy_getResourceMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") resourceMapping, err := h.GetResourceMapping(id) if err != nil { @@ -69,7 +69,8 @@ func policy_getResourceMapping(cmd *cobra.Command, args []string) { } func policy_listResourceMappings(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() rmList, err := h.ListResourceMappings() @@ -104,14 +105,14 @@ func policy_listResourceMappings(cmd *cobra.Command, args []string) { } func policy_updateResourceMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - attrValueId := flagHelper.GetOptionalString("attribute-value-id") - terms := flagHelper.GetStringSlice("terms", policy_resource_mappingsTerms, cli.FlagHelperStringSliceOptions{}) - labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + id := c.Flags.GetRequiredString("id") + attrValueId := c.Flags.GetOptionalString("attribute-value-id") + terms := c.Flags.GetStringSlice("terms", policy_resource_mappingsTerms, cli.FlagsStringSliceOptions{}) + labels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) resourceMapping, err := h.UpdateResourceMapping(id, attrValueId, terms, getMetadataMutable(labels), getMetadataUpdateBehavior()) if err != nil { @@ -131,11 +132,11 @@ func policy_updateResourceMapping(cmd *cobra.Command, args []string) { } func policy_deleteResourceMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") cli.ConfirmAction(cli.ActionDelete, "resource-mapping", id, false) diff --git a/cmd/policy-subjectConditionSets.go b/cmd/policy-subjectConditionSets.go index 1d6c32c3..9c387fb0 100644 --- a/cmd/policy-subjectConditionSets.go +++ b/cmd/policy-subjectConditionSets.go @@ -49,14 +49,14 @@ func marshalSubjectSetsProto(subjectSet []*policy.SubjectSet) ([]byte, error) { } func policy_createSubjectConditionSet(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() var ssBytes []byte - flagHelper := cli.NewFlagHelper(cmd) - ssFlagJSON := flagHelper.GetOptionalString("subject-sets") - ssFileJSON := flagHelper.GetOptionalString("subject-sets-file-json") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + ssFlagJSON := c.Flags.GetOptionalString("subject-sets") + ssFileJSON := c.Flags.GetOptionalString("subject-sets-file-json") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) // validate no flag conflicts if ssFileJSON == "" && ssFlagJSON == "" { @@ -111,11 +111,11 @@ func policy_createSubjectConditionSet(cmd *cobra.Command, args []string) { } func policy_getSubjectConditionSet(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") scs, err := h.GetSubjectConditionSet(id) if err != nil { @@ -139,7 +139,8 @@ func policy_getSubjectConditionSet(cmd *cobra.Command, args []string) { } func policy_listSubjectConditionSets(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() scsList, err := h.ListSubjectConditionSets() @@ -174,14 +175,14 @@ func policy_listSubjectConditionSets(cmd *cobra.Command, args []string) { } func policy_updateSubjectConditionSet(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) - ssFlagJSON := flagHelper.GetOptionalString("subject-sets") - ssFileJSON := flagHelper.GetOptionalString("subject-sets-file-json") + id := c.Flags.GetRequiredString("id") + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) + ssFlagJSON := c.Flags.GetOptionalString("subject-sets") + ssFileJSON := c.Flags.GetOptionalString("subject-sets-file-json") var ssBytes []byte // validate no flag conflicts @@ -242,11 +243,11 @@ func policy_updateSubjectConditionSet(cmd *cobra.Command, args []string) { } func policy_deleteSubjectConditionSet(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") scs, err := h.GetSubjectConditionSet(id) if err != nil { diff --git a/cmd/policy-subject_mappings.go b/cmd/policy-subject_mappings.go index 2511f42f..4887258b 100644 --- a/cmd/policy-subject_mappings.go +++ b/cmd/policy-subject_mappings.go @@ -19,11 +19,11 @@ var ( ) func policy_getSubjectMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") mapping, err := h.GetSubjectMapping(id) if err != nil { @@ -57,7 +57,8 @@ func policy_getSubjectMapping(cmd *cobra.Command, args []string) { } func policy_listSubjectMappings(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() list, err := h.ListSubjectMappings() @@ -105,17 +106,17 @@ func policy_listSubjectMappings(cmd *cobra.Command, args []string) { } func policy_createSubjectMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - attrValueId := flagHelper.GetRequiredString("attribute-value-id") - standardActions := flagHelper.GetStringSlice("action-standard", standardActions, cli.FlagHelperStringSliceOptions{Min: 0}) - customActions := flagHelper.GetStringSlice("action-custom", customActions, cli.FlagHelperStringSliceOptions{Min: 0}) - metadataLabels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) - existingSCSId := flagHelper.GetOptionalString("subject-condition-set-id") + attrValueId := c.Flags.GetRequiredString("attribute-value-id") + standardActions := c.Flags.GetStringSlice("action-standard", standardActions, cli.FlagsStringSliceOptions{Min: 0}) + customActions := c.Flags.GetStringSlice("action-custom", customActions, cli.FlagsStringSliceOptions{Min: 0}) + metadataLabels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) + existingSCSId := c.Flags.GetOptionalString("subject-condition-set-id") // NOTE: labels within a new Subject Condition Set created on a SM creation are not supported - newScsJSON := flagHelper.GetOptionalString("subject-condition-set-new") + newScsJSON := c.Flags.GetOptionalString("subject-condition-set-new") // validations if len(standardActions) == 0 && len(customActions) == 0 { @@ -178,11 +179,11 @@ func policy_createSubjectMapping(cmd *cobra.Command, args []string) { } func policy_deleteSubjectMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") + id := c.Flags.GetRequiredString("id") sm, err := h.GetSubjectMapping(id) if err != nil { @@ -206,15 +207,15 @@ func policy_deleteSubjectMapping(cmd *cobra.Command, args []string) { } func policy_updateSubjectMapping(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - id := flagHelper.GetRequiredString("id") - standardActions := flagHelper.GetStringSlice("action-standard", standardActions, cli.FlagHelperStringSliceOptions{Min: 0}) - customActions := flagHelper.GetStringSlice("action-custom", customActions, cli.FlagHelperStringSliceOptions{Min: 0}) - scsId := flagHelper.GetOptionalString("subject-condition-set-id") - labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0}) + id := c.Flags.GetRequiredString("id") + standardActions := c.Flags.GetStringSlice("action-standard", standardActions, cli.FlagsStringSliceOptions{Min: 0}) + customActions := c.Flags.GetStringSlice("action-custom", customActions, cli.FlagsStringSliceOptions{Min: 0}) + scsId := c.Flags.GetOptionalString("subject-condition-set-id") + labels := c.Flags.GetStringSlice("label", metadataLabels, cli.FlagsStringSliceOptions{Min: 0}) if len(standardActions) > 0 { for _, a := range standardActions { diff --git a/cmd/profile.go b/cmd/profile.go index 2129e7c1..01a30677 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -20,23 +20,21 @@ var profileCreateCmd = &cobra.Command{ Short: "Create a new profile", Args: cobra.ExactArgs(2), Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, true) + c := cli.New(cmd, args) + InitProfile(c, true) profileName := args[0] endpoint := args[1] - fh := cli.NewFlagHelper(cmd) - setDefault := fh.GetOptionalBool("set-default") - tlsNoVerify := fh.GetOptionalBool("tls-no-verify") + setDefault := c.FlagHelper.GetOptionalBool("set-default") + tlsNoVerify := c.FlagHelper.GetOptionalBool("tls-no-verify") - print := cli.NewPrinter(true) - print.Printf("Creating profile %s... ", profileName) + c.Printf("Creating profile %s... ", profileName) if err := profile.AddProfile(profileName, endpoint, tlsNoVerify, setDefault); err != nil { - print.Println("failed") - cli.ExitWithError("Failed to create profile", err) + c.Println("failed") + c.ExitWithError("Failed to create profile", err) } - print.Println("ok") + c.Println("ok") // suggest the user to set up authentication }, @@ -46,16 +44,15 @@ var profileListCmd = &cobra.Command{ Use: "list", Short: "List profiles", Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, false) + c := cli.New(cmd, args) + InitProfile(c, false) - print := cli.NewPrinter(true) for _, p := range profile.GetGlobalConfig().ListProfiles() { if p == profile.GetGlobalConfig().GetDefaultProfile() { - print.Printf("* %s\n", p) + c.Printf("* %s\n", p) continue } - print.Printf(" %s\n", p) + c.Printf(" %s\n", p) } }, } @@ -65,13 +62,13 @@ var profileGetCmd = &cobra.Command{ Short: "Get a profile value", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, false) + c := cli.New(cmd, args) + InitProfile(c, false) profileName := args[0] p, err := profile.GetProfile(profileName) if err != nil { - cli.ExitWithError("Failed to load profile", err) + c.ExitWithError("Failed to load profile", err) } isDefault := "false" @@ -93,8 +90,7 @@ var profileGetCmd = &cobra.Command{ []string{"Auth type", auth}, ) - print := cli.NewPrinter(true) - print.Print(t.View()) + c.Print(t.View()) }, } @@ -102,22 +98,21 @@ var profileDeleteCmd = &cobra.Command{ Use: "delete ", Short: "Delete a profile", Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, false) + c := cli.New(cmd, args) + InitProfile(c, false) profileName := args[0] // TODO: suggest delete-all command to delete all profiles including default - print := cli.NewPrinter(true) - print.Printf("Deleting profile %s... ", profileName) + c.Printf("Deleting profile %s... ", profileName) if err := profile.DeleteProfile(profileName); err != nil { if err == profiles.ErrDeletingDefaultProfile { - cli.ExitWithWarning("Profile is set as default. Please set another profile as default before deleting.") + c.ExitWithWarning("Profile is set as default. Please set another profile as default before deleting.") } - cli.ExitWithError("Failed to delete profile", err) + c.ExitWithError("Failed to delete profile", err) } - print.Println("ok") + c.Println("ok") }, } @@ -128,17 +123,16 @@ var profileSetDefaultCmd = &cobra.Command{ Short: "Set a profile as default", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, false) + c := cli.New(cmd, args) + InitProfile(c, false) profileName := args[0] - print := cli.NewPrinter(true) - print.Printf("Setting profile %s as default... ", profileName) + c.Printf("Setting profile %s as default... ", profileName) if err := profile.SetDefaultProfile(profileName); err != nil { - cli.ExitWithError("Failed to set default profile", err) + c.ExitWithError("Failed to set default profile", err) } - print.Println("ok") + c.Println("ok") }, } @@ -147,8 +141,8 @@ var profileSetEndpointCmd = &cobra.Command{ Short: "Set a profile value", Args: cobra.ExactArgs(2), Run: func(cmd *cobra.Command, args []string) { - // ensure profile is initialized - InitProfile(cmd, false) + c := cli.New(cmd, args) + InitProfile(c, false) profileName := args[0] endpoint := args[1] @@ -158,12 +152,11 @@ var profileSetEndpointCmd = &cobra.Command{ cli.ExitWithError("Failed to load profile", err) } - print := cli.NewPrinter(true) - print.Printf("Setting endpoint for profile %s... ", profileName) + c.Printf("Setting endpoint for profile %s... ", profileName) if err := p.SetEndpoint(endpoint); err != nil { - cli.ExitWithError("Failed to set endpoint", err) + c.ExitWithError("Failed to set endpoint", err) } - print.Println("ok") + c.Println("ok") }, } diff --git a/cmd/root.go b/cmd/root.go index 1da73a41..aecd4c43 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,7 +5,6 @@ package cmd import ( "errors" - "fmt" "github.com/opentdf/otdfctl/pkg/auth" "github.com/opentdf/otdfctl/pkg/cli" @@ -28,14 +27,20 @@ var ( RootCmd = &man.Docs.GetDoc("").Command ) -func InitProfile(cmd *cobra.Command, onlyNew bool) *profiles.ProfileStore { - flag := cli.NewFlagHelper(cmd) - profileName := flag.GetOptionalString("profile") +type version struct { + AppName string `json:"app_name"` + Version string `json:"version"` + CommitSha string `json:"commit_sha"` + BuildTime string `json:"build_time"` +} +func InitProfile(c *cli.Cli, onlyNew bool) *profiles.ProfileStore { var err error + profileName := c.FlagHelper.GetOptionalString("profile") + profile, err = profiles.New() if err != nil || profile == nil { - cli.ExitWithError("Failed to initialize profile store", err) + c.ExitWithError("Failed to initialize profile store", err) } // short circuit if onlyNew is set to enable creating a new profile @@ -45,9 +50,9 @@ func InitProfile(cmd *cobra.Command, onlyNew bool) *profiles.ProfileStore { // check if there exists a default profile and warn if not with steps to create one if profile.GetGlobalConfig().GetDefaultProfile() == "" { - cli.ExitWithWarning("No default profile set. Use `" + config.AppName + " profile create ` to create a default profile.") + c.ExitWithWarning("No default profile set. Use `" + config.AppName + " profile create ` to create a default profile.") } - fmt.Printf("Using profile [%s]\n", profile.GetGlobalConfig().GetDefaultProfile()) + c.Printf("Using profile [%s]\n", profile.GetGlobalConfig().GetDefaultProfile()) if profileName == "" { profileName = profile.GetGlobalConfig().GetDefaultProfile() @@ -56,7 +61,7 @@ func InitProfile(cmd *cobra.Command, onlyNew bool) *profiles.ProfileStore { // load profile cp, err := profile.UseProfile(profileName) if err != nil { - cli.ExitWithError("Failed to load profile "+profileName, err) + c.ExitWithError("Failed to load profile "+profileName, err) } return cp @@ -64,14 +69,12 @@ func InitProfile(cmd *cobra.Command, onlyNew bool) *profiles.ProfileStore { // instantiates a new handler with authentication via client credentials // TODO make this a preRun hook -func NewHandler(cmd *cobra.Command) handlers.Handler { - fh := cli.NewFlagHelper(cmd) - +func NewHandler(c *cli.Cli) handlers.Handler { // Non-profile flags - host := fh.GetOptionalString("host") - tlsNoVerify := fh.GetOptionalBool("tls-no-verify") - withClientCreds := fh.GetOptionalString("with-client-creds") - withClientCredsFile := fh.GetOptionalString("with-client-creds-file") + host := c.FlagHelper.GetOptionalString("host") + tlsNoVerify := c.FlagHelper.GetOptionalBool("tls-no-verify") + withClientCreds := c.FlagHelper.GetOptionalString("with-client-creds") + withClientCredsFile := c.FlagHelper.GetOptionalString("with-client-creds-file") // if global flags are set then validate and create a temporary profile in memory var cp *profiles.ProfileStore @@ -130,10 +133,10 @@ func NewHandler(cmd *cobra.Command) handlers.Handler { cli.ExitWithError("Failed to save profile", err) } } else { - cp = InitProfile(cmd, false) + cp = InitProfile(c, false) } - if err := auth.ValidateProfileAuthCredentials(cmd.Context(), cp); err != nil { + if err := auth.ValidateProfileAuthCredentials(c.Context(), cp); err != nil { if errors.Is(err, auth.ErrProfileCredentialsNotFound) { cli.ExitWithWarning("Profile missing credentials. Please login or add client credentials.") } @@ -156,10 +159,18 @@ func NewHandler(cmd *cobra.Command) handlers.Handler { func init() { rootCmd := man.Docs.GetCommand("", man.WithRun(func(cmd *cobra.Command, args []string) { - flaghelper := cli.NewFlagHelper(cmd) - - if flaghelper.GetOptionalBool("version") { - fmt.Println(config.AppName + " version " + config.Version + " (" + config.BuildTime + ") " + config.CommitSha) + c := cli.New(cmd, args) + + if c.Flags.GetOptionalBool("version") { + v := version{ + AppName: config.AppName, + Version: config.Version, + CommitSha: config.CommitSha, + BuildTime: config.BuildTime, + } + + c.Println(config.AppName + " version " + config.Version + " (" + config.BuildTime + ") " + config.CommitSha) + c.ExitWithJson(v) return } @@ -174,6 +185,18 @@ func init() { rootCmd.GetDocFlag("version").Description, ) + RootCmd.PersistentFlags().Bool( + rootCmd.GetDocFlag("debug").Name, + rootCmd.GetDocFlag("debug").DefaultAsBool(), + rootCmd.GetDocFlag("debug").Description, + ) + + RootCmd.PersistentFlags().Bool( + rootCmd.GetDocFlag("json").Name, + rootCmd.GetDocFlag("json").DefaultAsBool(), + rootCmd.GetDocFlag("json").Description, + ) + RootCmd.PersistentFlags().String( rootCmd.GetDocFlag("profile").Name, rootCmd.GetDocFlag("profile").Default, diff --git a/cmd/tdf-decrypt.go b/cmd/tdf-decrypt.go index 65a6da08..7f4d7bfe 100644 --- a/cmd/tdf-decrypt.go +++ b/cmd/tdf-decrypt.go @@ -12,12 +12,12 @@ import ( ) func dev_tdfDecryptCmd(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) - output := flagHelper.GetOptionalString("out") - tdfType := flagHelper.GetOptionalString("tdf-type") + output := c.Flags.GetOptionalString("out") + tdfType := c.Flags.GetOptionalString("tdf-type") if tdfType == "" { tdfType = TDF3 } diff --git a/cmd/tdf-encrypt.go b/cmd/tdf-encrypt.go index f68ba422..42625ecb 100644 --- a/cmd/tdf-encrypt.go +++ b/cmd/tdf-encrypt.go @@ -21,10 +21,10 @@ const ( ) func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args) + h := NewHandler(c) defer h.Close() - flagHelper := cli.NewFlagHelper(cmd) var filePath string var fileExt string if len(args) > 0 { @@ -32,14 +32,14 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) { fileExt = strings.ToLower(strings.TrimPrefix(filepath.Ext(filePath), ".")) } - out := flagHelper.GetOptionalString("out") - fileMimeType := flagHelper.GetOptionalString("mime-type") - values := flagHelper.GetStringSlice("attr", attrValues, cli.FlagHelperStringSliceOptions{Min: 0}) - tdfType := flagHelper.GetOptionalString("tdf-type") + out := c.Flags.GetOptionalString("out") + fileMimeType := c.Flags.GetOptionalString("mime-type") + values := c.Flags.GetStringSlice("attr", attrValues, cli.FlagsStringSliceOptions{Min: 0}) + tdfType := c.Flags.GetOptionalString("tdf-type") if tdfType == "" { tdfType = TDF3 } - kasURLPath := flagHelper.GetOptionalString("kas-url-path") + kasURLPath := c.Flags.GetOptionalString("kas-url-path") piped := readPipedStdin() diff --git a/cmd/tdf-inspect.go b/cmd/tdf-inspect.go index 2133039c..802d9855 100644 --- a/cmd/tdf-inspect.go +++ b/cmd/tdf-inspect.go @@ -1,9 +1,7 @@ package cmd import ( - "encoding/json" "errors" - "fmt" "github.com/opentdf/otdfctl/pkg/cli" "github.com/opentdf/otdfctl/pkg/handlers" @@ -32,20 +30,21 @@ type tdfInspectResult struct { } func tdf_InspectCmd(cmd *cobra.Command, args []string) { - h := NewHandler(cmd) + c := cli.New(cmd, args, cli.WithPrintJson()) + h := NewHandler(c) defer h.Close() data := cli.ReadFromArgsOrPipe(args, nil) if len(data) == 0 { - cli.ExitWithError("Must provide ONE of the following: [file argument, stdin input]", errors.New("no input provided")) + c.ExitWithError("must provide ONE of the following: [file argument, stdin input]", errors.New("no input provided")) } result, errs := h.InspectTDF(data) for _, err := range errs { if errors.Is(err, handlers.ErrTDFInspectFailNotValidTDF) { - cli.ExitWithError("Not a valid ZTDF", err) + c.ExitWithError("not a valid ZTDF", err) } else if errors.Is(err, handlers.ErrTDFInspectFailNotInspectable) { - cli.ExitWithError("Failed to inspect TDF", err) + c.ExitWithError("failed to inspect TDF", err) } } @@ -66,12 +65,7 @@ func tdf_InspectCmd(cmd *cobra.Command, args []string) { Attributes: result.Attributes, } - b, err := json.MarshalIndent(m, "", " ") - if err != nil { - cli.ExitWithError("Failed to marshal TDF inspect result", err) - } - - fmt.Printf("%s\n", string(b)) + c.PrintJson(m) } func init() { @@ -80,5 +74,10 @@ func init() { ) tdf_InspectCmd.Command.GroupID = "tdf" + tdf_InspectCmd.Command.PreRun = func(cmd *cobra.Command, args []string) { + // Set the json flag to true since we only support json output + cmd.SetArgs(append(args, "--json")) + } + RootCmd.AddCommand(&tdf_InspectCmd.Command) } diff --git a/docs/man/_index.md b/docs/man/_index.md index 4173ae86..6a1b2ca5 100644 --- a/docs/man/_index.md +++ b/docs/man/_index.md @@ -31,4 +31,10 @@ command: - name: with-client-creds description: JSON string containing a 'clientId' and 'clientSecret' for auth via client-credentials flow default: '' + - name: json + description: output in JSON format + default: false + - name: debug + description: enable debug output + default: false --- diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go new file mode 100644 index 00000000..60375b3c --- /dev/null +++ b/pkg/cli/cli.go @@ -0,0 +1,55 @@ +package cli + +import ( + "context" + + "github.com/spf13/cobra" +) + +type Cli struct { + cmd *cobra.Command + args []string + + // Helpers + Flags *flagHelper + FlagHelper *flagHelper + printer *Printer +} + +// New creates a new Cli object +func New(cmd *cobra.Command, args []string, options ...cliVariadicOption) *Cli { + opts := cliOptions{ + printerJson: false, + } + for _, opt := range options { + opts = opt(opts) + } + + cli := &Cli{ + cmd: cmd, + args: args, + } + + if cmd == nil { + ExitWithError("cli expects a command", ErrPrinterExpectsCommand) + } + + cli.Flags = newFlagHelper(cmd) + // Temp wrapper for FlagHelper until we can remove it + cli.FlagHelper = cli.Flags + + cli.printer = newPrinter(cli) + if opts.printerJson { + cli.printer.setJson(true) + } + + return cli +} + +func (c *Cli) Cmd() *cobra.Command { + return c.cmd +} + +func (c *Cli) Context() context.Context { + return c.cmd.Context() +} diff --git a/pkg/cli/clioptions.go b/pkg/cli/clioptions.go new file mode 100644 index 00000000..2fee4e9a --- /dev/null +++ b/pkg/cli/clioptions.go @@ -0,0 +1,15 @@ +package cli + +type cliOptions struct { + printerJson bool +} + +type cliVariadicOption func(cliOptions) cliOptions + +// WithPrintJson is a variadic option that enforces JSON output for the printer +func WithPrintJson() cliVariadicOption { + return func(o cliOptions) cliOptions { + o.printerJson = true + return o + } +} diff --git a/pkg/cli/errors.go b/pkg/cli/errors.go index 59fac343..4f2893a3 100644 --- a/pkg/cli/errors.go +++ b/pkg/cli/errors.go @@ -2,7 +2,6 @@ package cli import ( "errors" - "fmt" "os" "google.golang.org/grpc/codes" @@ -10,25 +9,57 @@ import ( ) func ExitWithError(errMsg string, err error) { + // This is temporary until we can refactor the code to use the Cli struct + (&Cli{printer: &Printer{enabled: true}}).ExitWithError(errMsg, err) +} + +func ExitWithNotFoundError(errMsg string, err error) { + // This is temporary until we can refactor the code to use the Cli struct + (&Cli{printer: &Printer{enabled: true}}).ExitWithNotFoundError(errMsg, err) +} + +func ExitWithWarning(warnMsg string) { + // This is temporary until we can refactor the code to use the Cli struct + (&Cli{printer: &Printer{enabled: true}}).ExitWithWarning(warnMsg) +} + +// ExitWithError prints an error message and exits with a non-zero status code. +func (c *Cli) ExitWithError(errMsg string, err error) { if err == nil { // ensure message and exit are satisfied even if nil error passed err = errors.New("") } - ExitWithNotFoundError(errMsg, err) + c.ExitWithNotFoundError(errMsg, err) if err != nil { - fmt.Println(ErrorMessage(errMsg, err)) + c.Println(ErrorMessage(errMsg, err)) os.Exit(1) } } -func ExitWithNotFoundError(errMsg string, err error) { +// ExitWithNotFoundError prints an error message and exits with a non-zero status code if the error is a NotFound error. +func (c *Cli) ExitWithNotFoundError(errMsg string, err error) { if e, ok := status.FromError(err); ok && e.Code() == codes.NotFound { - fmt.Println(ErrorMessage(errMsg+": not found", nil)) + c.Println(ErrorMessage(errMsg+": not found", nil)) os.Exit(1) } } -func ExitWithWarning(warnMsg string) { - fmt.Println(WarningMessage(warnMsg)) - os.Exit(0) +func (c *Cli) ExitWithMessage(msg string, code int) { + c.Println(msg) + os.Exit(code) +} + +func (c *Cli) ExitWithWarning(warnMsg string) { + c.ExitWithMessage(WarningMessage(warnMsg), 0) +} + +func (c *Cli) ExitWithSuccess(msg string) { + c.ExitWithMessage(SuccessMessage(msg), 0) +} + +func (c *Cli) ExitWithJson(v interface{}) { + if c.printer.json { + c.PrintJson(v) + os.Exit(0) + } } diff --git a/pkg/cli/flagValues.go b/pkg/cli/flagValues.go index a1bd6be1..4938d331 100644 --- a/pkg/cli/flagValues.go +++ b/pkg/cli/flagValues.go @@ -9,20 +9,20 @@ import ( "github.com/spf13/cobra" ) -type FlagHelperStringSliceOptions struct { +type FlagsStringSliceOptions struct { Min int Max int } -type FlagHelper struct { +type flagHelper struct { cmd *cobra.Command } -func NewFlagHelper(cmd *cobra.Command) *FlagHelper { - return &FlagHelper{cmd: cmd} +func newFlagHelper(cmd *cobra.Command) *flagHelper { + return &flagHelper{cmd: cmd} } -func (f FlagHelper) GetRequiredString(flag string) string { +func (f flagHelper) GetRequiredString(flag string) string { v := f.cmd.Flag(flag).Value.String() if v == "" { fmt.Println(ErrorMessage("Flag "+flag+" is required", nil)) @@ -31,7 +31,7 @@ func (f FlagHelper) GetRequiredString(flag string) string { return v } -func (f FlagHelper) GetOptionalString(flag string) string { +func (f flagHelper) GetOptionalString(flag string) string { p := f.cmd.Flag(flag) if p == nil { return "" @@ -39,7 +39,7 @@ func (f FlagHelper) GetOptionalString(flag string) string { return p.Value.String() } -func (f FlagHelper) GetStringSlice(flag string, v []string, opts FlagHelperStringSliceOptions) []string { +func (f flagHelper) GetStringSlice(flag string, v []string, opts FlagsStringSliceOptions) []string { if len(v) < opts.Min { fmt.Println(ErrorMessage(fmt.Sprintf("Flag %s must have at least %d non-empty values", flag, opts.Min), nil)) os.Exit(1) @@ -51,7 +51,7 @@ func (f FlagHelper) GetStringSlice(flag string, v []string, opts FlagHelperStrin return v } -func (f FlagHelper) GetRequiredInt32(flag string) int32 { +func (f flagHelper) GetRequiredInt32(flag string) int32 { v, e := f.cmd.Flags().GetInt32(flag) if e != nil { fmt.Println(ErrorMessage("Flag "+flag+" is required", nil)) @@ -64,12 +64,12 @@ func (f FlagHelper) GetRequiredInt32(flag string) int32 { return v } -func (f FlagHelper) GetOptionalBool(flag string) bool { +func (f flagHelper) GetOptionalBool(flag string) bool { v, _ := f.cmd.Flags().GetBool(flag) return v } -func (f FlagHelper) GetRequiredBool(flag string) bool { +func (f flagHelper) GetRequiredBool(flag string) bool { v, e := f.cmd.Flags().GetBool(flag) if e != nil { fmt.Println(ErrorMessage("Flag "+flag+" is required", nil)) @@ -92,7 +92,7 @@ func GetState(cmd *cobra.Command) common.ActiveStateEnum { return state } -// func (f FlagHelper) GetStructSlice(flag string, v []StructFlag[T], opts FlagHelperStringSliceOptions) ([]StructFlag[T], err) { +// func (f flagHelper) GetStructSlice(flag string, v []StructFlag[T], opts flagHelperStringSliceOptions) ([]StructFlag[T], err) { // if len(v) < opts.Min { // fmt.Println(ErrorMessage(fmt.Sprintf("Flag %s must have at least %d non-empty values", flag, opts.Min), nil)) // os.Exit(1) diff --git a/pkg/cli/messages.go b/pkg/cli/messages.go index 9ed815b9..036869af 100644 --- a/pkg/cli/messages.go +++ b/pkg/cli/messages.go @@ -3,11 +3,7 @@ package cli import "github.com/charmbracelet/lipgloss" func SuccessMessage(msg string) string { - return lipgloss.JoinHorizontal( - lipgloss.Left, - styleSuccessStatusBar. - MarginBottom(1). - Render("SUCCESS"), msg) + return lipgloss.JoinHorizontal(lipgloss.Left, styleSuccessStatusBar.Render("SUCCESS"), msg) } func FooterMessage(msg string) string { @@ -24,23 +20,17 @@ func FooterMessage(msg string) string { ) } +func DebugMessage(msg string) string { + return lipgloss.JoinHorizontal(lipgloss.Left, styleDebugStatusBar.Render("DEBUG"), msg) +} + func ErrorMessage(msg string, err error) string { if err != nil { msg += ": " + err.Error() } - - return lipgloss.JoinHorizontal( - lipgloss.Left, - styleErrorStatusBar. - PaddingRight(3). - Render("ERROR"), msg) + return lipgloss.JoinHorizontal(lipgloss.Left, styleErrorStatusBar.Render("ERROR"), msg) } func WarningMessage(msg string) string { - return lipgloss.JoinHorizontal( - lipgloss.Left, - styleWarningStatusBar. - Padding(0, 2). - MarginRight(1). - Render("WARNING"), msg) + return lipgloss.JoinHorizontal(lipgloss.Left, styleWarningStatusBar.Render("WARNING"), msg) } diff --git a/pkg/cli/printer.go b/pkg/cli/printer.go index dd1463f4..dc549264 100644 --- a/pkg/cli/printer.go +++ b/pkg/cli/printer.go @@ -1,31 +1,110 @@ package cli -import "fmt" +import ( + "encoding/json" + "fmt" +) + +var ErrPrinterExpectsCommand = fmt.Errorf("printer expects a command") type Printer struct { enabled bool + json bool + debug bool +} + +func newPrinter(cli *Cli) *Printer { + p := &Printer{ + enabled: true, + json: false, + debug: false, + } + + // if json output is enabled, disable the printer + if cli.cmd.Flag("json") != nil { + json, err := cli.cmd.Flags().GetBool("json") + if err != nil { + ExitWithError("failed to get json flag", err) + return nil + } + p.setJson(json) + } + + // if debug output is enabled, enable debug output + if cli.cmd.Flag("debug") != nil { + debug, err := cli.cmd.Flags().GetBool("debug") + if err != nil { + ExitWithError("failed to get debug flag", err) + return nil + } + p.setDebug(debug) + } + + return p +} + +func (p *Printer) setJson(json bool) { + p.json = json + p.enabled = !json +} + +func (p *Printer) setDebug(debug bool) { + p.debug = debug +} + +const debugPrefix = "DEBUG: " + +func (c *Cli) Debug(args ...interface{}) { + if c.printer.debug { + args = append([]interface{}{debugPrefix}, args...) + c.Print(args) + } +} + +func (c *Cli) Debugf(format string, args ...interface{}) { + format = "DEBUG: " + format + if c.printer.debug { + c.Printf(format, args...) + } +} + +func (c *Cli) Debugln(args ...interface{}) { + if c.printer.debug { + args = append([]interface{}{"DEBUG: "}, args) + c.Println(args...) + } +} + +// PrintJson prints the given value as json +// ignores the printer enabled flag +func (c *Cli) PrintJson(v interface{}) { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + ExitWithError("failed to marshal json", err) + } + fmt.Println(string(b)) } -func NewPrinter(enabled bool) *Printer { - return &Printer{ - enabled: enabled, +func (c *Cli) PrintIfJson(v interface{}) { + if c.printer.json { + c.PrintJson(v) } } -func (p *Printer) Print(args ...interface{}) { - if p.enabled { +func (c *Cli) Print(args ...interface{}) { + if c.printer.enabled { fmt.Print(args...) } } -func (p *Printer) Printf(format string, args ...interface{}) { - if p.enabled { +func (c *Cli) Printf(format string, args ...interface{}) { + if c.printer.enabled { fmt.Printf(format, args...) } } -func (p *Printer) Println(args ...interface{}) { - if p.enabled { +func (c *Cli) Println(args ...interface{}) { + if c.printer.enabled { fmt.Println(args...) } } diff --git a/pkg/cli/style.go b/pkg/cli/style.go index 0469e930..2bd42c37 100644 --- a/pkg/cli/style.go +++ b/pkg/cli/style.go @@ -288,13 +288,15 @@ var styleSuccessStatusBar = lipgloss.NewStyle(). Foreground(colorBlack.Foreground). Background(colorGreen.Background). Padding(0, 2). - MarginRight(1) + MarginRight(1). + MarginBottom(1) var styleErrorStatusBar = lipgloss.NewStyle(). Inherit(statusBarStyle). Foreground(colorBlack.Foreground). Background(colorRed.Background). Padding(0, 3). + PaddingRight(3). MarginRight(1) var styleNoteStatusBar = lipgloss.NewStyle(). @@ -302,10 +304,18 @@ var styleNoteStatusBar = lipgloss.NewStyle(). Foreground(colorYellow.Foreground). Background(colorYellow.Background) +var styleDebugStatusBar = lipgloss.NewStyle(). + Inherit(statusBarStyle). + Foreground(colorBlack.Foreground). + Background(colorIndigo.Background). + PaddingRight(3) + var styleWarningStatusBar = lipgloss.NewStyle(). Inherit(statusBarStyle). Foreground(colorOrange.Foreground). - Background(colorOrange.Background) + Background(colorOrange.Background). + Padding(0, 2). + MarginRight(1) var footerLabelStyle = lipgloss.NewStyle(). Inherit(statusBarStyle).