diff --git a/README.md b/README.md index 5ae21bbe..112d0abb 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build Status](https://build.coopcloud.tech/api/badges/toolshed/abra/status.svg?ref=refs/heads/main)](https://build.coopcloud.tech/toolshed/abra) [![Go Report Card](https://goreportcard.com/badge/git.coopcloud.tech/toolshed/abra)](https://goreportcard.com/report/git.coopcloud.tech/toolshed/abra) [![Go Reference](https://pkg.go.dev/badge/coopcloud.tech/abra.svg)](https://pkg.go.dev/coopcloud.tech/abra) +[![Translation status](https://translate.coopcloud.tech/widget/co-op-cloud/svg-badge.svg)](https://translate.coopcloud.tech/engage/co-op-cloud/) The Co-op Cloud utility belt 🎩🐇 diff --git a/cli/app/app.go b/cli/app/app.go index 259dadfc..57fd2d45 100644 --- a/cli/app/app.go +++ b/cli/app/app.go @@ -6,7 +6,7 @@ import ( ) var AppCommand = &cobra.Command{ - Use: "app [cmd] [args] [flags]", + Use: gotext.Get("app [cmd] [args] [flags]"), Aliases: []string{"a"}, Short: gotext.Get("Manage apps"), } diff --git a/cli/app/backup.go b/cli/app/backup.go index 83083172..739df513 100644 --- a/cli/app/backup.go +++ b/cli/app/backup.go @@ -7,13 +7,14 @@ import ( "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var AppBackupListCommand = &cobra.Command{ - Use: "list [flags]", + Use: gotext.Get("list [flags]"), Aliases: []string{"ls"}, - Short: "List the contents of a snapshot", + Short: gotext.Get("List the contents of a snapshot"), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -40,17 +41,17 @@ var AppBackupListCommand = &cobra.Command{ } if snapshot != "" { - log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot) + log.Debug(gotext.Get("including SNAPSHOT=%s in backupbot exec invocation", snapshot)) execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot)) } if showAllPaths { - log.Debugf("including SHOW_ALL=%v in backupbot exec invocation", showAllPaths) + log.Debug(gotext.Get("including SHOW_ALL=%v in backupbot exec invocation", showAllPaths)) execEnv = append(execEnv, fmt.Sprintf("SHOW_ALL=%v", showAllPaths)) } if timestamps { - log.Debugf("including TIMESTAMPS=%v in backupbot exec invocation", timestamps) + log.Debug(gotext.Get("including TIMESTAMPS=%v in backupbot exec invocation", timestamps)) execEnv = append(execEnv, fmt.Sprintf("TIMESTAMPS=%v", timestamps)) } @@ -61,13 +62,13 @@ var AppBackupListCommand = &cobra.Command{ } var AppBackupDownloadCommand = &cobra.Command{ - Use: "download [flags]", + Use: gotext.Get("download [flags]"), Aliases: []string{"d"}, - Short: "Download a snapshot", - Long: `Downloads a backup.tar.gz to the current working directory. + Short: gotext.Get("Download a snapshot"), + Long: gotext.Get(`Downloads a backup.tar.gz to the current working directory. "--volumes/-v" includes data contained in volumes alongide paths specified in -"backupbot.backup.path" labels.`, +"backupbot.backup.path" labels.`), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -98,22 +99,22 @@ var AppBackupDownloadCommand = &cobra.Command{ } if snapshot != "" { - log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot) + log.Debug(gotext.Get("including SNAPSHOT=%s in backupbot exec invocation", snapshot)) execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot)) } if includePath != "" { - log.Debugf("including INCLUDE_PATH=%s in backupbot exec invocation", includePath) + log.Debug(gotext.Get("including INCLUDE_PATH=%s in backupbot exec invocation", includePath)) execEnv = append(execEnv, fmt.Sprintf("INCLUDE_PATH=%s", includePath)) } if includeSecrets { - log.Debugf("including SECRETS=%v in backupbot exec invocation", includeSecrets) + log.Debug(gotext.Get("including SECRETS=%v in backupbot exec invocation", includeSecrets)) execEnv = append(execEnv, fmt.Sprintf("SECRETS=%v", includeSecrets)) } if includeVolumes { - log.Debugf("including VOLUMES=%v in backupbot exec invocation", includeVolumes) + log.Debug(gotext.Get("including VOLUMES=%v in backupbot exec invocation", includeVolumes)) execEnv = append(execEnv, fmt.Sprintf("VOLUMES=%v", includeVolumes)) } @@ -130,9 +131,9 @@ var AppBackupDownloadCommand = &cobra.Command{ } var AppBackupCreateCommand = &cobra.Command{ - Use: "create [flags]", + Use: gotext.Get("create [flags]"), Aliases: []string{"c"}, - Short: "Create a new snapshot", + Short: gotext.Get("Create a new snapshot"), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -163,7 +164,7 @@ var AppBackupCreateCommand = &cobra.Command{ } if retries != "" { - log.Debugf("including RETRIES=%s in backupbot exec invocation", retries) + log.Debug(gotext.Get("including RETRIES=%s in backupbot exec invocation", retries)) execEnv = append(execEnv, fmt.Sprintf("RETRIES=%s", retries)) } @@ -174,9 +175,9 @@ var AppBackupCreateCommand = &cobra.Command{ } var AppBackupSnapshotsCommand = &cobra.Command{ - Use: "snapshots [flags]", + Use: gotext.Get("snapshots [flags]"), Aliases: []string{"s"}, - Short: "List all snapshots", + Short: gotext.Get("List all snapshots"), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -209,9 +210,9 @@ var AppBackupSnapshotsCommand = &cobra.Command{ } var AppBackupCommand = &cobra.Command{ - Use: "backup [cmd] [args] [flags]", + Use: gotext.Get("backup [cmd] [args] [flags]"), Aliases: []string{"b"}, - Short: "Manage app backups", + Short: gotext.Get("Manage app backups"), } var ( @@ -230,7 +231,7 @@ func init() { "snapshot", "s", "", - "list specific snapshot", + gotext.Get("list specific snapshot"), ) AppBackupListCommand.Flags().BoolVarP( @@ -238,7 +239,7 @@ func init() { "all", "a", false, - "show all paths", + gotext.Get("show all paths"), ) AppBackupListCommand.Flags().BoolVarP( @@ -246,7 +247,7 @@ func init() { "timestamps", "t", false, - "include timestamps", + gotext.Get("include timestamps"), ) AppBackupDownloadCommand.Flags().StringVarP( @@ -254,7 +255,7 @@ func init() { "snapshot", "s", "", - "list specific snapshot", + gotext.Get("list specific snapshot"), ) AppBackupDownloadCommand.Flags().StringVarP( @@ -262,7 +263,7 @@ func init() { "path", "p", "", - "volumes path", + gotext.Get("volumes path"), ) AppBackupDownloadCommand.Flags().BoolVarP( @@ -270,7 +271,7 @@ func init() { "secrets", "S", false, - "include secrets", + gotext.Get("include secrets"), ) AppBackupDownloadCommand.Flags().BoolVarP( @@ -278,7 +279,7 @@ func init() { "volumes", "v", false, - "include volumes", + gotext.Get("include volumes"), ) AppBackupDownloadCommand.Flags().BoolVarP( @@ -286,7 +287,7 @@ func init() { "chaos", "C", false, - "ignore uncommitted recipes changes", + gotext.Get("ignore uncommitted recipes changes"), ) AppBackupCreateCommand.Flags().StringVarP( @@ -294,7 +295,7 @@ func init() { "retries", "r", "1", - "number of retry attempts", + gotext.Get("number of retry attempts"), ) AppBackupCreateCommand.Flags().BoolVarP( @@ -302,6 +303,6 @@ func init() { "chaos", "C", false, - "ignore uncommitted recipes changes", + gotext.Get("ignore uncommitted recipes changes"), ) } diff --git a/cli/app/check.go b/cli/app/check.go index dde31b93..86235f89 100644 --- a/cli/app/check.go +++ b/cli/app/check.go @@ -9,14 +9,15 @@ import ( "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/log" "github.com/charmbracelet/lipgloss" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var AppCheckCommand = &cobra.Command{ - Use: "check [flags]", + Use: gotext.Get("check [flags]"), Aliases: []string{"chk"}, - Short: "Ensure an app is well configured", - Long: `Compare env vars in both the app ".env" and recipe ".env.sample" file. + Short: gotext.Get("Ensure an app is well configured"), + Long: gotext.Get(`Compare env vars in both the app ".env" and recipe ".env.sample" file. The goal is to ensure that recipe ".env.sample" env vars are defined in your app ".env" file. Only env var definitions in the ".env.sample" which are @@ -25,7 +26,7 @@ these env vars, then "check" will complain. Recipe maintainers may or may not provide defaults for env vars within their recipes regardless of commenting or not (e.g. through the use of -${FOO:} syntax). "check" does not confirm or deny this for you.`, +${FOO:} syntax). "check" does not confirm or deny this for you.`), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -86,6 +87,6 @@ func init() { "chaos", "C", false, - "ignore uncommitted recipes changes", + gotext.Get("ignore uncommitted recipes changes"), ) } diff --git a/cli/app/cmd.go b/cli/app/cmd.go index a8e2e17f..dbb1e132 100644 --- a/cli/app/cmd.go +++ b/cli/app/cmd.go @@ -14,14 +14,15 @@ import ( "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var AppCmdCommand = &cobra.Command{ - Use: "command [service | --local] [[args] [flags] | [flags] -- [args]]", + Use: gotext.Get("command [service | --local] [[args] [flags] | [flags] -- [args]]"), Aliases: []string{"cmd"}, - Short: "Run app commands", - Long: `Run an app specific command. + Short: gotext.Get("Run app commands"), + Long: gotext.Get(`Run an app specific command. These commands are bash functions, defined in the abra.sh of the recipe itself. They can be run within the context of a service (e.g. app) or locally on your @@ -30,24 +31,24 @@ work station by passing "--local/-l". N.B. If using the "--" style to pass arguments, flags (e.g. "--local/-l") must be passed *before* the "--". It is possible to pass arguments without the "--" as long as no dashes are present (i.e. "foo" works without "--", "-foo" -does not).`, - Example: ` # pass args/flags without "--" +does not).`), + Example: gotext.Get(` # pass args/flags without "--" abra app cmd 1312.net app my_cmd_arg foo --user bar # pass args/flags with "--" abra app cmd 1312.net app my_cmd_args --user bar -- foo -vvv # drop the [service] arg if using "--local/-l" - abra app cmd 1312.net my_cmd --local`, + abra app cmd 1312.net my_cmd --local`), Args: func(cmd *cobra.Command, args []string) error { if local { if !(len(args) >= 2) { - return errors.New("requires at least 2 arguments with --local/-l") + return errors.New(gotext.Get("requires at least 2 arguments with --local/-l")) } if slices.Contains(os.Args, "--") { if cmd.ArgsLenAtDash() > 2 { - return errors.New("accepts at most 2 args with --local/-l") + return errors.New(gotext.Get("accepts at most 2 args with --local/-l")) } } @@ -63,7 +64,7 @@ does not).`, } if !(len(args) >= 3) { - return errors.New("requires at least 3 arguments") + return errors.New(gotext.Get("requires at least 3 arguments")) } return nil @@ -97,14 +98,14 @@ does not).`, } if local && remoteUser != "" { - log.Fatal("cannot use --local & --user together") + log.Fatal(gotext.Get("cannot use --local & --user together")) } hasCmdArgs, parsedCmdArgs := parseCmdArgs(args, local) if _, err := os.Stat(app.Recipe.AbraShPath); err != nil { if os.IsNotExist(err) { - log.Fatalf("%s does not exist for %s?", app.Recipe.AbraShPath, app.Name) + log.Fatal(gotext.Get("%s does not exist for %s?", app.Recipe.AbraShPath, app.Name)) } log.Fatal(err) } @@ -115,7 +116,7 @@ does not).`, log.Fatal(err) } - log.Debugf("--local detected, running %s on local work station", cmdName) + log.Debug(gotext.Get("--local detected, running %s on local work station", cmdName)) var exportEnv string for k, v := range app.Env { @@ -124,16 +125,16 @@ does not).`, var sourceAndExec string if hasCmdArgs { - log.Debugf("parsed following command arguments: %s", parsedCmdArgs) + log.Debug(gotext.Get("parsed following command arguments: %s", parsedCmdArgs)) sourceAndExec = fmt.Sprintf("TARGET=local; APP_NAME=%s; STACK_NAME=%s; %s . %s; %s %s", app.Name, app.StackName(), exportEnv, app.Recipe.AbraShPath, cmdName, parsedCmdArgs) } else { - log.Debug("did not detect any command arguments") + log.Debug(gotext.Get("did not detect any command arguments")) sourceAndExec = fmt.Sprintf("TARGET=local; APP_NAME=%s; STACK_NAME=%s; %s . %s; %s", app.Name, app.StackName(), exportEnv, app.Recipe.AbraShPath, cmdName) } shell := "/bin/bash" if _, err := os.Stat(shell); errors.Is(err, os.ErrNotExist) { - log.Debugf("%s does not exist locally, use /bin/sh as fallback", shell) + log.Debug(gotext.Get("%s does not exist locally, use /bin/sh as fallback", shell)) shell = "/bin/sh" } cmd := exec.Command(shell, "-c", sourceAndExec) @@ -164,15 +165,15 @@ does not).`, } if !matchingServiceName { - log.Fatalf("no service %s for %s?", targetServiceName, app.Name) + log.Fatal(gotext.Get("no service %s for %s?", targetServiceName, app.Name)) } - log.Debugf("running command %s within the context of %s_%s", cmdName, app.StackName(), targetServiceName) + log.Debug(gotext.Get("running command %s within the context of %s_%s", cmdName, app.StackName(), targetServiceName)) if hasCmdArgs { - log.Debugf("parsed following command arguments: %s", parsedCmdArgs) + log.Debug(gotext.Get("parsed following command arguments: %s", parsedCmdArgs)) } else { - log.Debug("did not detect any command arguments") + log.Debug(gotext.Get("did not detect any command arguments")) } cl, err := client.New(app.Server) @@ -192,9 +193,9 @@ does not).`, } var AppCmdListCommand = &cobra.Command{ - Use: "list [flags]", + Use: gotext.Get("list [flags]"), Aliases: []string{"ls"}, - Short: "List all available commands", + Short: gotext.Get("List all available commands"), Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { app := internal.ValidateApp(args) @@ -247,7 +248,7 @@ func init() { "local", "l", false, - "run command locally", + gotext.Get("run command locally"), ) AppCmdCommand.Flags().StringVarP( @@ -255,7 +256,7 @@ func init() { "user", "u", "", - "request remote user", + gotext.Get("request remote user"), ) AppCmdCommand.Flags().BoolVarP( @@ -263,7 +264,7 @@ func init() { "tty", "T", false, - "disable remote TTY", + gotext.Get("disable remote TTY"), ) AppCmdCommand.Flags().BoolVarP( @@ -271,6 +272,6 @@ func init() { "chaos", "C", false, - "ignore uncommitted recipes changes", + gotext.Get("ignore uncommitted recipes changes"), ) } diff --git a/cli/app/list.go b/cli/app/list.go index 50e7ce5c..4c4a59c3 100644 --- a/cli/app/list.go +++ b/cli/app/list.go @@ -13,6 +13,7 @@ import ( "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/log" "coopcloud.tech/tagcmp" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) @@ -39,20 +40,20 @@ type serverStatus struct { } var AppListCommand = &cobra.Command{ - Use: "list [flags]", + Use: gotext.Get("list [flags]"), Aliases: []string{"ls"}, - Short: "List all managed apps", - Long: `Generate a report of all managed apps. + Short: gotext.Get("List all managed apps"), + Long: gotext.Get(`Generate a report of all managed apps. -Use "--status/-S" flag to query all servers for the live deployment status.`, - Example: ` # list apps of all servers without live status +Use "--status/-S" flag to query all servers for the live deployment status.`), + Example: gotext.Get(` # list apps of all servers without live status abra app ls # list apps of a specific server with live status abra app ls -s 1312.net -S # list apps of all servers which match a specific recipe - abra app ls -r gitea`, + abra app ls -r gitea`), Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { appFiles, err := appPkg.LoadAppFiles(listAppServer) @@ -144,12 +145,12 @@ Use "--status/-S" flag to query all servers for the live deployment status.`, var newUpdates []string if version != "unknown" && chaos == "false" { if err := app.Recipe.EnsureExists(); err != nil { - log.Fatalf("unable to clone %s: %s", app.Name, err) + log.Fatal(gotext.Get("unable to clone %s: %s", app.Name, err)) } updates, err := app.Recipe.Tags() if err != nil { - log.Fatalf("unable to retrieve tags for %s: %s", app.Name, err) + log.Fatal(gotext.Get("unable to retrieve tags for %s: %s", app.Name, err)) } parsedVersion, err := tagcmp.Parse(version) @@ -215,11 +216,12 @@ Use "--status/-S" flag to query all servers for the live deployment status.`, headers := []string{"RECIPE", "DOMAIN", "SERVER"} if status { headers = append(headers, []string{ - "STATUS", - "CHAOS", - "VERSION", - "UPGRADE", - "AUTOUPDATE"}..., + gotext.Get("STATUS"), + gotext.Get("CHAOS"), + gotext.Get("VERSION"), + gotext.Get("UPGRADE"), + gotext.Get("AUTOUPDATE"), + }..., ) } @@ -286,7 +288,7 @@ func init() { "status", "S", false, - "show app deployment status", + gotext.Get("show app deployment status"), ) AppListCommand.Flags().StringVarP( @@ -294,7 +296,7 @@ func init() { "recipe", "r", "", - "show apps of a specific recipe", + gotext.Get("show apps of a specific recipe"), ) AppListCommand.RegisterFlagCompletionFunc( @@ -309,7 +311,7 @@ func init() { "machine", "m", false, - "print machine-readable output", + gotext.Get("print machine-readable output"), ) AppListCommand.Flags().StringVarP( @@ -317,7 +319,7 @@ func init() { "server", "s", "", - "show apps of a specific server", + gotext.Get("show apps of a specific server"), ) AppListCommand.RegisterFlagCompletionFunc( diff --git a/cli/catalogue/catalogue.go b/cli/catalogue/catalogue.go index 9c7abd27..bafd27ed 100644 --- a/cli/catalogue/catalogue.go +++ b/cli/catalogue/catalogue.go @@ -16,14 +16,15 @@ import ( "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/recipe" "github.com/go-git/go-git/v5" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var CatalogueGenerateCommand = &cobra.Command{ - Use: "generate [recipe] [flags]", + Use: gotext.Get("generate [recipe] [flags]"), Aliases: []string{"g"}, - Short: "Generate the recipe catalogue", - Long: `Generate a new copy of the recipe catalogue. + Short: gotext.Get("Generate the recipe catalogue"), + Long: gotext.Get(`Generate a new copy of the recipe catalogue. N.B. this command **will** wipe local unstaged changes from your local recipes if present. "--chaos/-C" on this command refers to the catalogue repository @@ -39,7 +40,7 @@ use those details. Push your new release to git.coopcloud.tech with "--publish/-p". This requires that you have permission to git push to these repositories and have your SSH -keys configured on your account.`, +keys configured on your account.`), Args: cobra.RangeArgs(0, 1), ValidArgsFunction: func( cmd *cobra.Command, @@ -85,7 +86,7 @@ keys configured on your account.`, var warnings []string catl := make(recipe.RecipeCatalogue) - catlBar := formatter.CreateProgressbar(barLength, "collecting catalogue metadata") + catlBar := formatter.CreateProgressbar(barLength, gotext.Get("collecting catalogue metadata")) for _, recipeMeta := range repos { if recipeName != "" && recipeName != recipeMeta.Name { if !internal.Debug { @@ -171,7 +172,7 @@ keys configured on your account.`, } } - log.Infof("generated recipe catalogue: %s", config.RECIPES_JSON) + log.Info(gotext.Get("generated recipe catalogue: %s", config.RECIPES_JSON)) cataloguePath := path.Join(config.ABRA_DIR, "catalogue") if publishChanges { @@ -183,11 +184,11 @@ keys configured on your account.`, if isClean { if !internal.Dry { - log.Fatalf("no changes discovered in %s, nothing to publish?", cataloguePath) + log.Fatal(gotext.Get("no changes discovered in %s, nothing to publish?", cataloguePath)) } } - msg := "chore: publish new catalogue release changes" + msg := gotext.Get("chore: publish new catalogue release changes") if err := gitPkg.Commit(cataloguePath, msg, internal.Dry); err != nil { log.Fatal(err) } @@ -219,19 +220,19 @@ keys configured on your account.`, if !internal.Dry && publishChanges { url := fmt.Sprintf("%s/%s/commit/%s", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME, head.Hash()) - log.Infof("new changes published: %s", url) + log.Info(gotext.Get("new changes published: %s", url)) } if internal.Dry { - log.Info("dry run: no changes published") + log.Info(gotext.Get("dry run: no changes published")) } }, } // CatalogueCommand defines the `abra catalogue` command and sub-commands. var CatalogueCommand = &cobra.Command{ - Use: "catalogue [cmd] [args] [flags]", - Short: "Manage the recipe catalogue", + Use: gotext.Get("catalogue [cmd] [args] [flags]"), + Short: gotext.Get("Manage the recipe catalogue"), Aliases: []string{"c"}, } @@ -246,7 +247,7 @@ func init() { "publish", "p", false, - "publish changes to git.coopcloud.tech", + gotext.Get("publish changes to git.coopcloud.tech"), ) CatalogueGenerateCommand.Flags().BoolVarP( @@ -254,7 +255,7 @@ func init() { "dry-run", "r", false, - "report changes that would be made", + gotext.Get("report changes that would be made"), ) CatalogueGenerateCommand.Flags().BoolVarP( @@ -262,7 +263,7 @@ func init() { "skip-updates", "s", false, - "skip updating recipe repositories", + gotext.Get("skip updating recipe repositories"), ) CatalogueGenerateCommand.Flags().BoolVarP( @@ -270,6 +271,6 @@ func init() { "chaos", "C", false, - "ignore uncommitted recipes changes", + gotext.Get("ignore uncommitted recipes changes"), ) } diff --git a/cli/complete.go b/cli/complete.go index 7f520df9..5bfba69a 100644 --- a/cli/complete.go +++ b/cli/complete.go @@ -3,13 +3,14 @@ package cli import ( "os" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var AutocompleteCommand = &cobra.Command{ - Use: "autocomplete [bash|zsh|fish|powershell]", - Short: "Generate autocompletion script", - Long: `To load completions: + Use: gotext.Get("autocomplete [bash|zsh|fish|powershell]"), + Short: gotext.Get("Generate autocompletion script"), + Long: gotext.Get(`To load completions: Bash: # Load autocompletion for the current Bash session @@ -43,7 +44,7 @@ PowerShell: # To load autocompletions for every new session, run: PS> abra autocomplete powershell > abra.ps1 - # and source this file from your PowerShell profile.`, + # and source this file from your PowerShell profile.`), DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), diff --git a/cli/internal/cli.go b/cli/internal/cli.go index 7c4825ad..be00b3f4 100644 --- a/cli/internal/cli.go +++ b/cli/internal/cli.go @@ -6,6 +6,7 @@ var ( NoInput bool Offline bool IgnoreEnvVersion bool + Locale string // NOTE(d1): sub-command specific Chaos bool diff --git a/cli/run.go b/cli/run.go index 13dd8aad..8eafd613 100644 --- a/cli/run.go +++ b/cli/run.go @@ -1,6 +1,7 @@ package cli import ( + "errors" "fmt" "os" @@ -10,27 +11,31 @@ import ( "coopcloud.tech/abra/cli/recipe" "coopcloud.tech/abra/cli/server" "coopcloud.tech/abra/pkg/config" + "coopcloud.tech/abra/pkg/formatter" + "coopcloud.tech/abra/pkg/lang" "coopcloud.tech/abra/pkg/log" charmLog "github.com/charmbracelet/log" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) func Run(version, commit string) { rootCmd := &cobra.Command{ - Use: "abra [cmd] [args] [flags]", - Short: "The Co-op Cloud command-line utility belt 🎩🐇", + Use: gotext.Get("abra [cmd] [args] [flags]"), + Short: gotext.Get("The Co-op Cloud command-line utility belt 🎩🐇"), Version: fmt.Sprintf("%s-%s", version, commit[:7]), ValidArgs: []string{ - "app", - "autocomplete", - "catalogue", - "man", - "recipe", - "server", - "upgrade", + gotext.Get("app"), + gotext.Get("autocomplete"), + gotext.Get("catalogue"), + gotext.Get("man"), + gotext.Get("recipe"), + gotext.Get("server"), + gotext.Get("upgrade"), }, - PersistentPreRun: func(cmd *cobra.Command, args []string) { + + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { dirs := []map[string]os.FileMode{ {config.ABRA_DIR: 0764}, {config.SERVERS_DIR: 0700}, @@ -42,7 +47,7 @@ func Run(version, commit string) { for path, perm := range dir { if err := os.Mkdir(path, perm); err != nil { if !os.IsExist(err) { - log.Fatal(err) + return errors.New(gotext.Get("unable to create %s: %s", path, err)) } continue } @@ -62,24 +67,57 @@ func Run(version, commit string) { log.SetReportCaller(true) } - log.Debugf("abra version %s, commit %s", version, commit) + if internal.Locale != "" { + // FIXME(d1): get list of valid locales from pkg/locales/* + switch internal.Locale { + case "es": + default: + return errors.New(gotext.Get("unsupported --lang: %s (want: es)", internal.Locale)) + } + } + + systemLocale := lang.GetLocale() + if internal.Locale == "" && systemLocale != "" { + // FIXME(d1): validate system locale also (as above FIXME) + internal.Locale = systemLocale + } + + if internal.Locale == "" { + // NOTE(d1): fallback when no --lang= / LANG= + internal.Locale = "en" + } + + // NOTE(d1): only required to load locale when not using en_ + // N.B we don't even bother with a _ (country code) atm for en because fuck it + if internal.Locale != "en" { + if err := lang.LoadLocale(internal.Locale); err != nil { + return errors.New(gotext.Get("unable to load supported language %s: %s", internal.Locale, err)) + } + } + + log.Debug(gotext.Get( + "abra version: %s, commit: %s, lang: %s", + version, formatter.SmallSHA(commit), internal.Locale, + )) + + return nil }, } rootCmd.CompletionOptions.DisableDefaultCmd = true manCommand := &cobra.Command{ - Use: "man [flags]", + Use: gotext.Get("man [flags]"), Aliases: []string{"m"}, - Short: "Generate manpage", - Example: ` # generate the man pages into /usr/local/share/man/man1 + Short: gotext.Get("Generate manpage"), + Example: gotext.Get(` # generate the man pages into /usr/local/share/man/man1 abra_path=$(which abra) # pass abra absolute path to sudo below sudo $abra_path man sudo mandb # read the man pages man abra - man abra-app-deploy`, + man abra-app-deploy`), Run: func(cmd *cobra.Command, args []string) { header := &doc.GenManHeader{ Title: "ABRA", @@ -88,7 +126,7 @@ func Run(version, commit string) { manDir := "/usr/local/share/man/man1" if _, err := os.Stat(manDir); os.IsNotExist(err) { - log.Fatalf("unable to proceed, '%s' does not exist?") + log.Fatal(gotext.Get("unable to proceed, %s does not exist?", manDir)) } err := doc.GenManTree(rootCmd, header, manDir) @@ -96,7 +134,7 @@ func Run(version, commit string) { log.Fatal(err) } - log.Info("don't forget to run 'sudo mandb'") + log.Info(gotext.Get("don't forget to run 'sudo mandb'")) }, } @@ -105,7 +143,7 @@ func Run(version, commit string) { "debug", "d", false, - "show debug messages", + gotext.Get("show debug messages"), ) rootCmd.PersistentFlags().BoolVarP( @@ -113,7 +151,7 @@ func Run(version, commit string) { "no-input", "n", false, - "toggle non-interactive mode", + gotext.Get("toggle non-interactive mode"), ) rootCmd.PersistentFlags().BoolVarP( @@ -121,7 +159,7 @@ func Run(version, commit string) { "offline", "o", false, - "prefer offline & filesystem access", + gotext.Get("prefer offline & filesystem access"), ) rootCmd.PersistentFlags().BoolVarP( @@ -129,7 +167,16 @@ func Run(version, commit string) { "ignore-env-version", "i", false, - "ignore .env version checkout", + gotext.Get("ignore .env version checkout"), + ) + + rootCmd.PersistentFlags().StringVarP( + &internal.Locale, + "lang", + "l", + "", + // FIXME(d1): provide supported list of language via *.po file listing + gotext.Get("force select language (supported: XXX)"), ) catalogue.CatalogueCommand.AddCommand( diff --git a/cli/server/add.go b/cli/server/add.go index 12ca137f..6f5a0b4a 100644 --- a/cli/server/add.go +++ b/cli/server/add.go @@ -13,14 +13,15 @@ import ( "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/server" sshPkg "coopcloud.tech/abra/pkg/ssh" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var ServerAddCommand = &cobra.Command{ - Use: "add [[server] | --local] [flags]", + Use: gotext.Get("add [[server] | --local] [flags]"), Aliases: []string{"a"}, - Short: "Add a new server", - Long: `Add a new server to your configuration so that it can be managed by Abra. + Short: gotext.Get("Add a new server"), + Long: gotext.Get(`Add a new server to your configuration so that it can be managed by Abra. Abra relies on the standard SSH command-line and ~/.ssh/config for client connection details. You must configure an entry per-host in your ~/.ssh/config @@ -35,8 +36,8 @@ for each server: If "--local" is passed, then Abra assumes that the current local server is intended as the target server. This is useful when you want to have your entire Co-op Cloud config located on the server itself, and not on your local -developer machine. The domain is then set to "default".`, - Example: " abra server add 1312.net", +developer machine. The domain is then set to "default".`), + Example: gotext.Get(" abra server add 1312.net"), Args: cobra.RangeArgs(0, 1), ValidArgsFunction: func( cmd *cobra.Command, @@ -49,11 +50,11 @@ developer machine. The domain is then set to "default".`, }, Run: func(cmd *cobra.Command, args []string) { if len(args) > 0 && local { - log.Fatal("cannot use [server] and --local together") + log.Fatal(gotext.Get("cannot use [server] and --local together")) } if len(args) == 0 && !local { - log.Fatal("missing argument or --local/-l flag") + log.Fatal(gotext.Get("missing argument or --local/-l flag")) } name := "default" @@ -72,7 +73,7 @@ developer machine. The domain is then set to "default".`, log.Fatal(err) } - log.Debugf("attempting to create client for %s", name) + log.Debug(gotext.Get("attempting to create client for %s", name)) if _, err := client.New(name, timeout); err != nil { cleanUp(name) @@ -80,9 +81,9 @@ developer machine. The domain is then set to "default".`, } if created { - log.Info("local server successfully added") + log.Info(gotext.Get("local server successfully added")) } else { - log.Warn("local server already exists") + log.Warn(gotext.Get("local server already exists")) } return @@ -96,27 +97,27 @@ developer machine. The domain is then set to "default".`, created, err := newContext(name) if err != nil { cleanUp(name) - log.Fatalf("unable to create local context: %s", err) + log.Fatal(gotext.Get("unable to create local context: %s", err)) } - log.Debugf("attempting to create client for %s", name) + log.Debug(gotext.Get("attempting to create client for %s", name)) if _, err := client.New(name, timeout); err != nil { cleanUp(name) - log.Fatalf("ssh %s error: %s", name, sshPkg.Fatal(name, err)) + log.Fatal(gotext.Get("ssh %s error: %s", name, sshPkg.Fatal(name, err))) } if created { - log.Infof("%s successfully added", name) + log.Info(gotext.Get("%s successfully added", name)) if _, err := dns.EnsureIPv4(name); err != nil { - log.Warnf("unable to resolve IPv4 for %s", name) + log.Warn(gotext.Get("unable to resolve IPv4 for %s", name)) } return } - log.Warnf("%s already exists", name) + log.Warn(gotext.Get("%s already exists", name)) }, } @@ -124,7 +125,7 @@ developer machine. The domain is then set to "default".`, // "server add" attempt. func cleanUp(name string) { if name != "default" { - log.Debugf("serverAdd: cleanUp: cleaning up context for %s", name) + log.Debug(gotext.Get("serverAdd: cleanUp: cleaning up context for %s", name)) if err := client.DeleteContext(name); err != nil { log.Fatal(err) } @@ -133,16 +134,16 @@ func cleanUp(name string) { serverDir := filepath.Join(config.SERVERS_DIR, name) files, err := config.GetAllFilesInDirectory(serverDir) if err != nil { - log.Fatalf("serverAdd: cleanUp: unable to list files in %s: %s", serverDir, err) + log.Fatal(gotext.Get("serverAdd: cleanUp: unable to list files in %s: %s", serverDir, err)) } if len(files) > 0 { - log.Debugf("serverAdd: cleanUp: %s is not empty, aborting cleanup", serverDir) + log.Debug(gotext.Get("serverAdd: cleanUp: %s is not empty, aborting cleanup", serverDir)) return } if err := os.RemoveAll(serverDir); err != nil { - log.Fatalf("serverAdd: cleanUp: failed to remove %s: %s", serverDir, err) + log.Fatal(gotext.Get("serverAdd: cleanUp: failed to remove %s: %s", serverDir, err)) } } @@ -159,12 +160,12 @@ func newContext(name string) (bool, error) { for _, context := range contexts { if context.Name == name { - log.Debugf("context for %s already exists", name) + log.Debug(gotext.Get("context for %s already exists", name)) return false, nil } } - log.Debugf("creating context with domain %s", name) + log.Debugf(gotext.Get("creating context with domain %s", name)) if err := client.CreateContext(name); err != nil { return false, nil @@ -180,7 +181,7 @@ func createServerDir(name string) (bool, error) { return false, err } - log.Debugf("server dir for %s already created", name) + log.Debug(gotext.Get("server dir for %s already created", name)) return false, nil } @@ -198,6 +199,6 @@ func init() { "local", "l", false, - "use local server", + gotext.Get("use local server"), ) } diff --git a/cli/server/list.go b/cli/server/list.go index dd3fd211..7584efcb 100644 --- a/cli/server/list.go +++ b/cli/server/list.go @@ -10,13 +10,14 @@ import ( "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/log" "github.com/docker/cli/cli/connhelper/ssh" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var ServerListCommand = &cobra.Command{ - Use: "list [flags]", + Use: gotext.Get("list [flags]"), Aliases: []string{"ls"}, - Short: "List managed servers", + Short: gotext.Get("List managed servers"), Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { dockerContextStore := contextPkg.NewDefaultDockerContextStore() @@ -78,7 +79,7 @@ var ServerListCommand = &cobra.Command{ if internal.MachineReadable { out, err := formatter.ToJSON(headers, rows) if err != nil { - log.Fatal("unable to render to JSON: %s", err) + log.Fatal(gotext.Get("unable to render to JSON: %s", err)) } fmt.Println(out) @@ -98,6 +99,6 @@ func init() { "machine", "m", false, - "print machine-readable output", + gotext.Get("print machine-readable output"), ) } diff --git a/cli/server/prune.go b/cli/server/prune.go index 7a4e5c25..09b78c41 100644 --- a/cli/server/prune.go +++ b/cli/server/prune.go @@ -7,17 +7,18 @@ import ( "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/log" "github.com/docker/docker/api/types/filters" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var ServerPruneCommand = &cobra.Command{ - Use: "prune [flags]", + Use: gotext.Get("prune [flags]"), Aliases: []string{"p"}, - Short: "Prune resources on a server", - Long: `Prunes unused containers, networks, and dangling images. + Short: gotext.Get("Prune resources on a server"), + Long: gotext.Get(`Prunes unused containers, networks, and dangling images. Use "--volumes/-v" to remove volumes that are not associated with a deployed -app. This can result in unwanted data loss if not used carefully.`, +app. This can result in unwanted data loss if not used carefully.`), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -41,18 +42,18 @@ app. This can result in unwanted data loss if not used carefully.`, } cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed) - log.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed) + log.Info(gotext.Get("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)) nr, err := cl.NetworksPrune(cmd.Context(), filterArgs) if err != nil { log.Fatal(err) } - log.Infof("networks pruned: %d", len(nr.NetworksDeleted)) + log.Info(gotext.Get("networks pruned: %d", len(nr.NetworksDeleted))) pruneFilters := filters.NewArgs() if allFilter { - log.Debugf("removing all images, not only dangling ones") + log.Debug(gotext.Get("removing all images, not only dangling ones")) pruneFilters.Add("dangling", "false") } @@ -62,7 +63,7 @@ app. This can result in unwanted data loss if not used carefully.`, } imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed) - log.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed) + log.Info(gotext.Get("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)) if volumesFilter { vr, err := cl.VolumesPrune(cmd.Context(), filterArgs) @@ -71,7 +72,7 @@ app. This can result in unwanted data loss if not used carefully.`, } volSpaceReclaimed := formatter.ByteCountSI(vr.SpaceReclaimed) - log.Infof("volumes pruned: %d; space reclaimed: %s", len(vr.VolumesDeleted), volSpaceReclaimed) + log.Info(gotext.Get("volumes pruned: %d; space reclaimed: %s", len(vr.VolumesDeleted), volSpaceReclaimed)) } return @@ -89,7 +90,7 @@ func init() { "all", "a", false, - "remove all unused images", + gotext.Get("remove all unused images"), ) ServerPruneCommand.Flags().BoolVarP( @@ -97,6 +98,6 @@ func init() { "volumes", "v", false, - "remove volumes", + gotext.Get("remove volumes"), ) } diff --git a/cli/server/remove.go b/cli/server/remove.go index 4e79643f..6550c8f8 100644 --- a/cli/server/remove.go +++ b/cli/server/remove.go @@ -9,18 +9,19 @@ import ( "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) var ServerRemoveCommand = &cobra.Command{ - Use: "remove [flags]", + Use: gotext.Get("remove [flags]"), Aliases: []string{"rm"}, - Short: "Remove a managed server", - Long: `Remove a managed server. + Short: gotext.Get("Remove a managed server"), + Long: gotext.Get(`Remove a managed server. Abra will remove the internal bookkeeping ($ABRA_DIR/servers/...) and underlying client connection context. This server will then be lost in time, -like tears in rain.`, +like tears in rain.`), Args: cobra.ExactArgs(1), ValidArgsFunction: func( cmd *cobra.Command, @@ -39,7 +40,7 @@ like tears in rain.`, log.Fatal(err) } - log.Infof("%s is now lost in time, like tears in rain", serverName) + log.Info(gotext.Get("%s is now lost in time, like tears in rain", serverName)) return }, diff --git a/cli/server/server.go b/cli/server/server.go index a9876aba..9fbe674c 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -1,10 +1,13 @@ package server -import "github.com/spf13/cobra" +import ( + "github.com/leonelquinteros/gotext" + "github.com/spf13/cobra" +) // ServerCommand defines the `abra server` command and its subcommands var ServerCommand = &cobra.Command{ - Use: "server [cmd] [args] [flags]", + Use: gotext.Get("server [cmd] [args] [flags]"), Aliases: []string{"s"}, - Short: "Manage servers", + Short: gotext.Get("Manage servers"), } diff --git a/cli/updater/updater.go b/cli/updater/updater.go index e0979107..de0fc652 100644 --- a/cli/updater/updater.go +++ b/cli/updater/updater.go @@ -2,6 +2,7 @@ package updater import ( "context" + "errors" "fmt" "os" "strconv" @@ -21,6 +22,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" dockerclient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" "coopcloud.tech/abra/pkg/log" @@ -30,14 +32,14 @@ const SERVER = "localhost" // NotifyCommand checks for available upgrades. var NotifyCommand = &cobra.Command{ - Use: "notify [flags]", + Use: gotext.Get("notify [flags]"), Aliases: []string{"n"}, - Short: "Check for available upgrades", - Long: `Notify on new versions for deployed apps. + Short: gotext.Get("Check for available upgrades"), + Long: gotext.Get(`Notify on new versions for deployed apps. If a new patch/minor version is available, a notification is printed. -Use "--major/-m" to include new major versions.`, +Use "--major/-m" to include new major versions.`), Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { cl, err := client.New("default") @@ -69,10 +71,10 @@ Use "--major/-m" to include new major versions.`, // UpgradeCommand upgrades apps. var UpgradeCommand = &cobra.Command{ - Use: "upgrade [[stack] [recipe] | --all] [flags]", + Use: gotext.Get("upgrade [[stack] [recipe] | --all] [flags]"), Aliases: []string{"u"}, - Short: "Upgrade apps", - Long: `Upgrade an app by specifying stack name and recipe. + Short: gotext.Get("Upgrade apps"), + Long: gotext.Get(`Upgrade an app by specifying stack name and recipe. Use "--all" to upgrade every deployed app. @@ -83,7 +85,7 @@ available, the app is upgraded. To include major versions use the "--major/-m" flag. You probably don't want that as it will break things. Only apps that are not deployed with "--chaos/-C" are upgraded, to update chaos deployments use the "--chaos/-C" flag. Use it -with care.`, +with care.`), Args: cobra.RangeArgs(0, 2), // TODO(d1): complete stack/recipe // ValidArgsFunction: func( @@ -98,7 +100,7 @@ with care.`, } if !updateAll && len(args) != 2 { - log.Fatal("missing arguments or --all/-a flag") + log.Fatal(gotext.Get("missing arguments or --all/-a flag")) } if !updateAll { @@ -150,7 +152,7 @@ func getLabel(cl *dockerclient.Client, stackName string, label string) (string, } } - log.Debugf("no %s label found for %s", label, stackName) + log.Debug(gotext.Get("no %s label found for %s", label, stackName)) return "", nil } @@ -171,7 +173,7 @@ func getBoolLabel(cl *dockerclient.Client, stackName string, label string) (bool return value, nil } - log.Debugf("boolean label %s could not be found for %s, set default to false.", label, stackName) + log.Debug(gotext.Get("boolean label %s could not be found for %s, set default to false.", label, stackName)) return false, nil } @@ -192,12 +194,12 @@ func getEnv(cl *dockerclient.Client, stackName string) (envfile.AppEnv, error) { for _, envString := range envList { splitString := strings.SplitN(envString, "=", 2) if len(splitString) != 2 { - log.Debugf("can't separate key from value: %s (this variable is probably unset)", envString) + log.Debug(gotext.Get("can't separate key from value: %s (this variable is probably unset)", envString)) continue } k := splitString[0] v := splitString[1] - log.Debugf("for %s read env %s with value: %s from docker service", stackName, k, v) + log.Debugf(gotext.Get("for %s read env %s with value: %s from docker service", stackName, k, v)) envMap[k] = v } } @@ -219,14 +221,14 @@ func getLatestUpgrade(cl *dockerclient.Client, stackName string, recipeName stri } if len(availableUpgrades) == 0 { - log.Debugf("no available upgrades for %s", stackName) + log.Debugf(gotext.Get("no available upgrades for %s", stackName)) return "", nil } var chosenUpgrade string if len(availableUpgrades) > 0 { chosenUpgrade = availableUpgrades[len(availableUpgrades)-1] - log.Infof("%s (%s) can be upgraded from version %s to %s", stackName, recipeName, deployedVersion, chosenUpgrade) + log.Info(gotext.Get("%s (%s) can be upgraded from version %s to %s", stackName, recipeName, deployedVersion, chosenUpgrade)) } return chosenUpgrade, nil @@ -234,7 +236,7 @@ func getLatestUpgrade(cl *dockerclient.Client, stackName string, recipeName stri // getDeployedVersion returns the currently deployed version of an app. func getDeployedVersion(cl *dockerclient.Client, stackName string, recipeName string) (string, error) { - log.Debugf("retrieve deployed version whether %s is already deployed", stackName) + log.Debug(gotext.Get("retrieve deployed version whether %s is already deployed", stackName)) deployMeta, err := stack.IsDeployed(context.Background(), cl, stackName) if err != nil { @@ -242,11 +244,11 @@ func getDeployedVersion(cl *dockerclient.Client, stackName string, recipeName st } if !deployMeta.IsDeployed { - return "", fmt.Errorf("%s is not deployed?", stackName) + return "", errors.New(gotext.Get("%s is not deployed?", stackName)) } if deployMeta.Version == "unknown" { - return "", fmt.Errorf("failed to determine deployed version of %s", stackName) + return "", errors.New(gotext.Get("failed to determine deployed version of %s", stackName)) } return deployMeta.Version, nil @@ -268,7 +270,7 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName } if len(versions) == 0 { - log.Warnf("no published releases for %s in the recipe catalogue?", recipeName) + log.Warn(gotext.Get("no published releases for %s in the recipe catalogue?", recipeName)) return nil, nil } @@ -294,7 +296,7 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName } } - log.Debugf("available updates for %s: %s", stackName, availableUpgrades) + log.Debug(gotext.Get("available updates for %s: %s", stackName, availableUpgrades)) return availableUpgrades, nil } diff --git a/cli/upgrade.go b/cli/upgrade.go index aafa1310..0b3fc516 100644 --- a/cli/upgrade.go +++ b/cli/upgrade.go @@ -7,22 +7,23 @@ import ( "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) // UpgradeCommand upgrades abra in-place. var UpgradeCommand = &cobra.Command{ - Use: "upgrade [flags]", + Use: gotext.Get("upgrade [flags]"), Aliases: []string{"u"}, - Short: "Upgrade abra", - Long: `Upgrade abra in-place with the latest stable or release candidate. + Short: gotext.Get("Upgrade abra"), + Long: gotext.Get(`Upgrade abra in-place with the latest stable or release candidate. By default, the latest stable release is downloaded. Use "--rc/-r" to install the latest release candidate. Please bear in mind that it may contain absolutely catastrophic deal-breaker bugs. Thank you very much -for the testing efforts 💗`, - Example: " abra upgrade --rc", +for the testing efforts 💗`), + Example: gotext.Get(" abra upgrade --rc"), Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { mainURL := "https://install.abra.coopcloud.tech" @@ -33,7 +34,7 @@ for the testing efforts 💗`, c = exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash -s -- --rc", releaseCandidateURL)) } - log.Debugf("attempting to run %s", c) + log.Debugf(gotext.Get("attempting to run %s", c)) if err := internal.RunCmd(c); err != nil { log.Fatal(err) @@ -51,6 +52,6 @@ func init() { "rc", "r", false, - "install release candidate (may contain bugs)", + gotext.Get("install release candidate (may contain bugs)"), ) } diff --git a/go.mod b/go.mod index be78dc17..8af1e328 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( require ( dario.cat/mergo v1.0.2 // indirect - github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -52,14 +51,12 @@ require ( github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect @@ -85,11 +82,9 @@ require ( github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.1.0 // indirect github.com/moby/sys/atomicwriter v0.1.0 // indirect - github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/morikuni/aec v1.0.0 // indirect @@ -100,7 +95,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/runc v1.1.13 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect github.com/pjbgf/sha1cd v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect diff --git a/go.sum b/go.sum index ed1015b9..ceab1712 100644 --- a/go.sum +++ b/go.sum @@ -22,21 +22,13 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb h1:Ws6WEwKXeaYEkfdkX6AqX1XLPuaCeyStEtxbmEJPllk= -coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ= -coopcloud.tech/tagcmp v0.0.0-20250427094623-9ea3bbbde8e5 h1:tphJCjFJw9fdjyKnbU0f7f3z5KtYE8VbUcAfu+oHKg8= -coopcloud.tech/tagcmp v0.0.0-20250427094623-9ea3bbbde8e5/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ= coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca h1:gSD53tBAsbIGq4SnFfq+mEep6foekQ2a5ea7b38qkm0= coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c h1:oeKnUB79PKYD8D0/unYuu7MRcWryQQWOns8+JL+acrs= git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c/go.mod h1:fQuhwrpg6qb9NlFXKYi/LysWu1wxjraS8sxyW12CUF0= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= @@ -57,8 +49,6 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -89,8 +79,6 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= -github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -98,7 +86,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -133,11 +120,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc= github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -145,29 +129,18 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI= -github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU= github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= -github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI= github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/log v0.4.1 h1:6AYnoHKADkghm/vt4neaNEXkxcXLSV2g1rdyFDOpTyk= -github.com/charmbracelet/log v0.4.1/go.mod h1:pXgyTsqsVu4N9hGdHmQ0xEA4RsXof402LX9ZgiITn2I= github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig= github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw= -github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= -github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= @@ -191,10 +164,7 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= -github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= -github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -316,7 +286,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -347,8 +316,6 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs= -github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v28.3.3+incompatible h1:fp9ZHAr1WWPGdIWBM1b3zLtgCF+83gRdVMTJsUeiyAo= github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= @@ -357,8 +324,6 @@ github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0= -github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= @@ -367,8 +332,6 @@ github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= @@ -413,8 +376,6 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= @@ -430,8 +391,6 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= -github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM= github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -447,8 +406,6 @@ github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -464,11 +421,8 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= @@ -522,7 +476,6 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI= github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -575,13 +528,9 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -592,13 +541,10 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= @@ -615,9 +561,7 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= -github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc= github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -670,7 +614,6 @@ github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -710,8 +653,6 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= @@ -725,8 +666,6 @@ github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtl github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= @@ -734,8 +673,6 @@ github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiT github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= -github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= -github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= @@ -817,15 +754,10 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pjbgf/sha1cd v0.4.0 h1:NXzbL1RvjTUi6kgYZCX3fPwwl27Q1LJndxtUDVfJGRY= github.com/pjbgf/sha1cd v0.4.0/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -843,8 +775,6 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -852,8 +782,6 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -862,8 +790,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= -github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -877,8 +803,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -890,7 +814,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -901,8 +824,6 @@ github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8G github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -923,10 +844,8 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -935,7 +854,6 @@ github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -943,12 +861,10 @@ github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bd github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1023,47 +939,27 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1090,8 +986,6 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1104,10 +998,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= -golang.org/x/exp v0.0.0-20250811191247-51f88131bc50 h1:3yiSh9fhy5/RhCSntf4Sy0Tnx50DmMpQ4MQdKKk4yg4= -golang.org/x/exp v0.0.0-20250811191247-51f88131bc50/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg= golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1173,8 +1063,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1194,8 +1082,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1275,17 +1161,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1297,8 +1178,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1307,8 +1186,6 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1404,12 +1281,8 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4 h1:IFnXJq3UPB3oBREOodn1v1aGQeZYQclEmvWRMN0PSsY= -google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:c8q6Z6OCqnfVIqUFJkCzKcrj8eCvUrz+K4KRzSTuANg= google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a h1:DMCgtIAIQGZqJXMVzJF4MV8BlWoJh2ZuFiRdAleyr58= google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a/go.mod h1:y2yVLIE/CSMCPXaHnSKXxu1spLPnglFLegmgdY23uuE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a h1:tPE/Kp+x9dMSwUm/uM0JKK0IfdiJkwAbSMSeZBXXJXc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1431,8 +1304,6 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1448,13 +1319,10 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII= gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1470,7 +1338,6 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM= gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -1491,7 +1358,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/locales/default.pot b/locales/default.pot deleted file mode 100644 index 39987c8b..00000000 --- a/locales/default.pot +++ /dev/null @@ -1,12 +0,0 @@ -msgid "" -msgstr "" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: \n" -"X-Generator: xgotext\n" - -#: app.go:11 -msgid "Manage apps" -msgstr "" \ No newline at end of file diff --git a/pkg/autocomplete/autocomplete.go b/pkg/autocomplete/autocomplete.go index aafea741..d51b2d7e 100644 --- a/pkg/autocomplete/autocomplete.go +++ b/pkg/autocomplete/autocomplete.go @@ -1,12 +1,12 @@ package autocomplete import ( - "fmt" "sort" "coopcloud.tech/abra/pkg/app" appPkg "coopcloud.tech/abra/pkg/app" "coopcloud.tech/abra/pkg/recipe" + "github.com/leonelquinteros/gotext" "github.com/spf13/cobra" ) @@ -14,7 +14,7 @@ import ( func AppNameComplete() ([]string, cobra.ShellCompDirective) { appFiles, err := app.LoadAppFiles("") if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -29,7 +29,7 @@ func AppNameComplete() ([]string, cobra.ShellCompDirective) { func ServiceNameComplete(appName string) ([]string, cobra.ShellCompDirective) { serviceNames, err := app.GetAppServiceNames(appName) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -40,7 +40,7 @@ func ServiceNameComplete(appName string) ([]string, cobra.ShellCompDirective) { func RecipeNameComplete() ([]string, cobra.ShellCompDirective) { catl, err := recipe.ReadRecipeCatalogue(false) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -56,7 +56,7 @@ func RecipeNameComplete() ([]string, cobra.ShellCompDirective) { func RecipeVersionComplete(recipeName string) ([]string, cobra.ShellCompDirective) { catl, err := recipe.ReadRecipeCatalogue(true) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -74,7 +74,7 @@ func RecipeVersionComplete(recipeName string) ([]string, cobra.ShellCompDirectiv func ServerNameComplete() ([]string, cobra.ShellCompDirective) { files, err := app.LoadAppFiles("") if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -90,13 +90,13 @@ func ServerNameComplete() ([]string, cobra.ShellCompDirective) { func CommandNameComplete(appName string) ([]string, cobra.ShellCompDirective) { app, err := app.Get(appName) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } cmdNames, err := appPkg.ReadAbraShCmdNames(app.Recipe.AbraShPath) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } @@ -111,7 +111,7 @@ func SecretComplete(recipeName string) ([]string, cobra.ShellCompDirective) { config, err := r.GetComposeConfig(nil) if err != nil { - err := fmt.Sprintf("autocomplete failed: %s", err) + err := gotext.Get("autocomplete failed: %s", err) return []string{err}, cobra.ShellCompDirectiveError } diff --git a/pkg/catalogue/catalogue.go b/pkg/catalogue/catalogue.go index 76859616..56270595 100644 --- a/pkg/catalogue/catalogue.go +++ b/pkg/catalogue/catalogue.go @@ -1,6 +1,7 @@ package catalogue import ( + "errors" "fmt" "os" "path" @@ -10,13 +11,14 @@ import ( gitPkg "coopcloud.tech/abra/pkg/git" "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" + "github.com/leonelquinteros/gotext" ) // EnsureCatalogue ensures that the catalogue is cloned locally & present. func EnsureCatalogue() error { catalogueDir := path.Join(config.ABRA_DIR, "catalogue") if _, err := os.Stat(catalogueDir); err != nil && os.IsNotExist(err) { - log.Debugf("catalogue is missing, retrieving now") + log.Debug(gotext.Get("catalogue is missing, retrieving now")) url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME) if err := gitPkg.Clone(catalogueDir, url); err != nil { @@ -35,8 +37,7 @@ func EnsureIsClean() error { } if !isClean { - msg := "%s has locally unstaged changes? please commit/remove your changes before proceeding" - return fmt.Errorf(msg, config.CATALOGUE_DIR) + return errors.New(gotext.Get("%s has locally unstaged changes? please commit/remove your changes before proceeding", config.CATALOGUE_DIR)) } return nil @@ -55,8 +56,7 @@ func EnsureUpToDate() error { } if len(remotes) == 0 { - msg := "cannot ensure %s is up-to-date, no git remotes configured" - log.Debugf(msg, config.CATALOGUE_DIR) + log.Debug(gotext.Get("cannot ensure %s is up-to-date, no git remotes configured", config.CATALOGUE_DIR)) return nil } @@ -81,7 +81,7 @@ func EnsureUpToDate() error { } } - log.Debugf("fetched latest git changes for %s", config.CATALOGUE_DIR) + log.Debug(gotext.Get("fetched latest git changes for %s", config.CATALOGUE_DIR)) return nil } diff --git a/pkg/client/client.go b/pkg/client/client.go index 315a2732..5b5ac112 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -4,7 +4,6 @@ package client import ( "context" "errors" - "fmt" "net/http" "os" "time" @@ -14,6 +13,7 @@ import ( sshPkg "coopcloud.tech/abra/pkg/ssh" commandconnPkg "coopcloud.tech/abra/pkg/upstream/commandconn" "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) // Conf is a Docker client configuration. @@ -41,7 +41,7 @@ func New(serverName string, opts ...Opt) (*client.Client, error) { if serverName != "default" { context, err := GetContext(serverName) if err != nil { - return nil, fmt.Errorf("unknown server, run \"abra server add %s\"?", serverName) + return nil, errors.New(gotext.Get("unknown server, run \"abra server add %s\"?", serverName)) } ctxEndpoint, err := contextPkg.GetContextEndpoint(context) @@ -85,7 +85,7 @@ func New(serverName string, opts ...Opt) (*client.Client, error) { return nil, err } - log.Debugf("created client for %s", serverName) + log.Debug(gotext.Get("created client for %s", serverName)) info, err := cl.Info(context.Background()) if err != nil { @@ -94,10 +94,10 @@ func New(serverName string, opts ...Opt) (*client.Client, error) { if info.Swarm.LocalNodeState == "inactive" { if serverName != "default" { - return cl, fmt.Errorf("swarm mode not enabled on %s?", serverName) + return cl, errors.New(gotext.Get("swarm mode not enabled on %s?", serverName)) } - return cl, errors.New("swarm mode not enabled on local server?") + return cl, errors.New(gotext.Get("swarm mode not enabled on local server?")) } return cl, nil diff --git a/pkg/client/configs.go b/pkg/client/configs.go index efe14ab4..26c8c392 100644 --- a/pkg/client/configs.go +++ b/pkg/client/configs.go @@ -2,11 +2,12 @@ package client import ( "context" - "fmt" + "errors" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) func GetConfigs(cl *client.Client, ctx context.Context, server string, fs filters.Args) ([]swarm.Config, error) { @@ -31,7 +32,7 @@ func GetConfigNames(configs []swarm.Config) []string { func RemoveConfigs(cl *client.Client, ctx context.Context, configNames []string, force bool) error { for _, confName := range configNames { if err := cl.ConfigRemove(context.Background(), confName); err != nil { - return fmt.Errorf("conf %s: %s", confName, err) + return errors.New(gotext.Get("conf %s: %s", confName, err)) } } return nil diff --git a/pkg/client/context.go b/pkg/client/context.go index 4408bda5..bcfd5aba 100644 --- a/pkg/client/context.go +++ b/pkg/client/context.go @@ -10,6 +10,7 @@ import ( dConfig "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/context/docker" contextStore "github.com/docker/cli/cli/context/store" + "github.com/leonelquinteros/gotext" ) type Context = contextStore.Metadata @@ -22,7 +23,7 @@ func CreateContext(contextName string) error { return err } - log.Debugf("created the %s context", contextName) + log.Debug(gotext.Get("created the %s context", contextName)) return nil } @@ -62,7 +63,7 @@ func createContext(name string, host string) error { func DeleteContext(name string) error { if name == "default" { - return errors.New("context 'default' cannot be removed") + return errors.New(gotext.Get("context 'default' cannot be removed")) } if _, err := GetContext(name); err != nil { diff --git a/pkg/client/registry.go b/pkg/client/registry.go index 36d0ea73..bb39c344 100644 --- a/pkg/client/registry.go +++ b/pkg/client/registry.go @@ -2,11 +2,13 @@ package client import ( "context" + "errors" "fmt" "github.com/containers/image/docker" "github.com/containers/image/types" "github.com/distribution/reference" + "github.com/leonelquinteros/gotext" ) // GetRegistryTags retrieves all tags of an image from a container registry. @@ -15,7 +17,7 @@ func GetRegistryTags(img reference.Named) ([]string, error) { ref, err := docker.ParseReference(fmt.Sprintf("//%s", img)) if err != nil { - return tags, fmt.Errorf("failed to parse image %s, saw: %s", img, err.Error()) + return tags, errors.New(gotext.Get("failed to parse image %s, saw: %s", img, err.Error())) } ctx := context.Background() diff --git a/pkg/client/volumes.go b/pkg/client/volumes.go index c7af7619..5f0734c2 100644 --- a/pkg/client/volumes.go +++ b/pkg/client/volumes.go @@ -2,6 +2,7 @@ package client import ( "context" + "errors" "fmt" "time" @@ -9,6 +10,7 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) func GetVolumes(cl *client.Client, ctx context.Context, server string, fs filters.Args) ([]*volume.Volume, error) { @@ -54,9 +56,9 @@ func retryFunc(retries int, fn func() error) error { } if i+1 < retries { sleep := time.Duration(i+1) * time.Duration(i+1) - log.Infof("%s: waiting %d seconds before next retry", err, sleep) + log.Infof(gotext.Get("%s: waiting %d seconds before next retry", err, sleep)) time.Sleep(sleep * time.Second) } } - return fmt.Errorf("%d retries failed", retries) + return errors.New(gotext.Get("%d retries failed", retries)) } diff --git a/pkg/config/abra.go b/pkg/config/abra.go index e0a5d452..e1ea09a2 100644 --- a/pkg/config/abra.go +++ b/pkg/config/abra.go @@ -6,6 +6,7 @@ import ( "path/filepath" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "gopkg.in/yaml.v3" ) @@ -16,13 +17,13 @@ func LoadAbraConfig() Abra { wd, _ := os.Getwd() configFile := findAbraConfig(wd) if configFile == "" { - log.Debugf("no config file found") + log.Debug(gotext.Get("no config file found")) return Abra{} } data, err := os.ReadFile(configFile) if err != nil { // Do nothing, when an error occurs - log.Debugf("error reading config file: %s", err) + log.Debug(gotext.Get("error reading config file: %s", err)) return Abra{} } @@ -30,10 +31,10 @@ func LoadAbraConfig() Abra { err = yaml.Unmarshal(data, &config) if err != nil { // Do nothing, when an error occurs - log.Debugf("error loading config file: %s", err) + log.Debug(gotext.Get("error loading config file: %s", err)) return Abra{} } - log.Debugf("config file loaded from: %s", configFile) + log.Debug(gotext.Get("config file loaded from: %s", configFile)) config.configPath = filepath.Dir(configFile) return config } @@ -73,26 +74,24 @@ type Abra struct { // 3. use $HOME/.abra when above two options failed func (a Abra) GetAbraDir() string { if dir, exists := os.LookupEnv("ABRA_DIR"); exists && dir != "" { - log.Debug("read abra dir from $ABRA_DIR") + log.Debug(gotext.Get("read abra dir from $ABRA_DIR")) return dir } if a.AbraDir != "" { - log.Debug("read abra dir from config file") + log.Debug(gotext.Get("read abra dir from config file")) if path.IsAbs(a.AbraDir) { return a.AbraDir } // Make the path absolute return path.Join(a.configPath, a.AbraDir) } - log.Debug("using default abra dir") + log.Debug(gotext.Get("using default abra dir")) return os.ExpandEnv("$HOME/.abra") } func (a Abra) GetServersDir() string { return path.Join(a.GetAbraDir(), "servers") } func (a Abra) GetRecipesDir() string { return path.Join(a.GetAbraDir(), "recipes") } func (a Abra) GetLogsDir() string { return path.Join(a.GetAbraDir(), "logs") } -func (a Abra) GetVendorDir() string { return path.Join(a.GetAbraDir(), "vendor") } -func (a Abra) GetBackupDir() string { return path.Join(a.GetAbraDir(), "backups") } func (a Abra) GetCatalogueDir() string { return path.Join(a.GetAbraDir(), "catalogue") } var config = LoadAbraConfig() @@ -102,8 +101,6 @@ var ( SERVERS_DIR = config.GetServersDir() RECIPES_DIR = config.GetRecipesDir() LOGS_DIR = config.GetLogsDir() - VENDOR_DIR = config.GetVendorDir() - BACKUP_DIR = config.GetBackupDir() CATALOGUE_DIR = config.GetCatalogueDir() RECIPES_JSON = path.Join(config.GetCatalogueDir(), "recipes.json") REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud" diff --git a/pkg/config/env.go b/pkg/config/env.go index c07a1e98..917e36c4 100644 --- a/pkg/config/env.go +++ b/pkg/config/env.go @@ -1,7 +1,7 @@ package config import ( - "fmt" + "errors" "io/fs" "io/ioutil" "os" @@ -10,6 +10,7 @@ import ( "strings" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" ) const MAX_SANITISED_APP_NAME_LENGTH = 45 @@ -33,7 +34,7 @@ func GetServers() ([]string, error) { } } - log.Debugf("retrieved %v servers: %s", len(filtered), filtered) + log.Debug(gotext.Get("retrieved %v servers: %s", len(filtered), filtered)) return filtered, nil } @@ -46,7 +47,7 @@ func ReadServerNames() ([]string, error) { return nil, err } - log.Debugf("read %s from %s", strings.Join(serverNames, ","), SERVERS_DIR) + log.Debug(gotext.Get("read %s from %s", strings.Join(serverNames, ","), SERVERS_DIR)) return serverNames, nil } @@ -70,7 +71,7 @@ func GetAllFilesInDirectory(directory string) ([]fs.FileInfo, error) { realPath, err := filepath.EvalSymlinks(filePath) if err != nil { - log.Warnf("broken symlink in your abra config folders: %s", filePath) + log.Warnf(gotext.Get("broken symlink in your abra config folders: %s", filePath)) } else { realFile, err := os.Stat(realPath) if err != nil { @@ -94,7 +95,7 @@ func GetAllFoldersInDirectory(directory string) ([]string, error) { return nil, err } if len(files) == 0 { - return nil, fmt.Errorf("directory is empty: %s", directory) + return nil, errors.New(gotext.Get("directory is empty: %s", directory)) } for _, file := range files { @@ -103,7 +104,7 @@ func GetAllFoldersInDirectory(directory string) ([]string, error) { filePath := path.Join(directory, file.Name()) realDir, err := filepath.EvalSymlinks(filePath) if err != nil { - log.Warnf("broken symlink in your abra config folders: %s", filePath) + log.Warnf(gotext.Get("broken symlink in your abra config folders: %s", filePath)) } else if stat, err := os.Stat(realDir); err == nil && stat.IsDir() { // path is a directory folders = append(folders, file.Name()) diff --git a/pkg/container/container.go b/pkg/container/container.go index 16316218..039d6fca 100644 --- a/pkg/container/container.go +++ b/pkg/container/container.go @@ -2,6 +2,7 @@ package container import ( "context" + "errors" "fmt" "strings" @@ -12,6 +13,7 @@ import ( containerTypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) // GetContainer retrieves a container. If noInput is false and the retrievd @@ -26,7 +28,7 @@ func GetContainer(c context.Context, cl *client.Client, filters filters.Args, no if len(containers) == 0 { filter := filters.Get("name")[0] - return types.Container{}, fmt.Errorf("no containers matching the %v filter found?", filter) + return types.Container{}, errors.New(gotext.Get("no containers matching the %v filter found?", filter)) } if len(containers) > 1 { @@ -35,19 +37,19 @@ func GetContainer(c context.Context, cl *client.Client, filters filters.Args, no containerName := strings.Join(container.Names, " ") trimmed := strings.TrimPrefix(containerName, "/") created := formatter.HumanDuration(container.Created) - containersRaw = append(containersRaw, fmt.Sprintf("%s (created %v)", trimmed, created)) + containersRaw = append(containersRaw, gotext.Get("%s (created %v)", trimmed, created)) } if noInput { - err := fmt.Errorf("expected 1 container but found %v: %s", len(containers), strings.Join(containersRaw, " ")) + err := errors.New(gotext.Get("expected 1 container but found %v: %s", len(containers), strings.Join(containersRaw, " "))) return types.Container{}, err } - log.Warnf("ambiguous container list received, prompting for input") + log.Warnf(gotext.Get("ambiguous container list received, prompting for input")) var response string prompt := &survey.Select{ - Message: "which container are you looking for?", + Message: gotext.Get("which container are you looking for?"), Options: containersRaw, } @@ -64,7 +66,7 @@ func GetContainer(c context.Context, cl *client.Client, filters filters.Args, no } } - log.Fatal("failed to match chosen container") + log.Fatal(gotext.Get("failed to match chosen container")) } return containers[0], nil @@ -79,5 +81,6 @@ func GetContainerFromStackAndService(cl *client.Client, stack, service string) ( if err != nil { return types.Container{}, err } + return container, nil } diff --git a/pkg/context/context.go b/pkg/context/context.go index 9842f23c..971c5353 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -8,6 +8,7 @@ import ( "github.com/docker/cli/cli/context" contextStore "github.com/docker/cli/cli/context/store" cliflags "github.com/docker/cli/cli/flags" + "github.com/leonelquinteros/gotext" ) func NewDefaultDockerContextStore() *command.ContextStoreWithDefault { @@ -30,7 +31,7 @@ func NewDefaultDockerContextStore() *command.ContextStoreWithDefault { func GetContextEndpoint(ctx contextStore.Metadata) (string, error) { endpointmeta, ok := ctx.Endpoints["docker"].(context.EndpointMetaBase) if !ok { - err := errors.New("context lacks Docker endpoint") + err := errors.New(gotext.Get("context lacks Docker endpoint")) return "", err } return endpointmeta.Host, nil diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go index 40497d66..4f94bf95 100644 --- a/pkg/dns/dns.go +++ b/pkg/dns/dns.go @@ -1,19 +1,21 @@ package dns import ( - "fmt" + "errors" "net" + + "github.com/leonelquinteros/gotext" ) // EnsureIPv4 ensures that an ipv4 address is set for a domain name func EnsureIPv4(domainName string) (string, error) { ipv4, err := net.ResolveIPAddr("ip4", domainName) if err != nil { - return "", fmt.Errorf("%s: unable to resolve IPv4 address: %s", domainName, err) + return "", errors.New(gotext.Get("%s: unable to resolve IPv4 address: %s", domainName, err)) } if ipv4 == nil { - return "", fmt.Errorf("%s: no IPv4 available", domainName) + return "", errors.New(gotext.Get("%s: no IPv4 available", domainName)) } return ipv4.String(), nil @@ -33,7 +35,7 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) { } if domainIPv4 == "" { - return ipv4, fmt.Errorf("cannot resolve ipv4 for %s?", domainName) + return ipv4, errors.New(gotext.Get("cannot resolve ipv4 for %s?", domainName)) } serverIPv4, err := EnsureIPv4(server) @@ -42,12 +44,16 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) { } if serverIPv4 == "" { - return ipv4, fmt.Errorf("cannot resolve ipv4 for %s?", server) + return ipv4, errors.New(gotext.Get("cannot resolve ipv4 for %s?", server)) } if domainIPv4 != serverIPv4 { - err := "app domain %s (%s) does not appear to resolve to app server %s (%s)?" - return ipv4, fmt.Errorf(err, domainName, domainIPv4, server, serverIPv4) + return ipv4, errors.New( + gotext.Get( + "app domain %s (%s) does not appear to resolve to app server %s (%s)?", + domainName, domainIPv4, server, serverIPv4, + ), + ) } return ipv4, nil diff --git a/pkg/envfile/envfile.go b/pkg/envfile/envfile.go index 0e3bd80f..f48ac7e8 100644 --- a/pkg/envfile/envfile.go +++ b/pkg/envfile/envfile.go @@ -2,13 +2,14 @@ package envfile import ( "bufio" - "fmt" + "errors" "os" "regexp" "strings" "coopcloud.tech/abra/pkg/log" "git.coopcloud.tech/toolshed/godotenv" + "github.com/leonelquinteros/gotext" ) // AppEnv is a map of the values in an apps env config @@ -38,7 +39,7 @@ func ReadEnvWithModifiers(filePath string) (AppEnv, AppModifiers, error) { return nil, mods, err } - log.Debugf("read %s from %s", envVars, filePath) + log.Debug(gotext.Get("read %s from %s", envVars, filePath)) return envVars, mods, nil } @@ -69,16 +70,16 @@ func ReadAbraShEnvVars(abraSh string) (map[string]string, error) { envVarDef := splitVals[len(splitVals)-1] keyVal := strings.Split(envVarDef, "=") if len(keyVal) != 2 { - return envVars, fmt.Errorf("couldn't parse %s", txt) + return envVars, errors.New(gotext.Get("couldn't parse %s", txt)) } envVars[keyVal[0]] = keyVal[1] } } if len(envVars) > 0 { - log.Debugf("read %s from %s", envVars, abraSh) + log.Debug(gotext.Get("read %s from %s", envVars, abraSh)) } else { - log.Debugf("read 0 env var exports from %s", abraSh) + log.Debug(gotext.Get("read 0 env var exports from %s", abraSh)) } return envVars, nil diff --git a/pkg/formatter/formatter.go b/pkg/formatter/formatter.go index 3c4d1400..41cfeb94 100644 --- a/pkg/formatter/formatter.go +++ b/pkg/formatter/formatter.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" "github.com/docker/go-units" + "github.com/leonelquinteros/gotext" "golang.org/x/term" "coopcloud.tech/abra/pkg/config" @@ -42,7 +43,7 @@ func RemoveSha(str string) string { func HumanDuration(timestamp int64) string { date := time.Unix(timestamp, 0) now := time.Now().UTC() - return units.HumanDuration(now.Sub(date)) + " ago" + return units.HumanDuration(now.Sub(date)) + gotext.Get(" ago") } // CreateTable prepares a table layout for output. @@ -76,7 +77,7 @@ func CreateTable() (*table.Table, error) { func PrintTable(t *table.Table) error { if isAbraCI, ok := os.LookupEnv("ABRA_CI"); ok && isAbraCI == "1" { // NOTE(d1): no width limits for CI testing since we test against outputs - log.Debug("detected ABRA_CI=1") + log.Debug(gotext.Get("detected ABRA_CI=1")) fmt.Println(t) return nil } @@ -130,7 +131,7 @@ func CreateOverview(header string, rows [][]string) string { } if len(row) > 2 { - panic("CreateOverview: only accepts rows of len == 2") + panic(gotext.Get("CreateOverview: only accepts rows of len == 2")) } lenOffset := 4 @@ -234,7 +235,7 @@ func StripTagMeta(image string) string { } if originalImage != image { - log.Debugf("stripped %s to %s for parsing", originalImage, image) + log.Debug(gotext.Get("stripped %s to %s for parsing", originalImage, image)) } return image diff --git a/pkg/git/add.go b/pkg/git/add.go index d5bc3d14..7070d9fe 100644 --- a/pkg/git/add.go +++ b/pkg/git/add.go @@ -3,6 +3,7 @@ package git import ( "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" + "github.com/leonelquinteros/gotext" ) // Add adds a file to the git index. @@ -18,7 +19,7 @@ func Add(repoPath, path string, dryRun bool) error { } if dryRun { - log.Debugf("dry run: adding %s", path) + log.Debug(gotext.Get("dry run: adding %s", path)) } else { worktree.Add(path) } diff --git a/pkg/git/branch.go b/pkg/git/branch.go index 1125bd3a..c937316b 100644 --- a/pkg/git/branch.go +++ b/pkg/git/branch.go @@ -1,11 +1,13 @@ package git import ( + "errors" "fmt" "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "github.com/leonelquinteros/gotext" ) // Check if a branch exists in a repo. Use this and not repository.Branch(), @@ -63,7 +65,7 @@ func GetDefaultBranch(repo *git.Repository, repoPath string) (plumbing.Reference if !HasBranch(repo, "master") { if !HasBranch(repo, "main") { - return "", fmt.Errorf("failed to select default branch in %s", repoPath) + return "", errors.New(gotext.Get("failed to select default branch in %s", repoPath)) } branch = "main" } @@ -90,11 +92,11 @@ func CheckoutDefaultBranch(repo *git.Repository, repoPath string) (plumbing.Refe } if err := worktree.Checkout(checkOutOpts); err != nil { - log.Debugf("failed to check out %s in %s", branch, repoPath) + log.Debug(gotext.Get("failed to check out %s in %s", branch, repoPath)) return branch, err } - log.Debugf("successfully checked out %v in %s", branch, repoPath) + log.Debug(gotext.Get("successfully checked out %v in %s", branch, repoPath)) return branch, nil } diff --git a/pkg/git/clone.go b/pkg/git/clone.go index 87145f54..df56e26f 100644 --- a/pkg/git/clone.go +++ b/pkg/git/clone.go @@ -2,6 +2,7 @@ package git import ( "context" + "errors" "fmt" "os" "os/signal" @@ -10,6 +11,7 @@ import ( "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "github.com/leonelquinteros/gotext" ) // gitCloneIgnoreErr checks whether we can ignore a git clone error or not. @@ -44,7 +46,7 @@ func Clone(dir, url string) error { go func() { if _, err := os.Stat(dir); os.IsNotExist(err) { - log.Debugf("git clone: %s", url) + log.Debug(gotext.Get("git clone: %s", url)) _, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{ URL: url, @@ -54,16 +56,16 @@ func Clone(dir, url string) error { }) if err != nil && gitCloneIgnoreErr(err) { - log.Debugf("git clone: %s cloned successfully", dir) + log.Debug(gotext.Get("git clone: %s cloned successfully", dir)) errCh <- nil } if err := ctx.Err(); err != nil { - errCh <- fmt.Errorf("git clone %s: cancelled due to interrupt", dir) + errCh <- errors.New(gotext.Get("git clone %s: cancelled due to interrupt", dir)) } if err != nil { - log.Debug("git clone: main branch failed, attempting master branch") + log.Debug(gotext.Get("git clone: main branch failed, attempting master branch")) _, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{ URL: url, @@ -73,7 +75,7 @@ func Clone(dir, url string) error { }) if err != nil && gitCloneIgnoreErr(err) { - log.Debugf("git clone: %s cloned successfully", dir) + log.Debug(gotext.Get("git clone: %s cloned successfully", dir)) errCh <- nil } @@ -82,9 +84,9 @@ func Clone(dir, url string) error { } } - log.Debugf("git clone: %s cloned successfully", dir) + log.Debug(gotext.Get("git clone: %s cloned successfully", dir)) } else { - log.Debugf("git clone: %s already exists", dir) + log.Debug(gotext.Get("git clone: %s already exists", dir)) } errCh <- nil @@ -95,9 +97,9 @@ func Clone(dir, url string) error { cancelCtx() fmt.Println() // NOTE(d1): newline after ^C if err := os.RemoveAll(dir); err != nil { - return fmt.Errorf("unable to clean up git clone of %s: %s", dir, err) + return errors.New(gotext.Get("unable to clean up git clone of %s: %s", dir, err)) } - return fmt.Errorf("git clone %s: cancelled due to interrupt", dir) + return errors.New(gotext.Get("git clone %s: cancelled due to interrupt", dir)) case err := <-errCh: return err } diff --git a/pkg/git/commit.go b/pkg/git/commit.go index 7775e518..d8d32481 100644 --- a/pkg/git/commit.go +++ b/pkg/git/commit.go @@ -1,16 +1,17 @@ package git import ( - "fmt" + "errors" "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" + "github.com/leonelquinteros/gotext" ) // Commit runs a git commit func Commit(repoPath, commitMessage string, dryRun bool) error { if commitMessage == "" { - return fmt.Errorf("no commit message specified?") + return errors.New(gotext.Get("no commit message specified?")) } commitRepo, err := git.PlainOpen(repoPath) @@ -38,9 +39,9 @@ func Commit(repoPath, commitMessage string, dryRun bool) error { if err != nil { return err } - log.Debug("git changes commited") + log.Debug(gotext.Get("git changes commited")) } else { - log.Debug("dry run: no changes commited") + log.Debug(gotext.Get("dry run: no changes commited")) } return nil diff --git a/pkg/git/common.go b/pkg/git/common.go index ff4eb7d7..178373c8 100644 --- a/pkg/git/common.go +++ b/pkg/git/common.go @@ -1,14 +1,16 @@ package git import ( - "fmt" + "errors" "os" + + "github.com/leonelquinteros/gotext" ) // EnsureGitRepo ensures a git repo .git folder exists func EnsureGitRepo(repoPath string) error { if _, err := os.Stat(repoPath); os.IsNotExist(err) { - return fmt.Errorf("no .git directory in %s?", repoPath) + return errors.New(gotext.Get("no .git directory in %s?", repoPath)) } return nil } diff --git a/pkg/git/diff.go b/pkg/git/diff.go index 6242d654..89fcf72e 100644 --- a/pkg/git/diff.go +++ b/pkg/git/diff.go @@ -5,6 +5,7 @@ import ( "os/exec" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" ) // getGitDiffArgs builds the `git diff` invocation args. It removes the usage @@ -26,7 +27,7 @@ func getGitDiffArgs(repoPath string) []string { // skips if it cannot find the command on the system. func DiffUnstaged(path string) error { if _, err := exec.LookPath("git"); err != nil { - log.Warnf("unable to locate git command, cannot output diff") + log.Warnf(gotext.Get("unable to locate git command, cannot output diff")) return nil } diff --git a/pkg/git/init.go b/pkg/git/init.go index 5adf37b1..6a7b6cd9 100644 --- a/pkg/git/init.go +++ b/pkg/git/init.go @@ -1,40 +1,41 @@ package git import ( - "fmt" + "errors" "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" + "github.com/leonelquinteros/gotext" ) // Init inits a new repo and commits all the stuff if you want func Init(repoPath string, commit bool, gitName, gitEmail string) error { repo, err := git.PlainInit(repoPath, false) if err != nil { - return fmt.Errorf("git init: %s", err) + return errors.New(gotext.Get("git init: %s", err)) } if err = SwitchToMain(repo); err != nil { - return fmt.Errorf("git branch rename: %s", err) + return errors.New(gotext.Get("git branch rename: %s", err)) } - log.Debugf("initialised new git repo in %s", repoPath) + log.Debug(gotext.Get("initialised new git repo in %s", repoPath)) if commit { commitRepo, err := git.PlainOpen(repoPath) if err != nil { - return fmt.Errorf("git open: %s", err) + return errors.New(gotext.Get("git open: %s", err)) } commitWorktree, err := commitRepo.Worktree() if err != nil { - return fmt.Errorf("git worktree: %s", err) + return errors.New(gotext.Get("git worktree: %s", err)) } if err := commitWorktree.AddWithOptions(&git.AddOptions{All: true}); err != nil { - return fmt.Errorf("git add: %s", err) + return errors.New(gotext.Get("git add: %s", err)) } var author *object.Signature @@ -43,10 +44,10 @@ func Init(repoPath string, commit bool, gitName, gitEmail string) error { } if _, err = commitWorktree.Commit("init", &git.CommitOptions{Author: author}); err != nil { - return fmt.Errorf("git commit: %s", err) + return errors.New(gotext.Get("git commit: %s", err)) } - log.Debugf("init committed all files for new git repo in %s", repoPath) + log.Debug(gotext.Get("init committed all files for new git repo in %s", repoPath)) } return nil @@ -56,20 +57,20 @@ func Init(repoPath string, commit bool, gitName, gitEmail string) error { func SwitchToMain(repo *git.Repository) error { ref := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.ReferenceName("refs/heads/main")) if err := repo.Storer.SetReference(ref); err != nil { - return fmt.Errorf("set reference: %s", err) + return errors.New(gotext.Get("set reference: %s", err)) } cfg, err := repo.Config() if err != nil { - return fmt.Errorf("repo config: %s", err) + return errors.New(gotext.Get("repo config: %s", err)) } cfg.Init.DefaultBranch = "main" if err := repo.SetConfig(cfg); err != nil { - return fmt.Errorf("repo set config: %s", err) + return errors.New(gotext.Get("repo set config: %s", err)) } - log.Debug("set 'main' as the default branch") + log.Debug(gotext.Get("set 'main' as the default branch")) return nil } diff --git a/pkg/git/push.go b/pkg/git/push.go index 9d279e65..03899bfa 100644 --- a/pkg/git/push.go +++ b/pkg/git/push.go @@ -4,12 +4,13 @@ import ( "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" + "github.com/leonelquinteros/gotext" ) // Push pushes the latest changes & optionally tags to the default remote func Push(repoDir string, remote string, tags bool, dryRun bool) error { if dryRun { - log.Debugf("dry run: no git changes pushed in %s", repoDir) + log.Debug(gotext.Get("dry run: no git changes pushed in %s", repoDir)) return nil } @@ -27,7 +28,7 @@ func Push(repoDir string, remote string, tags bool, dryRun bool) error { return err } - log.Debugf("git changes pushed") + log.Debug(gotext.Get("git changes pushed")) if tags { opts.RefSpecs = append(opts.RefSpecs, config.RefSpec("+refs/tags/*:refs/tags/*")) @@ -36,7 +37,7 @@ func Push(repoDir string, remote string, tags bool, dryRun bool) error { return err } - log.Debugf("git tags pushed") + log.Debug(gotext.Get("git tags pushed")) } return nil diff --git a/pkg/git/read.go b/pkg/git/read.go index b2991357..0b6b6976 100644 --- a/pkg/git/read.go +++ b/pkg/git/read.go @@ -2,7 +2,6 @@ package git import ( "errors" - "fmt" "io/ioutil" "os" "os/user" @@ -13,6 +12,7 @@ import ( "github.com/go-git/go-git/v5" gitConfigPkg "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing/format/gitignore" + "github.com/leonelquinteros/gotext" ) // IsClean checks if a repo has unstaged changes @@ -23,12 +23,12 @@ func IsClean(repoPath string) (bool, error) { return false, git.ErrRepositoryNotExists } - return false, fmt.Errorf("unable to open %s: %s", repoPath, err) + return false, errors.New(gotext.Get("unable to open %s: %s", repoPath, err)) } worktree, err := repo.Worktree() if err != nil { - return false, fmt.Errorf("unable to open worktree of %s: %s", repoPath, err) + return false, errors.New(gotext.Get("unable to open worktree of %s: %s", repoPath, err)) } patterns, err := GetExcludesFiles() @@ -42,14 +42,14 @@ func IsClean(repoPath string) (bool, error) { status, err := worktree.Status() if err != nil { - return false, fmt.Errorf("unable to query status of %s: %s", repoPath, err) + return false, errors.New(gotext.Get("unable to query status of %s: %s", repoPath, err)) } if status.String() != "" { noNewline := strings.TrimSuffix(status.String(), "\n") - log.Debugf("git status: %s: %s", repoPath, noNewline) + log.Debug(gotext.Get("git status: %s: %s", repoPath, noNewline)) } else { - log.Debugf("git status: %s: clean", repoPath) + log.Debug(gotext.Get("git status: %s: clean", repoPath)) } return status.IsClean(), nil @@ -85,7 +85,7 @@ func parseGitConfig() (*gitConfigPkg.Config, error) { globalGitConfig := filepath.Join(usr.HomeDir, ".gitconfig") if _, err := os.Stat(globalGitConfig); err != nil { if os.IsNotExist(err) { - log.Debugf("no %s exists, not reading any global gitignore config", globalGitConfig) + log.Debug(gotext.Get("no %s exists, not reading any global gitignore config", globalGitConfig)) return cfg, nil } return cfg, err @@ -127,7 +127,7 @@ func parseExcludesFile(excludesfile string) ([]gitignore.Pattern, error) { if _, err := os.Stat(excludesfile); err != nil { if os.IsNotExist(err) { - log.Debugf("no %s exists, skipping reading gitignore paths", excludesfile) + log.Debug(gotext.Get("no %s exists, skipping reading gitignore paths", excludesfile)) return ps, nil } return ps, err @@ -146,7 +146,7 @@ func parseExcludesFile(excludesfile string) ([]gitignore.Pattern, error) { } } - log.Debugf("read global ignore paths: %s", strings.Join(pathsRaw, " ")) + log.Debug(gotext.Get("read global ignore paths: %s", strings.Join(pathsRaw, " "))) return ps, nil } diff --git a/pkg/git/remote.go b/pkg/git/remote.go index 5d7d7af4..ee8dde2b 100644 --- a/pkg/git/remote.go +++ b/pkg/git/remote.go @@ -6,12 +6,13 @@ import ( "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" + "github.com/leonelquinteros/gotext" ) // CreateRemote creates a new git remote in a repository func CreateRemote(repo *git.Repository, name, url string, dryRun bool) error { if dryRun { - log.Debugf("dry run: remote %s (%s) not created", name, url) + log.Debug(gotext.Get("dry run: remote %s (%s) not created", name, url)) return nil } diff --git a/pkg/lang/lang.go b/pkg/lang/lang.go index a8f456e8..4966bcc0 100644 --- a/pkg/lang/lang.go +++ b/pkg/lang/lang.go @@ -1,30 +1,31 @@ package lang import ( + "embed" + "fmt" "os" - "strings" + + "github.com/leonelquinteros/gotext" ) +//go:embed locales +var assetFS embed.FS + func GetLocale() string { - if loc := os.Getenv("LC_MESSAGES"); loc != "" { - return NormalizeLocale(loc) - } - - if loc := os.Getenv("LANG"); loc != "" { - return NormalizeLocale(loc) - } - - return "C.UTF-8" + return os.Getenv("LANG") } -func NormalizeLocale(loc string) string { - if idx := strings.Index(loc, "."); idx != -1 { - return loc[:idx] +func LoadLocale(locale string) error { + localePath := fmt.Sprintf("locales/%s/%s.po", locale) + + b, err := assetFS.ReadFile(localePath) + if err != nil { + return fmt.Errorf("unable to load %s: %s", localePath, err) } - if idx := strings.Index(loc, "@"); idx != -1 { - return loc[:idx] - } + po := gotext.NewPo() + po.Parse(b) + gotext.GetStorage().AddTranslator("abra", po) - return loc + return nil } diff --git a/pkg/lang/locales/abra.pot b/pkg/lang/locales/abra.pot new file mode 100644 index 00000000..07ee99fe --- /dev/null +++ b/pkg/lang/locales/abra.pot @@ -0,0 +1,48 @@ +msgid "" +msgstr "" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: \n" +"X-Generator: xgotext\n" + +#: volumes.go:63 +msgid "%d retries failed" +msgstr "" + +#: volumes.go:59 +msgid "%s: waiting %d seconds before next retry" +msgstr "" + +#: configs.go:35 +msgid "conf %s: %s" +msgstr "" + +#: context.go:66 +msgid "context 'default' cannot be removed" +msgstr "" + +#: client.go:88 +msgid "created client for %s" +msgstr "" + +#: context.go:26 +msgid "created the %s context" +msgstr "" + +#: registry.go:20 +msgid "failed to parse image %s, saw: %s" +msgstr "" + +#: client.go:97 +msgid "swarm mode not enabled on %s?" +msgstr "" + +#: client.go:100 +msgid "swarm mode not enabled on local server?" +msgstr "" + +#: client.go:44 +msgid "unknown server, run 'abra server add %s'?" +msgstr "" diff --git a/locales/es/LC_MESSAGES/default.po b/pkg/lang/locales/es/LC_MESSAGES/es.po similarity index 100% rename from locales/es/LC_MESSAGES/default.po rename to pkg/lang/locales/es/LC_MESSAGES/es.po diff --git a/pkg/lint/recipe.go b/pkg/lint/recipe.go index 1855b6e2..6af14eff 100644 --- a/pkg/lint/recipe.go +++ b/pkg/lint/recipe.go @@ -1,6 +1,7 @@ package lint import ( + "errors" "fmt" "net/http" "os" @@ -13,11 +14,12 @@ import ( "github.com/distribution/reference" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "github.com/leonelquinteros/gotext" ) var ( - Warn = "warn" - Critical = "critical" + Warn = gotext.Get("warn") + Critical = gotext.Get("critical") ) type LintFunction func(recipe.Recipe) (bool, error) @@ -47,10 +49,10 @@ func (l LintRule) Skip(recipe recipe.Recipe) bool { if l.SkipCondition != nil { ok, err := l.SkipCondition(recipe) if err != nil { - log.Debugf("%s: skip condition: %s", l.Ref, err) + log.Debug(gotext.Get("%s: skip condition: %s", l.Ref, err)) } if ok { - log.Debugf("skipping %s based on skip condition", l.Ref) + log.Debug(gotext.Get("skipping %s based on skip condition", l.Ref)) return true } } @@ -62,117 +64,117 @@ var LintRules = map[string][]LintRule{ "warn": { { Ref: "R001", - Level: "warn", - Description: "compose config has expected version", - HowToResolve: "ensure 'version: \"3.8\"' in compose configs", + Level: gotext.Get("warn"), + Description: gotext.Get("compose config has expected version"), + HowToResolve: gotext.Get("ensure 'version: \"3.8\"' in compose configs"), Function: LintComposeVersion, }, { Ref: "R002", - Level: "warn", - Description: "healthcheck enabled for all services", - HowToResolve: "wire up healthchecks", + Level: gotext.Get("warn"), + Description: gotext.Get("healthcheck enabled for all services"), + HowToResolve: gotext.Get("wire up healthchecks"), Function: LintHealthchecks, }, { Ref: "R003", - Level: "warn", - Description: "all images use a tag", - HowToResolve: "use a tag for all images", + Level: gotext.Get("warn"), + Description: gotext.Get("all images use a tag"), + HowToResolve: gotext.Get("use a tag for all images"), Function: LintAllImagesTagged, }, { Ref: "R004", - Level: "warn", - Description: "no unstable tags", - HowToResolve: "tag all images with stable tags", + Level: gotext.Get("warn"), + Description: gotext.Get("no unstable tags"), + HowToResolve: gotext.Get("tag all images with stable tags"), Function: LintNoUnstableTags, }, { Ref: "R005", - Level: "warn", - Description: "tags use semver-like format", - HowToResolve: "use semver-like tags", + Level: gotext.Get("warn"), + Description: gotext.Get("tags use semver-like format"), + HowToResolve: gotext.Get("use semver-like tags"), Function: LintSemverLikeTags, }, { Ref: "R006", - Level: "warn", - Description: "has published catalogue version", - HowToResolve: "publish a recipe version to the catalogue", + Level: gotext.Get("warn"), + Description: gotext.Get("has published catalogue version"), + HowToResolve: gotext.Get("publish a recipe version to the catalogue"), Function: LintHasPublishedVersion, }, { Ref: "R007", - Level: "warn", - Description: "README.md metadata filled in", - HowToResolve: "fill out all the metadata", + Level: gotext.Get("warn"), + Description: gotext.Get("README.md metadata filled in"), + HowToResolve: gotext.Get("fill out all the metadata"), Function: LintMetadataFilledIn, }, { Ref: "R013", - Level: "warn", - Description: "git.coopcloud.tech repo exists", - HowToResolve: "upload your recipe to git.coopcloud.tech/coop-cloud/...", + Level: gotext.Get("warn"), + Description: gotext.Get("git.coopcloud.tech repo exists"), + HowToResolve: gotext.Get("upload your recipe to git.coopcloud.tech/coop-cloud/..."), Function: LintHasRecipeRepo, }, { Ref: "R015", - Level: "warn", - Description: "long secret names", - HowToResolve: "reduce length of secret names to 12 chars", + Level: gotext.Get("warn"), + Description: gotext.Get("long secret names"), + HowToResolve: gotext.Get("reduce length of secret names to 12 chars"), Function: LintSecretLengths, }, }, "error": { { Ref: "R008", - Level: "error", - Description: ".env.sample provided", - HowToResolve: "create an example .env.sample", + Level: gotext.Get("error"), + Description: gotext.Get(".env.sample provided"), + HowToResolve: gotext.Get("create an example .env.sample"), Function: LintEnvConfigPresent, }, { Ref: "R009", - Level: "error", - Description: "one service named 'app'", - HowToResolve: "name a servce 'app'", + Level: gotext.Get("error"), + Description: gotext.Get("one service named 'app'"), + HowToResolve: gotext.Get("name a servce 'app'"), Function: LintAppService, }, { Ref: "R015", - Level: "error", - Description: "deploy labels stanza present", - HowToResolve: "include \"deploy: labels: ...\" stanza", + Level: gotext.Get("error"), + Description: gotext.Get("deploy labels stanza present"), + HowToResolve: gotext.Get("include \"deploy: labels: ...\" stanza"), Function: LintDeployLabelsPresent, }, { Ref: "R010", - Level: "error", - Description: "traefik routing enabled", - HowToResolve: "include \"traefik.enable=true\" deploy label", + Level: gotext.Get("error"), + Description: gotext.Get("traefik routing enabled"), + HowToResolve: gotext.Get("include \"traefik.enable=true\" deploy label"), Function: LintTraefikEnabled, SkipCondition: LintTraefikEnabledSkipCondition, }, { Ref: "R011", - Level: "error", - Description: "all services have images", - HowToResolve: "ensure \"image: ...\" set on all services", + Level: gotext.Get("error"), + Description: gotext.Get("all services have images"), + HowToResolve: gotext.Get("ensure \"image: ...\" set on all services"), Function: LintImagePresent, }, { Ref: "R012", - Level: "error", - Description: "config version are vendored", - HowToResolve: "vendor config versions in an abra.sh", + Level: gotext.Get("error"), + Description: gotext.Get("config version are vendored"), + HowToResolve: gotext.Get("vendor config versions in an abra.sh"), Function: LintAbraShVendors, }, { Ref: "R014", - Level: "error", - Description: "only annotated tags used for recipe version", - HowToResolve: "replace lightweight tag with annotated tag", + Level: gotext.Get("error"), + Description: gotext.Get("only annotated tags used for recipe version"), + HowToResolve: gotext.Get("replace lightweight tag with annotated tag"), Function: LintValidTags, }, }, @@ -182,9 +184,9 @@ var LintRules = map[string][]LintRule{ // used in code paths such as "app deploy" to avoid nasty surprises but not for // the typical linting commands, which do handle other levels. func LintForErrors(recipe recipe.Recipe) error { - log.Debugf("linting for critical errors in %s configs", recipe.Name) + log.Debug(gotext.Get("linting for critical errors in %s configs", recipe.Name)) - var errors string + var errs string for level := range LintRules { if level != "error" { @@ -198,19 +200,19 @@ func LintForErrors(recipe recipe.Recipe) error { ok, err := rule.Function(recipe) if err != nil { - errors += fmt.Sprintf("\nlint %s: %s", rule.Ref, err) + errs += gotext.Get("\nlint %s: %s", rule.Ref, err) } if !ok { - errors += fmt.Sprintf("\n * %s (%s)", rule.Description, rule.Ref) + errs += fmt.Sprintf("\n * %s (%s)", rule.Description, rule.Ref) } } } - if len(errors) > 0 { - return fmt.Errorf("recipe '%s' failed lint checks:\n"+errors[1:], recipe.Name) + if len(errs) > 0 { + return errors.New(gotext.Get("recipe '%s' failed lint checks:\n"+errs[1:], recipe.Name)) } - log.Debugf("linting successful, %s is well configured", recipe.Name) + log.Debug(gotext.Get("linting successful, %s is well configured", recipe.Name)) return nil } @@ -256,7 +258,7 @@ func LintAppService(recipe recipe.Recipe) (bool, error) { func LintTraefikEnabledSkipCondition(r recipe.Recipe) (bool, error) { sampleEnv, err := r.SampleEnv() if err != nil { - return false, fmt.Errorf("Unable to discover .env.sample for %s", r.Name) + return false, errors.New(gotext.Get("unable to discover .env.sample for %s", r.Name)) } if _, ok := sampleEnv["DOMAIN"]; !ok { @@ -476,7 +478,7 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) { } for name := range config.Secrets { if len(name) > 12 { - return false, fmt.Errorf("secret %s is longer than 12 characters", name) + return false, errors.New(gotext.Get("secret %s is longer than 12 characters", name)) } } @@ -486,12 +488,12 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) { func LintValidTags(recipe recipe.Recipe) (bool, error) { repo, err := git.PlainOpen(recipe.Dir) if err != nil { - return false, fmt.Errorf("unable to open %s: %s", recipe.Dir, err) + return false, errors.New(gotext.Get("unable to open %s: %s", recipe.Dir, err)) } iter, err := repo.Tags() if err != nil { - log.Fatalf("unable to list local tags for %s", recipe.Name) + log.Fatal(gotext.Get("unable to list local tags for %s", recipe.Name)) } if err := iter.ForEach(func(ref *plumbing.Reference) error { @@ -499,7 +501,7 @@ func LintValidTags(recipe recipe.Recipe) (bool, error) { if err != nil { switch err { case plumbing.ErrObjectNotFound: - return fmt.Errorf("invalid lightweight tag detected") + return errors.New(gotext.Get("invalid lightweight tag detected")) default: return err } diff --git a/pkg/logs/logs.go b/pkg/logs/logs.go index 0820d9dc..841e82c0 100644 --- a/pkg/logs/logs.go +++ b/pkg/logs/logs.go @@ -3,6 +3,7 @@ package logs import ( "bufio" "context" + "errors" "fmt" "io" "os" @@ -13,6 +14,7 @@ import ( containerTypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) type TailOpts struct { @@ -81,7 +83,7 @@ func TailLogs( } if _, err = io.Copy(os.Stdout, logs); err != nil && err != io.EOF { - errCh <- fmt.Errorf("tailLogs: unable to copy buffer: %s", err) + errCh <- errors.New(gotext.Get("tailLogs: unable to copy buffer: %s", err)) } } }(service.ID) diff --git a/pkg/recipe/compose.go b/pkg/recipe/compose.go index 736e5f70..56030324 100644 --- a/pkg/recipe/compose.go +++ b/pkg/recipe/compose.go @@ -1,6 +1,7 @@ package recipe import ( + "errors" "fmt" "io/ioutil" "os" @@ -13,6 +14,7 @@ import ( loader "coopcloud.tech/abra/pkg/upstream/stack" "github.com/distribution/reference" composetypes "github.com/docker/cli/cli/compose/types" + "github.com/leonelquinteros/gotext" ) // GetComposeFiles gets the list of compose files for an app (or recipe if you @@ -24,7 +26,7 @@ func (r Recipe) GetComposeFiles(appEnv map[string]string) ([]string, error) { if err := ensurePathExists(r.ComposePath); err != nil { return []string{}, err } - log.Debugf("no COMPOSE_FILE detected, loading default: %s", r.ComposePath) + log.Debug(gotext.Get("no COMPOSE_FILE detected, loading default: %s", r.ComposePath)) return []string{r.ComposePath}, nil } @@ -33,7 +35,7 @@ func (r Recipe) GetComposeFiles(appEnv map[string]string) ([]string, error) { if err := ensurePathExists(path); err != nil { return []string{}, err } - log.Debugf("COMPOSE_FILE detected, loading %s", path) + log.Debug(gotext.Get("COMPOSE_FILE detected, loading %s", path)) return []string{path}, nil } @@ -42,7 +44,7 @@ func (r Recipe) GetComposeFiles(appEnv map[string]string) ([]string, error) { numComposeFiles := strings.Count(composeFileEnvVar, ":") + 1 envVars := strings.SplitN(composeFileEnvVar, ":", numComposeFiles) if len(envVars) != numComposeFiles { - return composeFiles, fmt.Errorf("COMPOSE_FILE (=\"%s\") parsing failed?", composeFileEnvVar) + return composeFiles, errors.New(gotext.Get("COMPOSE_FILE (=\"%s\") parsing failed?", composeFileEnvVar)) } for _, file := range envVars { @@ -53,8 +55,8 @@ func (r Recipe) GetComposeFiles(appEnv map[string]string) ([]string, error) { composeFiles = append(composeFiles, path) } - log.Debugf("COMPOSE_FILE detected (%s), loading %s", composeFileEnvVar, strings.Join(envVars, ", ")) - log.Debugf("retrieved %s configs for %s", strings.Join(composeFiles, ", "), r.Name) + log.Debug(gotext.Get("COMPOSE_FILE detected (%s), loading %s", composeFileEnvVar, strings.Join(envVars, ", "))) + log.Debug(gotext.Get("retrieved %s configs for %s", strings.Join(composeFiles, ", "), r.Name)) return composeFiles, nil } @@ -67,7 +69,7 @@ func (r Recipe) GetComposeConfig(env map[string]string) (*composetypes.Config, e } if len(composeFiles) == 0 { - return nil, fmt.Errorf("%s is missing a compose.yml or compose.*.yml file?", r.Name) + return nil, errors.New(gotext.Get("%s is missing a compose.yml or compose.*.yml file?", r.Name)) } if env == nil { @@ -102,7 +104,7 @@ func (r Recipe) GetVersionLabelLocal() (string, error) { } if label == "" { - return label, fmt.Errorf("%s has no version label? try running \"abra recipe sync %s\" first?", r.Name, r.Name) + return label, errors.New(gotext.Get("%s has no version label? try running \"abra recipe sync %s\" first?", r.Name, r.Name)) } return label, nil @@ -118,7 +120,7 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) { return false, err } - log.Debugf("considering %s config(s) for tag update", strings.Join(composeFiles, ", ")) + log.Debug(gotext.Get("considering %s config(s) for tag update", strings.Join(composeFiles, ", "))) for _, composeFile := range composeFiles { opts := stack.Deploy{Composefiles: []string{composeFile}} @@ -148,13 +150,13 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) { case reference.NamedTagged: composeTag = img.(reference.NamedTagged).Tag() default: - log.Debugf("unable to parse %s, skipping", img) + log.Debug(gotext.Get("unable to parse %s, skipping", img)) continue } composeImage := formatter.StripTagMeta(reference.Path(img)) - log.Debugf("parsed %s from %s", composeTag, service.Image) + log.Debug(gotext.Get("parsed %s from %s", composeTag, service.Image)) if image == composeImage { bytes, err := ioutil.ReadFile(composeFile) @@ -166,7 +168,7 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) { new := fmt.Sprintf("%s:%s", composeImage, tag) replacedBytes := strings.Replace(string(bytes), old, new, -1) - log.Debugf("updating %s to %s in %s", old, new, compose.Filename) + log.Debug(gotext.Get("updating %s to %s in %s", old, new, compose.Filename)) if err := os.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil { return false, err @@ -186,7 +188,7 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error { return err } - log.Debugf("considering %s config(s) for label update", strings.Join(composeFiles, ", ")) + log.Debug(gotext.Get("considering %s config(s) for label update", strings.Join(composeFiles, ", "))) for _, composeFile := range composeFiles { opts := stack.Deploy{Composefiles: []string{composeFile}} @@ -224,27 +226,27 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error { return err } - old := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", value) + old := gotext.Get("coop-cloud.${STACK_NAME}.version=%s", value) replacedBytes := strings.Replace(string(bytes), old, label, -1) if old == label { - log.Warnf("%s is already set, nothing to do?", label) + log.Warnf(gotext.Get("%s is already set, nothing to do?", label)) return nil } - log.Debugf("updating %s to %s in %s", old, label, compose.Filename) + log.Debug(gotext.Get("updating %s to %s in %s", old, label, compose.Filename)) if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil { return err } - log.Infof("synced label %s to service %s", label, serviceName) + log.Infof(gotext.Get("synced label %s to service %s", label, serviceName)) } } if !discovered { - log.Warn("no existing label found, automagic insertion not supported yet") - log.Fatalf("add '- \"%s\"' manually to the 'app' service in %s", label, composeFile) + log.Warn(gotext.Get("no existing label found, automagic insertion not supported yet")) + log.Fatal(gotext.Get("add '- \"%s\"' manually to the 'app' service in %s", label, composeFile)) } } diff --git a/pkg/recipe/files.go b/pkg/recipe/files.go index d3408fa4..cd639d8c 100644 --- a/pkg/recipe/files.go +++ b/pkg/recipe/files.go @@ -1,18 +1,20 @@ package recipe import ( + "errors" "fmt" "os" "path" "coopcloud.tech/abra/pkg/envfile" "coopcloud.tech/abra/pkg/formatter" + "github.com/leonelquinteros/gotext" ) func (r Recipe) SampleEnv() (map[string]string, error) { sampleEnv, err := envfile.ReadEnv(r.SampleEnvPath) if err != nil { - return sampleEnv, fmt.Errorf("unable to discover .env.sample for %s", r.Name) + return sampleEnv, errors.New(gotext.Get("unable to discover .env.sample for %s", r.Name)) } return sampleEnv, nil } @@ -31,7 +33,7 @@ func (r Recipe) GetReleaseNotes(version string) (string, error) { return "", err } - title := formatter.BoldStyle.Render(fmt.Sprintf("%s release notes:", version)) + title := formatter.BoldStyle.Render(gotext.Get("%s release notes:", version)) withTitle := fmt.Sprintf("%s\n%s\n", title, releaseNotes) return withTitle, nil diff --git a/pkg/recipe/git.go b/pkg/recipe/git.go index e430d71a..cec0aefa 100644 --- a/pkg/recipe/git.go +++ b/pkg/recipe/git.go @@ -1,6 +1,7 @@ package recipe import ( + "errors" "fmt" "os" "slices" @@ -15,6 +16,7 @@ import ( "github.com/distribution/reference" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "github.com/leonelquinteros/gotext" ) type EnsureContext struct { @@ -45,9 +47,9 @@ func (r Recipe) Ensure(ctx EnsureContext) error { } if r.EnvVersion != "" && !ctx.IgnoreEnvVersion { - log.Debugf("ensuring env version %s", r.EnvVersion) + log.Debug(gotext.Get("ensuring env version %s", r.EnvVersion)) if strings.Contains(r.EnvVersion, "+U") { - return fmt.Errorf("can not redeploy chaos version (%s) without --chaos", r.EnvVersion) + return errors.New(gotext.Get("can not redeploy chaos version (%s) without --chaos", r.EnvVersion)) } if _, err := r.EnsureVersion(r.EnvVersion); err != nil { @@ -146,16 +148,16 @@ func (r Recipe) EnsureVersion(version string) (bool, error) { joinedTags := strings.Join(parsedTags, ", ") if joinedTags != "" { - log.Debugf("read %s as tags for recipe %s", joinedTags, r.Name) + log.Debug(gotext.Get("read %s as tags for recipe %s", joinedTags, r.Name)) } var opts *git.CheckoutOptions if tagRef.String() == "" { - log.Debugf("attempting to checkout '%s' as chaos commit", version) + log.Debug(gotext.Get("attempting to checkout '%s' as chaos commit", version)) hash, err := repo.ResolveRevision(plumbing.Revision(version)) if err != nil { - log.Fatalf("unable to resolve '%s': %s", version, err) + log.Fatal(gotext.Get("unable to resolve '%s': %s", version, err)) } opts = &git.CheckoutOptions{Hash: *hash, Create: false, Force: true} @@ -173,7 +175,7 @@ func (r Recipe) EnsureVersion(version string) (bool, error) { return isChaosCommit, nil } - log.Debugf("successfully checked %s out to %s in %s", r.Name, tagRef.Short(), r.Dir) + log.Debug(gotext.Get("successfully checked %s out to %s in %s", r.Name, tagRef.Short(), r.Dir)) return isChaosCommit, nil } @@ -182,11 +184,11 @@ func (r Recipe) EnsureVersion(version string) (bool, error) { func (r Recipe) EnsureIsClean() error { isClean, err := gitPkg.IsClean(r.Dir) if err != nil { - return fmt.Errorf("unable to check git clean status in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to check git clean status in %s: %s", r.Dir, err)) } if !isClean { - return fmt.Errorf("%s (%s) has locally unstaged changes?", r.Name, r.Dir) + return errors.New(gotext.Get("%s (%s) has locally unstaged changes?", r.Name, r.Dir)) } return nil @@ -220,7 +222,7 @@ func (r Recipe) EnsureLatest() error { } if err := worktree.Checkout(checkOutOpts); err != nil { - log.Debugf("failed to check out %s in %s", branch, r.Dir) + log.Debug(gotext.Get("failed to check out %s in %s", branch, r.Dir)) return err } @@ -231,33 +233,33 @@ func (r Recipe) EnsureLatest() error { func (r Recipe) EnsureUpToDate() error { repo, err := git.PlainOpen(r.Dir) if err != nil { - return fmt.Errorf("unable to open %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to open %s: %s", r.Dir, err)) } remotes, err := repo.Remotes() if err != nil { - return fmt.Errorf("unable to read remotes in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to read remotes in %s: %s", r.Dir, err)) } if len(remotes) == 0 { - log.Debugf("cannot ensure %s is up-to-date, no git remotes configured", r.Name) + log.Debug(gotext.Get("cannot ensure %s is up-to-date, no git remotes configured", r.Name)) return nil } worktree, err := repo.Worktree() if err != nil { - return fmt.Errorf("unable to open git work tree in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to open git work tree in %s: %s", r.Dir, err)) } branch, err := gitPkg.CheckoutDefaultBranch(repo, r.Dir) if err != nil { - return fmt.Errorf("unable to check out default branch in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to check out default branch in %s: %s", r.Dir, err)) } fetchOpts := &git.FetchOptions{Tags: git.AllTags} if err := repo.Fetch(fetchOpts); err != nil { if !strings.Contains(err.Error(), "already up-to-date") { - return fmt.Errorf("unable to fetch tags in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to fetch tags in %s: %s", r.Dir, err)) } } @@ -269,11 +271,11 @@ func (r Recipe) EnsureUpToDate() error { if err := worktree.Pull(opts); err != nil { if !strings.Contains(err.Error(), "already up-to-date") { - return fmt.Errorf("unable to git pull in %s: %s", r.Dir, err) + return errors.New(gotext.Get("unable to git pull in %s: %s", r.Dir, err)) } } - log.Debugf("fetched latest git changes for %s", r.Name) + log.Debug(gotext.Get("fetched latest git changes for %s", r.Name)) return nil } @@ -362,7 +364,7 @@ func (r Recipe) Tags() ([]string, error) { return version1.IsLessThan(version2) }) - log.Debugf("detected %s as tags for recipe %s", strings.Join(tags, ", "), r.Name) + log.Debug(gotext.Get("detected %s as tags for recipe %s", strings.Join(tags, ", "), r.Name)) return tags, nil } @@ -373,7 +375,7 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) { versions := RecipeVersions{} - log.Debugf("git: opening repository in %s", r.Dir) + log.Debug(gotext.Get("git: opening repository in %s", r.Dir)) repo, err := git.PlainOpen(r.Dir) if err != nil { @@ -393,7 +395,7 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) { if err := gitTags.ForEach(func(ref *plumbing.Reference) (err error) { tag := strings.TrimPrefix(string(ref.Name()), "refs/tags/") - log.Debugf("processing %s for %s", tag, r.Name) + log.Debug(gotext.Get("processing %s for %s", tag, r.Name)) checkOutOpts := &git.CheckoutOptions{ Create: false, @@ -401,11 +403,11 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) { Branch: plumbing.ReferenceName(ref.Name()), } if err := worktree.Checkout(checkOutOpts); err != nil { - log.Debugf("failed to check out %s in %s", tag, r.Dir) + log.Debug(gotext.Get("failed to check out %s in %s", tag, r.Dir)) return err } - log.Debugf("git checkout: %s in %s", ref.Name(), r.Dir) + log.Debug(gotext.Get("git checkout: %s in %s", ref.Name(), r.Dir)) config, err := r.GetComposeConfig(nil) if err != nil { @@ -429,7 +431,7 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) { case reference.NamedTagged: tag = img.(reference.NamedTagged).Tag() case reference.Named: - warnMsg = append(warnMsg, fmt.Sprintf("%s service is missing image tag?", path)) + warnMsg = append(warnMsg, gotext.Get("%s service is missing image tag?", path)) continue } @@ -453,7 +455,7 @@ func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) { sortRecipeVersions(versions) - log.Debugf("collected %s for %s", versions, r.Dir) + log.Debug(gotext.Get("collected %s for %s", versions, r.Dir)) var uniqueWarnings []string for _, w := range warnMsg { diff --git a/pkg/recipe/recipe.go b/pkg/recipe/recipe.go index 728fadca..c2aa2748 100644 --- a/pkg/recipe/recipe.go +++ b/pkg/recipe/recipe.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/go-git/go-git/v5" + "github.com/leonelquinteros/gotext" "coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/config" @@ -70,7 +71,7 @@ func (r RecipeMeta) LatestVersion() string { version = tag } - log.Debugf("choosing %s as latest version of %s", version, r.Name) + log.Debug(gotext.Get("choosing %s as latest version of %s", version, r.Name)) return version } @@ -126,7 +127,7 @@ func Get(name string) Recipe { if strings.Contains(name, ":") { split := strings.Split(name, ":") if len(split) > 2 { - log.Fatalf("version seems invalid: %s", name) + log.Fatal(gotext.Get("version seems invalid: %s", name)) } name = split[0] @@ -134,7 +135,7 @@ func Get(name string) Recipe { versionRaw = version if strings.HasSuffix(version, config.DIRTY_DEFAULT) { version = strings.Replace(split[1], config.DIRTY_DEFAULT, "", 1) - log.Debugf("removed dirty suffix from .env version: %s -> %s", split[1], version) + log.Debug(gotext.Get("removed dirty suffix from .env version: %s -> %s", split[1], version)) } } @@ -143,7 +144,7 @@ func Get(name string) Recipe { if strings.Contains(name, "/") { u, err := url.Parse(name) if err != nil { - log.Fatalf("invalid recipe: %s", err) + log.Fatal(gotext.Get("invalid recipe: %s", err)) } u.Scheme = "https" gitURL = u.String() + ".git" @@ -171,7 +172,7 @@ func Get(name string) Recipe { dirty, err := r.IsDirty() if err != nil && !errors.Is(err, git.ErrRepositoryNotExists) { - log.Fatalf("failed to check git status of %s: %s", r.Name, err) + log.Fatal(gotext.Get("failed to check git status of %s: %s", r.Name, err)) } r.Dirty = dirty @@ -195,16 +196,16 @@ type Recipe struct { // String outputs a human-friendly string representation. func (r Recipe) String() string { - out := fmt.Sprintf("{name: %s, ", r.Name) - out += fmt.Sprintf("version : %s, ", r.EnvVersion) - out += fmt.Sprintf("dirty: %v, ", r.Dirty) - out += fmt.Sprintf("dir: %s, ", r.Dir) - out += fmt.Sprintf("git url: %s, ", r.GitURL) - out += fmt.Sprintf("ssh url: %s, ", r.SSHURL) - out += fmt.Sprintf("compose: %s, ", r.ComposePath) - out += fmt.Sprintf("readme: %s, ", r.ReadmePath) - out += fmt.Sprintf("sample env: %s, ", r.SampleEnvPath) - out += fmt.Sprintf("abra.sh: %s}", r.AbraShPath) + out := gotext.Get("{name: %s, ", r.Name) + out += gotext.Get("version : %s, ", r.EnvVersion) + out += gotext.Get("dirty: %v, ", r.Dirty) + out += gotext.Get("dir: %s, ", r.Dir) + out += gotext.Get("git url: %s, ", r.GitURL) + out += gotext.Get("ssh url: %s, ", r.SSHURL) + out += gotext.Get("compose: %s, ", r.ComposePath) + out += gotext.Get("readme: %s, ", r.ReadmePath) + out += gotext.Get("sample env: %s, ", r.SampleEnvPath) + out += gotext.Get("abra.sh: %s}", r.AbraShPath) return out } @@ -233,7 +234,7 @@ func GetRecipeFeaturesAndCategory(r Recipe) (Features, string, []string, error) feat = Features{} ) - log.Debugf("%s: attempt recipe metadata parse", r.ReadmePath) + log.Debug(gotext.Get("%s: attempt recipe metadata parse", r.ReadmePath)) readmeFS, err := ioutil.ReadFile(r.ReadmePath) if err != nil { @@ -321,12 +322,12 @@ func GetImageMetadata(imageRowString, recipeName string) (Image, []string, error if imageRowString != "" { warnMsgs = append( warnMsgs, - fmt.Sprintf("%s: image meta has incorrect format: %s", recipeName, imageRowString), + gotext.Get("%s: image meta has incorrect format: %s", recipeName, imageRowString), ) } else { warnMsgs = append( warnMsgs, - fmt.Sprintf("%s: image meta is empty?", recipeName), + gotext.Get("%s: image meta is empty?", recipeName), ) } @@ -357,14 +358,14 @@ func GetImageMetadata(imageRowString, recipeName string) (Image, []string, error func GetStringInBetween(recipeName, str, start, end string) (result string, err error) { s := strings.Index(str, start) if s == -1 { - return "", fmt.Errorf("%s: marker string %s not found", recipeName, start) + return "", errors.New(gotext.Get("%s: marker string %s not found", recipeName, start)) } s += len(start) e := strings.Index(str[s:], end) if e == -1 { - return "", fmt.Errorf("%s: end marker %s not found", recipeName, end) + return "", errors.New(gotext.Get("%s: end marker %s not found", recipeName, end)) } return str[s : s+e], nil @@ -402,7 +403,7 @@ func readRecipeCatalogueFS(target interface{}) error { return err } - log.Debugf("read recipe catalogue from file system cache in %s", config.RECIPES_JSON) + log.Debug(gotext.Get("read recipe catalogue from file system cache in %s", config.RECIPES_JSON)) return nil } @@ -431,7 +432,7 @@ func VersionsOfService(recipe, serviceName string, offline bool) ([]string, erro } } - log.Debugf("detected versions %s for %s", strings.Join(versions, ", "), recipe) + log.Debug(gotext.Get("detected versions %s for %s", strings.Join(versions, ", "), recipe)) return versions, nil } @@ -454,11 +455,11 @@ func GetRecipeMeta(recipeName string, offline bool) (RecipeMeta, error) { recipeMeta, ok := catl[recipeName] if !ok { return RecipeMeta{}, RecipeMissingFromCatalogue{ - err: fmt.Sprintf("recipe %s does not exist?", recipeName), + err: gotext.Get("recipe %s does not exist?", recipeName), } } - log.Debugf("recipe metadata retrieved for %s", recipeName) + log.Debug(gotext.Get("recipe metadata retrieved for %s", recipeName)) return recipeMeta, nil } @@ -545,13 +546,13 @@ func ReadReposMetadata(debug bool) (RepoCatalogue, error) { reposMeta := make(RepoCatalogue) pageIdx := 1 - bar := formatter.CreateProgressbar(-1, "collecting recipe listing") + bar := formatter.CreateProgressbar(-1, gotext.Get("collecting recipe listing")) for { var reposList []RepoMeta pagedURL := fmt.Sprintf("%s?page=%v", ReposMetadataURL, pageIdx) - log.Debugf("fetching repo metadata from %s", pagedURL) + log.Debug(gotext.Get("fetching repo metadata from %s", pagedURL)) if err := web.ReadJSON(pagedURL, &reposList); err != nil { return reposMeta, err @@ -655,7 +656,7 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string, debug bool) erro cloneLimiter := limit.New(3) - retrieveBar := formatter.CreateProgressbar(barLength, "retrieving recipes") + retrieveBar := formatter.CreateProgressbar(barLength, gotext.Get("retrieving recipes")) ch := make(chan string, barLength) for _, repoMeta := range repos { go func(rm RepoMeta) { diff --git a/pkg/secret/pass.go b/pkg/secret/pass.go index 1763e1f4..04044dc2 100644 --- a/pkg/secret/pass.go +++ b/pkg/secret/pass.go @@ -6,12 +6,13 @@ import ( "os/exec" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" ) // PassInsertSecret inserts a secret into a pass store. func PassInsertSecret(secretValue, secretName, appName, server string) error { if _, err := exec.LookPath("pass"); err != nil { - return errors.New("pass command not found on $PATH, is it installed?") + return errors.New(gotext.Get("pass command not found on $PATH, is it installed?")) } cmd := fmt.Sprintf( @@ -19,13 +20,13 @@ func PassInsertSecret(secretValue, secretName, appName, server string) error { secretValue, server, appName, secretName, ) - log.Debugf("attempting to run %s", cmd) + log.Debug(gotext.Get("attempting to run %s", cmd)) if err := exec.Command("bash", "-c", cmd).Run(); err != nil { return err } - log.Infof("%s inserted into pass store", secretName) + log.Infof(gotext.Get("%s inserted into pass store", secretName)) return nil } @@ -33,7 +34,7 @@ func PassInsertSecret(secretValue, secretName, appName, server string) error { // PassRmSecret deletes a secret from a pass store. func PassRmSecret(secretName, appName, server string) error { if _, err := exec.LookPath("pass"); err != nil { - return errors.New("pass command not found on $PATH, is it installed?") + return errors.New(gotext.Get("pass command not found on $PATH, is it installed?")) } cmd := fmt.Sprintf( @@ -41,13 +42,13 @@ func PassRmSecret(secretName, appName, server string) error { server, appName, secretName, ) - log.Debugf("attempting to run %s", cmd) + log.Debug(gotext.Get("attempting to run %s", cmd)) if err := exec.Command("bash", "-c", cmd).Run(); err != nil { return err } - log.Infof("%s removed from pass store", secretName) + log.Infof(gotext.Get("%s removed from pass store", secretName)) return nil } diff --git a/pkg/secret/secret.go b/pkg/secret/secret.go index f8366c7b..32cfd632 100644 --- a/pkg/secret/secret.go +++ b/pkg/secret/secret.go @@ -5,6 +5,7 @@ package secret import ( "context" + "errors" "fmt" "slices" "strconv" @@ -21,6 +22,7 @@ import ( "github.com/decentral1se/passgen" "github.com/docker/docker/api/types" dockerClient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) // Secret represents a secret. @@ -57,7 +59,7 @@ func GeneratePassword(length uint, charset string) (string, error) { return "", err } - log.Debugf("generated %s", strings.Join(passwords, ", ")) + log.Debug(gotext.Get("generated %s", strings.Join(passwords, ", "))) return passwords[0], nil } @@ -75,7 +77,7 @@ func GeneratePassphrase() (string, error) { return "", err } - log.Debugf("generated %s", strings.Join(passphrases, ", ")) + log.Debug(gotext.Get("generated %s", strings.Join(passphrases, ", "))) return passphrases[0], nil } @@ -114,18 +116,18 @@ func ReadSecretsConfig(appEnvPath string, composeFiles []string, stackName strin } if len(enabledSecrets) == 0 { - log.Debugf("not generating app secrets, none enabled in recipe config") + log.Debug(gotext.Get("not generating app secrets, none enabled in recipe config")) return nil, nil } secretValues := map[string]Secret{} for secretId, secretConfig := range composeConfig.Secrets { if string(secretConfig.Name[len(secretConfig.Name)-1]) == "_" { - return nil, fmt.Errorf("missing version for secret? (%s)", secretId) + return nil, errors.New(gotext.Get("missing version for secret? (%s)", secretId)) } if !(slices.Contains(enabledSecrets, secretId)) { - log.Warnf("%s not enabled in recipe config, skipping", secretId) + log.Warnf(gotext.Get("%s not enabled in recipe config, skipping", secretId)) continue } @@ -134,7 +136,7 @@ func ReadSecretsConfig(appEnvPath string, composeFiles []string, stackName strin value := Secret{Version: secretVersion, RemoteName: secretConfig.Name} if len(value.RemoteName) > config.MAX_DOCKER_SECRET_LENGTH { - return nil, fmt.Errorf("secret %s is > %d chars when combined with %s", secretId, config.MAX_DOCKER_SECRET_LENGTH, stackName) + return nil, errors.New(gotext.Get("secret %s is > %d chars when combined with %s", secretId, config.MAX_DOCKER_SECRET_LENGTH, stackName)) } // Check if the length modifier is set for this secret. @@ -202,12 +204,12 @@ func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server defer wg.Done() if secret.SkipGenerate { - log.Debugf("skipping generation of %s (generate=false)", secretName) + log.Debug(gotext.Get("skipping generation of %s (generate=false)", secretName)) ch <- nil return } - log.Debugf("attempting to generate and store %s on %s", secret.RemoteName, server) + log.Debug(gotext.Get("attempting to generate and store %s on %s", secret.RemoteName, server)) if secret.Length > 0 { password, err := GeneratePassword(uint(secret.Length), secret.Charset) @@ -218,7 +220,7 @@ func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server if err := client.StoreSecret(cl, secret.RemoteName, password, server); err != nil { if strings.Contains(err.Error(), "AlreadyExists") { - log.Warnf("%s already exists", secret.RemoteName) + log.Warnf(gotext.Get("%s already exists", secret.RemoteName)) ch <- nil } else { ch <- err @@ -238,7 +240,7 @@ func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server if err := client.StoreSecret(cl, secret.RemoteName, passphrase, server); err != nil { if strings.Contains(err.Error(), "AlreadyExists") { - log.Warnf("%s already exists", secret.RemoteName) + log.Warnf(gotext.Get("%s already exists", secret.RemoteName)) ch <- nil } else { ch <- err @@ -263,7 +265,7 @@ func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server } } - log.Debugf("generated and stored %v on %s", secrets, server) + log.Debug(gotext.Get("generated and stored %v on %s", secrets, server)) return secretsGenerated, nil } diff --git a/pkg/server/server.go b/pkg/server/server.go index 8f723a69..fe566d4f 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -6,6 +6,7 @@ import ( "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" ) // CreateServerDir creates a server directory under ~/.abra. @@ -17,11 +18,11 @@ func CreateServerDir(serverName string) error { return err } - log.Debugf("%s already exists", serverPath) + log.Debug(gotext.Get("%s already exists", serverPath)) return nil } - log.Debugf("successfully created %s", serverPath) + log.Debug(gotext.Get("successfully created %s", serverPath)) return nil } diff --git a/pkg/service/service.go b/pkg/service/service.go index 32d1f8f6..183dffa9 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "strings" @@ -12,6 +13,7 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) // GetService retrieves a service container based on a label. If prompt is true @@ -25,7 +27,7 @@ func GetServiceByLabel(c context.Context, cl *client.Client, label string, promp } if len(services) == 0 { - return swarm.Service{}, fmt.Errorf("no services deployed?") + return swarm.Service{}, errors.New(gotext.Get("no services deployed?")) } var matchingServices []swarm.Service @@ -36,7 +38,7 @@ func GetServiceByLabel(c context.Context, cl *client.Client, label string, promp } if len(matchingServices) == 0 { - return swarm.Service{}, fmt.Errorf("no services deployed matching label '%s'?", label) + return swarm.Service{}, errors.New(gotext.Get("no services deployed matching label '%s'?", label)) } if len(matchingServices) > 1 { @@ -48,15 +50,15 @@ func GetServiceByLabel(c context.Context, cl *client.Client, label string, promp } if !prompt { - err := fmt.Errorf("expected 1 service but found %v: %s", len(matchingServices), strings.Join(servicesRaw, " ")) + err := errors.New(gotext.Get("expected 1 service but found %v: %s", len(matchingServices), strings.Join(servicesRaw, " "))) return swarm.Service{}, err } - log.Warnf("ambiguous service list received, prompting for input") + log.Warnf(gotext.Get("ambiguous service list received, prompting for input")) var response string prompt := &survey.Select{ - Message: "which service are you looking for?", + Message: gotext.Get("which service are you looking for?"), Options: servicesRaw, } @@ -72,7 +74,7 @@ func GetServiceByLabel(c context.Context, cl *client.Client, label string, promp } } - log.Fatal("failed to match chosen service") + log.Fatal(gotext.Get("failed to match chosen service")) } return matchingServices[0], nil @@ -90,7 +92,7 @@ func GetService(c context.Context, cl *client.Client, filters filters.Args, prom if len(services) == 0 { filter := filters.Get("name")[0] - return swarm.Service{}, fmt.Errorf("no services matching the %v filter found?", filter) + return swarm.Service{}, errors.New(gotext.Get("no services matching the %v filter found?", filter)) } if len(services) != 1 { @@ -98,19 +100,19 @@ func GetService(c context.Context, cl *client.Client, filters filters.Args, prom for _, service := range services { serviceName := service.Spec.Name created := formatter.HumanDuration(service.CreatedAt.Unix()) - servicesRaw = append(servicesRaw, fmt.Sprintf("%s (created %v)", serviceName, created)) + servicesRaw = append(servicesRaw, gotext.Get("%s (created %v)", serviceName, created)) } if !prompt { - err := fmt.Errorf("expected 1 service but found %v: %s", len(services), strings.Join(servicesRaw, " ")) + err := errors.New(gotext.Get("expected 1 service but found %v: %s", len(services), strings.Join(servicesRaw, " "))) return swarm.Service{}, err } - log.Warnf("ambiguous service list received, prompting for input") + log.Warnf(gotext.Get("ambiguous service list received, prompting for input")) var response string prompt := &survey.Select{ - Message: "which service are you looking for?", + Message: gotext.Get("which service are you looking for?"), Options: servicesRaw, } @@ -126,7 +128,7 @@ func GetService(c context.Context, cl *client.Client, filters filters.Args, prom } } - log.Fatal("failed to match chosen service") + log.Fatal(gotext.Get("failed to match chosen service")) } return services[0], nil diff --git a/pkg/ssh/ssh.go b/pkg/ssh/ssh.go index 96489f43..96d89c72 100644 --- a/pkg/ssh/ssh.go +++ b/pkg/ssh/ssh.go @@ -1,8 +1,10 @@ package ssh import ( - "fmt" + "errors" "strings" + + "github.com/leonelquinteros/gotext" ) // Fatal is a error output wrapper which aims to make SSH failures easier to @@ -11,17 +13,17 @@ func Fatal(hostname string, err error) error { out := err.Error() if strings.Contains(out, "Host key verification failed.") { - return fmt.Errorf("SSH host key verification failed for %s", hostname) + return errors.New(gotext.Get("SSH host key verification failed for %s", hostname)) } else if strings.Contains(out, "Could not resolve hostname") { - return fmt.Errorf("could not resolve hostname for %s", hostname) + return errors.New(gotext.Get("could not resolve hostname for %s", hostname)) } else if strings.Contains(out, "Connection timed out") { - return fmt.Errorf("connection timed out for %s", hostname) + return errors.New(gotext.Get("connection timed out for %s", hostname)) } else if strings.Contains(out, "Permission denied") { - return fmt.Errorf("ssh auth: permission denied for %s", hostname) + return errors.New(gotext.Get("ssh auth: permission denied for %s", hostname)) } else if strings.Contains(out, "Network is unreachable") { - return fmt.Errorf("unable to connect to %s, please check your SSH config", hostname) + return errors.New(gotext.Get("unable to connect to %s, please check your SSH config", hostname)) } else if strings.Contains(out, "Is the docker daemon running") { - return fmt.Errorf("docker: is the daemon running / your user has docker permissions?") + return errors.New(gotext.Get("docker: is the daemon running / your user has docker permissions?")) } return err diff --git a/pkg/ui/deploy.go b/pkg/ui/deploy.go index 5b3a8ea8..1f2a390b 100644 --- a/pkg/ui/deploy.go +++ b/pkg/ui/deploy.go @@ -3,7 +3,6 @@ package ui import ( "context" "encoding/json" - "fmt" "io" "sort" "strings" @@ -17,6 +16,7 @@ import ( "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" "github.com/docker/docker/pkg/jsonmessage" + "github.com/leonelquinteros/gotext" ) var IsRunning bool @@ -79,13 +79,13 @@ type stream struct { } func (s stream) String() string { - out := fmt.Sprintf("{decoder: %v, ", s.decoder) - out += fmt.Sprintf("err: %v, ", s.Err) - out += fmt.Sprintf("id: %s, ", s.id) - out += fmt.Sprintf("name: %s, ", s.Name) - out += fmt.Sprintf("reader: %v, ", s.reader) - out += fmt.Sprintf("writer: %v, ", s.writer) - out += fmt.Sprintf("status: %s, ", s.status) + out := gotext.Get("{decoder: %v, ", s.decoder) + out += gotext.Get("err: %v, ", s.Err) + out += gotext.Get("id: %s, ", s.id) + out += gotext.Get("name: %s, ", s.Name) + out += gotext.Get("reader: %v, ", s.reader) + out += gotext.Get("writer: %v, ", s.writer) + out += gotext.Get("status: %s, ", s.status) return out } @@ -118,7 +118,7 @@ func (s stream) process() tea.Msg { func (s stream) healthcheck(m Model) tea.Msg { filters := filters.NewArgs() - filters.Add("name", fmt.Sprintf("^%s", s.Name)) + filters.Add("name", gotext.Get("^%s", s.Name)) containers, err := m.cl.ContainerList(m.ctx, containerTypes.ListOptions{Filters: filters}) if err != nil { @@ -327,10 +327,10 @@ func (m Model) View() string { status := stream.status if strings.Contains(stream.status, "converged") && !stream.rollback { - status = "succeeded" + status = gotext.Get("succeeded") } if strings.Contains(stream.status, "rolled back") { - status = "rolled back" + status = gotext.Get("rolled back") } retries := 0 @@ -338,7 +338,7 @@ func (m Model) View() string { retries = stream.retries } - output := fmt.Sprintf("%s: %s (retries: %v, healthcheck: %s)", + output := gotext.Get("%s: %s (retries: %v, healthcheck: %s)", formatter.BoldStyle.Render(short), status, retries, diff --git a/pkg/upstream/commandconn/commandconn.go b/pkg/upstream/commandconn/commandconn.go index 9f76c50f..23c46b7e 100644 --- a/pkg/upstream/commandconn/commandconn.go +++ b/pkg/upstream/commandconn/commandconn.go @@ -17,7 +17,6 @@ package commandconn import ( "bytes" "context" - "fmt" "io" "net" "os" @@ -28,6 +27,7 @@ import ( "time" "coopcloud.tech/abra/pkg/log" + "github.com/leonelquinteros/gotext" "github.com/pkg/errors" exec "golang.org/x/sys/execabs" ) @@ -46,7 +46,7 @@ func New(ctx context.Context, cmd string, args ...string) (net.Conn, error) { ) c.cmd = exec.CommandContext(ctx, cmd, args...) // we assume that args never contains sensitive information - log.Debugf("commandconn: starting %s with %v", cmd, args) + log.Debug(gotext.Get("commandconn: starting %s with %v", cmd, args)) c.cmd.Env = os.Environ() c.cmd.SysProcAttr = &syscall.SysProcAttr{} setPdeathsig(c.cmd) @@ -62,7 +62,7 @@ func New(ctx context.Context, cmd string, args ...string) (net.Conn, error) { c.cmd.Stderr = &stderrWriter{ stderrMu: &c.stderrMu, stderr: &c.stderr, - debugPrefix: fmt.Sprintf("commandconn (%s):", cmd), + debugPrefix: gotext.Get("commandconn (%s):", cmd), } c.localAddr = dummyAddr{network: "dummy", s: "dummy-0"} c.remoteAddr = dummyAddr{network: "dummy", s: "dummy-1"} @@ -138,7 +138,7 @@ func (c *commandConn) kill() error { return nil } } - return errors.Wrapf(werr, "commandconn: failed to wait") + return errors.Wrap(werr, gotext.Get("commandconn: failed to wait")) } func (c *commandConn) onEOF(eof error) error { @@ -159,7 +159,7 @@ func (c *commandConn) onEOF(eof error) error { c.stderrMu.Lock() stderr := c.stderr.String() c.stderrMu.Unlock() - return errors.Errorf("command %v did not exit after %v: stderr=%q", c.cmd.Args, eof, stderr) + return errors.New(gotext.Get("command %v did not exit after %v: stderr=%q", c.cmd.Args, eof, stderr)) } } c.cmdMutex.Unlock() @@ -169,7 +169,7 @@ func (c *commandConn) onEOF(eof error) error { c.stderrMu.Lock() stderr := c.stderr.String() c.stderrMu.Unlock() - return errors.Errorf("command %v has exited with %v, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=%s", c.cmd.Args, werr, stderr) + return errors.New(gotext.Get("command %v has exited with %v, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=%s", c.cmd.Args, werr, stderr)) } func ignorableCloseError(err error) bool { @@ -236,7 +236,7 @@ func (c *commandConn) Write(p []byte) (int, error) { func (c *commandConn) Close() error { var err error if err = c.CloseRead(); err != nil { - log.Warnf("commandConn.Close: CloseRead: %v", err) + log.Warnf(gotext.Get("commandConn.Close: CloseRead: %v", err)) } if err = c.CloseWrite(); err != nil { // muted because https://github.com/docker/compose/issues/8544 @@ -252,15 +252,15 @@ func (c *commandConn) RemoteAddr() net.Addr { return c.remoteAddr } func (c *commandConn) SetDeadline(t time.Time) error { - log.Debugf("unimplemented call: SetDeadline(%v)", t) + log.Debug(gotext.Get("unimplemented call: SetDeadline(%v)", t)) return nil } func (c *commandConn) SetReadDeadline(t time.Time) error { - log.Debugf("unimplemented call: SetReadDeadline(%v)", t) + log.Debug(gotext.Get("unimplemented call: SetReadDeadline(%v)", t)) return nil } func (c *commandConn) SetWriteDeadline(t time.Time) error { - log.Debugf("unimplemented call: SetWriteDeadline(%v)", t) + log.Debug(gotext.Get("unimplemented call: SetWriteDeadline(%v)", t)) return nil } diff --git a/pkg/upstream/commandconn/connection.go b/pkg/upstream/commandconn/connection.go index f48a77af..2146182a 100644 --- a/pkg/upstream/commandconn/connection.go +++ b/pkg/upstream/commandconn/connection.go @@ -11,6 +11,7 @@ import ( "github.com/docker/cli/cli/context/docker" dCliContextStore "github.com/docker/cli/cli/context/store" dClient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" "github.com/pkg/errors" ) @@ -34,7 +35,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*connhelper.Conne case "ssh": ctxConnDetails, err := ssh.ParseURL(daemonURL) if err != nil { - return nil, errors.Wrap(err, "ssh host connection is not valid") + return nil, errors.Wrap(err, gotext.Get("ssh host connection is not valid")) } return &connhelper.ConnectionHelper{ diff --git a/pkg/upstream/container/exec.go b/pkg/upstream/container/exec.go index ff551008..1ea999ec 100644 --- a/pkg/upstream/container/exec.go +++ b/pkg/upstream/container/exec.go @@ -11,6 +11,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types/container" apiclient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" ) // RunExec runs a command on a remote container. io.Writer corresponds to the @@ -39,7 +40,7 @@ func RunExec(dockerCli command.Cli, client *apiclient.Client, containerID string execID := response.ID if execID == "" { - return nil, errors.New("exec ID empty") + return nil, errors.New(gotext.Get("exec ID empty")) } if execOptions.Detach { @@ -104,12 +105,12 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, client *apiclie if execOpts.Tty && dockerCli.In().IsTerminal() { if err := MonitorTtySize(ctx, client, dockerCli, execID, true); err != nil { - fmt.Fprintln(dockerCli.Err(), "Error monitoring TTY size:", err) + fmt.Fprintln(dockerCli.Err(), gotext.Get("Error monitoring TTY size:"), err) } } if err := <-errCh; err != nil { - log.Debugf("Error hijack: %s", err) + log.Debug(gotext.Get("Error hijack: %s", err)) return out, err } diff --git a/pkg/upstream/container/hijack.go b/pkg/upstream/container/hijack.go index f2a9990e..5332bc91 100644 --- a/pkg/upstream/container/hijack.go +++ b/pkg/upstream/container/hijack.go @@ -2,7 +2,7 @@ package container // https://github.com/docker/cli/blob/master/cli/command/conta import ( "context" - "fmt" + "errors" "io" "runtime" "sync" @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/stdcopy" + "github.com/leonelquinteros/gotext" "github.com/moby/term" ) @@ -39,7 +40,7 @@ type hijackedIOStreamer struct { func (h *hijackedIOStreamer) stream(ctx context.Context) error { restoreInput, err := h.setupInput() if err != nil { - return fmt.Errorf("unable to setup input stream: %s", err) + return errors.New(gotext.Get("unable to setup input stream: %s", err)) } defer restoreInput() @@ -78,7 +79,7 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) { } if err := setRawTerminal(h.streams); err != nil { - return nil, fmt.Errorf("unable to set IO streams as raw terminal: %s", err) + return nil, errors.New(gotext.Get("unable to set IO streams as raw terminal: %s", err)) } // Use sync.Once so we may call restore multiple times but ensure we @@ -96,7 +97,7 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) { if h.detachKeys != "" { customEscapeKeys, err := term.ToBytes(h.detachKeys) if err != nil { - log.Warnf("invalid detach escape keys, using default: %s", err) + log.Warnf(gotext.Get("invalid detach escape keys, using default: %s", err)) } else { escapeKeys = customEscapeKeys } @@ -128,10 +129,10 @@ func (h *hijackedIOStreamer) beginOutputStream(restoreInput func()) <-chan error _, err = stdcopy.StdCopy(h.outputStream, h.errorStream, h.resp.Reader) } - log.Debug("[hijack] End of stdout") + log.Debug(gotext.Get("[hijack] end of stdout")) if err != nil { - log.Debugf("Error receiveStdout: %s", err) + log.Debug(gotext.Get("error receiveStdout: %s", err)) } outputDone <- err @@ -152,7 +153,7 @@ func (h *hijackedIOStreamer) beginInputStream(restoreInput func()) (doneC <-chan // messages will be in normal type. restoreInput() - log.Debug("[hijack] End of stdin") + log.Debug(gotext.Get("[hijack] End of stdin")) if _, ok := err.(term.EscapeError); ok { detached <- err @@ -163,12 +164,12 @@ func (h *hijackedIOStreamer) beginInputStream(restoreInput func()) (doneC <-chan // This error will also occur on the receive // side (from stdout) where it will be // propagated back to the caller. - log.Debugf("Error sendStdin: %s", err) + log.Debug(gotext.Get("error sendStdin: %s", err)) } } if err := h.resp.CloseWrite(); err != nil { - log.Debugf("Couldn't send EOF: %s", err) + log.Debug(gotext.Get("couldn't send EOF: %s", err)) } close(inputDone) diff --git a/pkg/upstream/container/tty.go b/pkg/upstream/container/tty.go index 2a5a55ae..a82311dd 100644 --- a/pkg/upstream/container/tty.go +++ b/pkg/upstream/container/tty.go @@ -13,6 +13,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" apiclient "github.com/docker/docker/client" + "github.com/leonelquinteros/gotext" "github.com/moby/sys/signal" ) @@ -35,7 +36,7 @@ func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id strin } if err != nil { - log.Debugf("Error resize: %s\r", err) + log.Debug(gotext.Get("error resize: %s\r", err)) } return err } @@ -62,7 +63,7 @@ func initTtySize(ctx context.Context, client *apiclient.Client, cli command.Cli, } } if err != nil { - fmt.Fprintln(cli.Err(), "failed to resize tty, using default size") + fmt.Fprintln(cli.Err(), gotext.Get("failed to resize tty, using default size")) } }() } diff --git a/pkg/upstream/convert/service.go b/pkg/upstream/convert/service.go index 16cd0cfa..f23a4fc2 100644 --- a/pkg/upstream/convert/service.go +++ b/pkg/upstream/convert/service.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/api/types/versions" "github.com/docker/docker/client" "github.com/docker/go-units" + "github.com/leonelquinteros/gotext" "github.com/pkg/errors" ) @@ -39,7 +40,7 @@ func ParseSecrets(client client.SecretAPIClient, requestedSecrets []*swarmtypes. for _, secret := range requestedSecrets { if _, exists := secretRefs[secret.File.Name]; exists { - return nil, errors.Errorf("duplicate secret target for %s not allowed", secret.SecretName) + return nil, errors.New(gotext.Get("duplicate secret target for %s not allowed", secret.SecretName)) } secretRef := new(swarmtypes.SecretReference) *secretRef = *secret @@ -68,7 +69,7 @@ func ParseSecrets(client client.SecretAPIClient, requestedSecrets []*swarmtypes. for _, ref := range secretRefs { id, ok := foundSecrets[ref.SecretName] if !ok { - return nil, errors.Errorf("secret not found: %s", ref.SecretName) + return nil, errors.New(gotext.Get("secret not found: %s", ref.SecretName)) } // set the id for the ref to properly assign in swarm @@ -118,7 +119,7 @@ func ParseConfigs(client client.ConfigAPIClient, requestedConfigs []*swarmtypes. } if _, exists := configRefs[config.File.Name]; exists { - return nil, errors.Errorf("duplicate config target for %s not allowed", config.ConfigName) + return nil, errors.New(gotext.Get("duplicate config target for %s not allowed", config.ConfigName)) } configRefs[config.File.Name] = configRef @@ -149,7 +150,7 @@ func ParseConfigs(client client.ConfigAPIClient, requestedConfigs []*swarmtypes. for _, ref := range configRefs { id, ok := foundConfigs[ref.ConfigName] if !ok { - return nil, errors.Errorf("config not found: %s", ref.ConfigName) + return nil, errors.New(gotext.Get("config not found: %s", ref.ConfigName)) } // set the id for the ref to properly assign in swarm @@ -164,7 +165,7 @@ func ParseConfigs(client client.ConfigAPIClient, requestedConfigs []*swarmtypes. for _, ref := range runtimeRefs { id, ok := foundConfigs[ref.ConfigName] if !ok { - return nil, errors.Errorf("config not found: %s", ref.ConfigName) + return nil, errors.New(gotext.Get("config not found: %s", ref.ConfigName)) } ref.ConfigID = id @@ -371,7 +372,7 @@ func convertServiceNetworks( for networkName, network := range networks { networkConfig, ok := networkConfigs[networkName] if !ok && networkName != defaultNetwork { - return nil, errors.Errorf("undefined network %q", networkName) + return nil, errors.New(gotext.Get("undefined network %q", networkName)) } var aliases []string if network != nil { @@ -410,7 +411,7 @@ func convertServiceSecrets( lookup := func(key string) (composetypes.FileObjectConfig, error) { secretSpec, exists := secretSpecs[key] if !exists { - return composetypes.FileObjectConfig{}, errors.Errorf("undefined secret %q", key) + return composetypes.FileObjectConfig{}, errors.New(gotext.Get("undefined secret %q", key)) } return composetypes.FileObjectConfig(secretSpec), nil } @@ -458,7 +459,7 @@ func convertServiceConfigObjs( lookup := func(key string) (composetypes.FileObjectConfig, error) { configSpec, exists := configSpecs[key] if !exists { - return composetypes.FileObjectConfig{}, errors.Errorf("undefined config %q", key) + return composetypes.FileObjectConfig{}, errors.New(gotext.Get("undefined config %q", key)) } return composetypes.FileObjectConfig(configSpec), nil } @@ -600,7 +601,7 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container ) if healthcheck.Disable { if len(healthcheck.Test) != 0 { - return nil, errors.Errorf("test and disable can't be set at the same time") + return nil, errors.New(gotext.Get("test and disable can't be set at the same time")) } return &container.HealthConfig{ Test: []string{"NONE"}, @@ -648,7 +649,7 @@ func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (* MaxAttempts: &attempts, }, nil default: - return nil, errors.Errorf("unknown restart policy: %s", restart) + return nil, errors.New(gotext.Get("unknown restart policy: %s", restart)) } } @@ -770,13 +771,13 @@ func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) switch mode { case "global": if replicas != nil { - return serviceMode, errors.Errorf("replicas can only be used with replicated mode") + return serviceMode, errors.New(gotext.Get("replicas can only be used with replicated mode")) } serviceMode.Global = &swarm.GlobalService{} case "replicated", "": serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas} default: - return serviceMode, errors.Errorf("Unknown mode: %s", mode) + return serviceMode, errors.New(gotext.Get("unknown mode: %s", mode)) } return serviceMode, nil } @@ -809,9 +810,9 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec case l == 0: return nil, nil case l == 2: - return nil, errors.Errorf("invalid credential spec: cannot specify both %s and %s", o[0], o[1]) + return nil, errors.New(gotext.Get("invalid credential spec: cannot specify both %s and %s", o[0], o[1])) case l > 2: - return nil, errors.Errorf("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1]) + return nil, errors.New(gotext.Get("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1])) } swarmCredSpec := swarm.CredentialSpec(spec) // if we're using a swarm Config for the credential spec, over-write it @@ -830,7 +831,7 @@ func convertCredentialSpec(namespace Namespace, spec composetypes.CredentialSpec return &swarmCredSpec, nil } } - return nil, errors.Errorf("invalid credential spec: spec specifies config %v, but no such config can be found", swarmCredSpec.Config) + return nil, errors.New(gotext.Get("invalid credential spec: spec specifies config %v, but no such config can be found", swarmCredSpec.Config)) } return &swarmCredSpec, nil } diff --git a/pkg/upstream/convert/volume.go b/pkg/upstream/convert/volume.go index 387fb727..ea3c2c46 100644 --- a/pkg/upstream/convert/volume.go +++ b/pkg/upstream/convert/volume.go @@ -3,6 +3,7 @@ package convert // https://github.com/docker/cli/blob/master/cli/compose/convert import ( composetypes "github.com/docker/cli/cli/compose/types" "github.com/docker/docker/api/types/mount" + "github.com/leonelquinteros/gotext" "github.com/pkg/errors" ) @@ -40,10 +41,10 @@ func handleVolumeToMount( result := createMountFromVolume(volume) if volume.Tmpfs != nil { - return mount.Mount{}, errors.New("tmpfs options are incompatible with type volume") + return mount.Mount{}, errors.New(gotext.Get("tmpfs options are incompatible with type volume")) } if volume.Bind != nil { - return mount.Mount{}, errors.New("bind options are incompatible with type volume") + return mount.Mount{}, errors.New(gotext.Get("bind options are incompatible with type volume")) } // Anonymous volumes if volume.Source == "" { @@ -52,7 +53,7 @@ func handleVolumeToMount( stackVolume, exists := stackVolumes[volume.Source] if !exists { - return mount.Mount{}, errors.Errorf("undefined volume %q", volume.Source) + return mount.Mount{}, errors.New(gotext.Get("undefined volume %q", volume.Source)) } result.Source = namespace.Scope(volume.Source) @@ -86,13 +87,13 @@ func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, er result := createMountFromVolume(volume) if volume.Source == "" { - return mount.Mount{}, errors.New("invalid bind source, source cannot be empty") + return mount.Mount{}, errors.New(gotext.Get("invalid bind source, source cannot be empty")) } if volume.Volume != nil { - return mount.Mount{}, errors.New("volume options are incompatible with type bind") + return mount.Mount{}, errors.New(gotext.Get("volume options are incompatible with type bind")) } if volume.Tmpfs != nil { - return mount.Mount{}, errors.New("tmpfs options are incompatible with type bind") + return mount.Mount{}, errors.New(gotext.Get("tmpfs options are incompatible with type bind")) } if volume.Bind != nil { result.BindOptions = &mount.BindOptions{ @@ -106,13 +107,13 @@ func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e result := createMountFromVolume(volume) if volume.Source != "" { - return mount.Mount{}, errors.New("invalid tmpfs source, source must be empty") + return mount.Mount{}, errors.New(gotext.Get("invalid tmpfs source, source must be empty")) } if volume.Bind != nil { - return mount.Mount{}, errors.New("bind options are incompatible with type tmpfs") + return mount.Mount{}, errors.New(gotext.Get("bind options are incompatible with type tmpfs")) } if volume.Volume != nil { - return mount.Mount{}, errors.New("volume options are incompatible with type tmpfs") + return mount.Mount{}, errors.New(gotext.Get("volume options are incompatible with type tmpfs")) } if volume.Tmpfs != nil { result.TmpfsOptions = &mount.TmpfsOptions{ @@ -126,13 +127,13 @@ func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e result := createMountFromVolume(volume) if volume.Source == "" { - return mount.Mount{}, errors.New("invalid npipe source, source cannot be empty") + return mount.Mount{}, errors.New(gotext.Get("invalid npipe source, source cannot be empty")) } if volume.Volume != nil { - return mount.Mount{}, errors.New("volume options are incompatible with type npipe") + return mount.Mount{}, errors.New(gotext.Get("volume options are incompatible with type npipe")) } if volume.Tmpfs != nil { - return mount.Mount{}, errors.New("tmpfs options are incompatible with type npipe") + return mount.Mount{}, errors.New(gotext.Get("tmpfs options are incompatible with type npipe")) } if volume.Bind != nil { result.BindOptions = &mount.BindOptions{ @@ -158,5 +159,5 @@ func convertVolumeToMount( case "npipe": return handleNpipeToMount(volume) } - return mount.Mount{}, errors.New("volume type must be volume, bind, tmpfs or npipe") + return mount.Mount{}, errors.New(gotext.Get("volume type must be volume, bind, tmpfs or npipe")) } diff --git a/pkg/web/web.go b/pkg/web/web.go index b1f871ab..982eaa47 100644 --- a/pkg/web/web.go +++ b/pkg/web/web.go @@ -3,11 +3,13 @@ package web import ( "encoding/json" - "fmt" + "errors" "io" "net/http" "os" "time" + + "github.com/leonelquinteros/gotext" ) // Timeout is the time it takes before a web request bails out waiting for a @@ -40,7 +42,7 @@ func GetFile(filepath string, url string) (err error) { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return fmt.Errorf("bad status: %s", resp.Status) + return errors.New(gotext.Get("bad status: %s", resp.Status)) } _, err = io.Copy(out, resp.Body) diff --git a/vendor/modules.txt b/vendor/modules.txt index b6d67d59..0595f6a0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,8 +7,6 @@ dario.cat/mergo # git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c ## explicit; go 1.12 git.coopcloud.tech/toolshed/godotenv -# github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 -## explicit; go 1.20 # github.com/AlecAivazis/survey/v2 v2.3.7 ## explicit; go 1.13 github.com/AlecAivazis/survey/v2 @@ -237,8 +235,6 @@ github.com/docker/docker/pkg/streamformatter ## explicit; go 1.21 github.com/docker/docker-credential-helpers/client github.com/docker/docker-credential-helpers/credentials -# github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c -## explicit # github.com/docker/go-connections v0.6.0 ## explicit; go 1.18 github.com/docker/go-connections/nat @@ -267,8 +263,6 @@ github.com/erikgeiser/coninput # github.com/felixge/httpsnoop v1.0.4 ## explicit; go 1.13 github.com/felixge/httpsnoop -# github.com/fsnotify/fsnotify v1.6.0 -## explicit; go 1.16 # github.com/fvbommel/sortorder v1.1.0 ## explicit; go 1.13 github.com/fvbommel/sortorder @@ -433,8 +427,6 @@ github.com/mgutz/ansi # github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db ## explicit github.com/mitchellh/colorstring -# github.com/mitchellh/mapstructure v1.5.0 -## explicit; go 1.14 # github.com/moby/docker-image-spec v1.3.1 ## explicit; go 1.18 github.com/moby/docker-image-spec/specs-go/v1 @@ -449,8 +441,6 @@ github.com/moby/patternmatcher # github.com/moby/sys/atomicwriter v0.1.0 ## explicit; go 1.18 github.com/moby/sys/atomicwriter -# github.com/moby/sys/mountinfo v0.7.2 -## explicit; go 1.17 # github.com/moby/sys/sequential v0.6.0 ## explicit; go 1.17 github.com/moby/sys/sequential @@ -494,8 +484,6 @@ github.com/opencontainers/image-spec/specs-go/v1 ## explicit; go 1.18 # github.com/opencontainers/runtime-spec v1.1.0 ## explicit -# github.com/pelletier/go-toml v1.9.5 -## explicit; go 1.12 # github.com/pjbgf/sha1cd v0.4.0 ## explicit; go 1.21 github.com/pjbgf/sha1cd