feat: translation support
All checks were successful
continuous-integration/drone/push Build is passing

See #483
This commit is contained in:
2025-08-19 11:22:52 +02:00
parent 5cf6048ecb
commit 53342a5dd4
25 changed files with 142 additions and 113 deletions

View File

@ -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) [![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 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) [![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 🎩🐇 The Co-op Cloud utility belt 🎩🐇

View File

@ -1,12 +1,12 @@
package autocomplete package autocomplete
import ( import (
"fmt"
"sort" "sort"
"coopcloud.tech/abra/pkg/app" "coopcloud.tech/abra/pkg/app"
appPkg "coopcloud.tech/abra/pkg/app" appPkg "coopcloud.tech/abra/pkg/app"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -14,7 +14,7 @@ import (
func AppNameComplete() ([]string, cobra.ShellCompDirective) { func AppNameComplete() ([]string, cobra.ShellCompDirective) {
appFiles, err := app.LoadAppFiles("") appFiles, err := app.LoadAppFiles("")
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -29,7 +29,7 @@ func AppNameComplete() ([]string, cobra.ShellCompDirective) {
func ServiceNameComplete(appName string) ([]string, cobra.ShellCompDirective) { func ServiceNameComplete(appName string) ([]string, cobra.ShellCompDirective) {
serviceNames, err := app.GetAppServiceNames(appName) serviceNames, err := app.GetAppServiceNames(appName)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -40,7 +40,7 @@ func ServiceNameComplete(appName string) ([]string, cobra.ShellCompDirective) {
func RecipeNameComplete() ([]string, cobra.ShellCompDirective) { func RecipeNameComplete() ([]string, cobra.ShellCompDirective) {
catl, err := recipe.ReadRecipeCatalogue(false) catl, err := recipe.ReadRecipeCatalogue(false)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -56,7 +56,7 @@ func RecipeNameComplete() ([]string, cobra.ShellCompDirective) {
func RecipeVersionComplete(recipeName string) ([]string, cobra.ShellCompDirective) { func RecipeVersionComplete(recipeName string) ([]string, cobra.ShellCompDirective) {
catl, err := recipe.ReadRecipeCatalogue(true) catl, err := recipe.ReadRecipeCatalogue(true)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -74,7 +74,7 @@ func RecipeVersionComplete(recipeName string) ([]string, cobra.ShellCompDirectiv
func ServerNameComplete() ([]string, cobra.ShellCompDirective) { func ServerNameComplete() ([]string, cobra.ShellCompDirective) {
files, err := app.LoadAppFiles("") files, err := app.LoadAppFiles("")
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -90,13 +90,13 @@ func ServerNameComplete() ([]string, cobra.ShellCompDirective) {
func CommandNameComplete(appName string) ([]string, cobra.ShellCompDirective) { func CommandNameComplete(appName string) ([]string, cobra.ShellCompDirective) {
app, err := app.Get(appName) app, err := app.Get(appName)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
cmdNames, err := appPkg.ReadAbraShCmdNames(app.Recipe.AbraShPath) cmdNames, err := appPkg.ReadAbraShCmdNames(app.Recipe.AbraShPath)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }
@ -111,7 +111,7 @@ func SecretComplete(recipeName string) ([]string, cobra.ShellCompDirective) {
config, err := r.GetComposeConfig(nil) config, err := r.GetComposeConfig(nil)
if err != nil { if err != nil {
err := fmt.Sprintf("autocomplete failed: %s", err) err := gotext.Get("autocomplete failed: %s", err)
return []string{err}, cobra.ShellCompDirectiveError return []string{err}, cobra.ShellCompDirectiveError
} }

View File

@ -1,6 +1,7 @@
package catalogue package catalogue
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path" "path"
@ -10,13 +11,14 @@ import (
gitPkg "coopcloud.tech/abra/pkg/git" gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/leonelquinteros/gotext"
) )
// EnsureCatalogue ensures that the catalogue is cloned locally & present. // EnsureCatalogue ensures that the catalogue is cloned locally & present.
func EnsureCatalogue() error { func EnsureCatalogue() error {
catalogueDir := path.Join(config.ABRA_DIR, "catalogue") catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
if _, err := os.Stat(catalogueDir); err != nil && os.IsNotExist(err) { 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) url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, config.CATALOGUE_JSON_REPO_NAME)
if err := gitPkg.Clone(catalogueDir, url); err != nil { if err := gitPkg.Clone(catalogueDir, url); err != nil {
@ -35,8 +37,7 @@ func EnsureIsClean() error {
} }
if !isClean { if !isClean {
msg := "%s has locally unstaged changes? please commit/remove your changes before proceeding" return errors.New(gotext.Get("%s has locally unstaged changes? please commit/remove your changes before proceeding", config.CATALOGUE_DIR))
return fmt.Errorf(msg, config.CATALOGUE_DIR)
} }
return nil return nil
@ -55,8 +56,7 @@ func EnsureUpToDate() error {
} }
if len(remotes) == 0 { if len(remotes) == 0 {
msg := "cannot ensure %s is up-to-date, no git remotes configured" log.Debugf(gotext.Get("cannot ensure %s is up-to-date, no git remotes configured", config.CATALOGUE_DIR))
log.Debugf(msg, config.CATALOGUE_DIR)
return nil 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 return nil
} }

View File

@ -4,7 +4,6 @@ package client
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net/http" "net/http"
"os" "os"
"time" "time"
@ -14,6 +13,7 @@ import (
sshPkg "coopcloud.tech/abra/pkg/ssh" sshPkg "coopcloud.tech/abra/pkg/ssh"
commandconnPkg "coopcloud.tech/abra/pkg/upstream/commandconn" commandconnPkg "coopcloud.tech/abra/pkg/upstream/commandconn"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/leonelquinteros/gotext"
) )
// Conf is a Docker client configuration. // Conf is a Docker client configuration.
@ -41,7 +41,7 @@ func New(serverName string, opts ...Opt) (*client.Client, error) {
if serverName != "default" { if serverName != "default" {
context, err := GetContext(serverName) context, err := GetContext(serverName)
if err != nil { 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) ctxEndpoint, err := contextPkg.GetContextEndpoint(context)
@ -85,7 +85,7 @@ func New(serverName string, opts ...Opt) (*client.Client, error) {
return nil, err 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()) info, err := cl.Info(context.Background())
if err != nil { if err != nil {
@ -94,10 +94,10 @@ func New(serverName string, opts ...Opt) (*client.Client, error) {
if info.Swarm.LocalNodeState == "inactive" { if info.Swarm.LocalNodeState == "inactive" {
if serverName != "default" { 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 return cl, nil

View File

@ -2,11 +2,12 @@ package client
import ( import (
"context" "context"
"fmt" "errors"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client" "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) { 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 { func RemoveConfigs(cl *client.Client, ctx context.Context, configNames []string, force bool) error {
for _, confName := range configNames { for _, confName := range configNames {
if err := cl.ConfigRemove(context.Background(), confName); err != nil { 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 return nil

View File

@ -10,6 +10,7 @@ import (
dConfig "github.com/docker/cli/cli/config" dConfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/context/docker" "github.com/docker/cli/cli/context/docker"
contextStore "github.com/docker/cli/cli/context/store" contextStore "github.com/docker/cli/cli/context/store"
"github.com/leonelquinteros/gotext"
) )
type Context = contextStore.Metadata type Context = contextStore.Metadata
@ -22,7 +23,7 @@ func CreateContext(contextName string) error {
return err return err
} }
log.Debugf("created the %s context", contextName) log.Debugf(gotext.Get("created the %s context", contextName))
return nil return nil
} }
@ -62,7 +63,7 @@ func createContext(name string, host string) error {
func DeleteContext(name string) error { func DeleteContext(name string) error {
if name == "default" { 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 { if _, err := GetContext(name); err != nil {

View File

@ -2,11 +2,13 @@ package client
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/containers/image/docker" "github.com/containers/image/docker"
"github.com/containers/image/types" "github.com/containers/image/types"
"github.com/distribution/reference" "github.com/distribution/reference"
"github.com/leonelquinteros/gotext"
) )
// GetRegistryTags retrieves all tags of an image from a container registry. // 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)) ref, err := docker.ParseReference(fmt.Sprintf("//%s", img))
if err != nil { 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() ctx := context.Background()

View File

@ -2,6 +2,7 @@ package client
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"time" "time"
@ -9,6 +10,7 @@ import (
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume" "github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client" "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) { 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 { if i+1 < retries {
sleep := time.Duration(i+1) * time.Duration(i+1) 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) time.Sleep(sleep * time.Second)
} }
} }
return fmt.Errorf("%d retries failed", retries) return errors.New(gotext.Get("%d retries failed", retries))
} }

View File

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/leonelquinteros/gotext"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -16,13 +17,13 @@ func LoadAbraConfig() Abra {
wd, _ := os.Getwd() wd, _ := os.Getwd()
configFile := findAbraConfig(wd) configFile := findAbraConfig(wd)
if configFile == "" { if configFile == "" {
log.Debugf("no config file found") log.Debugf(gotext.Get("no config file found"))
return Abra{} return Abra{}
} }
data, err := os.ReadFile(configFile) data, err := os.ReadFile(configFile)
if err != nil { if err != nil {
// Do nothing, when an error occurs // 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{} return Abra{}
} }
@ -30,10 +31,10 @@ func LoadAbraConfig() Abra {
err = yaml.Unmarshal(data, &config) err = yaml.Unmarshal(data, &config)
if err != nil { if err != nil {
// Do nothing, when an error occurs // 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{} 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) config.configPath = filepath.Dir(configFile)
return config return config
} }
@ -73,26 +74,24 @@ type Abra struct {
// 3. use $HOME/.abra when above two options failed // 3. use $HOME/.abra when above two options failed
func (a Abra) GetAbraDir() string { func (a Abra) GetAbraDir() string {
if dir, exists := os.LookupEnv("ABRA_DIR"); exists && dir != "" { 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 return dir
} }
if a.AbraDir != "" { 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) { if path.IsAbs(a.AbraDir) {
return a.AbraDir return a.AbraDir
} }
// Make the path absolute // Make the path absolute
return path.Join(a.configPath, a.AbraDir) 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") return os.ExpandEnv("$HOME/.abra")
} }
func (a Abra) GetServersDir() string { return path.Join(a.GetAbraDir(), "servers") } 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) GetRecipesDir() string { return path.Join(a.GetAbraDir(), "recipes") }
func (a Abra) GetLogsDir() string { return path.Join(a.GetAbraDir(), "logs") } 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") } func (a Abra) GetCatalogueDir() string { return path.Join(a.GetAbraDir(), "catalogue") }
var config = LoadAbraConfig() var config = LoadAbraConfig()
@ -102,8 +101,6 @@ var (
SERVERS_DIR = config.GetServersDir() SERVERS_DIR = config.GetServersDir()
RECIPES_DIR = config.GetRecipesDir() RECIPES_DIR = config.GetRecipesDir()
LOGS_DIR = config.GetLogsDir() LOGS_DIR = config.GetLogsDir()
VENDOR_DIR = config.GetVendorDir()
BACKUP_DIR = config.GetBackupDir()
CATALOGUE_DIR = config.GetCatalogueDir() CATALOGUE_DIR = config.GetCatalogueDir()
RECIPES_JSON = path.Join(config.GetCatalogueDir(), "recipes.json") RECIPES_JSON = path.Join(config.GetCatalogueDir(), "recipes.json")
REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud" REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud"

View File

@ -1,7 +1,7 @@
package config package config
import ( import (
"fmt" "errors"
"io/fs" "io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
@ -10,6 +10,7 @@ import (
"strings" "strings"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/leonelquinteros/gotext"
) )
const MAX_SANITISED_APP_NAME_LENGTH = 45 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 return filtered, nil
} }
@ -46,7 +47,7 @@ func ReadServerNames() ([]string, error) {
return nil, err 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 return serverNames, nil
} }
@ -70,7 +71,7 @@ func GetAllFilesInDirectory(directory string) ([]fs.FileInfo, error) {
realPath, err := filepath.EvalSymlinks(filePath) realPath, err := filepath.EvalSymlinks(filePath)
if err != nil { 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 { } else {
realFile, err := os.Stat(realPath) realFile, err := os.Stat(realPath)
if err != nil { if err != nil {
@ -94,7 +95,7 @@ func GetAllFoldersInDirectory(directory string) ([]string, error) {
return nil, err return nil, err
} }
if len(files) == 0 { 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 { for _, file := range files {
@ -103,7 +104,7 @@ func GetAllFoldersInDirectory(directory string) ([]string, error) {
filePath := path.Join(directory, file.Name()) filePath := path.Join(directory, file.Name())
realDir, err := filepath.EvalSymlinks(filePath) realDir, err := filepath.EvalSymlinks(filePath)
if err != nil { 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() { } else if stat, err := os.Stat(realDir); err == nil && stat.IsDir() {
// path is a directory // path is a directory
folders = append(folders, file.Name()) folders = append(folders, file.Name())

View File

@ -2,6 +2,7 @@ package container
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
@ -12,6 +13,7 @@ import (
containerTypes "github.com/docker/docker/api/types/container" containerTypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/leonelquinteros/gotext"
) )
// GetContainer retrieves a container. If noInput is false and the retrievd // 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 { if len(containers) == 0 {
filter := filters.Get("name")[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 { 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, " ") containerName := strings.Join(container.Names, " ")
trimmed := strings.TrimPrefix(containerName, "/") trimmed := strings.TrimPrefix(containerName, "/")
created := formatter.HumanDuration(container.Created) 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 { 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 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 var response string
prompt := &survey.Select{ prompt := &survey.Select{
Message: "which container are you looking for?", Message: gotext.Get("which container are you looking for?"),
Options: containersRaw, 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 return containers[0], nil
@ -79,5 +81,6 @@ func GetContainerFromStackAndService(cl *client.Client, stack, service string) (
if err != nil { if err != nil {
return types.Container{}, err return types.Container{}, err
} }
return container, nil return container, nil
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli/context" "github.com/docker/cli/cli/context"
contextStore "github.com/docker/cli/cli/context/store" contextStore "github.com/docker/cli/cli/context/store"
cliflags "github.com/docker/cli/cli/flags" cliflags "github.com/docker/cli/cli/flags"
"github.com/leonelquinteros/gotext"
) )
func NewDefaultDockerContextStore() *command.ContextStoreWithDefault { func NewDefaultDockerContextStore() *command.ContextStoreWithDefault {
@ -30,7 +31,7 @@ func NewDefaultDockerContextStore() *command.ContextStoreWithDefault {
func GetContextEndpoint(ctx contextStore.Metadata) (string, error) { func GetContextEndpoint(ctx contextStore.Metadata) (string, error) {
endpointmeta, ok := ctx.Endpoints["docker"].(context.EndpointMetaBase) endpointmeta, ok := ctx.Endpoints["docker"].(context.EndpointMetaBase)
if !ok { if !ok {
err := errors.New("context lacks Docker endpoint") err := errors.New(gotext.Get("context lacks Docker endpoint"))
return "", err return "", err
} }
return endpointmeta.Host, nil return endpointmeta.Host, nil

View File

@ -1,19 +1,21 @@
package dns package dns
import ( import (
"fmt" "errors"
"net" "net"
"github.com/leonelquinteros/gotext"
) )
// EnsureIPv4 ensures that an ipv4 address is set for a domain name // EnsureIPv4 ensures that an ipv4 address is set for a domain name
func EnsureIPv4(domainName string) (string, error) { func EnsureIPv4(domainName string) (string, error) {
ipv4, err := net.ResolveIPAddr("ip4", domainName) ipv4, err := net.ResolveIPAddr("ip4", domainName)
if err != nil { 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 { 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 return ipv4.String(), nil
@ -33,7 +35,7 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) {
} }
if domainIPv4 == "" { 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) serverIPv4, err := EnsureIPv4(server)
@ -42,12 +44,16 @@ func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) {
} }
if serverIPv4 == "" { 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 { if domainIPv4 != serverIPv4 {
err := "app domain %s (%s) does not appear to resolve to app server %s (%s)?" return ipv4, errors.New(
return ipv4, fmt.Errorf(err, domainName, domainIPv4, server, serverIPv4) gotext.Get(
"app domain %s (%s) does not appear to resolve to app server %s (%s)?",
domainName, domainIPv4, server, serverIPv4,
),
)
} }
return ipv4, nil return ipv4, nil

View File

@ -2,13 +2,14 @@ package envfile
import ( import (
"bufio" "bufio"
"fmt" "errors"
"os" "os"
"regexp" "regexp"
"strings" "strings"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"git.coopcloud.tech/toolshed/godotenv" "git.coopcloud.tech/toolshed/godotenv"
"github.com/leonelquinteros/gotext"
) )
// AppEnv is a map of the values in an apps env config // 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 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 return envVars, mods, nil
} }
@ -69,16 +70,16 @@ func ReadAbraShEnvVars(abraSh string) (map[string]string, error) {
envVarDef := splitVals[len(splitVals)-1] envVarDef := splitVals[len(splitVals)-1]
keyVal := strings.Split(envVarDef, "=") keyVal := strings.Split(envVarDef, "=")
if len(keyVal) != 2 { 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] envVars[keyVal[0]] = keyVal[1]
} }
} }
if len(envVars) > 0 { if len(envVars) > 0 {
log.Debugf("read %s from %s", envVars, abraSh) log.Debugf(gotext.Get("read %s from %s", envVars, abraSh))
} else { } 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 return envVars, nil

View File

@ -11,6 +11,7 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table" "github.com/charmbracelet/lipgloss/table"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/leonelquinteros/gotext"
"golang.org/x/term" "golang.org/x/term"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
@ -42,7 +43,7 @@ func RemoveSha(str string) string {
func HumanDuration(timestamp int64) string { func HumanDuration(timestamp int64) string {
date := time.Unix(timestamp, 0) date := time.Unix(timestamp, 0)
now := time.Now().UTC() 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. // CreateTable prepares a table layout for output.
@ -76,7 +77,7 @@ func CreateTable() (*table.Table, error) {
func PrintTable(t *table.Table) error { func PrintTable(t *table.Table) error {
if isAbraCI, ok := os.LookupEnv("ABRA_CI"); ok && isAbraCI == "1" { if isAbraCI, ok := os.LookupEnv("ABRA_CI"); ok && isAbraCI == "1" {
// NOTE(d1): no width limits for CI testing since we test against outputs // 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) fmt.Println(t)
return nil return nil
} }
@ -130,7 +131,7 @@ func CreateOverview(header string, rows [][]string) string {
} }
if len(row) > 2 { if len(row) > 2 {
panic("CreateOverview: only accepts rows of len == 2") panic(gotext.Get("CreateOverview: only accepts rows of len == 2"))
} }
lenOffset := 4 lenOffset := 4
@ -234,7 +235,7 @@ func StripTagMeta(image string) string {
} }
if originalImage != image { 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 return image

View File

@ -3,6 +3,7 @@ package git
import ( import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/leonelquinteros/gotext"
) )
// Add adds a file to the git index. // Add adds a file to the git index.
@ -18,7 +19,7 @@ func Add(repoPath, path string, dryRun bool) error {
} }
if dryRun { if dryRun {
log.Debugf("dry run: adding %s", path) log.Debugf(gotext.Get("dry run: adding %s", path))
} else { } else {
worktree.Add(path) worktree.Add(path)
} }

View File

@ -1,11 +1,13 @@
package git package git
import ( import (
"errors"
"fmt" "fmt"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "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(), // 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, "master") {
if !HasBranch(repo, "main") { 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" branch = "main"
} }
@ -90,11 +92,11 @@ func CheckoutDefaultBranch(repo *git.Repository, repoPath string) (plumbing.Refe
} }
if err := worktree.Checkout(checkOutOpts); err != nil { 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 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 return branch, nil
} }

View File

@ -2,6 +2,7 @@ package git
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
@ -10,6 +11,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/leonelquinteros/gotext"
) )
// gitCloneIgnoreErr checks whether we can ignore a git clone error or not. // gitCloneIgnoreErr checks whether we can ignore a git clone error or not.
@ -44,7 +46,7 @@ func Clone(dir, url string) error {
go func() { go func() {
if _, err := os.Stat(dir); os.IsNotExist(err) { 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{ _, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
URL: url, URL: url,
@ -54,16 +56,16 @@ func Clone(dir, url string) error {
}) })
if err != nil && gitCloneIgnoreErr(err) { 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 errCh <- nil
} }
if err := ctx.Err(); err != 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 { 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{ _, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
URL: url, URL: url,
@ -73,7 +75,7 @@ func Clone(dir, url string) error {
}) })
if err != nil && gitCloneIgnoreErr(err) { 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 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 { } else {
log.Debugf("git clone: %s already exists", dir) log.Debugf(gotext.Get("git clone: %s already exists", dir))
} }
errCh <- nil errCh <- nil
@ -95,9 +97,9 @@ func Clone(dir, url string) error {
cancelCtx() cancelCtx()
fmt.Println() // NOTE(d1): newline after ^C fmt.Println() // NOTE(d1): newline after ^C
if err := os.RemoveAll(dir); err != nil { 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: case err := <-errCh:
return err return err
} }

View File

@ -1,16 +1,17 @@
package git package git
import ( import (
"fmt" "errors"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/leonelquinteros/gotext"
) )
// Commit runs a git commit // Commit runs a git commit
func Commit(repoPath, commitMessage string, dryRun bool) error { func Commit(repoPath, commitMessage string, dryRun bool) error {
if commitMessage == "" { if commitMessage == "" {
return fmt.Errorf("no commit message specified?") return errors.New(gotext.Get("no commit message specified?"))
} }
commitRepo, err := git.PlainOpen(repoPath) commitRepo, err := git.PlainOpen(repoPath)
@ -38,9 +39,9 @@ func Commit(repoPath, commitMessage string, dryRun bool) error {
if err != nil { if err != nil {
return err return err
} }
log.Debug("git changes commited") log.Debug(gotext.Get("git changes commited"))
} else { } else {
log.Debug("dry run: no changes commited") log.Debug(gotext.Get("dry run: no changes commited"))
} }
return nil return nil

View File

@ -1,14 +1,16 @@
package git package git
import ( import (
"fmt" "errors"
"os" "os"
"github.com/leonelquinteros/gotext"
) )
// EnsureGitRepo ensures a git repo .git folder exists // EnsureGitRepo ensures a git repo .git folder exists
func EnsureGitRepo(repoPath string) error { func EnsureGitRepo(repoPath string) error {
if _, err := os.Stat(repoPath); os.IsNotExist(err) { 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 return nil
} }

View File

@ -5,6 +5,7 @@ import (
"os/exec" "os/exec"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/leonelquinteros/gotext"
) )
// getGitDiffArgs builds the `git diff` invocation args. It removes the usage // 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. // skips if it cannot find the command on the system.
func DiffUnstaged(path string) error { func DiffUnstaged(path string) error {
if _, err := exec.LookPath("git"); err != nil { 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 return nil
} }

View File

@ -1,40 +1,41 @@
package git package git
import ( import (
"fmt" "errors"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object" "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 // Init inits a new repo and commits all the stuff if you want
func Init(repoPath string, commit bool, gitName, gitEmail string) error { func Init(repoPath string, commit bool, gitName, gitEmail string) error {
repo, err := git.PlainInit(repoPath, false) repo, err := git.PlainInit(repoPath, false)
if err != nil { 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 { 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 { if commit {
commitRepo, err := git.PlainOpen(repoPath) commitRepo, err := git.PlainOpen(repoPath)
if err != nil { if err != nil {
return fmt.Errorf("git open: %s", err) return errors.New(gotext.Get("git open: %s", err))
} }
commitWorktree, err := commitRepo.Worktree() commitWorktree, err := commitRepo.Worktree()
if err != nil { 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 { 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 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 { 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 return nil
@ -56,20 +57,20 @@ func Init(repoPath string, commit bool, gitName, gitEmail string) error {
func SwitchToMain(repo *git.Repository) error { func SwitchToMain(repo *git.Repository) error {
ref := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.ReferenceName("refs/heads/main")) ref := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.ReferenceName("refs/heads/main"))
if err := repo.Storer.SetReference(ref); err != nil { 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() cfg, err := repo.Config()
if err != nil { if err != nil {
return fmt.Errorf("repo config: %s", err) return errors.New(gotext.Get("repo config: %s", err))
} }
cfg.Init.DefaultBranch = "main" cfg.Init.DefaultBranch = "main"
if err := repo.SetConfig(cfg); err != nil { 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 return nil
} }

View File

@ -4,12 +4,13 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/config"
"github.com/leonelquinteros/gotext"
) )
// Push pushes the latest changes & optionally tags to the default remote // Push pushes the latest changes & optionally tags to the default remote
func Push(repoDir string, remote string, tags bool, dryRun bool) error { func Push(repoDir string, remote string, tags bool, dryRun bool) error {
if dryRun { 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 return nil
} }
@ -27,7 +28,7 @@ func Push(repoDir string, remote string, tags bool, dryRun bool) error {
return err return err
} }
log.Debugf("git changes pushed") log.Debugf(gotext.Get("git changes pushed"))
if tags { if tags {
opts.RefSpecs = append(opts.RefSpecs, config.RefSpec("+refs/tags/*:refs/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 return err
} }
log.Debugf("git tags pushed") log.Debugf(gotext.Get("git tags pushed"))
} }
return nil return nil

View File

@ -2,7 +2,6 @@ package git
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/user" "os/user"
@ -13,6 +12,7 @@ import (
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
gitConfigPkg "github.com/go-git/go-git/v5/config" gitConfigPkg "github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing/format/gitignore" "github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/leonelquinteros/gotext"
) )
// IsClean checks if a repo has unstaged changes // IsClean checks if a repo has unstaged changes
@ -23,12 +23,12 @@ func IsClean(repoPath string) (bool, error) {
return false, git.ErrRepositoryNotExists 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() worktree, err := repo.Worktree()
if err != nil { 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() patterns, err := GetExcludesFiles()
@ -42,14 +42,14 @@ func IsClean(repoPath string) (bool, error) {
status, err := worktree.Status() status, err := worktree.Status()
if err != nil { 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() != "" { if status.String() != "" {
noNewline := strings.TrimSuffix(status.String(), "\n") 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 { } else {
log.Debugf("git status: %s: clean", repoPath) log.Debugf(gotext.Get("git status: %s: clean", repoPath))
} }
return status.IsClean(), nil return status.IsClean(), nil
@ -85,7 +85,7 @@ func parseGitConfig() (*gitConfigPkg.Config, error) {
globalGitConfig := filepath.Join(usr.HomeDir, ".gitconfig") globalGitConfig := filepath.Join(usr.HomeDir, ".gitconfig")
if _, err := os.Stat(globalGitConfig); err != nil { if _, err := os.Stat(globalGitConfig); err != nil {
if os.IsNotExist(err) { 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, nil
} }
return cfg, err return cfg, err
@ -127,7 +127,7 @@ func parseExcludesFile(excludesfile string) ([]gitignore.Pattern, error) {
if _, err := os.Stat(excludesfile); err != nil { if _, err := os.Stat(excludesfile); err != nil {
if os.IsNotExist(err) { 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, nil
} }
return ps, err 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 return ps, nil
} }

View File

@ -6,12 +6,13 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/config"
"github.com/leonelquinteros/gotext"
) )
// CreateRemote creates a new git remote in a repository // CreateRemote creates a new git remote in a repository
func CreateRemote(repo *git.Repository, name, url string, dryRun bool) error { func CreateRemote(repo *git.Repository, name, url string, dryRun bool) error {
if dryRun { 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 return nil
} }