diff --git a/cli/app/deploy.go b/cli/app/deploy.go index 41d2bad5..a8b7caab 100644 --- a/cli/app/deploy.go +++ b/cli/app/deploy.go @@ -260,6 +260,7 @@ checkout as-is. Recipe commit hashes are also supported as values for app.Name, app.Server, internal.DontWaitConverge, + internal.NoInput, f, ); err != nil { log.Fatal(err) diff --git a/cli/app/restart.go b/cli/app/restart.go index 49357743..1d9fbddb 100644 --- a/cli/app/restart.go +++ b/cli/app/restart.go @@ -128,6 +128,7 @@ Pass "--all-services/-a" to restart all services.`), AppName: app.Name, ServerName: app.Server, Filters: f, + NoInput: internal.NoInput, NoLog: true, Quiet: true, } diff --git a/cli/app/rollback.go b/cli/app/rollback.go index 43ceb3a8..9fd06a0b 100644 --- a/cli/app/rollback.go +++ b/cli/app/rollback.go @@ -246,6 +246,7 @@ beforehand. See "abra app backup" for more.`), stackName, app.Server, internal.DontWaitConverge, + internal.NoInput, f, ); err != nil { log.Fatal(err) diff --git a/cli/app/upgrade.go b/cli/app/upgrade.go index 0f73352b..d5e5513a 100644 --- a/cli/app/upgrade.go +++ b/cli/app/upgrade.go @@ -282,6 +282,7 @@ beforehand. See "abra app backup" for more.`), stackName, app.Server, internal.DontWaitConverge, + internal.NoInput, f, ); err != nil { log.Fatal(err) diff --git a/cli/internal/deploy.go b/cli/internal/deploy.go index 5d4706ea..a4d5f4ac 100644 --- a/cli/internal/deploy.go +++ b/cli/internal/deploy.go @@ -64,7 +64,7 @@ func DeployOverview( server = "local" } - domain := app.Domain + domain := fmt.Sprintf("https://%s", app.Domain) if domain == "" { domain = config.MISSING_DEFAULT } diff --git a/cli/recipe/sync.go b/cli/recipe/sync.go index 5e474743..9a888497 100644 --- a/cli/recipe/sync.go +++ b/cli/recipe/sync.go @@ -1,6 +1,7 @@ package recipe import ( + "errors" "fmt" "strconv" "strings" @@ -19,6 +20,9 @@ import ( "github.com/spf13/cobra" ) +// Errors +var emptyVersionsInCatalogue = errors.New(i18n.G("catalogue versions list is unexpectedly empty")) + // translators: `abra recipe reset` aliases. use a comma separated list of // aliases with no spaces in between var recipeSyncAliases = i18n.G("s") @@ -121,20 +125,18 @@ likely to change. log.Fatal(err) } - versions, err := recipePkg.GetRecipeCatalogueVersions(recipe.Name, catl) - if err != nil { - log.Fatal(err) - } - changesTable, err := formatter.CreateTable() if err != nil { log.Fatal(err) } latestRelease := tags[len(tags)-1] + latestRecipeVersion, err := getLatestVersion(recipe, catl) + if err != nil && err != emptyVersionsInCatalogue { + log.Fatal(err) + } changesTable.Headers(i18n.G("SERVICE"), latestRelease, i18n.G("PROPOSED CHANGES")) - latestRecipeVersion := versions[len(versions)-1] allRecipeVersions := catl[recipe.Name].Versions for _, recipeVersion := range allRecipeVersions { if serviceVersions, ok := recipeVersion[latestRecipeVersion]; ok { @@ -298,3 +300,14 @@ func init() { i18n.G("increase the patch part of the version"), ) } + +func getLatestVersion(recipe recipePkg.Recipe, catl recipePkg.RecipeCatalogue) (string, error) { + versions, err := recipePkg.GetRecipeCatalogueVersions(recipe.Name, catl) + if err != nil { + return "", err + } + if len(versions) > 0 { + return versions[len(versions)-1], nil + } + return "", emptyVersionsInCatalogue +} diff --git a/cli/recipe/sync_test.go b/cli/recipe/sync_test.go new file mode 100644 index 00000000..2e5df357 --- /dev/null +++ b/cli/recipe/sync_test.go @@ -0,0 +1,33 @@ +package recipe + +import ( + "testing" + + recipePkg "coopcloud.tech/abra/pkg/recipe" + "github.com/stretchr/testify/assert" +) + +func TestGetLatestVersionReturnsErrorWhenVersionsIsEmpty(t *testing.T) { + recipe := recipePkg.Recipe{} + catalogue := recipePkg.RecipeCatalogue{} + _, err := getLatestVersion(recipe, catalogue) + assert.Equal(t, err, emptyVersionsInCatalogue) +} + +func TestGetLatestVersionReturnsLastVersion(t *testing.T) { + recipe := recipePkg.Recipe{ + Name: "test", + } + versions := []map[string]map[string]recipePkg.ServiceMeta{ + make(map[string]map[string]recipePkg.ServiceMeta), + make(map[string]map[string]recipePkg.ServiceMeta), + } + versions[0]["0.0.3"] = make(map[string]recipePkg.ServiceMeta) + versions[1]["0.0.2"] = make(map[string]recipePkg.ServiceMeta) + catalogue := make(recipePkg.RecipeCatalogue) + catalogue["test"] = recipePkg.RecipeMeta{ + Versions: versions, + } + version, _ := getLatestVersion(recipe, catalogue) + assert.Equal(t, version, "0.0.3") +} diff --git a/cli/recipe/upgrade.go b/cli/recipe/upgrade.go index b202948c..f3776b0d 100644 --- a/cli/recipe/upgrade.go +++ b/cli/recipe/upgrade.go @@ -57,9 +57,7 @@ is up to the end-user to decide. The command is interactive and will show a select input which allows you to make a seclection. Use the "?" key to see more help on navigating this -interface. - -You may invoke this command in "wizard" mode and be prompted for input.`), +interface.`), Args: cobra.RangeArgs(0, 1), ValidArgsFunction: func( cmd *cobra.Command, diff --git a/go.mod b/go.mod index ee81b55b..8af87fcc 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c github.com/AlecAivazis/survey/v2 v2.3.7 - github.com/charmbracelet/bubbles v0.21.0 github.com/charmbracelet/bubbletea v1.3.10 github.com/charmbracelet/lipgloss v1.1.0 github.com/charmbracelet/log v0.4.2 @@ -16,7 +15,6 @@ require ( github.com/docker/cli v28.4.0+incompatible github.com/docker/docker v28.4.0+incompatible github.com/docker/go-units v0.5.0 - github.com/evertras/bubble-table v0.19.2 github.com/go-git/go-git/v5 v5.16.2 github.com/google/go-cmp v0.7.0 github.com/leonelquinteros/gotext v1.7.2 @@ -35,7 +33,6 @@ require ( github.com/BurntSushi/toml v1.5.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect - github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -44,6 +41,7 @@ require ( github.com/charmbracelet/colorprofile v0.3.2 // indirect github.com/charmbracelet/x/ansi v0.10.2 // indirect github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/clipperhouse/uax29/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect @@ -94,7 +92,6 @@ require ( github.com/morikuni/aec v1.0.0 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect diff --git a/go.sum b/go.sum index 6e15adf5..13d10638 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= @@ -135,8 +133,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf 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/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= -github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI= @@ -373,8 +369,6 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evertras/bubble-table v0.19.2 h1:u77oiM6JlRR+CvS5FZc3Hz+J6iEsvEDcR5kO8OFb1Yw= -github.com/evertras/bubble-table v0.19.2/go.mod h1:ifHujS1YxwnYSOgcR2+m3GnJ84f7CVU/4kUOxUCjEbQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -640,7 +634,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= @@ -702,8 +695,6 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -818,8 +809,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 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= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= diff --git a/pkg/app/app.go b/pkg/app/app.go index dc91797c..2b723f9f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -633,6 +633,11 @@ func (a App) WipeRecipeVersion() error { // WriteRecipeVersion writes the recipe version to the app .env file. func (a App) WriteRecipeVersion(version string, dryRun bool) error { + if version == config.UNKNOWN_DEFAULT { + log.Debug(i18n.G("version is unknown, skipping env write")) + return nil + } + file, err := os.Open(a.Path) if err != nil { return err diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 038ce294..a9de601c 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -224,3 +224,16 @@ func TestWriteRecipeVersionOverwrite(t *testing.T) { assert.Equal(t, "foo", app.Recipe.EnvVersion) } + +func TestWriteRecipeVersionUnknown(t *testing.T) { + app, err := appPkg.GetApp(testPkg.ExpectedAppFiles, testPkg.AppName) + if err != nil { + t.Fatal(err) + } + + if err := app.WriteRecipeVersion(config.UNKNOWN_DEFAULT, false); err != nil { + t.Fatal(err) + } + + assert.NotEqual(t, config.UNKNOWN_DEFAULT, app.Recipe.EnvVersion) +} diff --git a/pkg/client/client.go b/pkg/client/client.go index d1ddb438..4d72c006 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -37,18 +37,27 @@ func WithTimeout(timeout int) Opt { // New initiates a new Docker client. New client connections are validated so // that we ensure connections via SSH to the daemon can succeed. It takes into // account that you may only want the local client and not communicate via SSH. -// For this use-case, please pass "default" as the contextName. +// For this use-case, please pass "default" as the serverName. func New(serverName string, opts ...Opt) (*client.Client, error) { var clientOpts []client.Opt ctx, err := GetContext(serverName) if err != nil { serverDir := path.Join(config.SERVERS_DIR, serverName) - if _, err := os.Stat(serverDir); err == nil { - return nil, errors.New(i18n.G("server missing context, run \"abra server add %s\"?", serverName)) + if _, err := os.Stat(serverDir); err != nil { + return nil, errors.New(i18n.G("server missing, run \"abra server add %s\"?", serverName)) } - return nil, errors.New(i18n.G("unknown server, run \"abra server add %s\"?", serverName)) + // NOTE(p4u1): when the docker context does not exist but the server folder + // is there, let's create a new docker context. + if err = CreateContext(serverName); err != nil { + return nil, errors.New(i18n.G("server missing context, context creation failed: %s", err)) + } + + ctx, err = GetContext(serverName) + if err != nil { + return nil, errors.New(i18n.G("server missing context, run \"abra server add %s\"?", serverName)) + } } ctxEndpoint, err := contextPkg.GetContextEndpoint(ctx) diff --git a/pkg/i18n/locales/abra.pot b/pkg/i18n/locales/abra.pot index 62fad6c4..eaa7ede4 100644 --- a/pkg/i18n/locales/abra.pot +++ b/pkg/i18n/locales/abra.pot @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL\n" - "POT-Creation-Date: 2025-11-02 11:41+0100\n" + "POT-Creation-Date: 2025-12-21 16:38+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -219,7 +219,7 @@ msgstr "" msgid "%s created (version: %s)" msgstr "" -#: ./cli/recipe/release.go:161 ./cli/recipe/sync.go:260 ./cli/recipe/upgrade.go:336 +#: ./cli/recipe/release.go:161 ./cli/recipe/sync.go:262 ./cli/recipe/upgrade.go:334 #, c-format msgid "%s currently has these unstaged changes 👇" msgstr "" @@ -274,12 +274,12 @@ msgstr "" msgid "%s has been detected as not deployed" msgstr "" -#: ./cli/app/restart.go:139 +#: ./cli/app/restart.go:140 #, c-format msgid "%s has been scaled to 0" msgstr "" -#: ./cli/app/restart.go:150 +#: ./cli/app/restart.go:151 #, c-format msgid "%s has been scaled to 1" msgstr "" @@ -339,17 +339,17 @@ msgstr "" msgid "%s is missing the TYPE env var?" msgstr "" -#: ./cli/app/rollback.go:308 ./cli/app/rollback.go:312 +#: ./cli/app/rollback.go:309 ./cli/app/rollback.go:313 #, c-format msgid "%s is not a downgrade for %s?" msgstr "" -#: ./cli/app/upgrade.go:428 ./cli/app/upgrade.go:432 +#: ./cli/app/upgrade.go:429 ./cli/app/upgrade.go:433 #, c-format msgid "%s is not an upgrade for %s?" msgstr "" -#: ./cli/app/env.go:146 ./cli/app/logs.go:65 ./cli/app/ps.go:62 ./cli/app/restart.go:100 ./cli/app/services.go:55 ./cli/app/undeploy.go:66 ./cli/app/upgrade.go:449 +#: ./cli/app/env.go:146 ./cli/app/logs.go:65 ./cli/app/ps.go:62 ./cli/app/restart.go:100 ./cli/app/services.go:55 ./cli/app/undeploy.go:66 ./cli/app/upgrade.go:450 #, c-format msgid "%s is not deployed?" msgstr "" @@ -379,7 +379,7 @@ msgstr "" msgid "%s must first be deployed on %s before moving" msgstr "" -#: ./cli/recipe/upgrade.go:151 +#: ./cli/recipe/upgrade.go:149 #, c-format msgid "%s not considered semver-like" msgstr "" @@ -424,7 +424,7 @@ msgstr "" msgid "%s service is missing image tag?" msgstr "" -#: ./cli/app/restart.go:151 +#: ./cli/app/restart.go:152 #, c-format msgid "%s service successfully restarted" msgstr "" @@ -459,7 +459,7 @@ msgstr "" msgid "%s/example.git" msgstr "" -#: ./pkg/upstream/stack/stack.go:602 +#: ./pkg/upstream/stack/stack.go:613 #, c-format msgid "%s: %s" msgstr "" @@ -549,12 +549,12 @@ msgstr "" msgid "%s: waiting %d seconds before next retry" msgstr "" -#: ./cli/app/upgrade.go:423 +#: ./cli/app/upgrade.go:424 #, c-format msgid "'%s' is not a known version" msgstr "" -#: ./cli/app/rollback.go:303 ./cli/app/upgrade.go:418 +#: ./cli/app/rollback.go:304 ./cli/app/upgrade.go:419 #, c-format msgid "'%s' is not a known version for %s" msgstr "" @@ -621,7 +621,7 @@ msgstr "" msgid "Both local recipe and live deployment labels are shown." msgstr "" -#: ./cli/app/backup.go:319 ./cli/app/backup.go:335 ./cli/app/check.go:95 ./cli/app/cmd.go:285 ./cli/app/cp.go:385 ./cli/app/deploy.go:395 ./cli/app/labels.go:143 ./cli/app/new.go:397 ./cli/app/ps.go:213 ./cli/app/restart.go:162 ./cli/app/restore.go:138 ./cli/app/secret.go:569 ./cli/app/secret.go:609 ./cli/app/secret.go:633 ./cli/app/secret.go:641 ./cli/catalogue/catalogue.go:318 ./cli/recipe/lint.go:137 +#: ./cli/app/backup.go:319 ./cli/app/backup.go:335 ./cli/app/check.go:95 ./cli/app/cmd.go:285 ./cli/app/cp.go:385 ./cli/app/deploy.go:396 ./cli/app/labels.go:143 ./cli/app/new.go:397 ./cli/app/ps.go:213 ./cli/app/restart.go:163 ./cli/app/restore.go:138 ./cli/app/secret.go:569 ./cli/app/secret.go:609 ./cli/app/secret.go:633 ./cli/app/secret.go:641 ./cli/catalogue/catalogue.go:318 ./cli/recipe/lint.go:137 msgid "C" msgstr "" @@ -762,7 +762,7 @@ msgid "Creates a new app from a default recipe.\n" "on your $PATH." msgstr "" -#: ./cli/app/deploy.go:411 ./cli/app/new.go:373 ./cli/app/rollback.go:360 ./cli/app/upgrade.go:469 +#: ./cli/app/deploy.go:412 ./cli/app/new.go:373 ./cli/app/rollback.go:361 ./cli/app/upgrade.go:470 msgid "D" msgstr "" @@ -882,7 +882,7 @@ msgstr "" msgid "Generate autocompletion script" msgstr "" -#: ./cli/recipe/sync.go:32 +#: ./cli/recipe/sync.go:36 msgid "Generate labels for the main recipe service.\n" "\n" "By convention, the service named \"app\" using the following format:\n" @@ -1111,7 +1111,7 @@ msgstr "" msgid "ON SERVER" msgstr "" -#: ./cli/recipe/sync.go:135 +#: ./cli/recipe/sync.go:138 msgid "PROPOSED CHANGES" msgstr "" @@ -1275,7 +1275,7 @@ msgstr "" msgid "SERVER" msgstr "" -#: ./cli/app/ps.go:185 ./cli/recipe/sync.go:135 ./cli/recipe/version.go:69 ./cli/recipe/version.go:110 +#: ./cli/app/ps.go:185 ./cli/recipe/sync.go:138 ./cli/recipe/version.go:69 ./cli/recipe/version.go:110 msgid "SERVICE" msgstr "" @@ -1342,7 +1342,7 @@ msgid "Sync recipe catalogue for latest changes" msgstr "" #. translators: Short description for `recipe sync` command -#: ./cli/recipe/sync.go:31 +#: ./cli/recipe/sync.go:35 msgid "Sync recipe version label" msgstr "" @@ -1469,7 +1469,7 @@ msgid "To load completions:\n" " # and source this file from your PowerShell profile." msgstr "" -#: ./cli/app/deploy.go:435 ./cli/app/rollback.go:376 ./cli/app/upgrade.go:493 +#: ./cli/app/deploy.go:436 ./cli/app/rollback.go:377 ./cli/app/upgrade.go:494 msgid "U" msgstr "" @@ -1500,9 +1500,7 @@ msgid "Upgrade a given configuration.\n" "\n" "The command is interactive and will show a select input which allows you to\n" "make a seclection. Use the \"?\" key to see more help on navigating this\n" - "interface.\n" - "\n" - "You may invoke this command in \"wizard\" mode and be prompted for input." + "interface." msgstr "" #. translators: Short description for `upgrade` command @@ -1603,7 +1601,7 @@ msgstr "" msgid "[hijack] end of stdout" msgstr "" -#: ./cli/recipe/sync.go:85 +#: ./cli/recipe/sync.go:89 #, c-format msgid "\n" "The following options are two types of initial semantic version that you can\n" @@ -1676,7 +1674,7 @@ msgctxt "app backup list" msgid "a" msgstr "" -#: ./cli/app/restart.go:169 +#: ./cli/app/restart.go:170 msgctxt "app restart" msgid "a" msgstr "" @@ -1696,7 +1694,7 @@ msgctxt "recipe fetch" msgid "a" msgstr "" -#: ./cli/recipe/upgrade.go:384 +#: ./cli/recipe/upgrade.go:382 msgctxt "recipe upgrade" msgid "a" msgstr "" @@ -1785,11 +1783,11 @@ msgstr "" msgid "all tasks reached terminal state" msgstr "" -#: ./cli/app/restart.go:168 +#: ./cli/app/restart.go:169 msgid "all-services" msgstr "" -#: ./cli/recipe/upgrade.go:383 +#: ./cli/recipe/upgrade.go:381 msgid "all-tags" msgstr "" @@ -1844,7 +1842,7 @@ msgstr "" msgid "attempting to run %s" msgstr "" -#: ./cli/app/deploy.go:272 ./cli/app/upgrade.go:295 +#: ./cli/app/deploy.go:273 ./cli/app/upgrade.go:296 #, c-format msgid "attempting to run post deploy commands, saw: %s" msgstr "" @@ -1854,7 +1852,7 @@ msgstr "" msgid "attempting to scale %s to 0" msgstr "" -#: ./cli/app/restart.go:140 +#: ./cli/app/restart.go:141 #, c-format msgid "attempting to scale %s to 1" msgstr "" @@ -1924,7 +1922,7 @@ msgstr "" #. no spaces in between #. translators: `abra app cp` aliases. use a comma separated list of aliases with #. no spaces in between -#: ./cli/app/backup.go:148 ./cli/app/cp.go:30 ./cli/app/deploy.go:419 ./cli/app/rollback.go:368 ./cli/app/upgrade.go:477 +#: ./cli/app/backup.go:148 ./cli/app/cp.go:30 ./cli/app/deploy.go:420 ./cli/app/rollback.go:369 ./cli/app/upgrade.go:478 msgid "c" msgstr "" @@ -1932,7 +1930,7 @@ msgstr "" msgid "can not insert from file and read from stdin" msgstr "" -#: ./cli/recipe/upgrade.go:324 +#: ./cli/recipe/upgrade.go:322 #, c-format msgid "can upgrade service: %s, image: %s, tag: %s ::" msgstr "" @@ -1965,7 +1963,7 @@ msgstr "" msgid "cannot find app with name %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:657 +#: ./pkg/upstream/stack/stack.go:668 #, c-format msgid "cannot get label %s for %s" msgstr "" @@ -1980,7 +1978,7 @@ msgstr "" msgid "cannot redeploy previous chaos version (%s), did you mean to use \"--chaos\"?" msgstr "" -#: ./cli/app/deploy.go:369 +#: ./cli/app/deploy.go:370 #, c-format msgid "cannot redeploy previous chaos version (%s), did you mean to use \"--chaos\"?\n" " to return to a regular release, specify a release tag, commit SHA or use \"--latest\"" @@ -1999,7 +1997,7 @@ msgstr "" msgid "cannot use '[secret] [version]' and '--all' together" msgstr "" -#: ./cli/app/deploy.go:311 +#: ./cli/app/deploy.go:312 msgid "cannot use --chaos and --latest together" msgstr "" @@ -2023,11 +2021,11 @@ msgstr "" msgid "cannot use [service] and --all-services/-a together" msgstr "" -#: ./cli/app/deploy.go:303 ./cli/app/new.go:76 +#: ./cli/app/deploy.go:304 ./cli/app/new.go:76 msgid "cannot use [version] and --chaos together" msgstr "" -#: ./cli/app/deploy.go:307 +#: ./cli/app/deploy.go:308 msgid "cannot use [version] and --latest together" msgstr "" @@ -2049,6 +2047,10 @@ msgstr "" msgid "catalogue successfully synced" msgstr "" +#: ./cli/recipe/sync.go:24 +msgid "catalogue versions list is unexpectedly empty" +msgstr "" + #: ./cli/recipe/list.go:44 msgid "category" msgstr "" @@ -2059,7 +2061,7 @@ msgstr "" msgid "cfg" msgstr "" -#: ./cli/app/backup.go:318 ./cli/app/backup.go:334 ./cli/app/check.go:94 ./cli/app/cmd.go:284 ./cli/app/cp.go:384 ./cli/app/deploy.go:394 ./cli/app/labels.go:142 ./cli/app/new.go:396 ./cli/app/ps.go:212 ./cli/app/restart.go:161 ./cli/app/restore.go:137 ./cli/app/secret.go:568 ./cli/app/secret.go:608 ./cli/app/secret.go:632 ./cli/app/secret.go:640 ./cli/catalogue/catalogue.go:317 ./cli/recipe/lint.go:136 +#: ./cli/app/backup.go:318 ./cli/app/backup.go:334 ./cli/app/check.go:94 ./cli/app/cmd.go:284 ./cli/app/cp.go:384 ./cli/app/deploy.go:395 ./cli/app/labels.go:142 ./cli/app/new.go:396 ./cli/app/ps.go:212 ./cli/app/restart.go:162 ./cli/app/restore.go:137 ./cli/app/secret.go:568 ./cli/app/secret.go:608 ./cli/app/secret.go:632 ./cli/app/secret.go:640 ./cli/catalogue/catalogue.go:317 ./cli/recipe/lint.go:136 msgid "chaos" msgstr "" @@ -2068,7 +2070,7 @@ msgstr "" msgid "check [flags]" msgstr "" -#: ./cli/app/deploy.go:94 ./cli/app/undeploy.go:58 ./cli/app/upgrade.go:441 +#: ./cli/app/deploy.go:94 ./cli/app/undeploy.go:58 ./cli/app/upgrade.go:442 #, c-format msgid "checking whether %s is already deployed" msgstr "" @@ -2084,7 +2086,7 @@ msgstr "" msgid "choosing %s as latest version of %s" msgstr "" -#: ./cli/recipe/sync.go:237 +#: ./cli/recipe/sync.go:239 #, c-format msgid "choosing %s as new version for %s" msgstr "" @@ -2237,7 +2239,7 @@ msgstr "" msgid "context lacks Docker endpoint" msgstr "" -#: ./cli/recipe/sync.go:246 ./pkg/recipe/compose.go:229 +#: ./cli/recipe/sync.go:248 ./pkg/recipe/compose.go:229 #, c-format msgid "coop-cloud.${STACK_NAME}.version=%s" msgstr "" @@ -2291,7 +2293,7 @@ msgstr "" msgid "create remote directory: %s" msgstr "" -#: ./pkg/client/client.go:102 +#: ./pkg/client/client.go:111 #, c-format msgid "created client for %s" msgstr "" @@ -2311,7 +2313,7 @@ msgstr "" msgid "created the %s context" msgstr "" -#: ./pkg/upstream/stack/stack.go:520 +#: ./pkg/upstream/stack/stack.go:524 #, c-format msgid "creating %s" msgstr "" @@ -2326,12 +2328,12 @@ msgstr "" msgid "creating context with domain %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:422 +#: ./pkg/upstream/stack/stack.go:426 #, c-format msgid "creating network %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:369 +#: ./pkg/upstream/stack/stack.go:373 #, c-format msgid "creating secret %s" msgstr "" @@ -2350,7 +2352,7 @@ msgstr "" msgid "critical errors present in %s config" msgstr "" -#: ./cli/app/rollback.go:298 +#: ./cli/app/rollback.go:299 #, c-format msgid "current deployment '%s' is not a known version for %s" msgstr "" @@ -2390,11 +2392,11 @@ msgstr "" msgid "deploy [version] [flags]" msgstr "" -#: ./pkg/upstream/stack/stack.go:593 +#: ./pkg/upstream/stack/stack.go:604 msgid "deploy failed 🛑" msgstr "" -#: ./pkg/upstream/stack/stack.go:597 +#: ./pkg/upstream/stack/stack.go:608 msgid "deploy in progress 🟠" msgstr "" @@ -2402,15 +2404,15 @@ msgstr "" msgid "deploy labels stanza present" msgstr "" -#: ./cli/app/deploy.go:429 +#: ./cli/app/deploy.go:430 msgid "deploy latest recipe version" msgstr "" -#: ./pkg/upstream/stack/stack.go:637 +#: ./pkg/upstream/stack/stack.go:648 msgid "deploy succeeded 🟢" msgstr "" -#: ./pkg/upstream/stack/stack.go:595 +#: ./pkg/upstream/stack/stack.go:606 msgid "deploy timed out 🟠" msgstr "" @@ -2445,12 +2447,12 @@ msgstr "" msgid "detected ABRA_CI=1" msgstr "" -#: ./cli/recipe/upgrade.go:205 +#: ./cli/recipe/upgrade.go:203 #, c-format msgid "detected compatible upgradable tags %s for %s" msgstr "" -#: ./cli/recipe/upgrade.go:178 +#: ./cli/recipe/upgrade.go:176 #, c-format msgid "detected potential upgradable tags %s for %s" msgstr "" @@ -2464,7 +2466,7 @@ msgstr "" msgid "did not detect any command arguments" msgstr "" -#: ./cli/recipe/upgrade.go:125 +#: ./cli/recipe/upgrade.go:123 #, c-format msgid "did not find versions file for %s" msgstr "" @@ -2504,11 +2506,11 @@ msgstr "" msgid "dirty: %v, " msgstr "" -#: ./cli/app/deploy.go:421 ./cli/app/rollback.go:370 ./cli/app/upgrade.go:479 +#: ./cli/app/deploy.go:422 ./cli/app/rollback.go:371 ./cli/app/upgrade.go:480 msgid "disable converge logic checks" msgstr "" -#: ./cli/app/deploy.go:413 ./cli/app/rollback.go:362 ./cli/app/upgrade.go:471 +#: ./cli/app/deploy.go:414 ./cli/app/rollback.go:363 ./cli/app/upgrade.go:472 msgid "disable public DNS checks" msgstr "" @@ -2582,7 +2584,7 @@ msgstr "" msgid "dry run: no git tag created (%s)" msgstr "" -#: ./cli/recipe/sync.go:252 +#: ./cli/recipe/sync.go:254 #, c-format msgid "dry run: not syncing label %s for recipe %s" msgstr "" @@ -2592,7 +2594,7 @@ msgstr "" msgid "dry run: remote %s (%s) not created" msgstr "" -#: ./cli/app/move.go:349 ./cli/catalogue/catalogue.go:301 ./cli/recipe/release.go:648 ./cli/recipe/sync.go:271 +#: ./cli/app/move.go:349 ./cli/catalogue/catalogue.go:301 ./cli/recipe/release.go:648 ./cli/recipe/sync.go:273 msgid "dry-run" msgstr "" @@ -2643,7 +2645,7 @@ msgstr "" msgid "ensuring env version %s" msgstr "" -#: ./cli/recipe/upgrade.go:286 +#: ./cli/recipe/upgrade.go:284 msgid "enter / return to confirm, choose 'skip' to not upgrade this tag, vim mode is enabled" msgstr "" @@ -2726,7 +2728,7 @@ msgstr "" #. translators: `abra recipe fetch` aliases. use a comma separated list of aliases #. with no spaces in between -#: ./cli/app/deploy.go:403 ./cli/app/env.go:325 ./cli/app/remove.go:163 ./cli/app/rollback.go:352 ./cli/app/secret.go:593 ./cli/app/upgrade.go:461 ./cli/app/volume.go:217 ./cli/recipe/fetch.go:20 ./cli/recipe/fetch.go:138 +#: ./cli/app/deploy.go:404 ./cli/app/env.go:325 ./cli/app/remove.go:163 ./cli/app/rollback.go:353 ./cli/app/secret.go:593 ./cli/app/upgrade.go:462 ./cli/app/volume.go:217 ./cli/recipe/fetch.go:20 ./cli/recipe/fetch.go:138 msgid "f" msgstr "" @@ -2760,22 +2762,22 @@ msgstr "" msgid "failed to copy %s from local machine to %s: output:%s err:%s" msgstr "" -#: ./pkg/upstream/stack/stack.go:531 +#: ./pkg/upstream/stack/stack.go:535 #, c-format msgid "failed to create %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:393 +#: ./pkg/upstream/stack/stack.go:397 #, c-format msgid "failed to create config %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:424 +#: ./pkg/upstream/stack/stack.go:428 #, c-format msgid "failed to create network %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:371 +#: ./pkg/upstream/stack/stack.go:375 #, c-format msgid "failed to create secret %s" msgstr "" @@ -2872,7 +2874,7 @@ msgstr "" msgid "failed to retrieve latest commit for %s: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:468 +#: ./pkg/upstream/stack/stack.go:472 #, c-format msgid "failed to retrieve registry auth for image %s: %s" msgstr "" @@ -2892,17 +2894,17 @@ msgstr "" msgid "failed to tag release: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:508 +#: ./pkg/upstream/stack/stack.go:512 #, c-format msgid "failed to update %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:387 +#: ./pkg/upstream/stack/stack.go:391 #, c-format msgid "failed to update config %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:365 +#: ./pkg/upstream/stack/stack.go:369 #, c-format msgid "failed to update secret %s" msgstr "" @@ -2957,7 +2959,7 @@ msgstr "" msgid "final merged env values for %s are: %s" msgstr "" -#: ./cli/app/deploy.go:402 ./cli/app/env.go:324 ./cli/app/remove.go:162 ./cli/app/rollback.go:351 ./cli/app/upgrade.go:460 ./cli/app/volume.go:216 ./cli/recipe/fetch.go:137 +#: ./cli/app/deploy.go:403 ./cli/app/env.go:324 ./cli/app/remove.go:162 ./cli/app/rollback.go:352 ./cli/app/upgrade.go:461 ./cli/app/volume.go:216 ./cli/recipe/fetch.go:137 msgid "force" msgstr "" @@ -2965,7 +2967,7 @@ msgstr "" msgid "force re-fetch" msgstr "" -#: ./cli/recipe/upgrade.go:97 +#: ./cli/recipe/upgrade.go:95 #, c-format msgid "found versions file for %s" msgstr "" @@ -3171,7 +3173,7 @@ msgstr "" msgid "id: %s, " msgstr "" -#: ./cli/app/backup.go:321 ./cli/app/backup.go:337 ./cli/app/check.go:97 ./cli/app/cmd.go:287 ./cli/app/cp.go:387 ./cli/app/deploy.go:397 ./cli/app/labels.go:145 ./cli/app/new.go:399 ./cli/app/ps.go:215 ./cli/app/restart.go:164 ./cli/app/restore.go:140 ./cli/app/secret.go:571 ./cli/app/secret.go:611 ./cli/app/secret.go:635 ./cli/app/secret.go:643 ./cli/catalogue/catalogue.go:320 ./cli/recipe/lint.go:139 +#: ./cli/app/backup.go:321 ./cli/app/backup.go:337 ./cli/app/check.go:97 ./cli/app/cmd.go:287 ./cli/app/cp.go:387 ./cli/app/deploy.go:398 ./cli/app/labels.go:145 ./cli/app/new.go:399 ./cli/app/ps.go:215 ./cli/app/restart.go:165 ./cli/app/restore.go:140 ./cli/app/secret.go:571 ./cli/app/secret.go:611 ./cli/app/secret.go:635 ./cli/app/secret.go:643 ./cli/catalogue/catalogue.go:320 ./cli/recipe/lint.go:139 msgid "ignore uncommitted recipes changes" msgstr "" @@ -3260,15 +3262,15 @@ msgstr "" msgid "including VOLUMES=%v in backupbot exec invocation" msgstr "" -#: ./cli/recipe/release.go:659 ./cli/recipe/sync.go:282 ./cli/recipe/upgrade.go:354 +#: ./cli/recipe/release.go:659 ./cli/recipe/sync.go:284 ./cli/recipe/upgrade.go:352 msgid "increase the major part of the version" msgstr "" -#: ./cli/recipe/release.go:667 ./cli/recipe/sync.go:290 ./cli/recipe/upgrade.go:362 +#: ./cli/recipe/release.go:667 ./cli/recipe/sync.go:292 ./cli/recipe/upgrade.go:360 msgid "increase the minor part of the version" msgstr "" -#: ./cli/recipe/release.go:675 ./cli/recipe/sync.go:298 ./cli/recipe/upgrade.go:370 +#: ./cli/recipe/release.go:675 ./cli/recipe/sync.go:300 ./cli/recipe/upgrade.go:368 msgid "increase the patch part of the version" msgstr "" @@ -3282,7 +3284,7 @@ msgstr "" msgid "initialised new git repo in %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:206 +#: ./pkg/upstream/stack/stack.go:207 msgid "initialising deployment" msgstr "" @@ -3346,7 +3348,7 @@ msgstr "" msgid "invalid npipe source, source cannot be empty" msgstr "" -#: ./pkg/upstream/stack/stack.go:239 +#: ./pkg/upstream/stack/stack.go:241 #, c-format msgid "invalid option %s for flag --resolve-image" msgstr "" @@ -3360,7 +3362,7 @@ msgstr "" msgid "invalid tmpfs source, source must be empty" msgstr "" -#: ./cli/recipe/sync.go:242 +#: ./cli/recipe/sync.go:244 #, c-format msgid "invalid version %s specified" msgstr "" @@ -3369,7 +3371,7 @@ msgstr "" #. no spaces in between #. translators: `abra recipe lint` aliases. use a comma separated list of #. aliases with no spaces in between -#: ./cli/app/cmd.go:261 ./cli/app/deploy.go:427 ./cli/app/logs.go:20 ./cli/recipe/lint.go:17 ./cli/server/add.go:207 +#: ./cli/app/cmd.go:261 ./cli/app/deploy.go:428 ./cli/app/logs.go:20 ./cli/recipe/lint.go:17 ./cli/server/add.go:207 msgid "l" msgstr "" @@ -3384,7 +3386,7 @@ msgstr "" msgid "labels [flags]" msgstr "" -#: ./cli/app/deploy.go:426 ./cli/app/list.go:182 +#: ./cli/app/deploy.go:427 ./cli/app/list.go:182 msgid "latest" msgstr "" @@ -3438,7 +3440,7 @@ msgstr "" msgid "list [flags]" msgstr "" -#: ./cli/recipe/upgrade.go:386 +#: ./cli/recipe/upgrade.go:384 msgid "list all tags, not just upgrades" msgstr "" @@ -3473,12 +3475,12 @@ msgstr "" msgid "logs [service] [flags]" msgstr "" -#: ./pkg/upstream/stack/stack.go:628 +#: ./pkg/upstream/stack/stack.go:639 #, c-format msgid "logs: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:630 +#: ./pkg/upstream/stack/stack.go:641 msgid "logs: no log output received from deployment" msgstr "" @@ -3508,11 +3510,11 @@ msgstr "" #. with no spaces in between #. translators: `abra man` aliases. use a comma separated list of aliases #. with no spaces in between -#: ./cli/app/list.go:315 ./cli/app/move.go:34 ./cli/app/ps.go:205 ./cli/app/secret.go:553 ./cli/app/secret.go:649 ./cli/recipe/list.go:104 ./cli/recipe/upgrade.go:376 ./cli/recipe/version.go:139 ./cli/run.go:152 ./cli/server/list.go:106 +#: ./cli/app/list.go:315 ./cli/app/move.go:34 ./cli/app/ps.go:205 ./cli/app/secret.go:553 ./cli/app/secret.go:649 ./cli/recipe/list.go:104 ./cli/recipe/upgrade.go:374 ./cli/recipe/version.go:139 ./cli/run.go:152 ./cli/server/list.go:106 msgid "m" msgstr "" -#: ./cli/app/list.go:314 ./cli/app/ps.go:204 ./cli/app/secret.go:552 ./cli/app/secret.go:648 ./cli/recipe/list.go:103 ./cli/recipe/upgrade.go:375 ./cli/recipe/version.go:138 ./cli/server/list.go:105 +#: ./cli/app/list.go:314 ./cli/app/ps.go:204 ./cli/app/secret.go:552 ./cli/app/secret.go:648 ./cli/recipe/list.go:103 ./cli/recipe/upgrade.go:373 ./cli/recipe/version.go:138 ./cli/server/list.go:105 msgid "machine" msgstr "" @@ -3521,11 +3523,11 @@ msgstr "" msgid "main app service version for %s is empty?" msgstr "" -#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:66 ./cli/internal/recipe.go:80 ./cli/recipe/release.go:656 ./cli/recipe/sync.go:279 ./cli/recipe/upgrade.go:351 +#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:66 ./cli/internal/recipe.go:80 ./cli/recipe/release.go:656 ./cli/recipe/sync.go:281 ./cli/recipe/upgrade.go:349 msgid "major" msgstr "" -#: ./cli/recipe/upgrade.go:107 +#: ./cli/recipe/upgrade.go:105 #, c-format msgid "malformed version pin specification: %s" msgstr "" @@ -3550,7 +3552,7 @@ msgstr "" msgid "migrating app config from %s to %s" msgstr "" -#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:68 ./cli/internal/recipe.go:82 ./cli/recipe/release.go:664 ./cli/recipe/sync.go:287 ./cli/recipe/upgrade.go:359 +#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:68 ./cli/internal/recipe.go:82 ./cli/recipe/release.go:664 ./cli/recipe/sync.go:289 ./cli/recipe/upgrade.go:357 msgid "minor" msgstr "" @@ -3614,12 +3616,12 @@ msgstr "" msgid "need 3 or 4 arguments" msgstr "" -#: ./pkg/upstream/stack/stack.go:348 +#: ./pkg/upstream/stack/stack.go:352 #, c-format msgid "network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed, which you can do by running this on the server: docker network create -d overlay proxy" msgstr "" -#: ./pkg/upstream/stack/stack.go:352 +#: ./pkg/upstream/stack/stack.go:356 #, c-format msgid "network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"" msgstr "" @@ -3734,12 +3736,12 @@ msgstr "" msgid "no existing label found, automagic insertion not supported yet" msgstr "" -#: ./cli/recipe/sync.go:81 +#: ./cli/recipe/sync.go:85 #, c-format msgid "no git tags found for %s" msgstr "" -#: ./cli/recipe/upgrade.go:183 +#: ./cli/recipe/upgrade.go:181 #, c-format msgid "no new versions available for %s, assuming %s is the latest (use -a/--all-tags to see all anyway)" msgstr "" @@ -3842,11 +3844,11 @@ msgstr "" msgid "no volumes to remove" msgstr "" -#: ./cli/app/deploy.go:418 ./cli/app/rollback.go:367 ./cli/app/upgrade.go:476 +#: ./cli/app/deploy.go:419 ./cli/app/rollback.go:368 ./cli/app/upgrade.go:477 msgid "no-converge-checks" msgstr "" -#: ./cli/app/deploy.go:410 ./cli/app/rollback.go:359 ./cli/app/upgrade.go:468 +#: ./cli/app/deploy.go:411 ./cli/app/rollback.go:360 ./cli/app/upgrade.go:469 msgid "no-domain-checks" msgstr "" @@ -3867,12 +3869,12 @@ msgstr "" msgid "not requesting a remote TTY" msgstr "" -#: ./cli/recipe/upgrade.go:306 +#: ./cli/recipe/upgrade.go:304 #, c-format msgid "not upgrading %s, skipping as requested" msgstr "" -#: ./cli/recipe/upgrade.go:245 +#: ./cli/recipe/upgrade.go:243 #, c-format msgid "not upgrading from %s to %s for %s, because the upgrade type is more serious than what user wants" msgstr "" @@ -3902,7 +3904,7 @@ msgstr "" msgid "only show errors" msgstr "" -#: ./cli/app/upgrade.go:487 +#: ./cli/app/upgrade.go:488 msgid "only show release notes" msgstr "" @@ -3918,7 +3920,7 @@ msgstr "" msgid "p" msgstr "" -#: ./cli/recipe/upgrade.go:164 +#: ./cli/recipe/upgrade.go:162 #, c-format msgid "parsed %s for %s" msgstr "" @@ -3933,22 +3935,22 @@ msgstr "" msgid "parsed following command arguments: %s" msgstr "" -#: ./cli/app/upgrade.go:344 +#: ./cli/app/upgrade.go:345 #, c-format msgid "parsing chosen upgrade version failed: %s" msgstr "" -#: ./cli/app/upgrade.go:388 +#: ./cli/app/upgrade.go:389 #, c-format msgid "parsing deployed version failed: %s" msgstr "" -#: ./cli/app/upgrade.go:349 +#: ./cli/app/upgrade.go:350 #, c-format msgid "parsing deployment version failed: %s" msgstr "" -#: ./cli/app/upgrade.go:355 ./cli/app/upgrade.go:394 +#: ./cli/app/upgrade.go:356 ./cli/app/upgrade.go:395 #, c-format msgid "parsing recipe version failed: %s" msgstr "" @@ -3961,7 +3963,7 @@ msgstr "" msgid "pass command not found on $PATH, is it installed?" msgstr "" -#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:70 ./cli/internal/recipe.go:84 ./cli/recipe/release.go:672 ./cli/recipe/sync.go:295 ./cli/recipe/upgrade.go:367 +#: ./cli/internal/recipe.go:48 ./cli/internal/recipe.go:70 ./cli/internal/recipe.go:84 ./cli/recipe/release.go:672 ./cli/recipe/sync.go:297 ./cli/recipe/upgrade.go:365 msgid "patch" msgstr "" @@ -3973,7 +3975,7 @@ msgstr "" msgid "pattern" msgstr "" -#: ./cli/app/deploy.go:405 ./cli/app/env.go:327 ./cli/app/remove.go:165 ./cli/app/rollback.go:354 ./cli/app/upgrade.go:463 ./cli/app/volume.go:219 +#: ./cli/app/deploy.go:406 ./cli/app/env.go:327 ./cli/app/remove.go:165 ./cli/app/rollback.go:355 ./cli/app/upgrade.go:464 ./cli/app/volume.go:219 msgid "perform action without further prompt" msgstr "" @@ -3988,27 +3990,27 @@ msgstr "" msgid "please fix your synced label for %s and re-run this command" msgstr "" -#: ./cli/app/rollback.go:266 +#: ./cli/app/rollback.go:267 #, c-format msgid "please select a downgrade (version: %s):" msgstr "" -#: ./cli/app/rollback.go:271 +#: ./cli/app/rollback.go:272 #, c-format msgid "please select a downgrade (version: %s, chaos: %s):" msgstr "" -#: ./cli/app/upgrade.go:311 +#: ./cli/app/upgrade.go:312 #, c-format msgid "please select an upgrade (version: %s):" msgstr "" -#: ./cli/app/upgrade.go:316 +#: ./cli/app/upgrade.go:317 #, c-format msgid "please select an upgrade (version: %s, chaos: %s):" msgstr "" -#: ./pkg/upstream/stack/stack.go:576 +#: ./pkg/upstream/stack/stack.go:587 msgid "polling deployment status" msgstr "" @@ -4024,7 +4026,7 @@ msgstr "" msgid "previous git tags detected, assuming new semver release" msgstr "" -#: ./cli/app/list.go:317 ./cli/app/ps.go:207 ./cli/app/secret.go:555 ./cli/app/secret.go:651 ./cli/recipe/list.go:106 ./cli/recipe/upgrade.go:378 ./cli/recipe/version.go:141 ./cli/server/list.go:108 +#: ./cli/app/list.go:317 ./cli/app/ps.go:207 ./cli/app/secret.go:555 ./cli/app/secret.go:651 ./cli/recipe/list.go:106 ./cli/recipe/upgrade.go:376 ./cli/recipe/version.go:141 ./cli/server/list.go:108 msgid "print machine-readable output" msgstr "" @@ -4094,7 +4096,7 @@ msgstr "" #. with no spaces in between #. translators: `abra recipe` aliases. use a comma separated list of aliases #. with no spaces in between -#: ./cli/app/backup.go:327 ./cli/app/list.go:300 ./cli/app/move.go:350 ./cli/app/run.go:23 ./cli/app/upgrade.go:485 ./cli/catalogue/catalogue.go:302 ./cli/recipe/recipe.go:12 ./cli/recipe/release.go:649 ./cli/recipe/sync.go:272 +#: ./cli/app/backup.go:327 ./cli/app/list.go:300 ./cli/app/move.go:350 ./cli/app/run.go:23 ./cli/app/upgrade.go:486 ./cli/catalogue/catalogue.go:302 ./cli/recipe/recipe.go:12 ./cli/recipe/release.go:649 ./cli/recipe/sync.go:274 msgid "r" msgstr "" @@ -4210,7 +4212,7 @@ msgstr "" msgid "release [version] [flags]" msgstr "" -#: ./cli/app/upgrade.go:484 +#: ./cli/app/upgrade.go:485 msgid "releasenotes" msgstr "" @@ -4346,7 +4348,7 @@ msgstr "" msgid "repo set config: %s" msgstr "" -#: ./cli/app/move.go:352 ./cli/catalogue/catalogue.go:304 ./cli/recipe/release.go:651 ./cli/recipe/sync.go:274 +#: ./cli/app/move.go:352 ./cli/catalogue/catalogue.go:304 ./cli/recipe/release.go:651 ./cli/recipe/sync.go:276 msgid "report changes that would be made" msgstr "" @@ -4376,7 +4378,7 @@ msgstr "" msgid "restart [[service] | --all-services] [flags]" msgstr "" -#: ./cli/app/restart.go:171 +#: ./cli/app/restart.go:172 msgid "restart all services" msgstr "" @@ -4417,7 +4419,7 @@ msgstr "" msgid "retrieved %s for %s" msgstr "" -#: ./cli/recipe/upgrade.go:145 +#: ./cli/recipe/upgrade.go:143 #, c-format msgid "retrieved %s from remote registry for %s" msgstr "" @@ -4441,7 +4443,7 @@ msgstr "" msgid "retrieved versions from local recipe repository" msgstr "" -#: ./pkg/upstream/stack/stack.go:464 +#: ./pkg/upstream/stack/stack.go:468 #, c-format msgid "retrieving docker auth token: failed create docker cli: %s" msgstr "" @@ -4514,7 +4516,7 @@ msgstr "" msgid "run command locally" msgstr "" -#: ./cli/app/deploy.go:270 ./cli/app/upgrade.go:292 +#: ./cli/app/deploy.go:271 ./cli/app/upgrade.go:293 #, c-format msgid "run the following post-deploy commands: %s" msgstr "" @@ -4557,7 +4559,7 @@ msgstr "" #. aliases with no spaces in between #. translators: `abra server` aliases. use a comma separated list of aliases #. with no spaces in between -#: ./cli/app/backup.go:198 ./cli/app/backup.go:263 ./cli/app/backup.go:287 ./cli/app/env.go:333 ./cli/app/list.go:323 ./cli/app/logs.go:101 ./cli/app/new.go:358 ./cli/app/restore.go:114 ./cli/app/secret.go:535 ./cli/catalogue/catalogue.go:27 ./cli/catalogue/catalogue.go:310 ./cli/recipe/fetch.go:130 ./cli/recipe/sync.go:24 ./cli/server/server.go:12 +#: ./cli/app/backup.go:198 ./cli/app/backup.go:263 ./cli/app/backup.go:287 ./cli/app/env.go:333 ./cli/app/list.go:323 ./cli/app/logs.go:101 ./cli/app/new.go:358 ./cli/app/restore.go:114 ./cli/app/secret.go:535 ./cli/catalogue/catalogue.go:27 ./cli/catalogue/catalogue.go:310 ./cli/recipe/fetch.go:130 ./cli/recipe/sync.go:28 ./cli/server/server.go:12 msgid "s" msgstr "" @@ -4599,12 +4601,12 @@ msgstr "" msgid "secret not found: %s" msgstr "" -#: ./cli/app/deploy.go:339 +#: ./cli/app/deploy.go:340 #, c-format msgid "secret not generated: %s" msgstr "" -#: ./cli/app/deploy.go:337 +#: ./cli/app/deploy.go:338 #, c-format msgid "secret not inserted (#generate=false): %s" msgstr "" @@ -4651,11 +4653,21 @@ msgstr "" msgid "server doesn't exist?" msgstr "" -#: ./pkg/client/client.go:48 +#: ./pkg/client/client.go:54 +#, c-format +msgid "server missing context, context creation failed: %s" +msgstr "" + +#: ./pkg/client/client.go:59 #, c-format msgid "server missing context, run \"abra server add %s\"?" msgstr "" +#: ./pkg/client/client.go:48 +#, c-format +msgid "server missing, run \"abra server add %s\"?" +msgstr "" + #: ./cli/server/add.go:148 #, c-format msgid "serverAdd: cleanUp: %s is not empty, aborting cleanup" @@ -4676,12 +4688,12 @@ msgstr "" msgid "serverAdd: cleanUp: unable to list files in %s: %s" msgstr "" -#: ./cli/recipe/upgrade.go:228 +#: ./cli/recipe/upgrade.go:226 #, c-format msgid "service %s is at version %s, but pinned to %s, please correct your compose.yml file manually!" msgstr "" -#: ./cli/recipe/upgrade.go:224 +#: ./cli/recipe/upgrade.go:222 #, c-format msgid "service %s, image %s pinned to %s, no compatible upgrade found" msgstr "" @@ -4728,7 +4740,7 @@ msgstr "" msgid "severity" msgstr "" -#: ./cli/app/deploy.go:437 ./cli/app/rollback.go:378 ./cli/app/upgrade.go:495 +#: ./cli/app/deploy.go:438 ./cli/app/rollback.go:379 ./cli/app/upgrade.go:496 msgid "show all configs & images, including unchanged ones" msgstr "" @@ -4752,7 +4764,7 @@ msgstr "" msgid "show debug messages" msgstr "" -#: ./cli/app/deploy.go:434 ./cli/app/rollback.go:375 ./cli/app/upgrade.go:492 +#: ./cli/app/deploy.go:435 ./cli/app/rollback.go:376 ./cli/app/upgrade.go:493 msgid "show-unchanged" msgstr "" @@ -4796,7 +4808,7 @@ msgstr "" msgid "skipping as requested, undeploy still in progress 🟠" msgstr "" -#: ./pkg/upstream/stack/stack.go:306 +#: ./pkg/upstream/stack/stack.go:309 msgid "skipping converge logic checks" msgstr "" @@ -4818,12 +4830,12 @@ msgstr "" msgid "skipping secret (because it already exists) on %s: %s" msgstr "" -#: ./pkg/app/app.go:692 +#: ./pkg/app/app.go:697 #, c-format msgid "skipping version %s write as already exists in %s.env" msgstr "" -#: ./pkg/app/app.go:686 +#: ./pkg/app/app.go:691 #, c-format msgid "skipping writing version %s because dry run" msgstr "" @@ -4931,17 +4943,17 @@ msgstr "" msgid "successfully created %s" msgstr "" -#: ./pkg/client/client.go:111 +#: ./pkg/client/client.go:120 #, c-format msgid "swarm mode not enabled on %s?" msgstr "" -#: ./pkg/client/client.go:114 +#: ./pkg/client/client.go:123 msgid "swarm mode not enabled on local server?" msgstr "" #. translators: `recipe sync` command -#: ./cli/recipe/sync.go:28 +#: ./cli/recipe/sync.go:32 msgid "sync [version] [flags]" msgstr "" @@ -4963,12 +4975,12 @@ msgstr "" msgid "tag all images with stable tags" msgstr "" -#: ./cli/recipe/sync.go:178 +#: ./cli/recipe/sync.go:180 #, c-format msgid "tag at commit %s is unannotated or otherwise broken" msgstr "" -#: ./cli/recipe/upgrade.go:302 +#: ./cli/recipe/upgrade.go:300 #, c-format msgid "tag upgraded from %s to %s for %s" msgstr "" @@ -5012,7 +5024,7 @@ msgstr "" msgid "timeout label: %s" msgstr "" -#: ./pkg/upstream/stack/remove.go:29 ./pkg/upstream/stack/stack.go:209 +#: ./pkg/upstream/stack/remove.go:29 ./pkg/upstream/stack/stack.go:210 #, c-format msgid "timeout: set to %d second(s)" msgstr "" @@ -5106,7 +5118,7 @@ msgstr "" msgid "unable to connect to %s, please check your SSH config" msgstr "" -#: ./cli/recipe/sync.go:83 +#: ./cli/recipe/sync.go:87 msgid "unable to continue, input required for initial version" msgstr "" @@ -5145,7 +5157,7 @@ msgstr "" msgid "unable to determine server of app %s, please pass --server/-s" msgstr "" -#: ./cli/recipe/upgrade.go:253 +#: ./cli/recipe/upgrade.go:251 #, c-format msgid "unable to determine versioning semantics of %s, listing all tags" msgstr "" @@ -5219,7 +5231,7 @@ msgstr "" msgid "unable to open worktree of %s: %s" msgstr "" -#: ./cli/recipe/upgrade.go:160 +#: ./cli/recipe/upgrade.go:158 #, c-format msgid "unable to parse %s, error was: %s, skipping upgrade for %s" msgstr "" @@ -5259,7 +5271,7 @@ msgstr "" msgid "unable to read remotes in %s: %s" msgstr "" -#: ./cli/recipe/upgrade.go:154 +#: ./cli/recipe/upgrade.go:152 #, c-format msgid "unable to read tag for image %s, is it missing? skipping upgrade for %s" msgstr "" @@ -5435,11 +5447,6 @@ msgstr "" msgid "unknown server %s, run \"abra server add %s\"?" msgstr "" -#: ./pkg/client/client.go:51 -#, c-format -msgid "unknown server, run \"abra server add %s\"?" -msgstr "" - #: ./cli/app/cp.go:259 #, c-format msgid "untar: %s" @@ -5451,7 +5458,7 @@ msgstr "" msgid "up" msgstr "" -#: ./pkg/upstream/stack/stack.go:473 +#: ./pkg/upstream/stack/stack.go:477 #, c-format msgid "updating %s" msgstr "" @@ -5481,17 +5488,17 @@ msgstr "" msgid "upgrade [flags]" msgstr "" -#: ./cli/recipe/upgrade.go:249 +#: ./cli/recipe/upgrade.go:247 #, c-format msgid "upgrade to which tag? (service: %s, image: %s, tag: %s)" msgstr "" -#: ./cli/recipe/upgrade.go:255 +#: ./cli/recipe/upgrade.go:253 #, c-format msgid "upgrade to which tag? (service: %s, tag: %s)" msgstr "" -#: ./cli/recipe/upgrade.go:222 +#: ./cli/recipe/upgrade.go:220 #, c-format msgid "upgrading service %s from %s to %s (pinned tag: %s)" msgstr "" @@ -5563,7 +5570,7 @@ msgstr "" msgid "version" msgstr "" -#: ./pkg/app/app.go:690 +#: ./pkg/app/app.go:695 #, c-format msgid "version %s saved to %s.env" msgstr "" @@ -5582,6 +5589,10 @@ msgstr "" msgid "version for abra" msgstr "" +#: ./pkg/app/app.go:637 +msgid "version is unknown, skipping env write" +msgstr "" + #: ./pkg/recipe/recipe.go:130 #, c-format msgid "version seems invalid: %s" @@ -5592,27 +5603,27 @@ msgstr "" msgid "version wiped from %s.env" msgstr "" -#: ./cli/app/deploy.go:353 +#: ./cli/app/deploy.go:354 #, c-format msgid "version: taking chaos version: %s" msgstr "" -#: ./cli/app/deploy.go:379 +#: ./cli/app/deploy.go:380 #, c-format msgid "version: taking deployed version: %s" msgstr "" -#: ./cli/app/deploy.go:384 +#: ./cli/app/deploy.go:385 #, c-format msgid "version: taking new recipe version: %s" msgstr "" -#: ./cli/app/deploy.go:373 +#: ./cli/app/deploy.go:374 #, c-format msgid "version: taking version from .env file: %s" msgstr "" -#: ./cli/app/deploy.go:359 +#: ./cli/app/deploy.go:360 #, c-format msgid "version: taking version from cli arg: %s" msgstr "" @@ -5672,22 +5683,22 @@ msgstr "" msgid "volumes pruned: %d; space reclaimed: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:614 +#: ./pkg/upstream/stack/stack.go:625 #, c-format msgid "waitOnServices: error creating log dir: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:619 +#: ./pkg/upstream/stack/stack.go:630 #, c-format msgid "waitOnServices: error opening file: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:585 +#: ./pkg/upstream/stack/stack.go:596 #, c-format msgid "waitOnServices: error running TUI: %s" msgstr "" -#: ./pkg/upstream/stack/stack.go:625 +#: ./pkg/upstream/stack/stack.go:636 #, c-format msgid "waitOnServices: writeFile: %s" msgstr "" @@ -5718,7 +5729,7 @@ msgstr "" msgid "which service are you looking for?" msgstr "" -#: ./cli/recipe/sync.go:105 +#: ./cli/recipe/sync.go:109 msgid "which version do you want to begin with?" msgstr "" @@ -5735,16 +5746,16 @@ msgstr "" msgid "writer: %v, " msgstr "" -#: ./cli/app/deploy.go:277 ./cli/app/new.go:241 ./cli/app/rollback.go:255 ./cli/app/undeploy.go:120 ./cli/app/upgrade.go:300 +#: ./cli/app/deploy.go:278 ./cli/app/new.go:241 ./cli/app/rollback.go:256 ./cli/app/undeploy.go:120 ./cli/app/upgrade.go:301 #, c-format msgid "writing recipe version failed: %s" msgstr "" -#: ./cli/recipe/release.go:657 ./cli/recipe/sync.go:280 ./cli/recipe/upgrade.go:352 +#: ./cli/recipe/release.go:657 ./cli/recipe/sync.go:282 ./cli/recipe/upgrade.go:350 msgid "x" msgstr "" -#: ./cli/recipe/release.go:665 ./cli/recipe/sync.go:288 ./cli/recipe/upgrade.go:360 +#: ./cli/recipe/release.go:665 ./cli/recipe/sync.go:290 ./cli/recipe/upgrade.go:358 msgid "y" msgstr "" @@ -5752,15 +5763,15 @@ msgstr "" msgid "you can only use one of: --major, --minor, --patch" msgstr "" -#: ./cli/recipe/upgrade.go:81 +#: ./cli/recipe/upgrade.go:79 msgid "you can only use one of: --major, --minor, --patch." msgstr "" -#: ./cli/recipe/sync.go:203 +#: ./cli/recipe/sync.go:205 msgid "you can only use one version flag: --major, --minor or --patch" msgstr "" -#: ./cli/recipe/release.go:673 ./cli/recipe/sync.go:296 ./cli/recipe/upgrade.go:368 +#: ./cli/recipe/release.go:673 ./cli/recipe/sync.go:298 ./cli/recipe/upgrade.go:366 msgid "z" msgstr "" diff --git a/pkg/i18n/locales/es.mo b/pkg/i18n/locales/es.mo index 3dcc8f22..6b98ec66 100644 Binary files a/pkg/i18n/locales/es.mo and b/pkg/i18n/locales/es.mo differ diff --git a/pkg/i18n/locales/es.po b/pkg/i18n/locales/es.po index 03b2ec69..6ba1f6cb 100644 --- a/pkg/i18n/locales/es.po +++ b/pkg/i18n/locales/es.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL\n" -"POT-Creation-Date: 2025-11-02 11:41+0100\n" -"PO-Revision-Date: 2025-09-04 08:14+0000\n" +"POT-Creation-Date: 2025-12-21 16:38+0100\n" +"PO-Revision-Date: 2025-12-10 01:43+0000\n" "Last-Translator: chasqui \n" "Language-Team: Spanish \n" "Language: es\n" @@ -230,7 +230,7 @@ msgstr "" msgid "%s created (version: %s)" msgstr "" -#: cli/recipe/release.go:161 cli/recipe/sync.go:260 cli/recipe/upgrade.go:336 +#: cli/recipe/release.go:161 cli/recipe/sync.go:262 cli/recipe/upgrade.go:334 #, c-format msgid "%s currently has these unstaged changes 👇" msgstr "" @@ -285,12 +285,12 @@ msgstr "" msgid "%s has been detected as not deployed" msgstr "" -#: cli/app/restart.go:139 +#: cli/app/restart.go:140 #, c-format msgid "%s has been scaled to 0" msgstr "" -#: cli/app/restart.go:150 +#: cli/app/restart.go:151 #, c-format msgid "%s has been scaled to 1" msgstr "" @@ -350,19 +350,19 @@ msgstr "" msgid "%s is missing the TYPE env var?" msgstr "" -#: cli/app/rollback.go:308 cli/app/rollback.go:312 +#: cli/app/rollback.go:309 cli/app/rollback.go:313 #, c-format msgid "%s is not a downgrade for %s?" msgstr "" -#: cli/app/upgrade.go:428 cli/app/upgrade.go:432 +#: cli/app/upgrade.go:429 cli/app/upgrade.go:433 #, c-format msgid "%s is not an upgrade for %s?" msgstr "" #: cli/app/env.go:146 cli/app/logs.go:65 cli/app/ps.go:62 #: cli/app/restart.go:100 cli/app/services.go:55 cli/app/undeploy.go:66 -#: cli/app/upgrade.go:449 +#: cli/app/upgrade.go:450 #, c-format msgid "%s is not deployed?" msgstr "" @@ -392,7 +392,7 @@ msgstr "" msgid "%s must first be deployed on %s before moving" msgstr "" -#: cli/recipe/upgrade.go:151 +#: cli/recipe/upgrade.go:149 #, c-format msgid "%s not considered semver-like" msgstr "" @@ -437,7 +437,7 @@ msgstr "" msgid "%s service is missing image tag?" msgstr "" -#: cli/app/restart.go:151 +#: cli/app/restart.go:152 #, c-format msgid "%s service successfully restarted" msgstr "" @@ -472,7 +472,7 @@ msgstr "" msgid "%s/example.git" msgstr "" -#: pkg/upstream/stack/stack.go:602 +#: pkg/upstream/stack/stack.go:613 #, c-format msgid "%s: %s" msgstr "" @@ -562,12 +562,12 @@ msgstr "" msgid "%s: waiting %d seconds before next retry" msgstr "" -#: cli/app/upgrade.go:423 +#: cli/app/upgrade.go:424 #, c-format msgid "'%s' is not a known version" msgstr "" -#: cli/app/rollback.go:303 cli/app/upgrade.go:418 +#: cli/app/rollback.go:304 cli/app/upgrade.go:419 #, c-format msgid "'%s' is not a known version for %s" msgstr "" @@ -637,9 +637,9 @@ msgid "Both local recipe and live deployment labels are shown." msgstr "" #: cli/app/backup.go:319 cli/app/backup.go:335 cli/app/check.go:95 -#: cli/app/cmd.go:285 cli/app/cp.go:385 cli/app/deploy.go:395 +#: cli/app/cmd.go:285 cli/app/cp.go:385 cli/app/deploy.go:396 #: cli/app/labels.go:143 cli/app/new.go:397 cli/app/ps.go:213 -#: cli/app/restart.go:162 cli/app/restore.go:138 cli/app/secret.go:569 +#: cli/app/restart.go:163 cli/app/restore.go:138 cli/app/secret.go:569 #: cli/app/secret.go:609 cli/app/secret.go:633 cli/app/secret.go:641 #: cli/catalogue/catalogue.go:318 cli/recipe/lint.go:137 msgid "C" @@ -785,8 +785,8 @@ msgid "" "on your $PATH." msgstr "" -#: cli/app/deploy.go:411 cli/app/new.go:373 cli/app/rollback.go:360 -#: cli/app/upgrade.go:469 +#: cli/app/deploy.go:412 cli/app/new.go:373 cli/app/rollback.go:361 +#: cli/app/upgrade.go:470 msgid "D" msgstr "" @@ -910,7 +910,7 @@ msgstr "" msgid "Generate autocompletion script" msgstr "🤖 Genera un script de autocompletado" -#: cli/recipe/sync.go:32 +#: cli/recipe/sync.go:36 msgid "" "Generate labels for the main recipe service.\n" "\n" @@ -1144,7 +1144,7 @@ msgstr "" msgid "ON SERVER" msgstr "" -#: cli/recipe/sync.go:135 +#: cli/recipe/sync.go:138 msgid "PROPOSED CHANGES" msgstr "" @@ -1272,12 +1272,12 @@ msgstr "▶️ Restaurar una captura o instantánea 📸" #. translators: Short description for `app rollback` command #: cli/app/rollback.go:34 msgid "Roll an app back to a previous version" -msgstr "⏪ Revertir una plataforma 🚀 una versión anterior" +msgstr "⏪ Revertir una aplicación 🚀 una versión anterior" #. translators: Short description for `app run` command #: cli/app/run.go:30 msgid "Run a command inside a service container" -msgstr "💻 Ejecuta un comando dentro de un contenedor 🐋 creado solo para esa tarea" +msgstr "💻 Crea una instancia temporal de un contenedor 🐋 para ejecutar el comando especificado" #: cli/app/cmd.go:31 msgid "" @@ -1296,7 +1296,7 @@ msgstr "" #. translators: Short description for `app cmd` command #: cli/app/cmd.go:30 msgid "Run app commands" -msgstr "💻 Ejecutar comandos en una plataforma 🚀" +msgstr "💻 Ejecutar comandos en una aplicación 🚀" #: cli/app/backup.go:303 cli/app/list.go:292 cli/app/logs.go:109 #: cli/app/new.go:389 @@ -1315,7 +1315,7 @@ msgstr "" msgid "SERVER" msgstr "" -#: cli/app/ps.go:185 cli/recipe/sync.go:135 cli/recipe/version.go:69 +#: cli/app/ps.go:185 cli/recipe/sync.go:138 cli/recipe/version.go:69 #: cli/recipe/version.go:110 msgid "SERVICE" msgstr "" @@ -1384,7 +1384,7 @@ msgid "Sync recipe catalogue for latest changes" msgstr "🔃 Sincronizar catálogo de recetas 🧑‍🍳" #. translators: Short description for `recipe sync` command -#: cli/recipe/sync.go:31 +#: cli/recipe/sync.go:35 msgid "Sync recipe version label" msgstr "🔃 Sincronizar versión de la receta 🧑‍🍳" @@ -1399,7 +1399,7 @@ msgstr "" #. translators: Short description for `app logs` command #: cli/app/logs.go:27 msgid "Tail app logs" -msgstr "📋 Seguir logs 📈 de la plataforma 🚀" +msgstr "📋 Seguir logs 📈 de la aplicación 🚀" #. translators: Short description for `abra` binary #: cli/run.go:80 @@ -1518,7 +1518,7 @@ msgid "" " # and source this file from your PowerShell profile." msgstr "" -#: cli/app/deploy.go:435 cli/app/rollback.go:376 cli/app/upgrade.go:493 +#: cli/app/deploy.go:436 cli/app/rollback.go:377 cli/app/upgrade.go:494 msgid "U" msgstr "" @@ -1551,9 +1551,7 @@ msgid "" "\n" "The command is interactive and will show a select input which allows you to\n" "make a seclection. Use the \"?\" key to see more help on navigating this\n" -"interface.\n" -"\n" -"You may invoke this command in \"wizard\" mode and be prompted for input." +"interface." msgstr "" #. translators: Short description for `upgrade` command @@ -1575,7 +1573,7 @@ msgstr "" #. translators: Short description for `app upgrade` command #: cli/app/upgrade.go:36 msgid "Upgrade an app" -msgstr "📨 Actualizar una plataforma 🚀" +msgstr "📨 Actualizar una aplicación 🚀" #: cli/app/upgrade.go:37 msgid "" @@ -1658,7 +1656,7 @@ msgstr "" msgid "[hijack] end of stdout" msgstr "" -#: cli/recipe/sync.go:85 +#: cli/recipe/sync.go:89 #, c-format msgid "" "\n" @@ -1734,7 +1732,7 @@ msgctxt "app backup list" msgid "a" msgstr "" -#: cli/app/restart.go:169 +#: cli/app/restart.go:170 msgctxt "app restart" msgid "a" msgstr "" @@ -1754,7 +1752,7 @@ msgctxt "recipe fetch" msgid "a" msgstr "" -#: cli/recipe/upgrade.go:384 +#: cli/recipe/upgrade.go:382 msgctxt "recipe upgrade" msgid "a" msgstr "" @@ -1844,11 +1842,11 @@ msgstr "" msgid "all tasks reached terminal state" msgstr "" -#: cli/app/restart.go:168 +#: cli/app/restart.go:169 msgid "all-services" msgstr "" -#: cli/recipe/upgrade.go:383 +#: cli/recipe/upgrade.go:381 msgid "all-tags" msgstr "" @@ -1863,12 +1861,12 @@ msgstr "" #. translators: `abra app` command for autocompletion #: cli/run.go:91 msgid "app" -msgstr "plataforma" +msgstr "aplicacion" #. translators: `app` command group #: cli/app/app.go:16 msgid "app [cmd] [args] [flags]" -msgstr "plataforma [cmd] [args] [flags]" +msgstr "aplicacion [cmd] [args] [flags]" #: pkg/dns/dns.go:52 #, c-format @@ -1903,7 +1901,7 @@ msgstr "" msgid "attempting to run %s" msgstr "" -#: cli/app/deploy.go:272 cli/app/upgrade.go:295 +#: cli/app/deploy.go:273 cli/app/upgrade.go:296 #, c-format msgid "attempting to run post deploy commands, saw: %s" msgstr "" @@ -1913,7 +1911,7 @@ msgstr "" msgid "attempting to scale %s to 0" msgstr "" -#: cli/app/restart.go:140 +#: cli/app/restart.go:141 #, c-format msgid "attempting to scale %s to 1" msgstr "" @@ -1989,8 +1987,8 @@ msgstr "" #. no spaces in between #. translators: `abra app cp` aliases. use a comma separated list of aliases with #. no spaces in between -#: cli/app/backup.go:148 cli/app/cp.go:30 cli/app/deploy.go:419 -#: cli/app/rollback.go:368 cli/app/upgrade.go:477 +#: cli/app/backup.go:148 cli/app/cp.go:30 cli/app/deploy.go:420 +#: cli/app/rollback.go:369 cli/app/upgrade.go:478 msgid "c" msgstr "" @@ -1998,7 +1996,7 @@ msgstr "" msgid "can not insert from file and read from stdin" msgstr "" -#: cli/recipe/upgrade.go:324 +#: cli/recipe/upgrade.go:322 #, c-format msgid "can upgrade service: %s, image: %s, tag: %s ::" msgstr "" @@ -2031,7 +2029,7 @@ msgstr "" msgid "cannot find app with name %s" msgstr "" -#: pkg/upstream/stack/stack.go:657 +#: pkg/upstream/stack/stack.go:668 #, c-format msgid "cannot get label %s for %s" msgstr "" @@ -2046,7 +2044,7 @@ msgstr "" msgid "cannot redeploy previous chaos version (%s), did you mean to use \"--chaos\"?" msgstr "" -#: cli/app/deploy.go:369 +#: cli/app/deploy.go:370 #, c-format msgid "" "cannot redeploy previous chaos version (%s), did you mean to use \"--chaos\"?\n" @@ -2066,7 +2064,7 @@ msgstr "" msgid "cannot use '[secret] [version]' and '--all' together" msgstr "" -#: cli/app/deploy.go:311 +#: cli/app/deploy.go:312 msgid "cannot use --chaos and --latest together" msgstr "" @@ -2090,11 +2088,11 @@ msgstr "" msgid "cannot use [service] and --all-services/-a together" msgstr "" -#: cli/app/deploy.go:303 cli/app/new.go:76 +#: cli/app/deploy.go:304 cli/app/new.go:76 msgid "cannot use [version] and --chaos together" msgstr "" -#: cli/app/deploy.go:307 +#: cli/app/deploy.go:308 msgid "cannot use [version] and --latest together" msgstr "" @@ -2116,6 +2114,10 @@ msgstr "" msgid "catalogue successfully synced" msgstr "" +#: cli/recipe/sync.go:24 +msgid "catalogue versions list is unexpectedly empty" +msgstr "" + #: cli/recipe/list.go:44 msgid "category" msgstr "" @@ -2127,9 +2129,9 @@ msgid "cfg" msgstr "" #: cli/app/backup.go:318 cli/app/backup.go:334 cli/app/check.go:94 -#: cli/app/cmd.go:284 cli/app/cp.go:384 cli/app/deploy.go:394 +#: cli/app/cmd.go:284 cli/app/cp.go:384 cli/app/deploy.go:395 #: cli/app/labels.go:142 cli/app/new.go:396 cli/app/ps.go:212 -#: cli/app/restart.go:161 cli/app/restore.go:137 cli/app/secret.go:568 +#: cli/app/restart.go:162 cli/app/restore.go:137 cli/app/secret.go:568 #: cli/app/secret.go:608 cli/app/secret.go:632 cli/app/secret.go:640 #: cli/catalogue/catalogue.go:317 cli/recipe/lint.go:136 msgid "chaos" @@ -2140,7 +2142,7 @@ msgstr "" msgid "check [flags]" msgstr "verificar [flags]" -#: cli/app/deploy.go:94 cli/app/undeploy.go:58 cli/app/upgrade.go:441 +#: cli/app/deploy.go:94 cli/app/undeploy.go:58 cli/app/upgrade.go:442 #, c-format msgid "checking whether %s is already deployed" msgstr "" @@ -2156,7 +2158,7 @@ msgstr "" msgid "choosing %s as latest version of %s" msgstr "" -#: cli/recipe/sync.go:237 +#: cli/recipe/sync.go:239 #, c-format msgid "choosing %s as new version for %s" msgstr "" @@ -2309,7 +2311,7 @@ msgstr "" msgid "context lacks Docker endpoint" msgstr "" -#: cli/recipe/sync.go:246 pkg/recipe/compose.go:229 +#: cli/recipe/sync.go:248 pkg/recipe/compose.go:229 #, c-format msgid "coop-cloud.${STACK_NAME}.version=%s" msgstr "" @@ -2363,7 +2365,7 @@ msgstr "" msgid "create remote directory: %s" msgstr "" -#: pkg/client/client.go:102 +#: pkg/client/client.go:111 #, c-format msgid "created client for %s" msgstr "" @@ -2383,7 +2385,7 @@ msgstr "" msgid "created the %s context" msgstr "" -#: pkg/upstream/stack/stack.go:520 +#: pkg/upstream/stack/stack.go:524 #, c-format msgid "creating %s" msgstr "" @@ -2398,12 +2400,12 @@ msgstr "" msgid "creating context with domain %s" msgstr "" -#: pkg/upstream/stack/stack.go:422 +#: pkg/upstream/stack/stack.go:426 #, c-format msgid "creating network %s" msgstr "" -#: pkg/upstream/stack/stack.go:369 +#: pkg/upstream/stack/stack.go:373 #, c-format msgid "creating secret %s" msgstr "" @@ -2422,7 +2424,7 @@ msgstr "" msgid "critical errors present in %s config" msgstr "" -#: cli/app/rollback.go:298 +#: cli/app/rollback.go:299 #, c-format msgid "current deployment '%s' is not a known version for %s" msgstr "" @@ -2462,11 +2464,11 @@ msgstr "" msgid "deploy [version] [flags]" msgstr "desplegar [version] [flags]" -#: pkg/upstream/stack/stack.go:593 +#: pkg/upstream/stack/stack.go:604 msgid "deploy failed 🛑" msgstr "" -#: pkg/upstream/stack/stack.go:597 +#: pkg/upstream/stack/stack.go:608 msgid "deploy in progress 🟠" msgstr "" @@ -2474,16 +2476,16 @@ msgstr "" msgid "deploy labels stanza present" msgstr "" -#: cli/app/deploy.go:429 +#: cli/app/deploy.go:430 #, fuzzy msgid "deploy latest recipe version" msgstr "Publicar una nueva versión de una receta" -#: pkg/upstream/stack/stack.go:637 +#: pkg/upstream/stack/stack.go:648 msgid "deploy succeeded 🟢" msgstr "" -#: pkg/upstream/stack/stack.go:595 +#: pkg/upstream/stack/stack.go:606 msgid "deploy timed out 🟠" msgstr "" @@ -2518,12 +2520,12 @@ msgstr "" msgid "detected ABRA_CI=1" msgstr "" -#: cli/recipe/upgrade.go:205 +#: cli/recipe/upgrade.go:203 #, c-format msgid "detected compatible upgradable tags %s for %s" msgstr "" -#: cli/recipe/upgrade.go:178 +#: cli/recipe/upgrade.go:176 #, c-format msgid "detected potential upgradable tags %s for %s" msgstr "" @@ -2537,7 +2539,7 @@ msgstr "" msgid "did not detect any command arguments" msgstr "" -#: cli/recipe/upgrade.go:125 +#: cli/recipe/upgrade.go:123 #, c-format msgid "did not find versions file for %s" msgstr "" @@ -2577,11 +2579,11 @@ msgstr "" msgid "dirty: %v, " msgstr "" -#: cli/app/deploy.go:421 cli/app/rollback.go:370 cli/app/upgrade.go:479 +#: cli/app/deploy.go:422 cli/app/rollback.go:371 cli/app/upgrade.go:480 msgid "disable converge logic checks" msgstr "" -#: cli/app/deploy.go:413 cli/app/rollback.go:362 cli/app/upgrade.go:471 +#: cli/app/deploy.go:414 cli/app/rollback.go:363 cli/app/upgrade.go:472 msgid "disable public DNS checks" msgstr "" @@ -2655,7 +2657,7 @@ msgstr "" msgid "dry run: no git tag created (%s)" msgstr "" -#: cli/recipe/sync.go:252 +#: cli/recipe/sync.go:254 #, c-format msgid "dry run: not syncing label %s for recipe %s" msgstr "" @@ -2666,7 +2668,7 @@ msgid "dry run: remote %s (%s) not created" msgstr "" #: cli/app/move.go:349 cli/catalogue/catalogue.go:301 cli/recipe/release.go:648 -#: cli/recipe/sync.go:271 +#: cli/recipe/sync.go:273 msgid "dry-run" msgstr "" @@ -2717,7 +2719,7 @@ msgstr "" msgid "ensuring env version %s" msgstr "" -#: cli/recipe/upgrade.go:286 +#: cli/recipe/upgrade.go:284 msgid "enter / return to confirm, choose 'skip' to not upgrade this tag, vim mode is enabled" msgstr "" @@ -2803,8 +2805,8 @@ msgstr "" #. translators: `abra recipe fetch` aliases. use a comma separated list of aliases #. with no spaces in between -#: cli/app/deploy.go:403 cli/app/env.go:325 cli/app/remove.go:163 -#: cli/app/rollback.go:352 cli/app/secret.go:593 cli/app/upgrade.go:461 +#: cli/app/deploy.go:404 cli/app/env.go:325 cli/app/remove.go:163 +#: cli/app/rollback.go:353 cli/app/secret.go:593 cli/app/upgrade.go:462 #: cli/app/volume.go:217 cli/recipe/fetch.go:20 cli/recipe/fetch.go:138 msgid "f" msgstr "" @@ -2839,22 +2841,22 @@ msgstr "" msgid "failed to copy %s from local machine to %s: output:%s err:%s" msgstr "" -#: pkg/upstream/stack/stack.go:531 +#: pkg/upstream/stack/stack.go:535 #, c-format msgid "failed to create %s" msgstr "" -#: pkg/upstream/stack/stack.go:393 +#: pkg/upstream/stack/stack.go:397 #, c-format msgid "failed to create config %s" msgstr "" -#: pkg/upstream/stack/stack.go:424 +#: pkg/upstream/stack/stack.go:428 #, c-format msgid "failed to create network %s" msgstr "" -#: pkg/upstream/stack/stack.go:371 +#: pkg/upstream/stack/stack.go:375 #, c-format msgid "failed to create secret %s" msgstr "" @@ -2951,7 +2953,7 @@ msgstr "" msgid "failed to retrieve latest commit for %s: %s" msgstr "" -#: pkg/upstream/stack/stack.go:468 +#: pkg/upstream/stack/stack.go:472 #, c-format msgid "failed to retrieve registry auth for image %s: %s" msgstr "" @@ -2971,17 +2973,17 @@ msgstr "🥷 Genera secretos (contraseñas) automáticamente 🤖" msgid "failed to tag release: %s" msgstr "" -#: pkg/upstream/stack/stack.go:508 +#: pkg/upstream/stack/stack.go:512 #, c-format msgid "failed to update %s" msgstr "" -#: pkg/upstream/stack/stack.go:387 +#: pkg/upstream/stack/stack.go:391 #, c-format msgid "failed to update config %s" msgstr "" -#: pkg/upstream/stack/stack.go:365 +#: pkg/upstream/stack/stack.go:369 #, c-format msgid "failed to update secret %s" msgstr "" @@ -3036,8 +3038,8 @@ msgstr "" msgid "final merged env values for %s are: %s" msgstr "" -#: cli/app/deploy.go:402 cli/app/env.go:324 cli/app/remove.go:162 -#: cli/app/rollback.go:351 cli/app/upgrade.go:460 cli/app/volume.go:216 +#: cli/app/deploy.go:403 cli/app/env.go:324 cli/app/remove.go:162 +#: cli/app/rollback.go:352 cli/app/upgrade.go:461 cli/app/volume.go:216 #: cli/recipe/fetch.go:137 msgid "force" msgstr "" @@ -3046,7 +3048,7 @@ msgstr "" msgid "force re-fetch" msgstr "" -#: cli/recipe/upgrade.go:97 +#: cli/recipe/upgrade.go:95 #, c-format msgid "found versions file for %s" msgstr "" @@ -3254,9 +3256,9 @@ msgid "id: %s, " msgstr "" #: cli/app/backup.go:321 cli/app/backup.go:337 cli/app/check.go:97 -#: cli/app/cmd.go:287 cli/app/cp.go:387 cli/app/deploy.go:397 +#: cli/app/cmd.go:287 cli/app/cp.go:387 cli/app/deploy.go:398 #: cli/app/labels.go:145 cli/app/new.go:399 cli/app/ps.go:215 -#: cli/app/restart.go:164 cli/app/restore.go:140 cli/app/secret.go:571 +#: cli/app/restart.go:165 cli/app/restore.go:140 cli/app/secret.go:571 #: cli/app/secret.go:611 cli/app/secret.go:635 cli/app/secret.go:643 #: cli/catalogue/catalogue.go:320 cli/recipe/lint.go:139 msgid "ignore uncommitted recipes changes" @@ -3347,15 +3349,15 @@ msgstr "" msgid "including VOLUMES=%v in backupbot exec invocation" msgstr "" -#: cli/recipe/release.go:659 cli/recipe/sync.go:282 cli/recipe/upgrade.go:354 +#: cli/recipe/release.go:659 cli/recipe/sync.go:284 cli/recipe/upgrade.go:352 msgid "increase the major part of the version" msgstr "" -#: cli/recipe/release.go:667 cli/recipe/sync.go:290 cli/recipe/upgrade.go:362 +#: cli/recipe/release.go:667 cli/recipe/sync.go:292 cli/recipe/upgrade.go:360 msgid "increase the minor part of the version" msgstr "" -#: cli/recipe/release.go:675 cli/recipe/sync.go:298 cli/recipe/upgrade.go:370 +#: cli/recipe/release.go:675 cli/recipe/sync.go:300 cli/recipe/upgrade.go:368 msgid "increase the patch part of the version" msgstr "" @@ -3369,7 +3371,7 @@ msgstr "" msgid "initialised new git repo in %s" msgstr "" -#: pkg/upstream/stack/stack.go:206 +#: pkg/upstream/stack/stack.go:207 msgid "initialising deployment" msgstr "" @@ -3433,7 +3435,7 @@ msgstr "" msgid "invalid npipe source, source cannot be empty" msgstr "" -#: pkg/upstream/stack/stack.go:239 +#: pkg/upstream/stack/stack.go:241 #, c-format msgid "invalid option %s for flag --resolve-image" msgstr "" @@ -3447,7 +3449,7 @@ msgstr "" msgid "invalid tmpfs source, source must be empty" msgstr "" -#: cli/recipe/sync.go:242 +#: cli/recipe/sync.go:244 #, c-format msgid "invalid version %s specified" msgstr "" @@ -3456,7 +3458,7 @@ msgstr "" #. no spaces in between #. translators: `abra recipe lint` aliases. use a comma separated list of #. aliases with no spaces in between -#: cli/app/cmd.go:261 cli/app/deploy.go:427 cli/app/logs.go:20 +#: cli/app/cmd.go:261 cli/app/deploy.go:428 cli/app/logs.go:20 #: cli/recipe/lint.go:17 cli/server/add.go:207 msgid "l" msgstr "" @@ -3472,7 +3474,7 @@ msgstr "" msgid "labels [flags]" msgstr "etiquetas [flags]" -#: cli/app/deploy.go:426 cli/app/list.go:182 +#: cli/app/deploy.go:427 cli/app/list.go:182 msgid "latest" msgstr "" @@ -3527,7 +3529,7 @@ msgstr "listar [flags]" msgid "list [flags]" msgstr "listar [flags]" -#: cli/recipe/upgrade.go:386 +#: cli/recipe/upgrade.go:384 msgid "list all tags, not just upgrades" msgstr "" @@ -3562,12 +3564,12 @@ msgstr "" msgid "logs [service] [flags]" msgstr "" -#: pkg/upstream/stack/stack.go:628 +#: pkg/upstream/stack/stack.go:639 #, c-format msgid "logs: %s" msgstr "" -#: pkg/upstream/stack/stack.go:630 +#: pkg/upstream/stack/stack.go:641 msgid "logs: no log output received from deployment" msgstr "" @@ -3601,13 +3603,13 @@ msgstr "plataformas" #. with no spaces in between #: cli/app/list.go:315 cli/app/move.go:34 cli/app/ps.go:205 #: cli/app/secret.go:553 cli/app/secret.go:649 cli/recipe/list.go:104 -#: cli/recipe/upgrade.go:376 cli/recipe/version.go:139 cli/run.go:152 +#: cli/recipe/upgrade.go:374 cli/recipe/version.go:139 cli/run.go:152 #: cli/server/list.go:106 msgid "m" msgstr "" #: cli/app/list.go:314 cli/app/ps.go:204 cli/app/secret.go:552 -#: cli/app/secret.go:648 cli/recipe/list.go:103 cli/recipe/upgrade.go:375 +#: cli/app/secret.go:648 cli/recipe/list.go:103 cli/recipe/upgrade.go:373 #: cli/recipe/version.go:138 cli/server/list.go:105 msgid "machine" msgstr "" @@ -3618,12 +3620,12 @@ msgid "main app service version for %s is empty?" msgstr "" #: cli/internal/recipe.go:48 cli/internal/recipe.go:66 -#: cli/internal/recipe.go:80 cli/recipe/release.go:656 cli/recipe/sync.go:279 -#: cli/recipe/upgrade.go:351 +#: cli/internal/recipe.go:80 cli/recipe/release.go:656 cli/recipe/sync.go:281 +#: cli/recipe/upgrade.go:349 msgid "major" msgstr "" -#: cli/recipe/upgrade.go:107 +#: cli/recipe/upgrade.go:105 #, c-format msgid "malformed version pin specification: %s" msgstr "" @@ -3649,8 +3651,8 @@ msgid "migrating app config from %s to %s" msgstr "" #: cli/internal/recipe.go:48 cli/internal/recipe.go:68 -#: cli/internal/recipe.go:82 cli/recipe/release.go:664 cli/recipe/sync.go:287 -#: cli/recipe/upgrade.go:359 +#: cli/internal/recipe.go:82 cli/recipe/release.go:664 cli/recipe/sync.go:289 +#: cli/recipe/upgrade.go:357 msgid "minor" msgstr "" @@ -3714,12 +3716,12 @@ msgstr "" msgid "need 3 or 4 arguments" msgstr "" -#: pkg/upstream/stack/stack.go:348 +#: pkg/upstream/stack/stack.go:352 #, c-format msgid "network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed, which you can do by running this on the server: docker network create -d overlay proxy" msgstr "" -#: pkg/upstream/stack/stack.go:352 +#: pkg/upstream/stack/stack.go:356 #, c-format msgid "network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"" msgstr "" @@ -3834,12 +3836,12 @@ msgstr "" msgid "no existing label found, automagic insertion not supported yet" msgstr "" -#: cli/recipe/sync.go:81 +#: cli/recipe/sync.go:85 #, c-format msgid "no git tags found for %s" msgstr "" -#: cli/recipe/upgrade.go:183 +#: cli/recipe/upgrade.go:181 #, c-format msgid "no new versions available for %s, assuming %s is the latest (use -a/--all-tags to see all anyway)" msgstr "" @@ -3942,11 +3944,11 @@ msgstr "" msgid "no volumes to remove" msgstr "" -#: cli/app/deploy.go:418 cli/app/rollback.go:367 cli/app/upgrade.go:476 +#: cli/app/deploy.go:419 cli/app/rollback.go:368 cli/app/upgrade.go:477 msgid "no-converge-checks" msgstr "" -#: cli/app/deploy.go:410 cli/app/rollback.go:359 cli/app/upgrade.go:468 +#: cli/app/deploy.go:411 cli/app/rollback.go:360 cli/app/upgrade.go:469 msgid "no-domain-checks" msgstr "" @@ -3967,12 +3969,12 @@ msgstr "" msgid "not requesting a remote TTY" msgstr "" -#: cli/recipe/upgrade.go:306 +#: cli/recipe/upgrade.go:304 #, c-format msgid "not upgrading %s, skipping as requested" msgstr "" -#: cli/recipe/upgrade.go:245 +#: cli/recipe/upgrade.go:243 #, c-format msgid "not upgrading from %s to %s for %s, because the upgrade type is more serious than what user wants" msgstr "" @@ -4002,7 +4004,7 @@ msgstr "" msgid "only show errors" msgstr "" -#: cli/app/upgrade.go:487 +#: cli/app/upgrade.go:488 msgid "only show release notes" msgstr "" @@ -4021,7 +4023,7 @@ msgstr "" msgid "p" msgstr "" -#: cli/recipe/upgrade.go:164 +#: cli/recipe/upgrade.go:162 #, c-format msgid "parsed %s for %s" msgstr "" @@ -4036,22 +4038,22 @@ msgstr "" msgid "parsed following command arguments: %s" msgstr "" -#: cli/app/upgrade.go:344 +#: cli/app/upgrade.go:345 #, c-format msgid "parsing chosen upgrade version failed: %s" msgstr "" -#: cli/app/upgrade.go:388 +#: cli/app/upgrade.go:389 #, c-format msgid "parsing deployed version failed: %s" msgstr "" -#: cli/app/upgrade.go:349 +#: cli/app/upgrade.go:350 #, c-format msgid "parsing deployment version failed: %s" msgstr "" -#: cli/app/upgrade.go:355 cli/app/upgrade.go:394 +#: cli/app/upgrade.go:356 cli/app/upgrade.go:395 #, c-format msgid "parsing recipe version failed: %s" msgstr "" @@ -4066,8 +4068,8 @@ msgid "pass command not found on $PATH, is it installed?" msgstr "" #: cli/internal/recipe.go:48 cli/internal/recipe.go:70 -#: cli/internal/recipe.go:84 cli/recipe/release.go:672 cli/recipe/sync.go:295 -#: cli/recipe/upgrade.go:367 +#: cli/internal/recipe.go:84 cli/recipe/release.go:672 cli/recipe/sync.go:297 +#: cli/recipe/upgrade.go:365 msgid "patch" msgstr "" @@ -4079,8 +4081,8 @@ msgstr "" msgid "pattern" msgstr "" -#: cli/app/deploy.go:405 cli/app/env.go:327 cli/app/remove.go:165 -#: cli/app/rollback.go:354 cli/app/upgrade.go:463 cli/app/volume.go:219 +#: cli/app/deploy.go:406 cli/app/env.go:327 cli/app/remove.go:165 +#: cli/app/rollback.go:355 cli/app/upgrade.go:464 cli/app/volume.go:219 msgid "perform action without further prompt" msgstr "" @@ -4095,27 +4097,27 @@ msgstr "" msgid "please fix your synced label for %s and re-run this command" msgstr "" -#: cli/app/rollback.go:266 +#: cli/app/rollback.go:267 #, c-format msgid "please select a downgrade (version: %s):" msgstr "" -#: cli/app/rollback.go:271 +#: cli/app/rollback.go:272 #, c-format msgid "please select a downgrade (version: %s, chaos: %s):" msgstr "" -#: cli/app/upgrade.go:311 +#: cli/app/upgrade.go:312 #, c-format msgid "please select an upgrade (version: %s):" msgstr "" -#: cli/app/upgrade.go:316 +#: cli/app/upgrade.go:317 #, c-format msgid "please select an upgrade (version: %s, chaos: %s):" msgstr "" -#: pkg/upstream/stack/stack.go:576 +#: pkg/upstream/stack/stack.go:587 msgid "polling deployment status" msgstr "" @@ -4133,7 +4135,7 @@ msgid "previous git tags detected, assuming new semver release" msgstr "" #: cli/app/list.go:317 cli/app/ps.go:207 cli/app/secret.go:555 -#: cli/app/secret.go:651 cli/recipe/list.go:106 cli/recipe/upgrade.go:378 +#: cli/app/secret.go:651 cli/recipe/list.go:106 cli/recipe/upgrade.go:376 #: cli/recipe/version.go:141 cli/server/list.go:108 msgid "print machine-readable output" msgstr "" @@ -4206,8 +4208,8 @@ msgstr "" #. translators: `abra recipe` aliases. use a comma separated list of aliases #. with no spaces in between #: cli/app/backup.go:327 cli/app/list.go:300 cli/app/move.go:350 -#: cli/app/run.go:23 cli/app/upgrade.go:485 cli/catalogue/catalogue.go:302 -#: cli/recipe/recipe.go:12 cli/recipe/release.go:649 cli/recipe/sync.go:272 +#: cli/app/run.go:23 cli/app/upgrade.go:486 cli/catalogue/catalogue.go:302 +#: cli/recipe/recipe.go:12 cli/recipe/release.go:649 cli/recipe/sync.go:274 msgid "r" msgstr "" @@ -4325,7 +4327,7 @@ msgstr "" msgid "release [version] [flags]" msgstr "publicar [version] [flags]" -#: cli/app/upgrade.go:484 +#: cli/app/upgrade.go:485 msgid "releasenotes" msgstr "" @@ -4462,7 +4464,7 @@ msgid "repo set config: %s" msgstr "" #: cli/app/move.go:352 cli/catalogue/catalogue.go:304 cli/recipe/release.go:651 -#: cli/recipe/sync.go:274 +#: cli/recipe/sync.go:276 msgid "report changes that would be made" msgstr "" @@ -4492,7 +4494,7 @@ msgstr "" msgid "restart [[service] | --all-services] [flags]" msgstr "reiniciar [[service] | --all-services] [flags]" -#: cli/app/restart.go:171 +#: cli/app/restart.go:172 msgid "restart all services" msgstr "" @@ -4533,7 +4535,7 @@ msgstr "" msgid "retrieved %s for %s" msgstr "" -#: cli/recipe/upgrade.go:145 +#: cli/recipe/upgrade.go:143 #, c-format msgid "retrieved %s from remote registry for %s" msgstr "" @@ -4557,7 +4559,7 @@ msgstr "" msgid "retrieved versions from local recipe repository" msgstr "" -#: pkg/upstream/stack/stack.go:464 +#: pkg/upstream/stack/stack.go:468 #, c-format msgid "retrieving docker auth token: failed create docker cli: %s" msgstr "" @@ -4621,7 +4623,7 @@ msgstr "" #. translators: `app run` command #: cli/app/run.go:27 msgid "run [[args] [flags] | [flags] -- [args]]" -msgstr "lanzar [[args] [flags] | [flags] -- [args]]" +msgstr "correr [[args] [flags] | [flags] -- [args]]" #: cli/app/run.go:120 msgid "run command as user" @@ -4631,7 +4633,7 @@ msgstr "" msgid "run command locally" msgstr "" -#: cli/app/deploy.go:270 cli/app/upgrade.go:292 +#: cli/app/deploy.go:271 cli/app/upgrade.go:293 #, c-format msgid "run the following post-deploy commands: %s" msgstr "" @@ -4678,7 +4680,7 @@ msgstr "" #: cli/app/env.go:333 cli/app/list.go:323 cli/app/logs.go:101 #: cli/app/new.go:358 cli/app/restore.go:114 cli/app/secret.go:535 #: cli/catalogue/catalogue.go:27 cli/catalogue/catalogue.go:310 -#: cli/recipe/fetch.go:130 cli/recipe/sync.go:24 cli/server/server.go:12 +#: cli/recipe/fetch.go:130 cli/recipe/sync.go:28 cli/server/server.go:12 msgid "s" msgstr "" @@ -4720,12 +4722,12 @@ msgstr "" msgid "secret not found: %s" msgstr "" -#: cli/app/deploy.go:339 +#: cli/app/deploy.go:340 #, c-format msgid "secret not generated: %s" msgstr "" -#: cli/app/deploy.go:337 +#: cli/app/deploy.go:338 #, c-format msgid "secret not inserted (#generate=false): %s" msgstr "" @@ -4774,11 +4776,21 @@ msgstr "" msgid "server doesn't exist?" msgstr "" -#: pkg/client/client.go:48 +#: pkg/client/client.go:54 +#, c-format +msgid "server missing context, context creation failed: %s" +msgstr "" + +#: pkg/client/client.go:59 #, c-format msgid "server missing context, run \"abra server add %s\"?" msgstr "" +#: pkg/client/client.go:48 +#, c-format +msgid "server missing, run \"abra server add %s\"?" +msgstr "" + #: cli/server/add.go:148 #, c-format msgid "serverAdd: cleanUp: %s is not empty, aborting cleanup" @@ -4799,12 +4811,12 @@ msgstr "" msgid "serverAdd: cleanUp: unable to list files in %s: %s" msgstr "" -#: cli/recipe/upgrade.go:228 +#: cli/recipe/upgrade.go:226 #, c-format msgid "service %s is at version %s, but pinned to %s, please correct your compose.yml file manually!" msgstr "" -#: cli/recipe/upgrade.go:224 +#: cli/recipe/upgrade.go:222 #, c-format msgid "service %s, image %s pinned to %s, no compatible upgrade found" msgstr "" @@ -4851,7 +4863,7 @@ msgstr "" msgid "severity" msgstr "" -#: cli/app/deploy.go:437 cli/app/rollback.go:378 cli/app/upgrade.go:495 +#: cli/app/deploy.go:438 cli/app/rollback.go:379 cli/app/upgrade.go:496 msgid "show all configs & images, including unchanged ones" msgstr "" @@ -4875,7 +4887,7 @@ msgstr "" msgid "show debug messages" msgstr "" -#: cli/app/deploy.go:434 cli/app/rollback.go:375 cli/app/upgrade.go:492 +#: cli/app/deploy.go:435 cli/app/rollback.go:376 cli/app/upgrade.go:493 msgid "show-unchanged" msgstr "" @@ -4919,7 +4931,7 @@ msgstr "" msgid "skipping as requested, undeploy still in progress 🟠" msgstr "" -#: pkg/upstream/stack/stack.go:306 +#: pkg/upstream/stack/stack.go:309 msgid "skipping converge logic checks" msgstr "" @@ -4941,12 +4953,12 @@ msgstr "" msgid "skipping secret (because it already exists) on %s: %s" msgstr "" -#: pkg/app/app.go:692 +#: pkg/app/app.go:697 #, c-format msgid "skipping version %s write as already exists in %s.env" msgstr "" -#: pkg/app/app.go:686 +#: pkg/app/app.go:691 #, c-format msgid "skipping writing version %s because dry run" msgstr "" @@ -5054,17 +5066,17 @@ msgstr "" msgid "successfully created %s" msgstr "" -#: pkg/client/client.go:111 +#: pkg/client/client.go:120 #, c-format msgid "swarm mode not enabled on %s?" msgstr "" -#: pkg/client/client.go:114 +#: pkg/client/client.go:123 msgid "swarm mode not enabled on local server?" msgstr "" #. translators: `recipe sync` command -#: cli/recipe/sync.go:28 +#: cli/recipe/sync.go:32 msgid "sync [version] [flags]" msgstr "sincronizar [version] [flags]" @@ -5087,12 +5099,12 @@ msgstr "" msgid "tag all images with stable tags" msgstr "" -#: cli/recipe/sync.go:178 +#: cli/recipe/sync.go:180 #, c-format msgid "tag at commit %s is unannotated or otherwise broken" msgstr "" -#: cli/recipe/upgrade.go:302 +#: cli/recipe/upgrade.go:300 #, c-format msgid "tag upgraded from %s to %s for %s" msgstr "" @@ -5136,7 +5148,7 @@ msgstr "" msgid "timeout label: %s" msgstr "" -#: pkg/upstream/stack/remove.go:29 pkg/upstream/stack/stack.go:209 +#: pkg/upstream/stack/remove.go:29 pkg/upstream/stack/stack.go:210 #, c-format msgid "timeout: set to %d second(s)" msgstr "" @@ -5231,7 +5243,7 @@ msgstr "" msgid "unable to connect to %s, please check your SSH config" msgstr "" -#: cli/recipe/sync.go:83 +#: cli/recipe/sync.go:87 msgid "unable to continue, input required for initial version" msgstr "" @@ -5270,7 +5282,7 @@ msgstr "" msgid "unable to determine server of app %s, please pass --server/-s" msgstr "" -#: cli/recipe/upgrade.go:253 +#: cli/recipe/upgrade.go:251 #, c-format msgid "unable to determine versioning semantics of %s, listing all tags" msgstr "" @@ -5345,7 +5357,7 @@ msgstr "" msgid "unable to open worktree of %s: %s" msgstr "" -#: cli/recipe/upgrade.go:160 +#: cli/recipe/upgrade.go:158 #, c-format msgid "unable to parse %s, error was: %s, skipping upgrade for %s" msgstr "" @@ -5385,7 +5397,7 @@ msgstr "🥷 Genera secretos (contraseñas) automáticamente 🤖" msgid "unable to read remotes in %s: %s" msgstr "" -#: cli/recipe/upgrade.go:154 +#: cli/recipe/upgrade.go:152 #, c-format msgid "unable to read tag for image %s, is it missing? skipping upgrade for %s" msgstr "" @@ -5499,7 +5511,7 @@ msgstr "" #. translators: `app undeploy` command #: cli/app/undeploy.go:28 msgid "undeploy [flags]" -msgstr "desarmar [flags]" +msgstr "recoger [flags]" #: cli/app/undeploy.go:117 msgid "undeploy succeeded 🟢" @@ -5565,11 +5577,6 @@ msgstr "" msgid "unknown server %s, run \"abra server add %s\"?" msgstr "" -#: pkg/client/client.go:51 -#, c-format -msgid "unknown server, run \"abra server add %s\"?" -msgstr "" - #: cli/app/cp.go:259 #, c-format msgid "untar: %s" @@ -5581,7 +5588,7 @@ msgstr "" msgid "up" msgstr "" -#: pkg/upstream/stack/stack.go:473 +#: pkg/upstream/stack/stack.go:477 #, c-format msgid "updating %s" msgstr "" @@ -5611,17 +5618,17 @@ msgstr "actualizar [flags]" msgid "upgrade [flags]" msgstr "actualizar [flags]" -#: cli/recipe/upgrade.go:249 +#: cli/recipe/upgrade.go:247 #, c-format msgid "upgrade to which tag? (service: %s, image: %s, tag: %s)" msgstr "" -#: cli/recipe/upgrade.go:255 +#: cli/recipe/upgrade.go:253 #, c-format msgid "upgrade to which tag? (service: %s, tag: %s)" msgstr "" -#: cli/recipe/upgrade.go:222 +#: cli/recipe/upgrade.go:220 #, c-format msgid "upgrading service %s from %s to %s (pinned tag: %s)" msgstr "" @@ -5694,7 +5701,7 @@ msgstr "" msgid "version" msgstr "" -#: pkg/app/app.go:690 +#: pkg/app/app.go:695 #, c-format msgid "version %s saved to %s.env" msgstr "" @@ -5713,6 +5720,10 @@ msgstr "" msgid "version for abra" msgstr "" +#: pkg/app/app.go:637 +msgid "version is unknown, skipping env write" +msgstr "" + #: pkg/recipe/recipe.go:130 #, c-format msgid "version seems invalid: %s" @@ -5723,27 +5734,27 @@ msgstr "" msgid "version wiped from %s.env" msgstr "" -#: cli/app/deploy.go:353 +#: cli/app/deploy.go:354 #, c-format msgid "version: taking chaos version: %s" msgstr "" -#: cli/app/deploy.go:379 +#: cli/app/deploy.go:380 #, c-format msgid "version: taking deployed version: %s" msgstr "" -#: cli/app/deploy.go:384 +#: cli/app/deploy.go:385 #, c-format msgid "version: taking new recipe version: %s" msgstr "" -#: cli/app/deploy.go:373 +#: cli/app/deploy.go:374 #, c-format msgid "version: taking version from .env file: %s" msgstr "" -#: cli/app/deploy.go:359 +#: cli/app/deploy.go:360 #, c-format msgid "version: taking version from cli arg: %s" msgstr "" @@ -5803,22 +5814,22 @@ msgstr "" msgid "volumes pruned: %d; space reclaimed: %s" msgstr "" -#: pkg/upstream/stack/stack.go:614 +#: pkg/upstream/stack/stack.go:625 #, c-format msgid "waitOnServices: error creating log dir: %s" msgstr "" -#: pkg/upstream/stack/stack.go:619 +#: pkg/upstream/stack/stack.go:630 #, c-format msgid "waitOnServices: error opening file: %s" msgstr "" -#: pkg/upstream/stack/stack.go:585 +#: pkg/upstream/stack/stack.go:596 #, c-format msgid "waitOnServices: error running TUI: %s" msgstr "" -#: pkg/upstream/stack/stack.go:625 +#: pkg/upstream/stack/stack.go:636 #, c-format msgid "waitOnServices: writeFile: %s" msgstr "" @@ -5852,7 +5863,7 @@ msgstr "" msgid "which service are you looking for?" msgstr "" -#: cli/recipe/sync.go:105 +#: cli/recipe/sync.go:109 msgid "which version do you want to begin with?" msgstr "" @@ -5869,17 +5880,17 @@ msgstr "" msgid "writer: %v, " msgstr "" -#: cli/app/deploy.go:277 cli/app/new.go:241 cli/app/rollback.go:255 -#: cli/app/undeploy.go:120 cli/app/upgrade.go:300 +#: cli/app/deploy.go:278 cli/app/new.go:241 cli/app/rollback.go:256 +#: cli/app/undeploy.go:120 cli/app/upgrade.go:301 #, c-format msgid "writing recipe version failed: %s" msgstr "" -#: cli/recipe/release.go:657 cli/recipe/sync.go:280 cli/recipe/upgrade.go:352 +#: cli/recipe/release.go:657 cli/recipe/sync.go:282 cli/recipe/upgrade.go:350 msgid "x" msgstr "" -#: cli/recipe/release.go:665 cli/recipe/sync.go:288 cli/recipe/upgrade.go:360 +#: cli/recipe/release.go:665 cli/recipe/sync.go:290 cli/recipe/upgrade.go:358 msgid "y" msgstr "" @@ -5887,15 +5898,15 @@ msgstr "" msgid "you can only use one of: --major, --minor, --patch" msgstr "" -#: cli/recipe/upgrade.go:81 +#: cli/recipe/upgrade.go:79 msgid "you can only use one of: --major, --minor, --patch." msgstr "" -#: cli/recipe/sync.go:203 +#: cli/recipe/sync.go:205 msgid "you can only use one version flag: --major, --minor or --patch" msgstr "" -#: cli/recipe/release.go:673 cli/recipe/sync.go:296 cli/recipe/upgrade.go:368 +#: cli/recipe/release.go:673 cli/recipe/sync.go:298 cli/recipe/upgrade.go:366 msgid "z" msgstr "" diff --git a/pkg/upstream/stack/stack.go b/pkg/upstream/stack/stack.go index 129c18d2..2e19c138 100644 --- a/pkg/upstream/stack/stack.go +++ b/pkg/upstream/stack/stack.go @@ -201,6 +201,7 @@ func RunDeploy( appName string, serverName string, dontWait bool, + noInput bool, filters filters.Args, ) error { log.Info(i18n.G("initialising deployment")) @@ -226,6 +227,7 @@ func RunDeploy( appName, serverName, dontWait, + noInput, filters, ) } @@ -248,6 +250,7 @@ func deployCompose( appName string, serverName string, dontWait bool, + noInput bool, filters filters.Args, ) error { namespace := convert.NewNamespace(opts.Namespace) @@ -311,6 +314,7 @@ func deployCompose( Services: serviceIDs, AppName: appName, ServerName: serverName, + NoInput: noInput, Filters: filters, } @@ -561,6 +565,7 @@ func timestamp() string { type WaitOpts struct { AppName string Filters filters.Args + NoInput bool NoLog bool Quiet bool ServerName string @@ -570,7 +575,13 @@ type WaitOpts struct { func WaitOnServices(ctx context.Context, cl *dockerClient.Client, opts WaitOpts) error { timeout := time.Duration(WaitTimeout) * time.Second model := ui.DeployInitialModel(ctx, cl, opts.Services, opts.AppName, timeout, opts.Filters) - tui := tea.NewProgram(model) + + var tui *tea.Program + if opts.NoInput { + tui = tea.NewProgram(model, tea.WithoutRenderer(), tea.WithInput(nil)) + } else { + tui = tea.NewProgram(model) + } if !opts.Quiet { log.Info(i18n.G("polling deployment status")) diff --git a/scripts/installer/installer b/scripts/installer/installer index 3e76600a..9fe706b6 100755 --- a/scripts/installer/installer +++ b/scripts/installer/installer @@ -1,8 +1,8 @@ #!/usr/bin/env bash -ABRA_VERSION="0.11.0-beta" +ABRA_VERSION="0.12.0-beta" ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$ABRA_VERSION" -RC_VERSION="0.11.0-beta" +RC_VERSION="0.12.0-beta" RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$RC_VERSION" for arg in "$@"; do @@ -14,15 +14,15 @@ done function show_banner { echo "" - echo " ____ ____ _ _ " - echo " / ___|___ ___ _ __ / ___| | ___ _ _ __| |" - echo " | | / _ \ _____ / _ \| '_ \ | | | |/ _ \| | | |/ _' |" - echo " | |__| (_) |_____| (_) | |_) | | |___| | (_) | |_| | (_| |" - echo " \____\___/ \___/| .__/ \____|_|\___/ \__,_|\__,_|" - echo " |_|" + echo " ____ ____ _ _ " + echo " / ___|___ ___ _ __ / ___| | ___ _ _ __| |" + echo " | | / _ \ ___ / _ \| '_ \ | | | |/ _ \| | | |/ _' |" + echo " | |__| (_) |___| (_) | |_) | | |___| | (_) | |_| | (_| |" + echo " \____\___/ \___/| .__/ \____|_|\___/ \__,_|\__,_|" + echo " |_|" echo "" echo "" - echo " === Public interest infrastructure === " + echo " === Public interest infrastructure === " echo "" echo "" } @@ -89,7 +89,7 @@ function install_abra_release { if [ $? -ne 0 ]; then echo "$(tput setaf 3)WARNING: $HOME/.local/bin/ is not in \$PATH! If you want to run abra by just typing "abra" you should add it to your \$PATH! To do that run this once and restart your terminal:$(tput sgr0)" p=$HOME/.local/bin - com="echo PATH=\$PATH:$p" + com='echo PATH="$PATH:'"$p"'"' if [[ $SHELL =~ "bash" ]]; then echo "$com >> $HOME/.bashrc" elif [[ $SHELL =~ "fizsh" ]]; then diff --git a/tests/integration/app_deploy.bats b/tests/integration/app_deploy.bats index b582b222..44bfd6fe 100644 --- a/tests/integration/app_deploy.bats +++ b/tests/integration/app_deploy.bats @@ -543,7 +543,7 @@ teardown(){ # bats test_tags=slow @test "ignore timeout when not present in env" { - run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks --debug + run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks assert_success refute_output --partial "timeout: set to" } @@ -554,6 +554,7 @@ teardown(){ "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env" assert_success + # NOTE(d1}: --debug required run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks --debug assert_success assert_output --partial "timeout: set to 120" @@ -579,16 +580,25 @@ teardown(){ } # bats test_tags=slow -@test "manually created server without context bails gracefully" { - run mkdir -p "$ABRA_DIR/servers/default2" +@test "re-deploy updates existing env vars" { + run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input assert_success - assert_exists "$ABRA_DIR/servers/default2" - run cp "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env" "$ABRA_DIR/servers/default2/$TEST_APP_DOMAIN_2.env" + run docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \ + $(docker ps -f name="$TEST_APP_DOMAIN_$TEST_SERVER" -q) assert_success - assert_exists "$ABRA_DIR/servers/default2/$TEST_APP_DOMAIN_2.env" + assert_output --partial "WITH_COMMENT=foo" - run $ABRA app deploy "$TEST_APP_DOMAIN_2" --no-input --no-converge-checks - assert_failure - assert_output --partial "server missing context" + run sed -i 's/WITH_COMMENT=foo/WITH_COMMENT=bar/g' \ + "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env" + assert_success + + run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --force + assert_success + + run docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \ + $(docker ps -f name="$TEST_APP_DOMAIN_$TEST_SERVER" -q) + assert_success + refute_output --partial "WITH_COMMENT=foo" + assert_output --partial "WITH_COMMENT=bar" } diff --git a/tests/integration/app_deploy_overview.bats b/tests/integration/app_deploy_overview.bats index 4a2f0fb5..519bb9ae 100644 --- a/tests/integration/app_deploy_overview.bats +++ b/tests/integration/app_deploy_overview.bats @@ -68,6 +68,13 @@ teardown(){ assert_success } +@test "domain shown with https" { + run $ABRA app deploy "$TEST_APP_DOMAIN" \ + --no-input --no-converge-checks + assert_success + assert_output --partial "https://$TEST_DOMAIN" +} + # bats test_tags=slow @test "show changed config version on re-deploy" { run $ABRA app deploy "$TEST_APP_DOMAIN" \ diff --git a/tests/integration/app_list.bats b/tests/integration/app_list.bats index bba1cea5..ab4e64f4 100644 --- a/tests/integration/app_list.bats +++ b/tests/integration/app_list.bats @@ -160,23 +160,6 @@ teardown(){ assert_not_exists "$ABRA_DIR/servers/foo.com" } -@test "list with status skips unknown servers" { - if [[ ! -d "$ABRA_DIR/servers/foo" ]]; then - run mkdir -p "$ABRA_DIR/servers/foo" - assert_success - assert_exists "$ABRA_DIR/servers/foo" - - run cp "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env" \ - "$ABRA_DIR/servers/foo/$TEST_APP_DOMAIN.env" - assert_success - assert_exists "$ABRA_DIR/servers/foo/$TEST_APP_DOMAIN.env" - fi - - run $ABRA app ls --status - assert_success - assert_output --partial "server missing context" -} - # bats test_tags=slow @test "list does not fail if missing .env" { _deploy_app diff --git a/tests/integration/recipe_sync.bats b/tests/integration/recipe_sync.bats index 33edaa0c..c82bbc3b 100644 --- a/tests/integration/recipe_sync.bats +++ b/tests/integration/recipe_sync.bats @@ -19,6 +19,10 @@ setup(){ teardown(){ _reset_recipe _reset_tags + if [[ -d "$ABRA_DIR/recipes/foobar" ]]; then + run rm -rf "$ABRA_DIR/recipes/foobar" + assert_success + fi } @test "validate recipe argument" { @@ -126,3 +130,71 @@ teardown(){ assert_line --index 0 --partial 'synced label' refute_line --index 1 --partial 'synced label' } + +@test "sync with no tags or previous release" { + _remove_tags + + run $ABRA recipe upgrade "$TEST_RECIPE" --no-input --patch + assert_success + + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" diff + assert_success + assert_output --partial 'image: nginx:1.21.6' + + # NOTE(d1): ensure the latest tag is the one we expect + _remove_tags + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" tag \ + -a "0.3.0+1.21.0" -m "fake: 0.3.0+1.21.0" + assert_success + + run $ABRA recipe sync "$TEST_RECIPE" --no-input --patch + assert_success + + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" diff + assert_success + assert_output --regexp 'coop-cloud\.\$\{STACK_NAME\}\.version=0\.3\.1\+1\.2.*' +} + +@test "sync recipe without input fails with prompt" { + run $ABRA recipe new foobar + assert_success + assert_exists "$ABRA_DIR/recipes/foobar" + + run $ABRA recipe sync foobar --no-input --patch + assert_failure + assert_output --partial "input required for initial version" +} + +@test "sync new recipe: development release" { + run $ABRA recipe new foobar + assert_success + assert_exists "$ABRA_DIR/recipes/foobar" + + run bash -c "echo 0.1.0 | $ABRA recipe sync foobar --patch" + assert_success + assert_output --regexp 'coop-cloud\.\$\{STACK_NAME\}\.version=0\.1\.0\+1\.2.*' +} + +@test "sync new recipe: public release" { + run $ABRA recipe new foobar + assert_success + assert_exists "$ABRA_DIR/recipes/foobar" + + run bash -c "echo 1.0.0 | $ABRA recipe sync foobar --patch" + assert_success + assert_output --regexp 'coop-cloud\.\$\{STACK_NAME\}\.version=1\.0\.0\+1\.2.*' +} + +@test "sync newly created recipe with no version label" { + run $ABRA recipe new foobar + assert_success + assert_exists "$ABRA_DIR/recipes/foobar" + + run sed -i 's/- "coop-cloud.${STACK_NAME}.version="/#- "coop-cloud.${STACK_NAME}.version="/g' \ + "$ABRA_DIR/recipes/foobar/compose.yml" + assert_success + + run bash -c "echo 0.1.0 | $ABRA recipe sync foobar --patch" + assert_failure + assert_output --partial "automagic insertion not supported yet" +} diff --git a/vendor/github.com/atotto/clipboard/.travis.yml b/vendor/github.com/atotto/clipboard/.travis.yml deleted file mode 100644 index 23f21d83..00000000 --- a/vendor/github.com/atotto/clipboard/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: go - -os: - - linux - - osx - - windows - -go: - - go1.13.x - - go1.x - -services: - - xvfb - -before_install: - - export DISPLAY=:99.0 - -script: - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get install xsel; fi - - go test -v . - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get install xclip; fi - - go test -v . diff --git a/vendor/github.com/atotto/clipboard/LICENSE b/vendor/github.com/atotto/clipboard/LICENSE deleted file mode 100644 index dee3257b..00000000 --- a/vendor/github.com/atotto/clipboard/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 Ato Araki. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of @atotto. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/atotto/clipboard/README.md b/vendor/github.com/atotto/clipboard/README.md deleted file mode 100644 index 41fdd57b..00000000 --- a/vendor/github.com/atotto/clipboard/README.md +++ /dev/null @@ -1,48 +0,0 @@ -[![Build Status](https://travis-ci.org/atotto/clipboard.svg?branch=master)](https://travis-ci.org/atotto/clipboard) - -[![GoDoc](https://godoc.org/github.com/atotto/clipboard?status.svg)](http://godoc.org/github.com/atotto/clipboard) - -# Clipboard for Go - -Provide copying and pasting to the Clipboard for Go. - -Build: - - $ go get github.com/atotto/clipboard - -Platforms: - -* OSX -* Windows 7 (probably work on other Windows) -* Linux, Unix (requires 'xclip' or 'xsel' command to be installed) - - -Document: - -* http://godoc.org/github.com/atotto/clipboard - -Notes: - -* Text string only -* UTF-8 text encoding only (no conversion) - -TODO: - -* Clipboard watcher(?) - -## Commands: - -paste shell command: - - $ go get github.com/atotto/clipboard/cmd/gopaste - $ # example: - $ gopaste > document.txt - -copy shell command: - - $ go get github.com/atotto/clipboard/cmd/gocopy - $ # example: - $ cat document.txt | gocopy - - - diff --git a/vendor/github.com/atotto/clipboard/clipboard.go b/vendor/github.com/atotto/clipboard/clipboard.go deleted file mode 100644 index d7907d3a..00000000 --- a/vendor/github.com/atotto/clipboard/clipboard.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 @atotto. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package clipboard read/write on clipboard -package clipboard - -// ReadAll read string from clipboard -func ReadAll() (string, error) { - return readAll() -} - -// WriteAll write string to clipboard -func WriteAll(text string) error { - return writeAll(text) -} - -// Unsupported might be set true during clipboard init, to help callers decide -// whether or not to offer clipboard options. -var Unsupported bool diff --git a/vendor/github.com/atotto/clipboard/clipboard_darwin.go b/vendor/github.com/atotto/clipboard/clipboard_darwin.go deleted file mode 100644 index 6f33078d..00000000 --- a/vendor/github.com/atotto/clipboard/clipboard_darwin.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2013 @atotto. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin - -package clipboard - -import ( - "os/exec" -) - -var ( - pasteCmdArgs = "pbpaste" - copyCmdArgs = "pbcopy" -) - -func getPasteCommand() *exec.Cmd { - return exec.Command(pasteCmdArgs) -} - -func getCopyCommand() *exec.Cmd { - return exec.Command(copyCmdArgs) -} - -func readAll() (string, error) { - pasteCmd := getPasteCommand() - out, err := pasteCmd.Output() - if err != nil { - return "", err - } - return string(out), nil -} - -func writeAll(text string) error { - copyCmd := getCopyCommand() - in, err := copyCmd.StdinPipe() - if err != nil { - return err - } - - if err := copyCmd.Start(); err != nil { - return err - } - if _, err := in.Write([]byte(text)); err != nil { - return err - } - if err := in.Close(); err != nil { - return err - } - return copyCmd.Wait() -} diff --git a/vendor/github.com/atotto/clipboard/clipboard_plan9.go b/vendor/github.com/atotto/clipboard/clipboard_plan9.go deleted file mode 100644 index 9d2fef4e..00000000 --- a/vendor/github.com/atotto/clipboard/clipboard_plan9.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 @atotto. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build plan9 - -package clipboard - -import ( - "os" - "io/ioutil" -) - -func readAll() (string, error) { - f, err := os.Open("/dev/snarf") - if err != nil { - return "", err - } - defer f.Close() - - str, err := ioutil.ReadAll(f) - if err != nil { - return "", err - } - - return string(str), nil -} - -func writeAll(text string) error { - f, err := os.OpenFile("/dev/snarf", os.O_WRONLY, 0666) - if err != nil { - return err - } - defer f.Close() - - _, err = f.Write([]byte(text)) - if err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/atotto/clipboard/clipboard_unix.go b/vendor/github.com/atotto/clipboard/clipboard_unix.go deleted file mode 100644 index d9f6a561..00000000 --- a/vendor/github.com/atotto/clipboard/clipboard_unix.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2013 @atotto. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build freebsd linux netbsd openbsd solaris dragonfly - -package clipboard - -import ( - "errors" - "os" - "os/exec" -) - -const ( - xsel = "xsel" - xclip = "xclip" - powershellExe = "powershell.exe" - clipExe = "clip.exe" - wlcopy = "wl-copy" - wlpaste = "wl-paste" - termuxClipboardGet = "termux-clipboard-get" - termuxClipboardSet = "termux-clipboard-set" -) - -var ( - Primary bool - trimDos bool - - pasteCmdArgs []string - copyCmdArgs []string - - xselPasteArgs = []string{xsel, "--output", "--clipboard"} - xselCopyArgs = []string{xsel, "--input", "--clipboard"} - - xclipPasteArgs = []string{xclip, "-out", "-selection", "clipboard"} - xclipCopyArgs = []string{xclip, "-in", "-selection", "clipboard"} - - powershellExePasteArgs = []string{powershellExe, "Get-Clipboard"} - clipExeCopyArgs = []string{clipExe} - - wlpasteArgs = []string{wlpaste, "--no-newline"} - wlcopyArgs = []string{wlcopy} - - termuxPasteArgs = []string{termuxClipboardGet} - termuxCopyArgs = []string{termuxClipboardSet} - - missingCommands = errors.New("No clipboard utilities available. Please install xsel, xclip, wl-clipboard or Termux:API add-on for termux-clipboard-get/set.") -) - -func init() { - if os.Getenv("WAYLAND_DISPLAY") != "" { - pasteCmdArgs = wlpasteArgs - copyCmdArgs = wlcopyArgs - - if _, err := exec.LookPath(wlcopy); err == nil { - if _, err := exec.LookPath(wlpaste); err == nil { - return - } - } - } - - pasteCmdArgs = xclipPasteArgs - copyCmdArgs = xclipCopyArgs - - if _, err := exec.LookPath(xclip); err == nil { - return - } - - pasteCmdArgs = xselPasteArgs - copyCmdArgs = xselCopyArgs - - if _, err := exec.LookPath(xsel); err == nil { - return - } - - pasteCmdArgs = termuxPasteArgs - copyCmdArgs = termuxCopyArgs - - if _, err := exec.LookPath(termuxClipboardSet); err == nil { - if _, err := exec.LookPath(termuxClipboardGet); err == nil { - return - } - } - - pasteCmdArgs = powershellExePasteArgs - copyCmdArgs = clipExeCopyArgs - trimDos = true - - if _, err := exec.LookPath(clipExe); err == nil { - if _, err := exec.LookPath(powershellExe); err == nil { - return - } - } - - Unsupported = true -} - -func getPasteCommand() *exec.Cmd { - if Primary { - pasteCmdArgs = pasteCmdArgs[:1] - } - return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...) -} - -func getCopyCommand() *exec.Cmd { - if Primary { - copyCmdArgs = copyCmdArgs[:1] - } - return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...) -} - -func readAll() (string, error) { - if Unsupported { - return "", missingCommands - } - pasteCmd := getPasteCommand() - out, err := pasteCmd.Output() - if err != nil { - return "", err - } - result := string(out) - if trimDos && len(result) > 1 { - result = result[:len(result)-2] - } - return result, nil -} - -func writeAll(text string) error { - if Unsupported { - return missingCommands - } - copyCmd := getCopyCommand() - in, err := copyCmd.StdinPipe() - if err != nil { - return err - } - - if err := copyCmd.Start(); err != nil { - return err - } - if _, err := in.Write([]byte(text)); err != nil { - return err - } - if err := in.Close(); err != nil { - return err - } - return copyCmd.Wait() -} diff --git a/vendor/github.com/atotto/clipboard/clipboard_windows.go b/vendor/github.com/atotto/clipboard/clipboard_windows.go deleted file mode 100644 index 253bb932..00000000 --- a/vendor/github.com/atotto/clipboard/clipboard_windows.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2013 @atotto. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build windows - -package clipboard - -import ( - "runtime" - "syscall" - "time" - "unsafe" -) - -const ( - cfUnicodetext = 13 - gmemMoveable = 0x0002 -) - -var ( - user32 = syscall.MustLoadDLL("user32") - isClipboardFormatAvailable = user32.MustFindProc("IsClipboardFormatAvailable") - openClipboard = user32.MustFindProc("OpenClipboard") - closeClipboard = user32.MustFindProc("CloseClipboard") - emptyClipboard = user32.MustFindProc("EmptyClipboard") - getClipboardData = user32.MustFindProc("GetClipboardData") - setClipboardData = user32.MustFindProc("SetClipboardData") - - kernel32 = syscall.NewLazyDLL("kernel32") - globalAlloc = kernel32.NewProc("GlobalAlloc") - globalFree = kernel32.NewProc("GlobalFree") - globalLock = kernel32.NewProc("GlobalLock") - globalUnlock = kernel32.NewProc("GlobalUnlock") - lstrcpy = kernel32.NewProc("lstrcpyW") -) - -// waitOpenClipboard opens the clipboard, waiting for up to a second to do so. -func waitOpenClipboard() error { - started := time.Now() - limit := started.Add(time.Second) - var r uintptr - var err error - for time.Now().Before(limit) { - r, _, err = openClipboard.Call(0) - if r != 0 { - return nil - } - time.Sleep(time.Millisecond) - } - return err -} - -func readAll() (string, error) { - // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution). - // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - if formatAvailable, _, err := isClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 { - return "", err - } - err := waitOpenClipboard() - if err != nil { - return "", err - } - - h, _, err := getClipboardData.Call(cfUnicodetext) - if h == 0 { - _, _, _ = closeClipboard.Call() - return "", err - } - - l, _, err := globalLock.Call(h) - if l == 0 { - _, _, _ = closeClipboard.Call() - return "", err - } - - text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:]) - - r, _, err := globalUnlock.Call(h) - if r == 0 { - _, _, _ = closeClipboard.Call() - return "", err - } - - closed, _, err := closeClipboard.Call() - if closed == 0 { - return "", err - } - return text, nil -} - -func writeAll(text string) error { - // LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution). - // Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err := waitOpenClipboard() - if err != nil { - return err - } - - r, _, err := emptyClipboard.Call(0) - if r == 0 { - _, _, _ = closeClipboard.Call() - return err - } - - data := syscall.StringToUTF16(text) - - // "If the hMem parameter identifies a memory object, the object must have - // been allocated using the function with the GMEM_MOVEABLE flag." - h, _, err := globalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0])))) - if h == 0 { - _, _, _ = closeClipboard.Call() - return err - } - defer func() { - if h != 0 { - globalFree.Call(h) - } - }() - - l, _, err := globalLock.Call(h) - if l == 0 { - _, _, _ = closeClipboard.Call() - return err - } - - r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0]))) - if r == 0 { - _, _, _ = closeClipboard.Call() - return err - } - - r, _, err = globalUnlock.Call(h) - if r == 0 { - if err.(syscall.Errno) != 0 { - _, _, _ = closeClipboard.Call() - return err - } - } - - r, _, err = setClipboardData.Call(cfUnicodetext, h) - if r == 0 { - _, _, _ = closeClipboard.Call() - return err - } - h = 0 // suppress deferred cleanup - closed, _, err := closeClipboard.Call() - if closed == 0 { - return err - } - return nil -} diff --git a/vendor/github.com/charmbracelet/bubbles/LICENSE b/vendor/github.com/charmbracelet/bubbles/LICENSE deleted file mode 100644 index 31d76c1c..00000000 --- a/vendor/github.com/charmbracelet/bubbles/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020-2023 Charmbracelet, Inc - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go b/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go deleted file mode 100644 index d101332b..00000000 --- a/vendor/github.com/charmbracelet/bubbles/cursor/cursor.go +++ /dev/null @@ -1,219 +0,0 @@ -// Package cursor provides cursor functionality for Bubble Tea applications. -package cursor - -import ( - "context" - "time" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -const defaultBlinkSpeed = time.Millisecond * 530 - -// initialBlinkMsg initializes cursor blinking. -type initialBlinkMsg struct{} - -// BlinkMsg signals that the cursor should blink. It contains metadata that -// allows us to tell if the blink message is the one we're expecting. -type BlinkMsg struct { - id int - tag int -} - -// blinkCanceled is sent when a blink operation is canceled. -type blinkCanceled struct{} - -// blinkCtx manages cursor blinking. -type blinkCtx struct { - ctx context.Context - cancel context.CancelFunc -} - -// Mode describes the behavior of the cursor. -type Mode int - -// Available cursor modes. -const ( - CursorBlink Mode = iota - CursorStatic - CursorHide -) - -// String returns the cursor mode in a human-readable format. This method is -// provisional and for informational purposes only. -func (c Mode) String() string { - return [...]string{ - "blink", - "static", - "hidden", - }[c] -} - -// Model is the Bubble Tea model for this cursor element. -type Model struct { - BlinkSpeed time.Duration - // Style for styling the cursor block. - Style lipgloss.Style - // TextStyle is the style used for the cursor when it is hidden (when blinking). - // I.e. displaying normal text. - TextStyle lipgloss.Style - - // char is the character under the cursor - char string - // The ID of this Model as it relates to other cursors - id int - // focus indicates whether the containing input is focused - focus bool - // Cursor Blink state. - Blink bool - // Used to manage cursor blink - blinkCtx *blinkCtx - // The ID of the blink message we're expecting to receive. - blinkTag int - // mode determines the behavior of the cursor - mode Mode -} - -// New creates a new model with default settings. -func New() Model { - return Model{ - BlinkSpeed: defaultBlinkSpeed, - - Blink: true, - mode: CursorBlink, - - blinkCtx: &blinkCtx{ - ctx: context.Background(), - }, - } -} - -// Update updates the cursor. -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - switch msg := msg.(type) { - case initialBlinkMsg: - // We accept all initialBlinkMsgs generated by the Blink command. - - if m.mode != CursorBlink || !m.focus { - return m, nil - } - - cmd := m.BlinkCmd() - return m, cmd - - case tea.FocusMsg: - return m, m.Focus() - - case tea.BlurMsg: - m.Blur() - return m, nil - - case BlinkMsg: - // We're choosy about whether to accept blinkMsgs so that our cursor - // only exactly when it should. - - // Is this model blink-able? - if m.mode != CursorBlink || !m.focus { - return m, nil - } - - // Were we expecting this blink message? - if msg.id != m.id || msg.tag != m.blinkTag { - return m, nil - } - - var cmd tea.Cmd - if m.mode == CursorBlink { - m.Blink = !m.Blink - cmd = m.BlinkCmd() - } - return m, cmd - - case blinkCanceled: // no-op - return m, nil - } - return m, nil -} - -// Mode returns the model's cursor mode. For available cursor modes, see -// type Mode. -func (m Model) Mode() Mode { - return m.mode -} - -// SetMode sets the model's cursor mode. This method returns a command. -// -// For available cursor modes, see type CursorMode. -func (m *Model) SetMode(mode Mode) tea.Cmd { - // Adjust the mode value if it's value is out of range - if mode < CursorBlink || mode > CursorHide { - return nil - } - m.mode = mode - m.Blink = m.mode == CursorHide || !m.focus - if mode == CursorBlink { - return Blink - } - return nil -} - -// BlinkCmd is a command used to manage cursor blinking. -func (m *Model) BlinkCmd() tea.Cmd { - if m.mode != CursorBlink { - return nil - } - - if m.blinkCtx != nil && m.blinkCtx.cancel != nil { - m.blinkCtx.cancel() - } - - ctx, cancel := context.WithTimeout(m.blinkCtx.ctx, m.BlinkSpeed) - m.blinkCtx.cancel = cancel - - m.blinkTag++ - - return func() tea.Msg { - defer cancel() - <-ctx.Done() - if ctx.Err() == context.DeadlineExceeded { - return BlinkMsg{id: m.id, tag: m.blinkTag} - } - return blinkCanceled{} - } -} - -// Blink is a command used to initialize cursor blinking. -func Blink() tea.Msg { - return initialBlinkMsg{} -} - -// Focus focuses the cursor to allow it to blink if desired. -func (m *Model) Focus() tea.Cmd { - m.focus = true - m.Blink = m.mode == CursorHide // show the cursor unless we've explicitly hidden it - - if m.mode == CursorBlink && m.focus { - return m.BlinkCmd() - } - return nil -} - -// Blur blurs the cursor. -func (m *Model) Blur() { - m.focus = false - m.Blink = true -} - -// SetChar sets the character under the cursor. -func (m *Model) SetChar(char string) { - m.char = char -} - -// View displays the cursor. -func (m Model) View() string { - if m.Blink { - return m.TextStyle.Inline(true).Render(m.char) - } - return m.Style.Inline(true).Reverse(true).Render(m.char) -} diff --git a/vendor/github.com/charmbracelet/bubbles/key/key.go b/vendor/github.com/charmbracelet/bubbles/key/key.go deleted file mode 100644 index 0682665d..00000000 --- a/vendor/github.com/charmbracelet/bubbles/key/key.go +++ /dev/null @@ -1,140 +0,0 @@ -// Package key provides some types and functions for generating user-definable -// keymappings useful in Bubble Tea components. There are a few different ways -// you can define a keymapping with this package. Here's one example: -// -// type KeyMap struct { -// Up key.Binding -// Down key.Binding -// } -// -// var DefaultKeyMap = KeyMap{ -// Up: key.NewBinding( -// key.WithKeys("k", "up"), // actual keybindings -// key.WithHelp("↑/k", "move up"), // corresponding help text -// ), -// Down: key.NewBinding( -// key.WithKeys("j", "down"), -// key.WithHelp("↓/j", "move down"), -// ), -// } -// -// func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { -// switch msg := msg.(type) { -// case tea.KeyMsg: -// switch { -// case key.Matches(msg, DefaultKeyMap.Up): -// // The user pressed up -// case key.Matches(msg, DefaultKeyMap.Down): -// // The user pressed down -// } -// } -// -// // ... -// } -// -// The help information, which is not used in the example above, can be used -// to render help text for keystrokes in your views. -package key - -import "fmt" - -// Binding describes a set of keybindings and, optionally, their associated -// help text. -type Binding struct { - keys []string - help Help - disabled bool -} - -// BindingOpt is an initialization option for a keybinding. It's used as an -// argument to NewBinding. -type BindingOpt func(*Binding) - -// NewBinding returns a new keybinding from a set of BindingOpt options. -func NewBinding(opts ...BindingOpt) Binding { - b := &Binding{} - for _, opt := range opts { - opt(b) - } - return *b -} - -// WithKeys initializes a keybinding with the given keystrokes. -func WithKeys(keys ...string) BindingOpt { - return func(b *Binding) { - b.keys = keys - } -} - -// WithHelp initializes a keybinding with the given help text. -func WithHelp(key, desc string) BindingOpt { - return func(b *Binding) { - b.help = Help{Key: key, Desc: desc} - } -} - -// WithDisabled initializes a disabled keybinding. -func WithDisabled() BindingOpt { - return func(b *Binding) { - b.disabled = true - } -} - -// SetKeys sets the keys for the keybinding. -func (b *Binding) SetKeys(keys ...string) { - b.keys = keys -} - -// Keys returns the keys for the keybinding. -func (b Binding) Keys() []string { - return b.keys -} - -// SetHelp sets the help text for the keybinding. -func (b *Binding) SetHelp(key, desc string) { - b.help = Help{Key: key, Desc: desc} -} - -// Help returns the Help information for the keybinding. -func (b Binding) Help() Help { - return b.help -} - -// Enabled returns whether or not the keybinding is enabled. Disabled -// keybindings won't be activated and won't show up in help. Keybindings are -// enabled by default. -func (b Binding) Enabled() bool { - return !b.disabled && b.keys != nil -} - -// SetEnabled enables or disables the keybinding. -func (b *Binding) SetEnabled(v bool) { - b.disabled = !v -} - -// Unbind removes the keys and help from this binding, effectively nullifying -// it. This is a step beyond disabling it, since applications can enable -// or disable key bindings based on application state. -func (b *Binding) Unbind() { - b.keys = nil - b.help = Help{} -} - -// Help is help information for a given keybinding. -type Help struct { - Key string - Desc string -} - -// Matches checks if the given key matches the given bindings. -func Matches[Key fmt.Stringer](k Key, b ...Binding) bool { - keys := k.String() - for _, binding := range b { - for _, v := range binding.keys { - if keys == v && binding.Enabled() { - return true - } - } - } - return false -} diff --git a/vendor/github.com/charmbracelet/bubbles/runeutil/runeutil.go b/vendor/github.com/charmbracelet/bubbles/runeutil/runeutil.go deleted file mode 100644 index 82ea90a2..00000000 --- a/vendor/github.com/charmbracelet/bubbles/runeutil/runeutil.go +++ /dev/null @@ -1,102 +0,0 @@ -// Package runeutil provides a utility function for use in Bubbles -// that can process Key messages containing runes. -package runeutil - -import ( - "unicode" - "unicode/utf8" -) - -// Sanitizer is a helper for bubble widgets that want to process -// Runes from input key messages. -type Sanitizer interface { - // Sanitize removes control characters from runes in a KeyRunes - // message, and optionally replaces newline/carriage return/tabs by a - // specified character. - // - // The rune array is modified in-place if possible. In that case, the - // returned slice is the original slice shortened after the control - // characters have been removed/translated. - Sanitize(runes []rune) []rune -} - -// NewSanitizer constructs a rune sanitizer. -func NewSanitizer(opts ...Option) Sanitizer { - s := sanitizer{ - replaceNewLine: []rune("\n"), - replaceTab: []rune(" "), - } - for _, o := range opts { - s = o(s) - } - return &s -} - -// Option is the type of option that can be passed to Sanitize(). -type Option func(sanitizer) sanitizer - -// ReplaceTabs replaces tabs by the specified string. -func ReplaceTabs(tabRepl string) Option { - return func(s sanitizer) sanitizer { - s.replaceTab = []rune(tabRepl) - return s - } -} - -// ReplaceNewlines replaces newline characters by the specified string. -func ReplaceNewlines(nlRepl string) Option { - return func(s sanitizer) sanitizer { - s.replaceNewLine = []rune(nlRepl) - return s - } -} - -func (s *sanitizer) Sanitize(runes []rune) []rune { - // dstrunes are where we are storing the result. - dstrunes := runes[:0:len(runes)] - // copied indicates whether dstrunes is an alias of runes - // or a copy. We need a copy when dst moves past src. - // We use this as an optimization to avoid allocating - // a new rune slice in the common case where the output - // is smaller or equal to the input. - copied := false - - for src := 0; src < len(runes); src++ { - r := runes[src] - switch { - case r == utf8.RuneError: - // skip - - case r == '\r' || r == '\n': - if len(dstrunes)+len(s.replaceNewLine) > src && !copied { - dst := len(dstrunes) - dstrunes = make([]rune, dst, len(runes)+len(s.replaceNewLine)) - copy(dstrunes, runes[:dst]) - copied = true - } - dstrunes = append(dstrunes, s.replaceNewLine...) - - case r == '\t': - if len(dstrunes)+len(s.replaceTab) > src && !copied { - dst := len(dstrunes) - dstrunes = make([]rune, dst, len(runes)+len(s.replaceTab)) - copy(dstrunes, runes[:dst]) - copied = true - } - dstrunes = append(dstrunes, s.replaceTab...) - - case unicode.IsControl(r): - // Other control characters: skip. - - default: - // Keep the character. - dstrunes = append(dstrunes, runes[src]) - } - } - return dstrunes -} - -type sanitizer struct { - replaceNewLine []rune - replaceTab []rune -} diff --git a/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go b/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go deleted file mode 100644 index b2d24b09..00000000 --- a/vendor/github.com/charmbracelet/bubbles/spinner/spinner.go +++ /dev/null @@ -1,224 +0,0 @@ -// Package spinner provides a spinner component for Bubble Tea applications. -package spinner - -import ( - "sync/atomic" - "time" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -// Internal ID management. Used during animating to ensure that frame messages -// are received only by spinner components that sent them. -var lastID int64 - -func nextID() int { - return int(atomic.AddInt64(&lastID, 1)) -} - -// Spinner is a set of frames used in animating the spinner. -type Spinner struct { - Frames []string - FPS time.Duration -} - -// Some spinners to choose from. You could also make your own. -var ( - Line = Spinner{ - Frames: []string{"|", "/", "-", "\\"}, - FPS: time.Second / 10, //nolint:mnd - } - Dot = Spinner{ - Frames: []string{"⣾ ", "⣽ ", "⣻ ", "⢿ ", "⡿ ", "⣟ ", "⣯ ", "⣷ "}, - FPS: time.Second / 10, //nolint:mnd - } - MiniDot = Spinner{ - Frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, - FPS: time.Second / 12, //nolint:mnd - } - Jump = Spinner{ - Frames: []string{"⢄", "⢂", "⢁", "⡁", "⡈", "⡐", "⡠"}, - FPS: time.Second / 10, //nolint:mnd - } - Pulse = Spinner{ - Frames: []string{"█", "▓", "▒", "░"}, - FPS: time.Second / 8, //nolint:mnd - } - Points = Spinner{ - Frames: []string{"∙∙∙", "●∙∙", "∙●∙", "∙∙●"}, - FPS: time.Second / 7, //nolint:mnd - } - Globe = Spinner{ - Frames: []string{"🌍", "🌎", "🌏"}, - FPS: time.Second / 4, //nolint:mnd - } - Moon = Spinner{ - Frames: []string{"🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"}, - FPS: time.Second / 8, //nolint:mnd - } - Monkey = Spinner{ - Frames: []string{"🙈", "🙉", "🙊"}, - FPS: time.Second / 3, //nolint:mnd - } - Meter = Spinner{ - Frames: []string{ - "▱▱▱", - "▰▱▱", - "▰▰▱", - "▰▰▰", - "▰▰▱", - "▰▱▱", - "▱▱▱", - }, - FPS: time.Second / 7, //nolint:mnd - } - Hamburger = Spinner{ - Frames: []string{"☱", "☲", "☴", "☲"}, - FPS: time.Second / 3, //nolint:mnd - } - Ellipsis = Spinner{ - Frames: []string{"", ".", "..", "..."}, - FPS: time.Second / 3, //nolint:mnd - } -) - -// Model contains the state for the spinner. Use New to create new models -// rather than using Model as a struct literal. -type Model struct { - // Spinner settings to use. See type Spinner. - Spinner Spinner - - // Style sets the styling for the spinner. Most of the time you'll just - // want foreground and background coloring, and potentially some padding. - // - // For an introduction to styling with Lip Gloss see: - // https://github.com/charmbracelet/lipgloss - Style lipgloss.Style - - frame int - id int - tag int -} - -// ID returns the spinner's unique ID. -func (m Model) ID() int { - return m.id -} - -// New returns a model with default values. -func New(opts ...Option) Model { - m := Model{ - Spinner: Line, - id: nextID(), - } - - for _, opt := range opts { - opt(&m) - } - - return m -} - -// NewModel returns a model with default values. -// -// Deprecated: use [New] instead. -var NewModel = New - -// TickMsg indicates that the timer has ticked and we should render a frame. -type TickMsg struct { - Time time.Time - tag int - ID int -} - -// Update is the Tea update function. -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - switch msg := msg.(type) { - case TickMsg: - // If an ID is set, and the ID doesn't belong to this spinner, reject - // the message. - if msg.ID > 0 && msg.ID != m.id { - return m, nil - } - - // If a tag is set, and it's not the one we expect, reject the message. - // This prevents the spinner from receiving too many messages and - // thus spinning too fast. - if msg.tag > 0 && msg.tag != m.tag { - return m, nil - } - - m.frame++ - if m.frame >= len(m.Spinner.Frames) { - m.frame = 0 - } - - m.tag++ - return m, m.tick(m.id, m.tag) - default: - return m, nil - } -} - -// View renders the model's view. -func (m Model) View() string { - if m.frame >= len(m.Spinner.Frames) { - return "(error)" - } - - return m.Style.Render(m.Spinner.Frames[m.frame]) -} - -// Tick is the command used to advance the spinner one frame. Use this command -// to effectively start the spinner. -func (m Model) Tick() tea.Msg { - return TickMsg{ - // The time at which the tick occurred. - Time: time.Now(), - - // The ID of the spinner that this message belongs to. This can be - // helpful when routing messages, however bear in mind that spinners - // will ignore messages that don't contain ID by default. - ID: m.id, - - tag: m.tag, - } -} - -func (m Model) tick(id, tag int) tea.Cmd { - return tea.Tick(m.Spinner.FPS, func(t time.Time) tea.Msg { - return TickMsg{ - Time: t, - ID: id, - tag: tag, - } - }) -} - -// Tick is the command used to advance the spinner one frame. Use this command -// to effectively start the spinner. -// -// Deprecated: Use [Model.Tick] instead. -func Tick() tea.Msg { - return TickMsg{Time: time.Now()} -} - -// Option is used to set options in New. For example: -// -// spinner := New(WithSpinner(Dot)) -type Option func(*Model) - -// WithSpinner is an option to set the spinner. -func WithSpinner(spinner Spinner) Option { - return func(m *Model) { - m.Spinner = spinner - } -} - -// WithStyle is an option to set the spinner style. -func WithStyle(style lipgloss.Style) Option { - return func(m *Model) { - m.Style = style - } -} diff --git a/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go b/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go deleted file mode 100644 index 84cbbc93..00000000 --- a/vendor/github.com/charmbracelet/bubbles/textinput/textinput.go +++ /dev/null @@ -1,898 +0,0 @@ -// Package textinput provides a text input component for Bubble Tea -// applications. -package textinput - -import ( - "reflect" - "strings" - "time" - "unicode" - - "github.com/atotto/clipboard" - "github.com/charmbracelet/bubbles/cursor" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/runeutil" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - rw "github.com/mattn/go-runewidth" - "github.com/rivo/uniseg" -) - -// Internal messages for clipboard operations. -type ( - pasteMsg string - pasteErrMsg struct{ error } -) - -// EchoMode sets the input behavior of the text input field. -type EchoMode int - -const ( - // EchoNormal displays text as is. This is the default behavior. - EchoNormal EchoMode = iota - - // EchoPassword displays the EchoCharacter mask instead of actual - // characters. This is commonly used for password fields. - EchoPassword - - // EchoNone displays nothing as characters are entered. This is commonly - // seen for password fields on the command line. - EchoNone -) - -// ValidateFunc is a function that returns an error if the input is invalid. -type ValidateFunc func(string) error - -// KeyMap is the key bindings for different actions within the textinput. -type KeyMap struct { - CharacterForward key.Binding - CharacterBackward key.Binding - WordForward key.Binding - WordBackward key.Binding - DeleteWordBackward key.Binding - DeleteWordForward key.Binding - DeleteAfterCursor key.Binding - DeleteBeforeCursor key.Binding - DeleteCharacterBackward key.Binding - DeleteCharacterForward key.Binding - LineStart key.Binding - LineEnd key.Binding - Paste key.Binding - AcceptSuggestion key.Binding - NextSuggestion key.Binding - PrevSuggestion key.Binding -} - -// DefaultKeyMap is the default set of key bindings for navigating and acting -// upon the textinput. -var DefaultKeyMap = KeyMap{ - CharacterForward: key.NewBinding(key.WithKeys("right", "ctrl+f")), - CharacterBackward: key.NewBinding(key.WithKeys("left", "ctrl+b")), - WordForward: key.NewBinding(key.WithKeys("alt+right", "ctrl+right", "alt+f")), - WordBackward: key.NewBinding(key.WithKeys("alt+left", "ctrl+left", "alt+b")), - DeleteWordBackward: key.NewBinding(key.WithKeys("alt+backspace", "ctrl+w")), - DeleteWordForward: key.NewBinding(key.WithKeys("alt+delete", "alt+d")), - DeleteAfterCursor: key.NewBinding(key.WithKeys("ctrl+k")), - DeleteBeforeCursor: key.NewBinding(key.WithKeys("ctrl+u")), - DeleteCharacterBackward: key.NewBinding(key.WithKeys("backspace", "ctrl+h")), - DeleteCharacterForward: key.NewBinding(key.WithKeys("delete", "ctrl+d")), - LineStart: key.NewBinding(key.WithKeys("home", "ctrl+a")), - LineEnd: key.NewBinding(key.WithKeys("end", "ctrl+e")), - Paste: key.NewBinding(key.WithKeys("ctrl+v")), - AcceptSuggestion: key.NewBinding(key.WithKeys("tab")), - NextSuggestion: key.NewBinding(key.WithKeys("down", "ctrl+n")), - PrevSuggestion: key.NewBinding(key.WithKeys("up", "ctrl+p")), -} - -// Model is the Bubble Tea model for this text input element. -type Model struct { - Err error - - // General settings. - Prompt string - Placeholder string - EchoMode EchoMode - EchoCharacter rune - Cursor cursor.Model - - // Deprecated: use [cursor.BlinkSpeed] instead. - BlinkSpeed time.Duration - - // Styles. These will be applied as inline styles. - // - // For an introduction to styling with Lip Gloss see: - // https://github.com/charmbracelet/lipgloss - PromptStyle lipgloss.Style - TextStyle lipgloss.Style - PlaceholderStyle lipgloss.Style - CompletionStyle lipgloss.Style - - // Deprecated: use Cursor.Style instead. - CursorStyle lipgloss.Style - - // CharLimit is the maximum amount of characters this input element will - // accept. If 0 or less, there's no limit. - CharLimit int - - // Width is the maximum number of characters that can be displayed at once. - // It essentially treats the text field like a horizontally scrolling - // viewport. If 0 or less this setting is ignored. - Width int - - // KeyMap encodes the keybindings recognized by the widget. - KeyMap KeyMap - - // Underlying text value. - value []rune - - // focus indicates whether user input focus should be on this input - // component. When false, ignore keyboard input and hide the cursor. - focus bool - - // Cursor position. - pos int - - // Used to emulate a viewport when width is set and the content is - // overflowing. - offset int - offsetRight int - - // Validate is a function that checks whether or not the text within the - // input is valid. If it is not valid, the `Err` field will be set to the - // error returned by the function. If the function is not defined, all - // input is considered valid. - Validate ValidateFunc - - // rune sanitizer for input. - rsan runeutil.Sanitizer - - // Should the input suggest to complete - ShowSuggestions bool - - // suggestions is a list of suggestions that may be used to complete the - // input. - suggestions [][]rune - matchedSuggestions [][]rune - currentSuggestionIndex int -} - -// New creates a new model with default settings. -func New() Model { - return Model{ - Prompt: "> ", - EchoCharacter: '*', - CharLimit: 0, - PlaceholderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")), - ShowSuggestions: false, - CompletionStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")), - Cursor: cursor.New(), - KeyMap: DefaultKeyMap, - - suggestions: [][]rune{}, - value: nil, - focus: false, - pos: 0, - } -} - -// NewModel creates a new model with default settings. -// -// Deprecated: Use [New] instead. -var NewModel = New - -// SetValue sets the value of the text input. -func (m *Model) SetValue(s string) { - // Clean up any special characters in the input provided by the - // caller. This avoids bugs due to e.g. tab characters and whatnot. - runes := m.san().Sanitize([]rune(s)) - err := m.validate(runes) - m.setValueInternal(runes, err) -} - -func (m *Model) setValueInternal(runes []rune, err error) { - m.Err = err - - empty := len(m.value) == 0 - - if m.CharLimit > 0 && len(runes) > m.CharLimit { - m.value = runes[:m.CharLimit] - } else { - m.value = runes - } - if (m.pos == 0 && empty) || m.pos > len(m.value) { - m.SetCursor(len(m.value)) - } - m.handleOverflow() -} - -// Value returns the value of the text input. -func (m Model) Value() string { - return string(m.value) -} - -// Position returns the cursor position. -func (m Model) Position() int { - return m.pos -} - -// SetCursor moves the cursor to the given position. If the position is -// out of bounds the cursor will be moved to the start or end accordingly. -func (m *Model) SetCursor(pos int) { - m.pos = clamp(pos, 0, len(m.value)) - m.handleOverflow() -} - -// CursorStart moves the cursor to the start of the input field. -func (m *Model) CursorStart() { - m.SetCursor(0) -} - -// CursorEnd moves the cursor to the end of the input field. -func (m *Model) CursorEnd() { - m.SetCursor(len(m.value)) -} - -// Focused returns the focus state on the model. -func (m Model) Focused() bool { - return m.focus -} - -// Focus sets the focus state on the model. When the model is in focus it can -// receive keyboard input and the cursor will be shown. -func (m *Model) Focus() tea.Cmd { - m.focus = true - return m.Cursor.Focus() -} - -// Blur removes the focus state on the model. When the model is blurred it can -// not receive keyboard input and the cursor will be hidden. -func (m *Model) Blur() { - m.focus = false - m.Cursor.Blur() -} - -// Reset sets the input to its default state with no input. -func (m *Model) Reset() { - m.value = nil - m.SetCursor(0) -} - -// SetSuggestions sets the suggestions for the input. -func (m *Model) SetSuggestions(suggestions []string) { - m.suggestions = make([][]rune, len(suggestions)) - for i, s := range suggestions { - m.suggestions[i] = []rune(s) - } - - m.updateSuggestions() -} - -// rsan initializes or retrieves the rune sanitizer. -func (m *Model) san() runeutil.Sanitizer { - if m.rsan == nil { - // Textinput has all its input on a single line so collapse - // newlines/tabs to single spaces. - m.rsan = runeutil.NewSanitizer( - runeutil.ReplaceTabs(" "), runeutil.ReplaceNewlines(" ")) - } - return m.rsan -} - -func (m *Model) insertRunesFromUserInput(v []rune) { - // Clean up any special characters in the input provided by the - // clipboard. This avoids bugs due to e.g. tab characters and - // whatnot. - paste := m.san().Sanitize(v) - - var availSpace int - if m.CharLimit > 0 { - availSpace = m.CharLimit - len(m.value) - - // If the char limit's been reached, cancel. - if availSpace <= 0 { - return - } - - // If there's not enough space to paste the whole thing cut the pasted - // runes down so they'll fit. - if availSpace < len(paste) { - paste = paste[:availSpace] - } - } - - // Stuff before and after the cursor - head := m.value[:m.pos] - tailSrc := m.value[m.pos:] - tail := make([]rune, len(tailSrc)) - copy(tail, tailSrc) - - // Insert pasted runes - for _, r := range paste { - head = append(head, r) - m.pos++ - if m.CharLimit > 0 { - availSpace-- - if availSpace <= 0 { - break - } - } - } - - // Put it all back together - value := append(head, tail...) - inputErr := m.validate(value) - m.setValueInternal(value, inputErr) -} - -// If a max width is defined, perform some logic to treat the visible area -// as a horizontally scrolling viewport. -func (m *Model) handleOverflow() { - if m.Width <= 0 || uniseg.StringWidth(string(m.value)) <= m.Width { - m.offset = 0 - m.offsetRight = len(m.value) - return - } - - // Correct right offset if we've deleted characters - m.offsetRight = min(m.offsetRight, len(m.value)) - - if m.pos < m.offset { - m.offset = m.pos - - w := 0 - i := 0 - runes := m.value[m.offset:] - - for i < len(runes) && w <= m.Width { - w += rw.RuneWidth(runes[i]) - if w <= m.Width+1 { - i++ - } - } - - m.offsetRight = m.offset + i - } else if m.pos >= m.offsetRight { - m.offsetRight = m.pos - - w := 0 - runes := m.value[:m.offsetRight] - i := len(runes) - 1 - - for i > 0 && w < m.Width { - w += rw.RuneWidth(runes[i]) - if w <= m.Width { - i-- - } - } - - m.offset = m.offsetRight - (len(runes) - 1 - i) - } -} - -// deleteBeforeCursor deletes all text before the cursor. -func (m *Model) deleteBeforeCursor() { - m.value = m.value[m.pos:] - m.Err = m.validate(m.value) - m.offset = 0 - m.SetCursor(0) -} - -// deleteAfterCursor deletes all text after the cursor. If input is masked -// delete everything after the cursor so as not to reveal word breaks in the -// masked input. -func (m *Model) deleteAfterCursor() { - m.value = m.value[:m.pos] - m.Err = m.validate(m.value) - m.SetCursor(len(m.value)) -} - -// deleteWordBackward deletes the word left to the cursor. -func (m *Model) deleteWordBackward() { - if m.pos == 0 || len(m.value) == 0 { - return - } - - if m.EchoMode != EchoNormal { - m.deleteBeforeCursor() - return - } - - // Linter note: it's critical that we acquire the initial cursor position - // here prior to altering it via SetCursor() below. As such, moving this - // call into the corresponding if clause does not apply here. - oldPos := m.pos //nolint:ifshort - - m.SetCursor(m.pos - 1) - for unicode.IsSpace(m.value[m.pos]) { - if m.pos <= 0 { - break - } - // ignore series of whitespace before cursor - m.SetCursor(m.pos - 1) - } - - for m.pos > 0 { - if !unicode.IsSpace(m.value[m.pos]) { - m.SetCursor(m.pos - 1) - } else { - if m.pos > 0 { - // keep the previous space - m.SetCursor(m.pos + 1) - } - break - } - } - - if oldPos > len(m.value) { - m.value = m.value[:m.pos] - } else { - m.value = append(m.value[:m.pos], m.value[oldPos:]...) - } - m.Err = m.validate(m.value) -} - -// deleteWordForward deletes the word right to the cursor. If input is masked -// delete everything after the cursor so as not to reveal word breaks in the -// masked input. -func (m *Model) deleteWordForward() { - if m.pos >= len(m.value) || len(m.value) == 0 { - return - } - - if m.EchoMode != EchoNormal { - m.deleteAfterCursor() - return - } - - oldPos := m.pos - m.SetCursor(m.pos + 1) - for unicode.IsSpace(m.value[m.pos]) { - // ignore series of whitespace after cursor - m.SetCursor(m.pos + 1) - - if m.pos >= len(m.value) { - break - } - } - - for m.pos < len(m.value) { - if !unicode.IsSpace(m.value[m.pos]) { - m.SetCursor(m.pos + 1) - } else { - break - } - } - - if m.pos > len(m.value) { - m.value = m.value[:oldPos] - } else { - m.value = append(m.value[:oldPos], m.value[m.pos:]...) - } - m.Err = m.validate(m.value) - - m.SetCursor(oldPos) -} - -// wordBackward moves the cursor one word to the left. If input is masked, move -// input to the start so as not to reveal word breaks in the masked input. -func (m *Model) wordBackward() { - if m.pos == 0 || len(m.value) == 0 { - return - } - - if m.EchoMode != EchoNormal { - m.CursorStart() - return - } - - i := m.pos - 1 - for i >= 0 { - if unicode.IsSpace(m.value[i]) { - m.SetCursor(m.pos - 1) - i-- - } else { - break - } - } - - for i >= 0 { - if !unicode.IsSpace(m.value[i]) { - m.SetCursor(m.pos - 1) - i-- - } else { - break - } - } -} - -// wordForward moves the cursor one word to the right. If the input is masked, -// move input to the end so as not to reveal word breaks in the masked input. -func (m *Model) wordForward() { - if m.pos >= len(m.value) || len(m.value) == 0 { - return - } - - if m.EchoMode != EchoNormal { - m.CursorEnd() - return - } - - i := m.pos - for i < len(m.value) { - if unicode.IsSpace(m.value[i]) { - m.SetCursor(m.pos + 1) - i++ - } else { - break - } - } - - for i < len(m.value) { - if !unicode.IsSpace(m.value[i]) { - m.SetCursor(m.pos + 1) - i++ - } else { - break - } - } -} - -func (m Model) echoTransform(v string) string { - switch m.EchoMode { - case EchoPassword: - return strings.Repeat(string(m.EchoCharacter), uniseg.StringWidth(v)) - case EchoNone: - return "" - case EchoNormal: - return v - default: - return v - } -} - -// Update is the Bubble Tea update loop. -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - if !m.focus { - return m, nil - } - - // Need to check for completion before, because key is configurable and might be double assigned - keyMsg, ok := msg.(tea.KeyMsg) - if ok && key.Matches(keyMsg, m.KeyMap.AcceptSuggestion) { - if m.canAcceptSuggestion() { - m.value = append(m.value, m.matchedSuggestions[m.currentSuggestionIndex][len(m.value):]...) - m.CursorEnd() - } - } - - // Let's remember where the position of the cursor currently is so that if - // the cursor position changes, we can reset the blink. - oldPos := m.pos - - switch msg := msg.(type) { - case tea.KeyMsg: - switch { - case key.Matches(msg, m.KeyMap.DeleteWordBackward): - m.deleteWordBackward() - case key.Matches(msg, m.KeyMap.DeleteCharacterBackward): - m.Err = nil - if len(m.value) > 0 { - m.value = append(m.value[:max(0, m.pos-1)], m.value[m.pos:]...) - m.Err = m.validate(m.value) - if m.pos > 0 { - m.SetCursor(m.pos - 1) - } - } - case key.Matches(msg, m.KeyMap.WordBackward): - m.wordBackward() - case key.Matches(msg, m.KeyMap.CharacterBackward): - if m.pos > 0 { - m.SetCursor(m.pos - 1) - } - case key.Matches(msg, m.KeyMap.WordForward): - m.wordForward() - case key.Matches(msg, m.KeyMap.CharacterForward): - if m.pos < len(m.value) { - m.SetCursor(m.pos + 1) - } - case key.Matches(msg, m.KeyMap.LineStart): - m.CursorStart() - case key.Matches(msg, m.KeyMap.DeleteCharacterForward): - if len(m.value) > 0 && m.pos < len(m.value) { - m.value = append(m.value[:m.pos], m.value[m.pos+1:]...) - m.Err = m.validate(m.value) - } - case key.Matches(msg, m.KeyMap.LineEnd): - m.CursorEnd() - case key.Matches(msg, m.KeyMap.DeleteAfterCursor): - m.deleteAfterCursor() - case key.Matches(msg, m.KeyMap.DeleteBeforeCursor): - m.deleteBeforeCursor() - case key.Matches(msg, m.KeyMap.Paste): - return m, Paste - case key.Matches(msg, m.KeyMap.DeleteWordForward): - m.deleteWordForward() - case key.Matches(msg, m.KeyMap.NextSuggestion): - m.nextSuggestion() - case key.Matches(msg, m.KeyMap.PrevSuggestion): - m.previousSuggestion() - default: - // Input one or more regular characters. - m.insertRunesFromUserInput(msg.Runes) - } - - // Check again if can be completed - // because value might be something that does not match the completion prefix - m.updateSuggestions() - - case pasteMsg: - m.insertRunesFromUserInput([]rune(msg)) - - case pasteErrMsg: - m.Err = msg - } - - var cmds []tea.Cmd - var cmd tea.Cmd - - m.Cursor, cmd = m.Cursor.Update(msg) - cmds = append(cmds, cmd) - - if oldPos != m.pos && m.Cursor.Mode() == cursor.CursorBlink { - m.Cursor.Blink = false - cmds = append(cmds, m.Cursor.BlinkCmd()) - } - - m.handleOverflow() - return m, tea.Batch(cmds...) -} - -// View renders the textinput in its current state. -func (m Model) View() string { - // Placeholder text - if len(m.value) == 0 && m.Placeholder != "" { - return m.placeholderView() - } - - styleText := m.TextStyle.Inline(true).Render - - value := m.value[m.offset:m.offsetRight] - pos := max(0, m.pos-m.offset) - v := styleText(m.echoTransform(string(value[:pos]))) - - if pos < len(value) { //nolint:nestif - char := m.echoTransform(string(value[pos])) - m.Cursor.SetChar(char) - v += m.Cursor.View() // cursor and text under it - v += styleText(m.echoTransform(string(value[pos+1:]))) // text after cursor - v += m.completionView(0) // suggested completion - } else { - if m.focus && m.canAcceptSuggestion() { - suggestion := m.matchedSuggestions[m.currentSuggestionIndex] - if len(value) < len(suggestion) { - m.Cursor.TextStyle = m.CompletionStyle - m.Cursor.SetChar(m.echoTransform(string(suggestion[pos]))) - v += m.Cursor.View() - v += m.completionView(1) - } else { - m.Cursor.SetChar(" ") - v += m.Cursor.View() - } - } else { - m.Cursor.SetChar(" ") - v += m.Cursor.View() - } - } - - // If a max width and background color were set fill the empty spaces with - // the background color. - valWidth := uniseg.StringWidth(string(value)) - if m.Width > 0 && valWidth <= m.Width { - padding := max(0, m.Width-valWidth) - if valWidth+padding <= m.Width && pos < len(value) { - padding++ - } - v += styleText(strings.Repeat(" ", padding)) - } - - return m.PromptStyle.Render(m.Prompt) + v -} - -// placeholderView returns the prompt and placeholder view, if any. -func (m Model) placeholderView() string { - var ( - v string - style = m.PlaceholderStyle.Inline(true).Render - ) - - p := make([]rune, m.Width+1) - copy(p, []rune(m.Placeholder)) - - m.Cursor.TextStyle = m.PlaceholderStyle - m.Cursor.SetChar(string(p[:1])) - v += m.Cursor.View() - - // If the entire placeholder is already set and no padding is needed, finish - if m.Width < 1 && len(p) <= 1 { - return m.PromptStyle.Render(m.Prompt) + v - } - - // If Width is set then size placeholder accordingly - if m.Width > 0 { - // available width is width - len + cursor offset of 1 - minWidth := lipgloss.Width(m.Placeholder) - availWidth := m.Width - minWidth + 1 - - // if width < len, 'subtract'(add) number to len and dont add padding - if availWidth < 0 { - minWidth += availWidth - availWidth = 0 - } - // append placeholder[len] - cursor, append padding - v += style(string(p[1:minWidth])) - v += style(strings.Repeat(" ", availWidth)) - } else { - // if there is no width, the placeholder can be any length - v += style(string(p[1:])) - } - - return m.PromptStyle.Render(m.Prompt) + v -} - -// Blink is a command used to initialize cursor blinking. -func Blink() tea.Msg { - return cursor.Blink() -} - -// Paste is a command for pasting from the clipboard into the text input. -func Paste() tea.Msg { - str, err := clipboard.ReadAll() - if err != nil { - return pasteErrMsg{err} - } - return pasteMsg(str) -} - -func clamp(v, low, high int) int { - if high < low { - low, high = high, low - } - return min(high, max(low, v)) -} - -// Deprecated. - -// Deprecated: use [cursor.Mode]. -// -//nolint:revive -type CursorMode int - -//nolint:revive -const ( - // Deprecated: use [cursor.CursorBlink]. - CursorBlink = CursorMode(cursor.CursorBlink) - // Deprecated: use [cursor.CursorStatic]. - CursorStatic = CursorMode(cursor.CursorStatic) - // Deprecated: use [cursor.CursorHide]. - CursorHide = CursorMode(cursor.CursorHide) -) - -func (c CursorMode) String() string { - return cursor.Mode(c).String() -} - -// Deprecated: use [cursor.Mode]. -// -//nolint:revive -func (m Model) CursorMode() CursorMode { - return CursorMode(m.Cursor.Mode()) -} - -// Deprecated: use cursor.SetMode(). -// -//nolint:revive -func (m *Model) SetCursorMode(mode CursorMode) tea.Cmd { - return m.Cursor.SetMode(cursor.Mode(mode)) -} - -func (m Model) completionView(offset int) string { - var ( - value = m.value - style = m.PlaceholderStyle.Inline(true).Render - ) - - if m.canAcceptSuggestion() { - suggestion := m.matchedSuggestions[m.currentSuggestionIndex] - if len(value) < len(suggestion) { - return style(string(suggestion[len(value)+offset:])) - } - } - return "" -} - -func (m *Model) getSuggestions(sugs [][]rune) []string { - suggestions := make([]string, len(sugs)) - for i, s := range sugs { - suggestions[i] = string(s) - } - return suggestions -} - -// AvailableSuggestions returns the list of available suggestions. -func (m *Model) AvailableSuggestions() []string { - return m.getSuggestions(m.suggestions) -} - -// MatchedSuggestions returns the list of matched suggestions. -func (m *Model) MatchedSuggestions() []string { - return m.getSuggestions(m.matchedSuggestions) -} - -// CurrentSuggestionIndex returns the currently selected suggestion index. -func (m *Model) CurrentSuggestionIndex() int { - return m.currentSuggestionIndex -} - -// CurrentSuggestion returns the currently selected suggestion. -func (m *Model) CurrentSuggestion() string { - if m.currentSuggestionIndex >= len(m.matchedSuggestions) { - return "" - } - - return string(m.matchedSuggestions[m.currentSuggestionIndex]) -} - -// canAcceptSuggestion returns whether there is an acceptable suggestion to -// autocomplete the current value. -func (m *Model) canAcceptSuggestion() bool { - return len(m.matchedSuggestions) > 0 -} - -// updateSuggestions refreshes the list of matching suggestions. -func (m *Model) updateSuggestions() { - if !m.ShowSuggestions { - return - } - - if len(m.value) <= 0 || len(m.suggestions) <= 0 { - m.matchedSuggestions = [][]rune{} - return - } - - matches := [][]rune{} - for _, s := range m.suggestions { - suggestion := string(s) - - if strings.HasPrefix(strings.ToLower(suggestion), strings.ToLower(string(m.value))) { - matches = append(matches, []rune(suggestion)) - } - } - if !reflect.DeepEqual(matches, m.matchedSuggestions) { - m.currentSuggestionIndex = 0 - } - - m.matchedSuggestions = matches -} - -// nextSuggestion selects the next suggestion. -func (m *Model) nextSuggestion() { - m.currentSuggestionIndex = (m.currentSuggestionIndex + 1) - if m.currentSuggestionIndex >= len(m.matchedSuggestions) { - m.currentSuggestionIndex = 0 - } -} - -// previousSuggestion selects the previous suggestion. -func (m *Model) previousSuggestion() { - m.currentSuggestionIndex = (m.currentSuggestionIndex - 1) - if m.currentSuggestionIndex < 0 { - m.currentSuggestionIndex = len(m.matchedSuggestions) - 1 - } -} - -func (m Model) validate(v []rune) error { - if m.Validate != nil { - return m.Validate(string(v)) - } - return nil -} diff --git a/vendor/github.com/evertras/bubble-table/LICENSE b/vendor/github.com/evertras/bubble-table/LICENSE deleted file mode 100644 index 0a30e64a..00000000 --- a/vendor/github.com/evertras/bubble-table/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Brandon Fulljames - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/evertras/bubble-table/table/border.go b/vendor/github.com/evertras/bubble-table/table/border.go deleted file mode 100644 index 756d4c81..00000000 --- a/vendor/github.com/evertras/bubble-table/table/border.go +++ /dev/null @@ -1,439 +0,0 @@ -package table - -import "github.com/charmbracelet/lipgloss" - -// Border defines the borders in and around the table. -type Border struct { - Top string - Left string - Right string - Bottom string - TopRight string - TopLeft string - BottomRight string - BottomLeft string - - TopJunction string - LeftJunction string - RightJunction string - BottomJunction string - - InnerJunction string - - InnerDivider string - - // Styles for 2x2 tables and larger - styleMultiTopLeft lipgloss.Style - styleMultiTop lipgloss.Style - styleMultiTopRight lipgloss.Style - styleMultiRight lipgloss.Style - styleMultiBottomRight lipgloss.Style - styleMultiBottom lipgloss.Style - styleMultiBottomLeft lipgloss.Style - styleMultiLeft lipgloss.Style - styleMultiInner lipgloss.Style - - // Styles for a single column table - styleSingleColumnTop lipgloss.Style - styleSingleColumnInner lipgloss.Style - styleSingleColumnBottom lipgloss.Style - - // Styles for a single row table - styleSingleRowLeft lipgloss.Style - styleSingleRowInner lipgloss.Style - styleSingleRowRight lipgloss.Style - - // Style for a table with only one cell - styleSingleCell lipgloss.Style - - // Style for the footer - styleFooter lipgloss.Style -} - -var ( - // https://www.w3.org/TR/xml-entity-names/025.html - - borderDefault = Border{ - Top: "━", - Left: "┃", - Right: "┃", - Bottom: "━", - - TopRight: "┓", - TopLeft: "┏", - BottomRight: "┛", - BottomLeft: "┗", - - TopJunction: "┳", - LeftJunction: "┣", - RightJunction: "┫", - BottomJunction: "┻", - InnerJunction: "╋", - - InnerDivider: "┃", - } - - borderRounded = Border{ - Top: "─", - Left: "│", - Right: "│", - Bottom: "─", - - TopRight: "╮", - TopLeft: "╭", - BottomRight: "╯", - BottomLeft: "╰", - - TopJunction: "┬", - LeftJunction: "├", - RightJunction: "┤", - BottomJunction: "┴", - InnerJunction: "┼", - - InnerDivider: "│", - } -) - -func init() { - borderDefault.generateStyles() - borderRounded.generateStyles() -} - -func (b *Border) generateStyles() { - b.generateMultiStyles() - b.generateSingleColumnStyles() - b.generateSingleRowStyles() - b.generateSingleCellStyle() - - // The footer is a single cell with the top taken off... usually. We can - // re-enable the top if needed this way for certain format configurations. - b.styleFooter = b.styleSingleCell.Copy(). - Align(lipgloss.Right). - BorderBottom(true). - BorderRight(true). - BorderLeft(true) -} - -func (b *Border) styleLeftWithFooter(original lipgloss.Style) lipgloss.Style { - border := original.GetBorderStyle() - - border.BottomLeft = b.LeftJunction - - return original.Copy().BorderStyle(border) -} - -func (b *Border) styleRightWithFooter(original lipgloss.Style) lipgloss.Style { - border := original.GetBorderStyle() - - border.BottomRight = b.RightJunction - - return original.Copy().BorderStyle(border) -} - -func (b *Border) styleBothWithFooter(original lipgloss.Style) lipgloss.Style { - border := original.GetBorderStyle() - - border.BottomLeft = b.LeftJunction - border.BottomRight = b.RightJunction - - return original.Copy().BorderStyle(border) -} - -// This function is long, but it's just repetitive... -// -//nolint:funlen -func (b *Border) generateMultiStyles() { - b.styleMultiTopLeft = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - TopLeft: b.TopLeft, - Top: b.Top, - TopRight: b.TopJunction, - Right: b.InnerDivider, - BottomRight: b.InnerJunction, - Bottom: b.Bottom, - BottomLeft: b.LeftJunction, - Left: b.Left, - }, - ) - - b.styleMultiTop = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Right: b.InnerDivider, - Bottom: b.Bottom, - - TopRight: b.TopJunction, - BottomRight: b.InnerJunction, - }, - ).BorderTop(true).BorderBottom(true).BorderRight(true) - - b.styleMultiTopRight = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Right: b.Right, - Bottom: b.Bottom, - - TopRight: b.TopRight, - BottomRight: b.RightJunction, - }, - ).BorderTop(true).BorderBottom(true).BorderRight(true) - - b.styleMultiLeft = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Left: b.Left, - Right: b.InnerDivider, - }, - ).BorderRight(true).BorderLeft(true) - - b.styleMultiRight = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Right: b.Right, - }, - ).BorderRight(true) - - b.styleMultiInner = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Right: b.InnerDivider, - }, - ).BorderRight(true) - - b.styleMultiBottomLeft = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Left: b.Left, - Right: b.InnerDivider, - Bottom: b.Bottom, - - BottomLeft: b.BottomLeft, - BottomRight: b.BottomJunction, - }, - ).BorderLeft(true).BorderBottom(true).BorderRight(true) - - b.styleMultiBottom = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Right: b.InnerDivider, - Bottom: b.Bottom, - - BottomRight: b.BottomJunction, - }, - ).BorderBottom(true).BorderRight(true) - - b.styleMultiBottomRight = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Right: b.Right, - Bottom: b.Bottom, - - BottomRight: b.BottomRight, - }, - ).BorderBottom(true).BorderRight(true) -} - -func (b *Border) generateSingleColumnStyles() { - b.styleSingleColumnTop = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Left: b.Left, - Right: b.Right, - Bottom: b.Bottom, - - TopLeft: b.TopLeft, - TopRight: b.TopRight, - BottomLeft: b.LeftJunction, - BottomRight: b.RightJunction, - }, - ) - - b.styleSingleColumnInner = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Left: b.Left, - Right: b.Right, - }, - ).BorderRight(true).BorderLeft(true) - - b.styleSingleColumnBottom = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Left: b.Left, - Right: b.Right, - Bottom: b.Bottom, - - BottomLeft: b.BottomLeft, - BottomRight: b.BottomRight, - }, - ).BorderRight(true).BorderLeft(true).BorderBottom(true) -} - -func (b *Border) generateSingleRowStyles() { - b.styleSingleRowLeft = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Left: b.Left, - Right: b.InnerDivider, - Bottom: b.Bottom, - - BottomLeft: b.BottomLeft, - BottomRight: b.BottomJunction, - TopRight: b.TopJunction, - TopLeft: b.TopLeft, - }, - ) - - b.styleSingleRowInner = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Right: b.InnerDivider, - Bottom: b.Bottom, - - BottomRight: b.BottomJunction, - TopRight: b.TopJunction, - }, - ).BorderTop(true).BorderBottom(true).BorderRight(true) - - b.styleSingleRowRight = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Right: b.Right, - Bottom: b.Bottom, - - BottomRight: b.BottomRight, - TopRight: b.TopRight, - }, - ).BorderTop(true).BorderBottom(true).BorderRight(true) -} - -func (b *Border) generateSingleCellStyle() { - b.styleSingleCell = lipgloss.NewStyle().BorderStyle( - lipgloss.Border{ - Top: b.Top, - Left: b.Left, - Right: b.Right, - Bottom: b.Bottom, - - BottomLeft: b.BottomLeft, - BottomRight: b.BottomRight, - TopRight: b.TopRight, - TopLeft: b.TopLeft, - }, - ) -} - -// BorderDefault uses the basic square border, useful to reset the border if -// it was changed somehow. -func (m Model) BorderDefault() Model { - // Already generated styles - m.border = borderDefault - - return m -} - -// BorderRounded uses a thin, rounded border. -func (m Model) BorderRounded() Model { - // Already generated styles - m.border = borderRounded - - return m -} - -// Border uses the given border components to render the table. -func (m Model) Border(border Border) Model { - border.generateStyles() - - m.border = border - - return m -} - -type borderStyleRow struct { - left lipgloss.Style - inner lipgloss.Style - right lipgloss.Style -} - -func (b *borderStyleRow) inherit(s lipgloss.Style) { - b.left = b.left.Copy().Inherit(s) - b.inner = b.inner.Copy().Inherit(s) - b.right = b.right.Copy().Inherit(s) -} - -// There's a lot of branches here, but splitting it up further would make it -// harder to follow. So just be careful with comments and make sure it's tested! -// -//nolint:nestif -func (m Model) styleHeaders() borderStyleRow { - hasRows := len(m.GetVisibleRows()) > 0 || m.calculatePadding(0) > 0 - singleColumn := len(m.columns) == 1 - styles := borderStyleRow{} - - // Possible configurations: - // - Single cell - // - Single row - // - Single column - // - Multi - - if singleColumn { - if hasRows { - // Single column - styles.left = m.border.styleSingleColumnTop - styles.inner = styles.left - styles.right = styles.left - } else { - // Single cell - styles.left = m.border.styleSingleCell - styles.inner = styles.left - styles.right = styles.left - - if m.hasFooter() { - styles.left = m.border.styleBothWithFooter(styles.left) - } - } - } else if !hasRows { - // Single row - styles.left = m.border.styleSingleRowLeft - styles.inner = m.border.styleSingleRowInner - styles.right = m.border.styleSingleRowRight - - if m.hasFooter() { - styles.left = m.border.styleLeftWithFooter(styles.left) - styles.right = m.border.styleRightWithFooter(styles.right) - } - } else { - // Multi - styles.left = m.border.styleMultiTopLeft - styles.inner = m.border.styleMultiTop - styles.right = m.border.styleMultiTopRight - } - - styles.inherit(m.headerStyle) - - return styles -} - -func (m Model) styleRows() (inner borderStyleRow, last borderStyleRow) { - if len(m.columns) == 1 { - inner.left = m.border.styleSingleColumnInner - inner.inner = inner.left - inner.right = inner.left - - last.left = m.border.styleSingleColumnBottom - - if m.hasFooter() { - last.left = m.border.styleBothWithFooter(last.left) - } - - last.inner = last.left - last.right = last.left - } else { - inner.left = m.border.styleMultiLeft - inner.inner = m.border.styleMultiInner - inner.right = m.border.styleMultiRight - - last.left = m.border.styleMultiBottomLeft - last.inner = m.border.styleMultiBottom - last.right = m.border.styleMultiBottomRight - - if m.hasFooter() { - last.left = m.border.styleLeftWithFooter(last.left) - last.right = m.border.styleRightWithFooter(last.right) - } - } - - return inner, last -} diff --git a/vendor/github.com/evertras/bubble-table/table/calc.go b/vendor/github.com/evertras/bubble-table/table/calc.go deleted file mode 100644 index 21b7a7d7..00000000 --- a/vendor/github.com/evertras/bubble-table/table/calc.go +++ /dev/null @@ -1,36 +0,0 @@ -package table - -// Keep compatibility with Go 1.21 by re-declaring min. -// -//nolint:predeclared -func min(x, y int) int { - if x < y { - return x - } - - return y -} - -// Keep compatibility with Go 1.21 by re-declaring max. -// -//nolint:predeclared -func max(x, y int) int { - if x > y { - return x - } - - return y -} - -// These var names are fine for this little function -// -//nolint:varnamelen -func gcd(x, y int) int { - if x == 0 { - return y - } else if y == 0 { - return x - } - - return gcd(y%x, x) -} diff --git a/vendor/github.com/evertras/bubble-table/table/cell.go b/vendor/github.com/evertras/bubble-table/table/cell.go deleted file mode 100644 index ac9e5c40..00000000 --- a/vendor/github.com/evertras/bubble-table/table/cell.go +++ /dev/null @@ -1,60 +0,0 @@ -package table - -import "github.com/charmbracelet/lipgloss" - -// StyledCell represents a cell in the table that has a particular style applied. -// The cell style takes highest precedence and will overwrite more general styles -// from the row, column, or table as a whole. This style should be generally -// limited to colors, font style, and alignments - spacing style such as margin -// will break the table format. -type StyledCell struct { - // Data is the content of the cell. - Data any - - // Style is the specific style to apply. This is ignored if StyleFunc is not nil. - Style lipgloss.Style - - // StyleFunc is a function that takes the row/column of the cell and - // returns a lipgloss.Style allowing for dynamic styling based on the cell's - // content or position. Overrides Style if set. - StyleFunc StyledCellFunc -} - -// StyledCellFuncInput is the input to the StyledCellFunc. Sent as a struct -// to allow for future additions without breaking changes. -type StyledCellFuncInput struct { - // Data is the data in the cell. - Data any - - // Column is the column that the cell belongs to. - Column Column - - // Row is the row that the cell belongs to. - Row Row - - // GlobalMetadata is the global table metadata that's been set by WithGlobalMetadata - GlobalMetadata map[string]any -} - -// StyledCellFunc is a function that takes various information about the cell and -// returns a lipgloss.Style allowing for easier dynamic styling based on the cell's -// content or position. -type StyledCellFunc = func(input StyledCellFuncInput) lipgloss.Style - -// NewStyledCell creates an entry that can be set in the row data and show as -// styled with the given style. -func NewStyledCell(data any, style lipgloss.Style) StyledCell { - return StyledCell{ - Data: data, - Style: style, - } -} - -// NewStyledCellWithStyleFunc creates an entry that can be set in the row data and show as -// styled with the given style function. -func NewStyledCellWithStyleFunc(data any, styleFunc StyledCellFunc) StyledCell { - return StyledCell{ - Data: data, - StyleFunc: styleFunc, - } -} diff --git a/vendor/github.com/evertras/bubble-table/table/column.go b/vendor/github.com/evertras/bubble-table/table/column.go deleted file mode 100644 index 44714755..00000000 --- a/vendor/github.com/evertras/bubble-table/table/column.go +++ /dev/null @@ -1,118 +0,0 @@ -package table - -import ( - "github.com/charmbracelet/lipgloss" -) - -// Column is a column in the table. -type Column struct { - title string - key string - width int - - flexFactor int - - filterable bool - style lipgloss.Style - - fmtString string -} - -// NewColumn creates a new fixed-width column with the given information. -func NewColumn(key, title string, width int) Column { - return Column{ - key: key, - title: title, - width: width, - - filterable: false, - } -} - -// NewFlexColumn creates a new flexible width column that tries to fill in the -// total table width. If multiple flex columns exist, each will measure against -// each other depending on their flexFactor. For example, if both have a flexFactor -// of 1, they will have equal width. If one has a flexFactor of 1 and the other -// has a flexFactor of 3, the second will be 3 times larger than the first. You -// must use WithTargetWidth if you have any flex columns, so that the table knows -// how much width it should fill. -func NewFlexColumn(key, title string, flexFactor int) Column { - return Column{ - key: key, - title: title, - - flexFactor: max(flexFactor, 1), - } -} - -// WithStyle applies a style to the column as a whole. -func (c Column) WithStyle(style lipgloss.Style) Column { - c.style = style.Copy().Width(c.width) - - return c -} - -// WithFiltered sets whether the column should be considered for filtering (true) -// or not (false). -func (c Column) WithFiltered(filterable bool) Column { - c.filterable = filterable - - return c -} - -// WithFormatString sets the format string used by fmt.Sprintf to display the data. -// If not set, the default is "%v" for all data types. Intended mainly for -// numeric formatting. -// -// Since data is of the any type, make sure that all data in the column -// is of the expected type or the format may fail. For example, hardcoding '3' -// instead of '3.0' and using '%.2f' will fail because '3' is an integer. -func (c Column) WithFormatString(fmtString string) Column { - c.fmtString = fmtString - - return c -} - -func (c *Column) isFlex() bool { - return c.flexFactor != 0 -} - -// Title returns the title of the column. -func (c Column) Title() string { - return c.title -} - -// Key returns the key of the column. -func (c Column) Key() string { - return c.key -} - -// Width returns the width of the column. -func (c Column) Width() int { - return c.width -} - -// FlexFactor returns the flex factor of the column. -func (c Column) FlexFactor() int { - return c.flexFactor -} - -// IsFlex returns whether the column is a flex column. -func (c Column) IsFlex() bool { - return c.isFlex() -} - -// Filterable returns whether the column is filterable. -func (c Column) Filterable() bool { - return c.filterable -} - -// Style returns the style of the column. -func (c Column) Style() lipgloss.Style { - return c.style -} - -// FmtString returns the format string of the column. -func (c Column) FmtString() string { - return c.fmtString -} diff --git a/vendor/github.com/evertras/bubble-table/table/data.go b/vendor/github.com/evertras/bubble-table/table/data.go deleted file mode 100644 index 901a4f4b..00000000 --- a/vendor/github.com/evertras/bubble-table/table/data.go +++ /dev/null @@ -1,67 +0,0 @@ -package table - -import "time" - -// This is just a bunch of data type checks, so... no linting here -// -//nolint:cyclop -func asInt(data any) (int64, bool) { - switch val := data.(type) { - case int: - return int64(val), true - - case int8: - return int64(val), true - - case int16: - return int64(val), true - - case int32: - return int64(val), true - - case int64: - return val, true - - case uint: - // #nosec: G115 - return int64(val), true - - case uint8: - return int64(val), true - - case uint16: - return int64(val), true - - case uint32: - return int64(val), true - - case uint64: - // #nosec: G115 - return int64(val), true - - case time.Duration: - return int64(val), true - - case StyledCell: - return asInt(val.Data) - } - - return 0, false -} - -func asNumber(data any) (float64, bool) { - switch val := data.(type) { - case float32: - return float64(val), true - - case float64: - return val, true - - case StyledCell: - return asNumber(val.Data) - } - - intVal, isInt := asInt(data) - - return float64(intVal), isInt -} diff --git a/vendor/github.com/evertras/bubble-table/table/dimensions.go b/vendor/github.com/evertras/bubble-table/table/dimensions.go deleted file mode 100644 index 38074616..00000000 --- a/vendor/github.com/evertras/bubble-table/table/dimensions.go +++ /dev/null @@ -1,116 +0,0 @@ -package table - -import ( - "github.com/charmbracelet/lipgloss" -) - -func (m *Model) recalculateWidth() { - if m.targetTotalWidth != 0 { - m.totalWidth = m.targetTotalWidth - } else { - total := 0 - - for _, column := range m.columns { - total += column.width - } - - m.totalWidth = total + len(m.columns) + 1 - } - - updateColumnWidths(m.columns, m.targetTotalWidth) - - m.recalculateLastHorizontalColumn() -} - -// Updates column width in-place. This could be optimized but should be called -// very rarely so we prioritize simplicity over performance here. -func updateColumnWidths(cols []Column, totalWidth int) { - totalFlexWidth := totalWidth - len(cols) - 1 - totalFlexFactor := 0 - flexGCD := 0 - - for index, col := range cols { - if !col.isFlex() { - totalFlexWidth -= col.width - cols[index].style = col.style.Width(col.width) - } else { - totalFlexFactor += col.flexFactor - flexGCD = gcd(flexGCD, col.flexFactor) - } - } - - if totalFlexFactor == 0 { - return - } - - // We use the GCD here because otherwise very large values won't divide - // nicely as ints - totalFlexFactor /= flexGCD - - flexUnit := totalFlexWidth / totalFlexFactor - leftoverWidth := totalFlexWidth % totalFlexFactor - - for index := range cols { - if !cols[index].isFlex() { - continue - } - - width := flexUnit * (cols[index].flexFactor / flexGCD) - - if leftoverWidth > 0 { - width++ - leftoverWidth-- - } - - if index == len(cols)-1 { - width += leftoverWidth - leftoverWidth = 0 - } - - width = max(width, 1) - - cols[index].width = width - - // Take borders into account for the actual style - cols[index].style = cols[index].style.Width(width) - } -} - -func (m *Model) recalculateHeight() { - header := m.renderHeaders() - headerHeight := 1 // Header always has the top border - if m.headerVisible { - headerHeight = lipgloss.Height(header) - } - - footer := m.renderFooter(lipgloss.Width(header), false) - var footerHeight int - if footer != "" { - footerHeight = lipgloss.Height(footer) - } - - m.metaHeight = headerHeight + footerHeight -} - -func (m *Model) calculatePadding(numRows int) int { - if m.minimumHeight == 0 { - return 0 - } - - padding := m.minimumHeight - m.metaHeight - numRows - 1 // additional 1 for bottom border - - if padding == 0 && numRows == 0 { - // This is an edge case where we want to add 1 additional line of height, i.e. - // add a border without an empty row. However, this is not possible, so we need - // to add an extra row which will result in the table being 1 row taller than - // the requested minimum height. - return 1 - } - - if padding < 0 { - // Table is already larger than minimum height, do nothing. - return 0 - } - - return padding -} diff --git a/vendor/github.com/evertras/bubble-table/table/doc.go b/vendor/github.com/evertras/bubble-table/table/doc.go deleted file mode 100644 index 554944af..00000000 --- a/vendor/github.com/evertras/bubble-table/table/doc.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Package table contains a Bubble Tea component for an interactive and customizable -table. - -The simplest useful table can be created with table.New(...).WithRows(...). Row -data should map to the column keys, as shown below. Note that extra data will -simply not be shown, while missing data will be safely blank in the row's cell. - - const ( - // This is not necessary, but recommended to avoid typos - columnKeyName = "name" - columnKeyCount = "count" - ) - - // Define the columns and how they appear - columns := []table.Column{ - table.NewColumn(columnKeyName, "Name", 10), - table.NewColumn(columnKeyCount, "Count", 6), - } - - // Define the data that will be in the table, mapping to the column keys - rows := []table.Row{ - table.NewRow(table.RowData{ - columnKeyName: "Cheeseburger", - columnKeyCount: 3, - }), - table.NewRow(table.RowData{ - columnKeyName: "Fries", - columnKeyCount: 2, - }), - } - - // Create the table - tbl := table.New(columns).WithRows(rows) - - // Use it like any Bubble Tea component in your view - tbl.View() -*/ -package table diff --git a/vendor/github.com/evertras/bubble-table/table/events.go b/vendor/github.com/evertras/bubble-table/table/events.go deleted file mode 100644 index b519623d..00000000 --- a/vendor/github.com/evertras/bubble-table/table/events.go +++ /dev/null @@ -1,60 +0,0 @@ -package table - -// UserEvent is some state change that has occurred due to user input. These will -// ONLY be generated when a user has interacted directly with the table. These -// will NOT be generated when code programmatically changes values in the table. -type UserEvent any - -func (m *Model) appendUserEvent(e UserEvent) { - m.lastUpdateUserEvents = append(m.lastUpdateUserEvents, e) -} - -func (m *Model) clearUserEvents() { - m.lastUpdateUserEvents = nil -} - -// GetLastUpdateUserEvents returns a list of events that happened due to user -// input in the last Update call. This is useful to look for triggers such as -// whether the user moved to a new highlighted row. -func (m *Model) GetLastUpdateUserEvents() []UserEvent { - // Most common case - if len(m.lastUpdateUserEvents) == 0 { - return nil - } - - returned := make([]UserEvent, len(m.lastUpdateUserEvents)) - - // Slightly wasteful but helps guarantee immutability, and this should only - // have data very rarely so this is fine - copy(returned, m.lastUpdateUserEvents) - - return returned -} - -// UserEventHighlightedIndexChanged indicates that the user has scrolled to a new -// row. -type UserEventHighlightedIndexChanged struct { - // PreviousRow is the row that was selected before the change. - PreviousRowIndex int - - // SelectedRow is the row index that is now selected - SelectedRowIndex int -} - -// UserEventRowSelectToggled indicates that the user has either selected or -// deselected a row by toggling the selection. The event contains information -// about which row index was selected and whether it was selected or deselected. -type UserEventRowSelectToggled struct { - RowIndex int - IsSelected bool -} - -// UserEventFilterInputFocused indicates that the user has focused the filter -// text input, so that any other typing will type into the filter field. Only -// activates for the built-in filter text box. -type UserEventFilterInputFocused struct{} - -// UserEventFilterInputUnfocused indicates that the user has unfocused the filter -// text input, which means the user is done typing into the filter field. Only -// activates for the built-in filter text box. -type UserEventFilterInputUnfocused struct{} diff --git a/vendor/github.com/evertras/bubble-table/table/filter.go b/vendor/github.com/evertras/bubble-table/table/filter.go deleted file mode 100644 index 765e5b33..00000000 --- a/vendor/github.com/evertras/bubble-table/table/filter.go +++ /dev/null @@ -1,164 +0,0 @@ -package table - -import ( - "fmt" - "strings" -) - -// FilterFuncInput is the input to a FilterFunc. It's a struct so we can add more things later -// without breaking compatibility. -type FilterFuncInput struct { - // Columns is a list of the columns of the table - Columns []Column - - // Row is the row that's being considered for filtering - Row Row - - // GlobalMetadata is an arbitrary set of metadata from the table set by WithGlobalMetadata - GlobalMetadata map[string]any - - // Filter is the filter string input to consider - Filter string -} - -// FilterFunc takes a FilterFuncInput and returns true if the row should be visible, -// or false if the row should be hidden. -type FilterFunc func(FilterFuncInput) bool - -func (m Model) getFilteredRows(rows []Row) []Row { - filterInputValue := m.filterTextInput.Value() - if !m.filtered || filterInputValue == "" { - return rows - } - - filteredRows := make([]Row, 0) - - for _, row := range rows { - var availableFilterFunc FilterFunc - - if m.filterFunc != nil { - availableFilterFunc = m.filterFunc - } else { - availableFilterFunc = filterFuncContains - } - - if availableFilterFunc(FilterFuncInput{ - Columns: m.columns, - Row: row, - Filter: filterInputValue, - GlobalMetadata: m.metadata, - }) { - filteredRows = append(filteredRows, row) - } - } - - return filteredRows -} - -// filterFuncContains returns a filterFunc that performs case-insensitive -// "contains" matching over all filterable columns in a row. -func filterFuncContains(input FilterFuncInput) bool { - if input.Filter == "" { - return true - } - - checkedAny := false - - filterLower := strings.ToLower(input.Filter) - - for _, column := range input.Columns { - if !column.filterable { - continue - } - - checkedAny = true - - data, ok := input.Row.Data[column.key] - - if !ok { - continue - } - - // Extract internal StyledCell data - switch dataV := data.(type) { - case StyledCell: - data = dataV.Data - } - - var target string - switch dataV := data.(type) { - case string: - target = dataV - - case fmt.Stringer: - target = dataV.String() - - default: - target = fmt.Sprintf("%v", data) - } - - if strings.Contains(strings.ToLower(target), filterLower) { - return true - } - } - - return !checkedAny -} - -// filterFuncFuzzy returns a filterFunc that performs case-insensitive fuzzy -// matching (subsequence) over the concatenation of all filterable column values. -func filterFuncFuzzy(input FilterFuncInput) bool { - filter := strings.TrimSpace(input.Filter) - if filter == "" { - return true - } - - var builder strings.Builder - for _, col := range input.Columns { - if !col.filterable { - continue - } - value, ok := input.Row.Data[col.key] - if !ok { - continue - } - if sc, ok := value.(StyledCell); ok { - value = sc.Data - } - builder.WriteString(fmt.Sprint(value)) // uses Stringer if implemented - builder.WriteByte(' ') - } - - haystack := strings.ToLower(builder.String()) - if haystack == "" { - return false - } - - for _, token := range strings.Fields(strings.ToLower(filter)) { - if !fuzzySubsequenceMatch(haystack, token) { - return false - } - } - - return true -} - -// fuzzySubsequenceMatch returns true if all runes in needle appear in order -// within haystack (not necessarily contiguously). Case must be normalized by caller. -func fuzzySubsequenceMatch(haystack, needle string) bool { - if needle == "" { - return true - } - haystackIndex, needleIndex := 0, 0 - haystackRunes := []rune(haystack) - needleRunes := []rune(needle) - - for haystackIndex < len(haystackRunes) && needleIndex < len(needleRunes) { - if haystackRunes[haystackIndex] == needleRunes[needleIndex] { - needleIndex++ - } - haystackIndex++ - } - - return needleIndex == len(needleRunes) -} diff --git a/vendor/github.com/evertras/bubble-table/table/footer.go b/vendor/github.com/evertras/bubble-table/table/footer.go deleted file mode 100644 index c68709ce..00000000 --- a/vendor/github.com/evertras/bubble-table/table/footer.go +++ /dev/null @@ -1,51 +0,0 @@ -package table - -import ( - "fmt" - "strings" -) - -func (m Model) hasFooter() bool { - return m.footerVisible && (m.staticFooter != "" || m.pageSize != 0 || m.filtered) -} - -func (m Model) renderFooter(width int, includeTop bool) string { - if !m.hasFooter() { - return "" - } - - const borderAdjustment = 2 - - styleFooter := m.baseStyle.Copy().Inherit(m.border.styleFooter).Width(width - borderAdjustment) - - if includeTop { - styleFooter = styleFooter.BorderTop(true) - } - - if m.staticFooter != "" { - return styleFooter.Render(m.staticFooter) - } - - sections := []string{} - - if m.filtered && (m.filterTextInput.Focused() || m.filterTextInput.Value() != "") { - sections = append(sections, m.filterTextInput.View()) - } - - // paged feature enabled - if m.pageSize != 0 { - str := fmt.Sprintf("%d/%d", m.CurrentPage(), m.MaxPages()) - if m.filtered && m.filterTextInput.Focused() { - // Need to apply inline style here in case of filter input cursor, because - // the input cursor resets the style after rendering. Note that Inline(true) - // creates a copy, so it's safe to use here without mutating the underlying - // base style. - str = m.baseStyle.Inline(true).Render(str) - } - sections = append(sections, str) - } - - footerText := strings.Join(sections, " ") - - return styleFooter.Render(footerText) -} diff --git a/vendor/github.com/evertras/bubble-table/table/header.go b/vendor/github.com/evertras/bubble-table/table/header.go deleted file mode 100644 index fdd5ac0b..00000000 --- a/vendor/github.com/evertras/bubble-table/table/header.go +++ /dev/null @@ -1,93 +0,0 @@ -package table - -import "github.com/charmbracelet/lipgloss" - -// This is long and could use some refactoring in the future, but unsure of how -// to pick it apart right now. -// -//nolint:funlen,cyclop -func (m Model) renderHeaders() string { - headerStrings := []string{} - - totalRenderedWidth := 0 - - headerStyles := m.styleHeaders() - - renderHeader := func(column Column, borderStyle lipgloss.Style) string { - borderStyle = borderStyle.Inherit(column.style).Inherit(m.baseStyle) - - headerSection := limitStr(column.title, column.width) - - return borderStyle.Render(headerSection) - } - - for columnIndex, column := range m.columns { - var borderStyle lipgloss.Style - - if m.horizontalScrollOffsetCol > 0 && columnIndex == m.horizontalScrollFreezeColumnsCount { - if columnIndex == 0 { - borderStyle = headerStyles.left.Copy() - } else { - borderStyle = headerStyles.inner.Copy() - } - - rendered := renderHeader(genOverflowColumnLeft(1), borderStyle) - - totalRenderedWidth += lipgloss.Width(rendered) - - headerStrings = append(headerStrings, rendered) - } - - if columnIndex >= m.horizontalScrollFreezeColumnsCount && - columnIndex < m.horizontalScrollOffsetCol+m.horizontalScrollFreezeColumnsCount { - continue - } - - if len(headerStrings) == 0 { - borderStyle = headerStyles.left.Copy() - } else if columnIndex < len(m.columns)-1 { - borderStyle = headerStyles.inner.Copy() - } else { - borderStyle = headerStyles.right.Copy() - } - - rendered := renderHeader(column, borderStyle) - - if m.maxTotalWidth != 0 { - renderedWidth := lipgloss.Width(rendered) - - const ( - borderAdjustment = 1 - overflowColWidth = 2 - ) - - targetWidth := m.maxTotalWidth - overflowColWidth - - if columnIndex == len(m.columns)-1 { - // If this is the last header, we don't need to account for the - // overflow arrow column - targetWidth = m.maxTotalWidth - } - - if totalRenderedWidth+renderedWidth > targetWidth { - overflowWidth := m.maxTotalWidth - totalRenderedWidth - borderAdjustment - overflowStyle := genOverflowStyle(headerStyles.right, overflowWidth) - overflowColumn := genOverflowColumnRight(overflowWidth) - - overflowStr := renderHeader(overflowColumn, overflowStyle) - - headerStrings = append(headerStrings, overflowStr) - - break - } - - totalRenderedWidth += renderedWidth - } - - headerStrings = append(headerStrings, rendered) - } - - headerBlock := lipgloss.JoinHorizontal(lipgloss.Bottom, headerStrings...) - - return headerBlock -} diff --git a/vendor/github.com/evertras/bubble-table/table/keys.go b/vendor/github.com/evertras/bubble-table/table/keys.go deleted file mode 100644 index fe2eccc3..00000000 --- a/vendor/github.com/evertras/bubble-table/table/keys.go +++ /dev/null @@ -1,120 +0,0 @@ -package table - -import "github.com/charmbracelet/bubbles/key" - -// KeyMap defines the keybindings for the table when it's focused. -type KeyMap struct { - RowDown key.Binding - RowUp key.Binding - - RowSelectToggle key.Binding - - PageDown key.Binding - PageUp key.Binding - PageFirst key.Binding - PageLast key.Binding - - // Filter allows the user to start typing and filter the rows. - Filter key.Binding - - // FilterBlur is the key that stops the user's input from typing into the filter. - FilterBlur key.Binding - - // FilterClear will clear the filter while it's blurred. - FilterClear key.Binding - - // ScrollRight will move one column to the right when overflow occurs. - ScrollRight key.Binding - - // ScrollLeft will move one column to the left when overflow occurs. - ScrollLeft key.Binding -} - -// DefaultKeyMap returns a set of sensible defaults for controlling a focused table with help text. -func DefaultKeyMap() KeyMap { - return KeyMap{ - RowDown: key.NewBinding( - key.WithKeys("down", "j"), - key.WithHelp("↓/j", "move down"), - ), - RowUp: key.NewBinding( - key.WithKeys("up", "k"), - key.WithHelp("↑/k", "move up"), - ), - RowSelectToggle: key.NewBinding( - key.WithKeys(" ", "enter"), - key.WithHelp("/enter", "select row"), - ), - PageDown: key.NewBinding( - key.WithKeys("right", "l", "pgdown"), - key.WithHelp("→/h/page down", "next page"), - ), - PageUp: key.NewBinding( - key.WithKeys("left", "h", "pgup"), - key.WithHelp("←/h/page up", "previous page"), - ), - PageFirst: key.NewBinding( - key.WithKeys("home", "g"), - key.WithHelp("home/g", "first page"), - ), - PageLast: key.NewBinding( - key.WithKeys("end", "G"), - key.WithHelp("end/G", "last page"), - ), - Filter: key.NewBinding( - key.WithKeys("/"), - key.WithHelp("/", "filter"), - ), - FilterBlur: key.NewBinding( - key.WithKeys("enter", "esc"), - key.WithHelp("enter/esc", "unfocus"), - ), - FilterClear: key.NewBinding( - key.WithKeys("esc"), - key.WithHelp("esc", "clear filter"), - ), - ScrollRight: key.NewBinding( - key.WithKeys("shift+right"), - key.WithHelp("shift+→", "scroll right"), - ), - ScrollLeft: key.NewBinding( - key.WithKeys("shift+left"), - key.WithHelp("shift+←", "scroll left"), - ), - } -} - -// FullHelp returns a multi row view of all the helpkeys that are defined. Needed to fullfil the 'help.Model' interface. -// Also appends all user defined extra keys to the help. -func (m Model) FullHelp() [][]key.Binding { - keyBinds := [][]key.Binding{ - {m.keyMap.RowDown, m.keyMap.RowUp, m.keyMap.RowSelectToggle}, - {m.keyMap.PageDown, m.keyMap.PageUp, m.keyMap.PageFirst, m.keyMap.PageLast}, - {m.keyMap.Filter, m.keyMap.FilterBlur, m.keyMap.FilterClear, m.keyMap.ScrollRight, m.keyMap.ScrollLeft}, - } - if m.additionalFullHelpKeys != nil { - keyBinds = append(keyBinds, m.additionalFullHelpKeys()) - } - - return keyBinds -} - -// ShortHelp just returns a single row of help views. Needed to fullfil the 'help.Model' interface. -// Also appends all user defined extra keys to the help. -func (m Model) ShortHelp() []key.Binding { - keyBinds := []key.Binding{ - m.keyMap.RowDown, - m.keyMap.RowUp, - m.keyMap.RowSelectToggle, - m.keyMap.PageDown, - m.keyMap.PageUp, - m.keyMap.Filter, - m.keyMap.FilterBlur, - m.keyMap.FilterClear, - } - if m.additionalShortHelpKeys != nil { - keyBinds = append(keyBinds, m.additionalShortHelpKeys()...) - } - - return keyBinds -} diff --git a/vendor/github.com/evertras/bubble-table/table/model.go b/vendor/github.com/evertras/bubble-table/table/model.go deleted file mode 100644 index 33e1458c..00000000 --- a/vendor/github.com/evertras/bubble-table/table/model.go +++ /dev/null @@ -1,148 +0,0 @@ -package table - -import ( - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textinput" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -const ( - columnKeySelect = "___select___" -) - -var ( - defaultHighlightStyle = lipgloss.NewStyle().Background(lipgloss.Color("#334")) -) - -// Model is the main table model. Create using New(). -type Model struct { - // Data - columns []Column - rows []Row - metadata map[string]any - - // Caches for optimizations - visibleRowCacheUpdated bool - visibleRowCache []Row - - // Shown when data is missing from a row - missingDataIndicator any - - // Interaction - focused bool - keyMap KeyMap - - // Taken from: 'Bubbles/List' - // Additional key mappings for the short and full help views. This allows - // you to add additional key mappings to the help menu without - // re-implementing the help component. Of course, you can also disable the - // list's help component and implement a new one if you need more - // flexibility. - // You have to supply a keybinding like this: - // key.NewBinding( key.WithKeys("shift+left"), key.WithHelp("shift+←", "scroll left")) - // It needs both 'WithKeys' and 'WithHelp' - additionalShortHelpKeys func() []key.Binding - additionalFullHelpKeys func() []key.Binding - - selectableRows bool - rowCursorIndex int - - // Events - lastUpdateUserEvents []UserEvent - - // Styles - baseStyle lipgloss.Style - highlightStyle lipgloss.Style - headerStyle lipgloss.Style - rowStyleFunc func(RowStyleFuncInput) lipgloss.Style - border Border - selectedText string - unselectedText string - - // Header - headerVisible bool - - // Footers - footerVisible bool - staticFooter string - - // Pagination - pageSize int - currentPage int - paginationWrapping bool - - // Sorting, where a stable sort is applied from first element to last so - // that elements are grouped by the later elements. - sortOrder []SortColumn - - // Filter - filtered bool - filterTextInput textinput.Model - filterFunc FilterFunc - - // For flex columns - targetTotalWidth int - - // The maximum total width for overflow/scrolling - maxTotalWidth int - - // Internal cached calculations for reference, may be higher than - // maxTotalWidth. If this is the case, we need to adjust the view - totalWidth int - - // How far to scroll to the right, in columns - horizontalScrollOffsetCol int - - // How many columns to freeze when scrolling horizontally - horizontalScrollFreezeColumnsCount int - - // Calculated maximum column we can scroll to before the last is displayed - maxHorizontalColumnIndex int - - // Minimum total height of the table - minimumHeight int - - // Internal cached calculation, the height of the header and footer - // including borders. Used to determine how many padding rows to add. - metaHeight int - - // If true, the table will be multiline - multiline bool -} - -// New creates a new table ready for further modifications. -func New(columns []Column) Model { - filterInput := textinput.New() - filterInput.Prompt = "/" - model := Model{ - columns: make([]Column, len(columns)), - metadata: make(map[string]any), - highlightStyle: defaultHighlightStyle.Copy(), - border: borderDefault, - headerVisible: true, - footerVisible: true, - keyMap: DefaultKeyMap(), - - selectedText: "[x]", - unselectedText: "[ ]", - - filterTextInput: filterInput, - filterFunc: filterFuncContains, - baseStyle: lipgloss.NewStyle().Align(lipgloss.Right), - - paginationWrapping: true, - } - - // Do a full deep copy to avoid unexpected edits - copy(model.columns, columns) - - model.recalculateWidth() - - return model -} - -// Init initializes the table per the Bubble Tea architecture. -func (m Model) Init() tea.Cmd { - return nil -} diff --git a/vendor/github.com/evertras/bubble-table/table/options.go b/vendor/github.com/evertras/bubble-table/table/options.go deleted file mode 100644 index c35fc1e7..00000000 --- a/vendor/github.com/evertras/bubble-table/table/options.go +++ /dev/null @@ -1,510 +0,0 @@ -package table - -import ( - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textinput" - "github.com/charmbracelet/lipgloss" -) - -// RowStyleFuncInput is the input to the style function that can -// be applied to each row. This is useful for things like zebra -// striping or other data-based styles. -// -// Note that we use a struct here to allow for future expansion -// while keeping backwards compatibility. -type RowStyleFuncInput struct { - // Index is the index of the row, starting at 0. - Index int - - // Row is the full row data. - Row Row - - // IsHighlighted is true if the row is currently highlighted. - IsHighlighted bool -} - -// WithRowStyleFunc sets a function that can be used to apply a style to each row -// based on the row data. This is useful for things like zebra striping or other -// data-based styles. It can be safely set to nil to remove it later. -// This style is applied after the base style and before individual row styles. -// This will override any HighlightStyle settings. -func (m Model) WithRowStyleFunc(f func(RowStyleFuncInput) lipgloss.Style) Model { - m.rowStyleFunc = f - - return m -} - -// WithHighlightedRow sets the highlighted row to the given index. -func (m Model) WithHighlightedRow(index int) Model { - m.rowCursorIndex = index - - if m.rowCursorIndex >= len(m.GetVisibleRows()) { - m.rowCursorIndex = len(m.GetVisibleRows()) - 1 - } - - if m.rowCursorIndex < 0 { - m.rowCursorIndex = 0 - } - - m.currentPage = m.expectedPageForRowIndex(m.rowCursorIndex) - - return m -} - -// HeaderStyle sets the style to apply to the header text, such as color or bold. -func (m Model) HeaderStyle(style lipgloss.Style) Model { - m.headerStyle = style.Copy() - - return m -} - -// WithRows sets the rows to show as data in the table. -func (m Model) WithRows(rows []Row) Model { - m.rows = rows - m.visibleRowCacheUpdated = false - - if m.rowCursorIndex >= len(m.rows) { - m.rowCursorIndex = len(m.rows) - 1 - } - - if m.rowCursorIndex < 0 { - m.rowCursorIndex = 0 - } - - if m.pageSize != 0 { - maxPage := m.MaxPages() - - // MaxPages is 1-index, currentPage is 0 index - if maxPage <= m.currentPage { - m.pageLast() - } - } - - return m -} - -// WithKeyMap sets the key map to use for controls when focused. -func (m Model) WithKeyMap(keyMap KeyMap) Model { - m.keyMap = keyMap - - return m -} - -// KeyMap returns a copy of the current key map in use. -func (m Model) KeyMap() KeyMap { - return m.keyMap -} - -// SelectableRows sets whether or not rows are selectable. If set, adds a column -// in the front that acts as a checkbox and responds to controls if Focused. -func (m Model) SelectableRows(selectable bool) Model { - m.selectableRows = selectable - - hasSelectColumn := len(m.columns) > 0 && m.columns[0].key == columnKeySelect - - if hasSelectColumn != selectable { - if selectable { - m.columns = append([]Column{ - NewColumn(columnKeySelect, m.selectedText, len([]rune(m.selectedText))), - }, m.columns...) - } else { - m.columns = m.columns[1:] - } - } - - m.recalculateWidth() - - return m -} - -// HighlightedRow returns the full Row that's currently highlighted by the user. -func (m Model) HighlightedRow() Row { - if len(m.GetVisibleRows()) > 0 { - return m.GetVisibleRows()[m.rowCursorIndex] - } - - // TODO: Better way to do this without pointers/nil? Or should it be nil? - return Row{} -} - -// SelectedRows returns all rows that have been set as selected by the user. -func (m Model) SelectedRows() []Row { - selectedRows := []Row{} - - for _, row := range m.GetVisibleRows() { - if row.selected { - selectedRows = append(selectedRows, row) - } - } - - return selectedRows -} - -// HighlightStyle sets a custom style to use when the row is being highlighted -// by the cursor. This should not be used with WithRowStyleFunc. Instead, use -// the IsHighlighted field in the style function. -func (m Model) HighlightStyle(style lipgloss.Style) Model { - m.highlightStyle = style - - return m -} - -// Focused allows the table to show highlighted rows and take in controls of -// up/down/space/etc to let the user navigate the table and interact with it. -func (m Model) Focused(focused bool) Model { - m.focused = focused - - return m -} - -// Filtered allows the table to show rows that match the filter. -func (m Model) Filtered(filtered bool) Model { - m.filtered = filtered - m.visibleRowCacheUpdated = false - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// StartFilterTyping focuses the text input to allow user typing to filter. -func (m Model) StartFilterTyping() Model { - m.filterTextInput.Focus() - - return m -} - -// WithStaticFooter adds a footer that only displays the given text. -func (m Model) WithStaticFooter(footer string) Model { - m.staticFooter = footer - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// WithPageSize enables pagination using the given page size. This can be called -// again at any point to resize the height of the table. -func (m Model) WithPageSize(pageSize int) Model { - m.pageSize = pageSize - - maxPages := m.MaxPages() - - if m.currentPage >= maxPages { - m.currentPage = maxPages - 1 - } - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// WithNoPagination disables pagination in the table. -func (m Model) WithNoPagination() Model { - m.pageSize = 0 - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// WithPaginationWrapping sets whether to wrap around from the beginning to the -// end when navigating through pages. Defaults to true. -func (m Model) WithPaginationWrapping(wrapping bool) Model { - m.paginationWrapping = wrapping - - return m -} - -// WithSelectedText describes what text to show when selectable rows are enabled. -// The selectable column header will use the selected text string. -func (m Model) WithSelectedText(unselected, selected string) Model { - m.selectedText = selected - m.unselectedText = unselected - - if len(m.columns) > 0 && m.columns[0].key == columnKeySelect { - m.columns[0] = NewColumn(columnKeySelect, m.selectedText, len([]rune(m.selectedText))) - m.recalculateWidth() - } - - return m -} - -// WithBaseStyle applies a base style as the default for everything in the table. -// This is useful for border colors, default alignment, default color, etc. -func (m Model) WithBaseStyle(style lipgloss.Style) Model { - m.baseStyle = style - - return m -} - -// WithTargetWidth sets the total target width of the table, including borders. -// This only takes effect when using flex columns. When using flex columns, -// columns will stretch to fill out to the total width given here. -func (m Model) WithTargetWidth(totalWidth int) Model { - m.targetTotalWidth = totalWidth - - m.recalculateWidth() - - return m -} - -// WithMinimumHeight sets the minimum total height of the table, including borders. -func (m Model) WithMinimumHeight(minimumHeight int) Model { - m.minimumHeight = minimumHeight - - m.recalculateHeight() - - return m -} - -// PageDown goes to the next page of a paginated table, wrapping to the first -// page if the table is already on the last page. -func (m Model) PageDown() Model { - m.pageDown() - - return m -} - -// PageUp goes to the previous page of a paginated table, wrapping to the -// last page if the table is already on the first page. -func (m Model) PageUp() Model { - m.pageUp() - - return m -} - -// PageLast goes to the last page of a paginated table. -func (m Model) PageLast() Model { - m.pageLast() - - return m -} - -// PageFirst goes to the first page of a paginated table. -func (m Model) PageFirst() Model { - m.pageFirst() - - return m -} - -// WithCurrentPage sets the current page (1 as the first page) of a paginated -// table, bounded to the total number of pages. The current selected row will -// be set to the top row of the page if the page changed. -func (m Model) WithCurrentPage(currentPage int) Model { - if m.pageSize == 0 || currentPage == m.CurrentPage() { - return m - } - if currentPage < 1 { - currentPage = 1 - } else { - maxPages := m.MaxPages() - - if currentPage > maxPages { - currentPage = maxPages - } - } - m.currentPage = currentPage - 1 - m.rowCursorIndex = m.currentPage * m.pageSize - - return m -} - -// WithColumns sets the visible columns for the table, so that columns can be -// added/removed/resized or headers rewritten. -func (m Model) WithColumns(columns []Column) Model { - // Deep copy to avoid edits - m.columns = make([]Column, len(columns)) - copy(m.columns, columns) - - m.recalculateWidth() - - if m.selectableRows { - // Re-add the selectable column - m = m.SelectableRows(true) - } - - return m -} - -// WithFilterInput makes the table use the provided text input bubble for -// filtering rather than using the built-in default. This allows for external -// text input controls to be used. -func (m Model) WithFilterInput(input textinput.Model) Model { - if m.filterTextInput.Value() != input.Value() { - m.pageFirst() - } - - m.filterTextInput = input - m.visibleRowCacheUpdated = false - - return m -} - -// WithFilterInputValue sets the filter value to the given string, immediately -// applying it as if the user had typed it in. Useful for external filter inputs -// that are not necessarily a text input. -func (m Model) WithFilterInputValue(value string) Model { - if m.filterTextInput.Value() != value { - m.pageFirst() - } - - m.filterTextInput.SetValue(value) - m.filterTextInput.Blur() - m.visibleRowCacheUpdated = false - - return m -} - -// WithFilterFunc adds a filter function to the model. If the function returns -// true, the row will be included in the filtered results. If the function -// is nil, the function won't be used and instead the default filtering will be applied, -// if any. -func (m Model) WithFilterFunc(shouldInclude FilterFunc) Model { - m.filterFunc = shouldInclude - - m.visibleRowCacheUpdated = false - - return m -} - -// WithFuzzyFilter enables fuzzy filtering for the table. -func (m Model) WithFuzzyFilter() Model { - return m.WithFilterFunc(filterFuncFuzzy) -} - -// WithFooterVisibility sets the visibility of the footer. -func (m Model) WithFooterVisibility(visibility bool) Model { - m.footerVisible = visibility - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// WithHeaderVisibility sets the visibility of the header. -func (m Model) WithHeaderVisibility(visibility bool) Model { - m.headerVisible = visibility - - if m.minimumHeight > 0 { - m.recalculateHeight() - } - - return m -} - -// WithMaxTotalWidth sets the maximum total width that the table should render. -// If this width is exceeded by either the target width or by the total width -// of all the columns (including borders!), anything extra will be treated as -// overflow and horizontal scrolling will be enabled to see the rest. -func (m Model) WithMaxTotalWidth(maxTotalWidth int) Model { - m.maxTotalWidth = maxTotalWidth - - m.recalculateWidth() - - return m -} - -// WithHorizontalFreezeColumnCount freezes the given number of columns to the -// left side. This is useful for things like ID or Name columns that should -// always be visible even when scrolling. -func (m Model) WithHorizontalFreezeColumnCount(columnsToFreeze int) Model { - m.horizontalScrollFreezeColumnsCount = columnsToFreeze - - m.recalculateWidth() - - return m -} - -// ScrollRight moves one column to the right. Use with WithMaxTotalWidth. -func (m Model) ScrollRight() Model { - m.scrollRight() - - return m -} - -// ScrollLeft moves one column to the left. Use with WithMaxTotalWidth. -func (m Model) ScrollLeft() Model { - m.scrollLeft() - - return m -} - -// WithMissingDataIndicator sets an indicator to use when data for a column is -// not found in a given row. Note that this is for completely missing data, -// an empty string or other zero value that is explicitly set is not considered -// to be missing. -func (m Model) WithMissingDataIndicator(str string) Model { - m.missingDataIndicator = str - - return m -} - -// WithMissingDataIndicatorStyled sets a styled indicator to use when data for -// a column is not found in a given row. Note that this is for completely -// missing data, an empty string or other zero value that is explicitly set is -// not considered to be missing. -func (m Model) WithMissingDataIndicatorStyled(styled StyledCell) Model { - m.missingDataIndicator = styled - - return m -} - -// WithAllRowsDeselected deselects any rows that are currently selected. -func (m Model) WithAllRowsDeselected() Model { - rows := m.GetVisibleRows() - - for i, row := range rows { - if row.selected { - rows[i] = row.Selected(false) - } - } - - m.rows = rows - - return m -} - -// WithMultiline sets whether or not to wrap text in cells to multiple lines. -func (m Model) WithMultiline(multiline bool) Model { - m.multiline = multiline - - return m -} - -// WithAdditionalShortHelpKeys enables you to add more keybindings to the 'short help' view. -func (m Model) WithAdditionalShortHelpKeys(keys []key.Binding) Model { - m.additionalShortHelpKeys = func() []key.Binding { - return keys - } - - return m -} - -// WithAdditionalFullHelpKeys enables you to add more keybindings to the 'full help' view. -func (m Model) WithAdditionalFullHelpKeys(keys []key.Binding) Model { - m.additionalFullHelpKeys = func() []key.Binding { - return keys - } - - return m -} - -// WithGlobalMetadata applies the given metadata to the table. This metadata is passed to -// some functions in FilterFuncInput and StyleFuncInput to enable more advanced decisions, -// such as setting some global theme variable to reference, etc. Has no effect otherwise. -func (m Model) WithGlobalMetadata(metadata map[string]any) Model { - m.metadata = metadata - - return m -} diff --git a/vendor/github.com/evertras/bubble-table/table/overflow.go b/vendor/github.com/evertras/bubble-table/table/overflow.go deleted file mode 100644 index 19c5b0aa..00000000 --- a/vendor/github.com/evertras/bubble-table/table/overflow.go +++ /dev/null @@ -1,18 +0,0 @@ -package table - -import "github.com/charmbracelet/lipgloss" - -const columnKeyOverflowRight = "___overflow_r___" -const columnKeyOverflowLeft = "___overflow_l__" - -func genOverflowStyle(base lipgloss.Style, width int) lipgloss.Style { - return base.Width(width).Align(lipgloss.Right) -} - -func genOverflowColumnRight(width int) Column { - return NewColumn(columnKeyOverflowRight, ">", width) -} - -func genOverflowColumnLeft(width int) Column { - return NewColumn(columnKeyOverflowLeft, "<", width) -} diff --git a/vendor/github.com/evertras/bubble-table/table/pagination.go b/vendor/github.com/evertras/bubble-table/table/pagination.go deleted file mode 100644 index 6fce9b51..00000000 --- a/vendor/github.com/evertras/bubble-table/table/pagination.go +++ /dev/null @@ -1,112 +0,0 @@ -package table - -// PageSize returns the current page size for the table, or 0 if there is no -// pagination enabled. -func (m *Model) PageSize() int { - return m.pageSize -} - -// CurrentPage returns the current page that the table is on, starting from an -// index of 1. -func (m *Model) CurrentPage() int { - return m.currentPage + 1 -} - -// MaxPages returns the maximum number of pages that are visible. -func (m *Model) MaxPages() int { - totalRows := len(m.GetVisibleRows()) - - if m.pageSize == 0 || totalRows == 0 { - return 1 - } - - return (totalRows-1)/m.pageSize + 1 -} - -// TotalRows returns the current total row count of the table. If the table is -// paginated, this is the total number of rows across all pages. -func (m *Model) TotalRows() int { - return len(m.GetVisibleRows()) -} - -// VisibleIndices returns the current visible rows by their 0 based index. -// Useful for custom pagination footers. -func (m *Model) VisibleIndices() (start, end int) { - totalRows := len(m.GetVisibleRows()) - - if m.pageSize == 0 { - start = 0 - end = totalRows - 1 - - return start, end - } - - start = m.pageSize * m.currentPage - end = start + m.pageSize - 1 - - if end >= totalRows { - end = totalRows - 1 - } - - return start, end -} - -func (m *Model) pageDown() { - if m.pageSize == 0 || len(m.GetVisibleRows()) <= m.pageSize { - return - } - - m.currentPage++ - - maxPageIndex := m.MaxPages() - 1 - - if m.currentPage > maxPageIndex { - if m.paginationWrapping { - m.currentPage = 0 - } else { - m.currentPage = maxPageIndex - } - } - - m.rowCursorIndex = m.currentPage * m.pageSize -} - -func (m *Model) pageUp() { - if m.pageSize == 0 || len(m.GetVisibleRows()) <= m.pageSize { - return - } - - m.currentPage-- - - maxPageIndex := m.MaxPages() - 1 - - if m.currentPage < 0 { - if m.paginationWrapping { - m.currentPage = maxPageIndex - } else { - m.currentPage = 0 - } - } - - m.rowCursorIndex = m.currentPage * m.pageSize -} - -func (m *Model) pageFirst() { - m.currentPage = 0 - m.rowCursorIndex = 0 -} - -func (m *Model) pageLast() { - m.currentPage = m.MaxPages() - 1 - m.rowCursorIndex = m.currentPage * m.pageSize -} - -func (m *Model) expectedPageForRowIndex(rowIndex int) int { - if m.pageSize == 0 { - return 0 - } - - expectedPage := rowIndex / m.pageSize - - return expectedPage -} diff --git a/vendor/github.com/evertras/bubble-table/table/query.go b/vendor/github.com/evertras/bubble-table/table/query.go deleted file mode 100644 index 79da50f0..00000000 --- a/vendor/github.com/evertras/bubble-table/table/query.go +++ /dev/null @@ -1,96 +0,0 @@ -package table - -// GetColumnSorting returns the current sorting rules for the table as a list of -// SortColumns, which are applied from first to last. This means that data will -// be grouped by the later elements in the list. The returned list is a copy -// and modifications will have no effect. -func (m *Model) GetColumnSorting() []SortColumn { - c := make([]SortColumn, len(m.sortOrder)) - - copy(c, m.sortOrder) - - return c -} - -// GetCanFilter returns true if the table enables filtering at all. This does -// not say whether a filter is currently active, only that the feature is enabled. -func (m *Model) GetCanFilter() bool { - return m.filtered -} - -// GetIsFilterActive returns true if the table is currently being filtered. This -// does not say whether the table CAN be filtered, only whether or not a filter -// is actually currently being applied. -func (m *Model) GetIsFilterActive() bool { - return m.filterTextInput.Value() != "" -} - -// GetIsFilterInputFocused returns true if the table's built-in filter input is -// currently focused. -func (m *Model) GetIsFilterInputFocused() bool { - return m.filterTextInput.Focused() -} - -// GetCurrentFilter returns the current filter text being applied, or an empty -// string if none is applied. -func (m *Model) GetCurrentFilter() string { - return m.filterTextInput.Value() -} - -// GetVisibleRows returns sorted and filtered rows. -func (m *Model) GetVisibleRows() []Row { - if m.visibleRowCacheUpdated { - return m.visibleRowCache - } - - rows := make([]Row, len(m.rows)) - copy(rows, m.rows) - if m.filtered { - rows = m.getFilteredRows(rows) - } - rows = getSortedRows(m.sortOrder, rows) - - m.visibleRowCache = rows - m.visibleRowCacheUpdated = true - - return rows -} - -// GetHighlightedRowIndex returns the index of the Row that's currently highlighted -// by the user. -func (m *Model) GetHighlightedRowIndex() int { - return m.rowCursorIndex -} - -// GetFocused returns whether or not the table is focused and is receiving inputs. -func (m *Model) GetFocused() bool { - return m.focused -} - -// GetHorizontalScrollColumnOffset returns how many columns to the right the table -// has been scrolled. 0 means the table is all the way to the left, which is -// the starting default. -func (m *Model) GetHorizontalScrollColumnOffset() int { - return m.horizontalScrollOffsetCol -} - -// GetHeaderVisibility returns true if the header has been set to visible (default) -// or false if the header has been set to hidden. -func (m *Model) GetHeaderVisibility() bool { - return m.headerVisible -} - -// GetFooterVisibility returns true if the footer has been set to -// visible (default) or false if the footer has been set to hidden. -// Note that even if the footer is visible it will only be rendered if -// it has contents. -func (m *Model) GetFooterVisibility() bool { - return m.footerVisible -} - -// GetPaginationWrapping returns true if pagination wrapping is enabled, or false -// if disabled. If disabled, navigating through pages will stop at the first -// and last pages. -func (m *Model) GetPaginationWrapping() bool { - return m.paginationWrapping -} diff --git a/vendor/github.com/evertras/bubble-table/table/row.go b/vendor/github.com/evertras/bubble-table/table/row.go deleted file mode 100644 index b9a5d6bb..00000000 --- a/vendor/github.com/evertras/bubble-table/table/row.go +++ /dev/null @@ -1,252 +0,0 @@ -package table - -import ( - "fmt" - "sync/atomic" - - "github.com/charmbracelet/lipgloss" - "github.com/muesli/reflow/wordwrap" -) - -// RowData is a map of string column keys to arbitrary data. Data with a key -// that matches a column key will be displayed. Data with a key that does not -// match a column key will not be displayed, but will remain attached to the Row. -// This can be useful for attaching hidden metadata for future reference when -// retrieving rows. -type RowData map[string]any - -// Row represents a row in the table with some data keyed to the table columns> -// Can have a style applied to it such as color/bold. Create using NewRow(). -type Row struct { - Style lipgloss.Style - Data RowData - - selected bool - - // id is an internal unique ID to match rows after they're copied - id uint32 -} - -var lastRowID uint32 = 1 - -// NewRow creates a new row and copies the given row data. -func NewRow(data RowData) Row { - row := Row{ - Data: make(map[string]any), - id: lastRowID, - } - - atomic.AddUint32(&lastRowID, 1) - - for key, val := range data { - // Doesn't deep copy val, but close enough for now... - row.Data[key] = val - } - - return row -} - -// WithStyle uses the given style for the text in the row. -func (r Row) WithStyle(style lipgloss.Style) Row { - r.Style = style.Copy() - - return r -} - -//nolint:cyclop,funlen // Breaking this up will be more complicated than it's worth for now -func (m Model) renderRowColumnData(row Row, column Column, rowStyle lipgloss.Style, borderStyle lipgloss.Style) string { - cellStyle := rowStyle.Copy().Inherit(column.style).Inherit(m.baseStyle) - - var str string - - switch column.key { - case columnKeySelect: - if row.selected { - str = m.selectedText - } else { - str = m.unselectedText - } - case columnKeyOverflowRight: - cellStyle = cellStyle.Align(lipgloss.Right) - str = ">" - case columnKeyOverflowLeft: - str = "<" - default: - fmtString := "%v" - - var data any - - if entry, exists := row.Data[column.key]; exists { - data = entry - - if column.fmtString != "" { - fmtString = column.fmtString - } - } else if m.missingDataIndicator != nil { - data = m.missingDataIndicator - } else { - data = "" - } - - switch entry := data.(type) { - case StyledCell: - str = fmt.Sprintf(fmtString, entry.Data) - - if entry.StyleFunc != nil { - cellStyle = entry.StyleFunc(StyledCellFuncInput{ - Column: column, - Data: entry.Data, - Row: row, - GlobalMetadata: m.metadata, - }).Copy().Inherit(cellStyle) - } else { - cellStyle = entry.Style.Copy().Inherit(cellStyle) - } - default: - str = fmt.Sprintf(fmtString, entry) - } - } - - if m.multiline { - str = wordwrap.String(str, column.width) - cellStyle = cellStyle.Align(lipgloss.Top) - } else { - str = limitStr(str, column.width) - } - - cellStyle = cellStyle.Inherit(borderStyle) - cellStr := cellStyle.Render(str) - - return cellStr -} - -func (m Model) renderRow(rowIndex int, last bool) string { - row := m.GetVisibleRows()[rowIndex] - highlighted := rowIndex == m.rowCursorIndex - - rowStyle := row.Style.Copy() - - if m.rowStyleFunc != nil { - styleResult := m.rowStyleFunc(RowStyleFuncInput{ - Index: rowIndex, - Row: row, - IsHighlighted: m.focused && highlighted, - }) - - rowStyle = rowStyle.Inherit(styleResult) - } else if m.focused && highlighted { - rowStyle = rowStyle.Inherit(m.highlightStyle) - } - - return m.renderRowData(row, rowStyle, last) -} - -func (m Model) renderBlankRow(last bool) string { - return m.renderRowData(NewRow(nil), lipgloss.NewStyle(), last) -} - -// This is long and could use some refactoring in the future, but not quite sure -// how to pick it apart yet. -// -//nolint:funlen, cyclop -func (m Model) renderRowData(row Row, rowStyle lipgloss.Style, last bool) string { - numColumns := len(m.columns) - - columnStrings := []string{} - totalRenderedWidth := 0 - - stylesInner, stylesLast := m.styleRows() - - maxCellHeight := 1 - if m.multiline { - for _, column := range m.columns { - cellStr := m.renderRowColumnData(row, column, rowStyle, lipgloss.NewStyle()) - maxCellHeight = max(maxCellHeight, lipgloss.Height(cellStr)) - } - } - - for columnIndex, column := range m.columns { - var borderStyle lipgloss.Style - var rowStyles borderStyleRow - - if !last { - rowStyles = stylesInner - } else { - rowStyles = stylesLast - } - rowStyle = rowStyle.Copy().Height(maxCellHeight) - - if m.horizontalScrollOffsetCol > 0 && columnIndex == m.horizontalScrollFreezeColumnsCount { - var borderStyle lipgloss.Style - - if columnIndex == 0 { - borderStyle = rowStyles.left.Copy() - } else { - borderStyle = rowStyles.inner.Copy() - } - - rendered := m.renderRowColumnData(row, genOverflowColumnLeft(1), rowStyle, borderStyle) - - totalRenderedWidth += lipgloss.Width(rendered) - - columnStrings = append(columnStrings, rendered) - } - - if columnIndex >= m.horizontalScrollFreezeColumnsCount && - columnIndex < m.horizontalScrollOffsetCol+m.horizontalScrollFreezeColumnsCount { - continue - } - - if len(columnStrings) == 0 { - borderStyle = rowStyles.left - } else if columnIndex < numColumns-1 { - borderStyle = rowStyles.inner - } else { - borderStyle = rowStyles.right - } - - cellStr := m.renderRowColumnData(row, column, rowStyle, borderStyle) - - if m.maxTotalWidth != 0 { - renderedWidth := lipgloss.Width(cellStr) - - const ( - borderAdjustment = 1 - overflowColWidth = 2 - ) - - targetWidth := m.maxTotalWidth - overflowColWidth - - if columnIndex == len(m.columns)-1 { - // If this is the last header, we don't need to account for the - // overflow arrow column - targetWidth = m.maxTotalWidth - } - - if totalRenderedWidth+renderedWidth > targetWidth { - overflowWidth := m.maxTotalWidth - totalRenderedWidth - borderAdjustment - overflowStyle := genOverflowStyle(rowStyles.right, overflowWidth) - overflowColumn := genOverflowColumnRight(overflowWidth) - overflowStr := m.renderRowColumnData(row, overflowColumn, rowStyle, overflowStyle) - - columnStrings = append(columnStrings, overflowStr) - - break - } - - totalRenderedWidth += renderedWidth - } - - columnStrings = append(columnStrings, cellStr) - } - - return lipgloss.JoinHorizontal(lipgloss.Bottom, columnStrings...) -} - -// Selected returns a copy of the row that's set to be selected or deselected. -// The old row is not changed in-place. -func (r Row) Selected(selected bool) Row { - r.selected = selected - - return r -} diff --git a/vendor/github.com/evertras/bubble-table/table/scrolling.go b/vendor/github.com/evertras/bubble-table/table/scrolling.go deleted file mode 100644 index 3ee3256c..00000000 --- a/vendor/github.com/evertras/bubble-table/table/scrolling.go +++ /dev/null @@ -1,50 +0,0 @@ -package table - -func (m *Model) scrollRight() { - if m.horizontalScrollOffsetCol < m.maxHorizontalColumnIndex { - m.horizontalScrollOffsetCol++ - } -} - -func (m *Model) scrollLeft() { - if m.horizontalScrollOffsetCol > 0 { - m.horizontalScrollOffsetCol-- - } -} - -func (m *Model) recalculateLastHorizontalColumn() { - if m.horizontalScrollFreezeColumnsCount >= len(m.columns) { - m.maxHorizontalColumnIndex = 0 - - return - } - - if m.totalWidth <= m.maxTotalWidth { - m.maxHorizontalColumnIndex = 0 - - return - } - - const ( - leftOverflowWidth = 2 - borderAdjustment = 1 - ) - - // Always have left border - visibleWidth := borderAdjustment + leftOverflowWidth - - for i := 0; i < m.horizontalScrollFreezeColumnsCount; i++ { - visibleWidth += m.columns[i].width + borderAdjustment - } - - m.maxHorizontalColumnIndex = len(m.columns) - 1 - - // Work backwards from the right - for i := len(m.columns) - 1; i >= m.horizontalScrollFreezeColumnsCount && visibleWidth <= m.maxTotalWidth; i-- { - visibleWidth += m.columns[i].width + borderAdjustment - - if visibleWidth <= m.maxTotalWidth { - m.maxHorizontalColumnIndex = i - m.horizontalScrollFreezeColumnsCount - } - } -} diff --git a/vendor/github.com/evertras/bubble-table/table/sort.go b/vendor/github.com/evertras/bubble-table/table/sort.go deleted file mode 100644 index 9a282cbd..00000000 --- a/vendor/github.com/evertras/bubble-table/table/sort.go +++ /dev/null @@ -1,178 +0,0 @@ -package table - -import ( - "fmt" - "sort" -) - -// SortDirection indicates whether a column should sort by ascending or descending. -type SortDirection int - -const ( - // SortDirectionAsc indicates the column should be in ascending order. - SortDirectionAsc SortDirection = iota - - // SortDirectionDesc indicates the column should be in descending order. - SortDirectionDesc -) - -// SortColumn describes which column should be sorted and how. -type SortColumn struct { - ColumnKey string - Direction SortDirection -} - -// SortByAsc sets the main sorting column to the given key, in ascending order. -// If a previous sort was used, it is replaced by the given column each time -// this function is called. Values are sorted as numbers if possible, or just -// as simple string comparisons if not numbers. -func (m Model) SortByAsc(columnKey string) Model { - m.sortOrder = []SortColumn{ - { - ColumnKey: columnKey, - Direction: SortDirectionAsc, - }, - } - - m.visibleRowCacheUpdated = false - - return m -} - -// SortByDesc sets the main sorting column to the given key, in descending order. -// If a previous sort was used, it is replaced by the given column each time -// this function is called. Values are sorted as numbers if possible, or just -// as simple string comparisons if not numbers. -func (m Model) SortByDesc(columnKey string) Model { - m.sortOrder = []SortColumn{ - { - ColumnKey: columnKey, - Direction: SortDirectionDesc, - }, - } - - m.visibleRowCacheUpdated = false - - return m -} - -// ThenSortByAsc provides a secondary sort after the first, in ascending order. -// Can be chained multiple times, applying to smaller subgroups each time. -func (m Model) ThenSortByAsc(columnKey string) Model { - m.sortOrder = append([]SortColumn{ - { - ColumnKey: columnKey, - Direction: SortDirectionAsc, - }, - }, m.sortOrder...) - - m.visibleRowCacheUpdated = false - - return m -} - -// ThenSortByDesc provides a secondary sort after the first, in descending order. -// Can be chained multiple times, applying to smaller subgroups each time. -func (m Model) ThenSortByDesc(columnKey string) Model { - m.sortOrder = append([]SortColumn{ - { - ColumnKey: columnKey, - Direction: SortDirectionDesc, - }, - }, m.sortOrder...) - - m.visibleRowCacheUpdated = false - - return m -} - -type sortableTable struct { - rows []Row - byColumn SortColumn -} - -func (s *sortableTable) Len() int { - return len(s.rows) -} - -func (s *sortableTable) Swap(i, j int) { - old := s.rows[i] - s.rows[i] = s.rows[j] - s.rows[j] = old -} - -func (s *sortableTable) extractString(i int, column string) string { - iData, exists := s.rows[i].Data[column] - - if !exists { - return "" - } - - switch iData := iData.(type) { - case StyledCell: - return fmt.Sprintf("%v", iData.Data) - - case string: - return iData - - default: - return fmt.Sprintf("%v", iData) - } -} - -func (s *sortableTable) extractNumber(i int, column string) (float64, bool) { - iData, exists := s.rows[i].Data[column] - - if !exists { - return 0, false - } - - return asNumber(iData) -} - -func (s *sortableTable) Less(first, second int) bool { - firstNum, firstNumIsValid := s.extractNumber(first, s.byColumn.ColumnKey) - secondNum, secondNumIsValid := s.extractNumber(second, s.byColumn.ColumnKey) - - if firstNumIsValid && secondNumIsValid { - if s.byColumn.Direction == SortDirectionAsc { - return firstNum < secondNum - } - - return firstNum > secondNum - } - - firstVal := s.extractString(first, s.byColumn.ColumnKey) - secondVal := s.extractString(second, s.byColumn.ColumnKey) - - if s.byColumn.Direction == SortDirectionAsc { - return firstVal < secondVal - } - - return firstVal > secondVal -} - -func getSortedRows(sortOrder []SortColumn, rows []Row) []Row { - var sortedRows []Row - if len(sortOrder) == 0 { - sortedRows = rows - - return sortedRows - } - - sortedRows = make([]Row, len(rows)) - copy(sortedRows, rows) - - for _, byColumn := range sortOrder { - sorted := &sortableTable{ - rows: sortedRows, - byColumn: byColumn, - } - - sort.Stable(sorted) - - sortedRows = sorted.rows - } - - return sortedRows -} diff --git a/vendor/github.com/evertras/bubble-table/table/strlimit.go b/vendor/github.com/evertras/bubble-table/table/strlimit.go deleted file mode 100644 index 9889d831..00000000 --- a/vendor/github.com/evertras/bubble-table/table/strlimit.go +++ /dev/null @@ -1,26 +0,0 @@ -package table - -import ( - "strings" - - "github.com/muesli/reflow/ansi" - "github.com/muesli/reflow/truncate" -) - -func limitStr(str string, maxLen int) string { - if maxLen == 0 { - return "" - } - - newLineIndex := strings.Index(str, "\n") - if newLineIndex > -1 { - str = str[:newLineIndex] + "…" - } - - if ansi.PrintableRuneWidth(str) > maxLen { - // #nosec: G115 - return truncate.StringWithTail(str, uint(maxLen), "…") - } - - return str -} diff --git a/vendor/github.com/evertras/bubble-table/table/update.go b/vendor/github.com/evertras/bubble-table/table/update.go deleted file mode 100644 index 198a57d2..00000000 --- a/vendor/github.com/evertras/bubble-table/table/update.go +++ /dev/null @@ -1,154 +0,0 @@ -package table - -import ( - "github.com/charmbracelet/bubbles/key" - tea "github.com/charmbracelet/bubbletea" -) - -func (m *Model) moveHighlightUp() { - m.rowCursorIndex-- - - if m.rowCursorIndex < 0 { - m.rowCursorIndex = len(m.GetVisibleRows()) - 1 - } - - m.currentPage = m.expectedPageForRowIndex(m.rowCursorIndex) -} - -func (m *Model) moveHighlightDown() { - m.rowCursorIndex++ - - if m.rowCursorIndex >= len(m.GetVisibleRows()) { - m.rowCursorIndex = 0 - } - - m.currentPage = m.expectedPageForRowIndex(m.rowCursorIndex) -} - -func (m *Model) toggleSelect() { - if !m.selectableRows || len(m.GetVisibleRows()) == 0 { - return - } - - rows := m.GetVisibleRows() - - rowID := rows[m.rowCursorIndex].id - - currentSelectedState := false - - for i := range m.rows { - if m.rows[i].id == rowID { - currentSelectedState = m.rows[i].selected - m.rows[i].selected = !m.rows[i].selected - } - } - - m.visibleRowCacheUpdated = false - - m.appendUserEvent(UserEventRowSelectToggled{ - RowIndex: m.rowCursorIndex, - IsSelected: !currentSelectedState, - }) -} - -func (m Model) updateFilterTextInput(msg tea.Msg) (Model, tea.Cmd) { - var cmd tea.Cmd - switch msg := msg.(type) { - case tea.KeyMsg: - if key.Matches(msg, m.keyMap.FilterBlur) { - m.filterTextInput.Blur() - } - } - m.filterTextInput, cmd = m.filterTextInput.Update(msg) - m.pageFirst() - m.visibleRowCacheUpdated = false - - return m, cmd -} - -// This is a series of Matches tests with minimal logic -// -//nolint:cyclop -func (m *Model) handleKeypress(msg tea.KeyMsg) { - previousRowIndex := m.rowCursorIndex - - if key.Matches(msg, m.keyMap.RowDown) { - m.moveHighlightDown() - } - - if key.Matches(msg, m.keyMap.RowUp) { - m.moveHighlightUp() - } - - if key.Matches(msg, m.keyMap.RowSelectToggle) { - m.toggleSelect() - } - - if key.Matches(msg, m.keyMap.PageDown) { - m.pageDown() - } - - if key.Matches(msg, m.keyMap.PageUp) { - m.pageUp() - } - - if key.Matches(msg, m.keyMap.PageFirst) { - m.pageFirst() - } - - if key.Matches(msg, m.keyMap.PageLast) { - m.pageLast() - } - - if key.Matches(msg, m.keyMap.Filter) { - m.filterTextInput.Focus() - m.appendUserEvent(UserEventFilterInputFocused{}) - } - - if key.Matches(msg, m.keyMap.FilterClear) { - m.visibleRowCacheUpdated = false - m.filterTextInput.Reset() - } - - if key.Matches(msg, m.keyMap.ScrollRight) { - m.scrollRight() - } - - if key.Matches(msg, m.keyMap.ScrollLeft) { - m.scrollLeft() - } - - if m.rowCursorIndex != previousRowIndex { - m.appendUserEvent(UserEventHighlightedIndexChanged{ - PreviousRowIndex: previousRowIndex, - SelectedRowIndex: m.rowCursorIndex, - }) - } -} - -// Update responds to input from the user or other messages from Bubble Tea. -func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { - m.clearUserEvents() - - if !m.focused { - return m, nil - } - - if m.filterTextInput.Focused() { - var cmd tea.Cmd - m, cmd = m.updateFilterTextInput(msg) - - if !m.filterTextInput.Focused() { - m.appendUserEvent(UserEventFilterInputUnfocused{}) - } - - return m, cmd - } - - switch msg := msg.(type) { - case tea.KeyMsg: - m.handleKeypress(msg) - } - - return m, nil -} diff --git a/vendor/github.com/evertras/bubble-table/table/view.go b/vendor/github.com/evertras/bubble-table/table/view.go deleted file mode 100644 index 7be99c23..00000000 --- a/vendor/github.com/evertras/bubble-table/table/view.go +++ /dev/null @@ -1,65 +0,0 @@ -package table - -import ( - "strings" - - "github.com/charmbracelet/lipgloss" -) - -// View renders the table. It does not end in a newline, so that it can be -// composed with other elements more consistently. -// -//nolint:cyclop -func (m Model) View() string { - // Safety valve for empty tables - if len(m.columns) == 0 { - return "" - } - - body := strings.Builder{} - - rowStrs := make([]string, 0, 1) - - headers := m.renderHeaders() - - startRowIndex, endRowIndex := m.VisibleIndices() - numRows := endRowIndex - startRowIndex + 1 - - padding := m.calculatePadding(numRows) - - if m.headerVisible { - rowStrs = append(rowStrs, headers) - } else if numRows > 0 || padding > 0 { - //nolint: mnd // This is just getting the first newlined substring - split := strings.SplitN(headers, "\n", 2) - rowStrs = append(rowStrs, split[0]) - } - - for i := startRowIndex; i <= endRowIndex; i++ { - rowStrs = append(rowStrs, m.renderRow(i, padding == 0 && i == endRowIndex)) - } - - for i := 1; i <= padding; i++ { - rowStrs = append(rowStrs, m.renderBlankRow(i == padding)) - } - - var footer string - - if len(rowStrs) > 0 { - footer = m.renderFooter(lipgloss.Width(rowStrs[0]), false) - } else { - footer = m.renderFooter(lipgloss.Width(headers), true) - } - - if footer != "" { - rowStrs = append(rowStrs, footer) - } - - if len(rowStrs) == 0 { - return "" - } - - body.WriteString(lipgloss.JoinVertical(lipgloss.Left, rowStrs...)) - - return body.String() -} diff --git a/vendor/github.com/muesli/reflow/LICENSE b/vendor/github.com/muesli/reflow/LICENSE deleted file mode 100644 index 8532c45c..00000000 --- a/vendor/github.com/muesli/reflow/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Christian Muehlhaeuser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/muesli/reflow/ansi/ansi.go b/vendor/github.com/muesli/reflow/ansi/ansi.go deleted file mode 100644 index f3d0700a..00000000 --- a/vendor/github.com/muesli/reflow/ansi/ansi.go +++ /dev/null @@ -1,7 +0,0 @@ -package ansi - -const Marker = '\x1B' - -func IsTerminator(c rune) bool { - return (c >= 0x40 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) -} diff --git a/vendor/github.com/muesli/reflow/ansi/buffer.go b/vendor/github.com/muesli/reflow/ansi/buffer.go deleted file mode 100644 index 471bcaf7..00000000 --- a/vendor/github.com/muesli/reflow/ansi/buffer.go +++ /dev/null @@ -1,40 +0,0 @@ -package ansi - -import ( - "bytes" - - "github.com/mattn/go-runewidth" -) - -// Buffer is a buffer aware of ANSI escape sequences. -type Buffer struct { - bytes.Buffer -} - -// PrintableRuneWidth returns the cell width of all printable runes in the -// buffer. -func (w Buffer) PrintableRuneWidth() int { - return PrintableRuneWidth(w.String()) -} - -// PrintableRuneWidth returns the cell width of the given string. -func PrintableRuneWidth(s string) int { - var n int - var ansi bool - - for _, c := range s { - if c == Marker { - // ANSI escape sequence - ansi = true - } else if ansi { - if IsTerminator(c) { - // ANSI sequence terminated - ansi = false - } - } else { - n += runewidth.RuneWidth(c) - } - } - - return n -} diff --git a/vendor/github.com/muesli/reflow/ansi/writer.go b/vendor/github.com/muesli/reflow/ansi/writer.go deleted file mode 100644 index a6aaa1ec..00000000 --- a/vendor/github.com/muesli/reflow/ansi/writer.go +++ /dev/null @@ -1,76 +0,0 @@ -package ansi - -import ( - "bytes" - "io" - "unicode/utf8" -) - -type Writer struct { - Forward io.Writer - - ansi bool - ansiseq bytes.Buffer - lastseq bytes.Buffer - seqchanged bool - runeBuf []byte -} - -// Write is used to write content to the ANSI buffer. -func (w *Writer) Write(b []byte) (int, error) { - for _, c := range string(b) { - if c == Marker { - // ANSI escape sequence - w.ansi = true - w.seqchanged = true - _, _ = w.ansiseq.WriteRune(c) - } else if w.ansi { - _, _ = w.ansiseq.WriteRune(c) - if IsTerminator(c) { - // ANSI sequence terminated - w.ansi = false - - if bytes.HasSuffix(w.ansiseq.Bytes(), []byte("[0m")) { - // reset sequence - w.lastseq.Reset() - w.seqchanged = false - } else if c == 'm' { - // color code - _, _ = w.lastseq.Write(w.ansiseq.Bytes()) - } - - _, _ = w.ansiseq.WriteTo(w.Forward) - } - } else { - _, err := w.writeRune(c) - if err != nil { - return 0, err - } - } - } - - return len(b), nil -} - -func (w *Writer) writeRune(r rune) (int, error) { - if w.runeBuf == nil { - w.runeBuf = make([]byte, utf8.UTFMax) - } - n := utf8.EncodeRune(w.runeBuf, r) - return w.Forward.Write(w.runeBuf[:n]) -} - -func (w *Writer) LastSequence() string { - return w.lastseq.String() -} - -func (w *Writer) ResetAnsi() { - if !w.seqchanged { - return - } - _, _ = w.Forward.Write([]byte("\x1b[0m")) -} - -func (w *Writer) RestoreAnsi() { - _, _ = w.Forward.Write(w.lastseq.Bytes()) -} diff --git a/vendor/github.com/muesli/reflow/truncate/truncate.go b/vendor/github.com/muesli/reflow/truncate/truncate.go deleted file mode 100644 index 5aab5f89..00000000 --- a/vendor/github.com/muesli/reflow/truncate/truncate.go +++ /dev/null @@ -1,120 +0,0 @@ -package truncate - -import ( - "bytes" - "io" - - "github.com/mattn/go-runewidth" - - "github.com/muesli/reflow/ansi" -) - -type Writer struct { - width uint - tail string - - ansiWriter *ansi.Writer - buf bytes.Buffer - ansi bool -} - -func NewWriter(width uint, tail string) *Writer { - w := &Writer{ - width: width, - tail: tail, - } - w.ansiWriter = &ansi.Writer{ - Forward: &w.buf, - } - return w -} - -func NewWriterPipe(forward io.Writer, width uint, tail string) *Writer { - return &Writer{ - width: width, - tail: tail, - ansiWriter: &ansi.Writer{ - Forward: forward, - }, - } -} - -// Bytes is shorthand for declaring a new default truncate-writer instance, -// used to immediately truncate a byte slice. -func Bytes(b []byte, width uint) []byte { - return BytesWithTail(b, width, []byte("")) -} - -// Bytes is shorthand for declaring a new default truncate-writer instance, -// used to immediately truncate a byte slice. A tail is then added to the -// end of the byte slice. -func BytesWithTail(b []byte, width uint, tail []byte) []byte { - f := NewWriter(width, string(tail)) - _, _ = f.Write(b) - - return f.Bytes() -} - -// String is shorthand for declaring a new default truncate-writer instance, -// used to immediately truncate a string. -func String(s string, width uint) string { - return StringWithTail(s, width, "") -} - -// StringWithTail is shorthand for declaring a new default truncate-writer instance, -// used to immediately truncate a string. A tail is then added to the end of the -// string. -func StringWithTail(s string, width uint, tail string) string { - return string(BytesWithTail([]byte(s), width, []byte(tail))) -} - -// Write truncates content at the given printable cell width, leaving any -// ansi sequences intact. -func (w *Writer) Write(b []byte) (int, error) { - tw := ansi.PrintableRuneWidth(w.tail) - if w.width < uint(tw) { - return w.buf.WriteString(w.tail) - } - - w.width -= uint(tw) - var curWidth uint - - for _, c := range string(b) { - if c == ansi.Marker { - // ANSI escape sequence - w.ansi = true - } else if w.ansi { - if ansi.IsTerminator(c) { - // ANSI sequence terminated - w.ansi = false - } - } else { - curWidth += uint(runewidth.RuneWidth(c)) - } - - if curWidth > w.width { - n, err := w.buf.WriteString(w.tail) - if w.ansiWriter.LastSequence() != "" { - w.ansiWriter.ResetAnsi() - } - return n, err - } - - _, err := w.ansiWriter.Write([]byte(string(c))) - if err != nil { - return 0, err - } - } - - return len(b), nil -} - -// Bytes returns the truncated result as a byte slice. -func (w *Writer) Bytes() []byte { - return w.buf.Bytes() -} - -// String returns the truncated result as a string. -func (w *Writer) String() string { - return w.buf.String() -} diff --git a/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go b/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go deleted file mode 100644 index 488fb210..00000000 --- a/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go +++ /dev/null @@ -1,167 +0,0 @@ -package wordwrap - -import ( - "bytes" - "strings" - "unicode" - - "github.com/muesli/reflow/ansi" -) - -var ( - defaultBreakpoints = []rune{'-'} - defaultNewline = []rune{'\n'} -) - -// WordWrap contains settings and state for customisable text reflowing with -// support for ANSI escape sequences. This means you can style your terminal -// output without affecting the word wrapping algorithm. -type WordWrap struct { - Limit int - Breakpoints []rune - Newline []rune - KeepNewlines bool - - buf bytes.Buffer - space bytes.Buffer - word ansi.Buffer - - lineLen int - ansi bool -} - -// NewWriter returns a new instance of a word-wrapping writer, initialized with -// default settings. -func NewWriter(limit int) *WordWrap { - return &WordWrap{ - Limit: limit, - Breakpoints: defaultBreakpoints, - Newline: defaultNewline, - KeepNewlines: true, - } -} - -// Bytes is shorthand for declaring a new default WordWrap instance, -// used to immediately word-wrap a byte slice. -func Bytes(b []byte, limit int) []byte { - f := NewWriter(limit) - _, _ = f.Write(b) - _ = f.Close() - - return f.Bytes() -} - -// String is shorthand for declaring a new default WordWrap instance, -// used to immediately word-wrap a string. -func String(s string, limit int) string { - return string(Bytes([]byte(s), limit)) -} - -func (w *WordWrap) addSpace() { - w.lineLen += w.space.Len() - _, _ = w.buf.Write(w.space.Bytes()) - w.space.Reset() -} - -func (w *WordWrap) addWord() { - if w.word.Len() > 0 { - w.addSpace() - w.lineLen += w.word.PrintableRuneWidth() - _, _ = w.buf.Write(w.word.Bytes()) - w.word.Reset() - } -} - -func (w *WordWrap) addNewLine() { - _, _ = w.buf.WriteRune('\n') - w.lineLen = 0 - w.space.Reset() -} - -func inGroup(a []rune, c rune) bool { - for _, v := range a { - if v == c { - return true - } - } - return false -} - -// Write is used to write more content to the word-wrap buffer. -func (w *WordWrap) Write(b []byte) (int, error) { - if w.Limit == 0 { - return w.buf.Write(b) - } - - s := string(b) - if !w.KeepNewlines { - s = strings.Replace(strings.TrimSpace(s), "\n", " ", -1) - } - - for _, c := range s { - if c == '\x1B' { - // ANSI escape sequence - _, _ = w.word.WriteRune(c) - w.ansi = true - } else if w.ansi { - _, _ = w.word.WriteRune(c) - if (c >= 0x40 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) { - // ANSI sequence terminated - w.ansi = false - } - } else if inGroup(w.Newline, c) { - // end of current line - // see if we can add the content of the space buffer to the current line - if w.word.Len() == 0 { - if w.lineLen+w.space.Len() > w.Limit { - w.lineLen = 0 - } else { - // preserve whitespace - _, _ = w.buf.Write(w.space.Bytes()) - } - w.space.Reset() - } - - w.addWord() - w.addNewLine() - } else if unicode.IsSpace(c) { - // end of current word - w.addWord() - _, _ = w.space.WriteRune(c) - } else if inGroup(w.Breakpoints, c) { - // valid breakpoint - w.addSpace() - w.addWord() - _, _ = w.buf.WriteRune(c) - } else { - // any other character - _, _ = w.word.WriteRune(c) - - // add a line break if the current word would exceed the line's - // character limit - if w.lineLen+w.space.Len()+w.word.PrintableRuneWidth() > w.Limit && - w.word.PrintableRuneWidth() < w.Limit { - w.addNewLine() - } - } - } - - return len(b), nil -} - -// Close will finish the word-wrap operation. Always call it before trying to -// retrieve the final result. -func (w *WordWrap) Close() error { - w.addWord() - return nil -} - -// Bytes returns the word-wrapped result as a byte slice. -func (w *WordWrap) Bytes() []byte { - return w.buf.Bytes() -} - -// String returns the word-wrapped result as a string. -func (w *WordWrap) String() string { - return w.buf.String() -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 72c4be64..d5828a17 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -51,9 +51,6 @@ github.com/ProtonMail/go-crypto/openpgp/packet github.com/ProtonMail/go-crypto/openpgp/s2k github.com/ProtonMail/go-crypto/openpgp/x25519 github.com/ProtonMail/go-crypto/openpgp/x448 -# github.com/atotto/clipboard v0.1.4 -## explicit -github.com/atotto/clipboard # github.com/aymanbagabas/go-osc52/v2 v2.0.1 ## explicit; go 1.16 github.com/aymanbagabas/go-osc52/v2 @@ -68,13 +65,6 @@ github.com/cenkalti/backoff/v5 # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 -# github.com/charmbracelet/bubbles v0.21.0 -## explicit; go 1.23.0 -github.com/charmbracelet/bubbles/cursor -github.com/charmbracelet/bubbles/key -github.com/charmbracelet/bubbles/runeutil -github.com/charmbracelet/bubbles/spinner -github.com/charmbracelet/bubbles/textinput # github.com/charmbracelet/bubbletea v1.3.10 ## explicit; go 1.24.0 github.com/charmbracelet/bubbletea @@ -95,6 +85,8 @@ github.com/charmbracelet/x/ansi/parser # github.com/charmbracelet/x/cellbuf v0.0.13 ## explicit; go 1.18 github.com/charmbracelet/x/cellbuf +# github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 +## explicit; go 1.19 # github.com/charmbracelet/x/term v0.2.1 ## explicit; go 1.18 github.com/charmbracelet/x/term @@ -283,9 +275,6 @@ github.com/emirpasic/gods/utils # github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f ## explicit; go 1.16 github.com/erikgeiser/coninput -# github.com/evertras/bubble-table v0.19.2 -## explicit; go 1.18 -github.com/evertras/bubble-table/table # github.com/felixge/httpsnoop v1.0.4 ## explicit; go 1.13 github.com/felixge/httpsnoop @@ -493,11 +482,6 @@ github.com/muesli/ansi/compressor # github.com/muesli/cancelreader v0.2.2 ## explicit; go 1.17 github.com/muesli/cancelreader -# github.com/muesli/reflow v0.3.0 -## explicit; go 1.13 -github.com/muesli/reflow/ansi -github.com/muesli/reflow/truncate -github.com/muesli/reflow/wordwrap # github.com/muesli/termenv v0.16.0 ## explicit; go 1.17 github.com/muesli/termenv