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/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..59533db3 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.Debugf(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.Debugf(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..6f43b125 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.Debugf(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..414138e5 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.Debugf(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..f34053b4 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.Debugf(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.Debugf(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.Debugf(gotext.Get("error loading config file: %s", err)) return Abra{} } - log.Debugf("config file loaded from: %s", configFile) + log.Debugf(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..4de9d1e3 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.Debugf(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.Debugf(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..260f46ed 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.Debugf(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.Debugf(gotext.Get("read %s from %s", envVars, abraSh)) } else { - log.Debugf("read 0 env var exports from %s", abraSh) + log.Debugf(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..1f67a09c 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.Debugf(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..4cc5bbf4 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.Debugf(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..6365ab2b 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.Debugf(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.Debugf(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..a629e914 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.Debugf(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.Debugf(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.Debugf(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.Debugf(gotext.Get("git clone: %s cloned successfully", dir)) } else { - log.Debugf("git clone: %s already exists", dir) + log.Debugf(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..3e216b74 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.Debugf(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.Debugf(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..fc026a20 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.Debugf(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.Debugf(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.Debugf(gotext.Get("git tags pushed")) } return nil diff --git a/pkg/git/read.go b/pkg/git/read.go index b2991357..82f4e9eb 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.Debugf(gotext.Get("git status: %s: %s", repoPath, noNewline)) } else { - log.Debugf("git status: %s: clean", repoPath) + log.Debugf(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.Debugf(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.Debugf(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.Debugf(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..6e7cc931 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.Debugf(gotext.Get("dry run: remote %s (%s) not created", name, url)) return nil }