refactor: urfave v3

This commit is contained in:
decentral1se 2024-07-09 13:57:54 +02:00
parent 16aeb441e7
commit ca37621ce3
Signed by: decentral1se
GPG Key ID: 03789458B3D0C410
46 changed files with 405 additions and 345 deletions

View File

@ -1,7 +1,7 @@
package app package app
import ( import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var AppCommand = cli.Command{ var AppCommand = cli.Command{
@ -9,7 +9,7 @@ var AppCommand = cli.Command{
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "Manage apps", Usage: "Manage apps",
ArgsUsage: "<domain>", ArgsUsage: "<domain>",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&appBackupCommand, &appBackupCommand,
&appCheckCommand, &appCheckCommand,
&appCmdCommand, &appCmdCommand,

View File

@ -1,13 +1,14 @@
package app package app
import ( import (
"context"
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var snapshot string var snapshot string
@ -43,11 +44,12 @@ var appBackupListCommand = cli.Command{
snapshotFlag, snapshotFlag,
includePathFlag, includePathFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "List all backups", Usage: "List all backups",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
@ -90,11 +92,12 @@ var appBackupDownloadCommand = cli.Command{
snapshotFlag, snapshotFlag,
includePathFlag, includePathFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "Download a backup", Usage: "Download a backup",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.EnsureExists(); err != nil { if err := app.Recipe.EnsureExists(); err != nil {
log.Fatal(err) log.Fatal(err)
@ -160,11 +163,12 @@ var appBackupCreateCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
resticRepoFlag, resticRepoFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "Create a new backup", Usage: "Create a new backup",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.EnsureExists(); err != nil { if err := app.Recipe.EnsureExists(); err != nil {
log.Fatal(err) log.Fatal(err)
@ -218,11 +222,12 @@ var appBackupSnapshotsCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
snapshotFlag, snapshotFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "List backup snapshots", Usage: "List backup snapshots",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.EnsureExists(); err != nil { if err := app.Recipe.EnsureExists(); err != nil {
log.Fatal(err) log.Fatal(err)
@ -273,7 +278,7 @@ var appBackupCommand = cli.Command{
Aliases: []string{"b"}, Aliases: []string{"b"},
Usage: "Manage app backups", Usage: "Manage app backups",
ArgsUsage: "<domain>", ArgsUsage: "<domain>",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&appBackupListCommand, &appBackupListCommand,
&appBackupSnapshotsCommand, &appBackupSnapshotsCommand,
&appBackupDownloadCommand, &appBackupDownloadCommand,

View File

@ -1,12 +1,14 @@
package app package app
import ( import (
"context"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
appPkg "coopcloud.tech/abra/pkg/app" appPkg "coopcloud.tech/abra/pkg/app"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appCheckCommand = cli.Command{ var appCheckCommand = cli.Command{
@ -31,10 +33,11 @@ ${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
internal.ChaosFlag, internal.ChaosFlag,
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,6 +1,7 @@
package app package app
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -14,7 +15,8 @@ import (
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "coopcloud.tech/abra/pkg/recipe"
"github.com/urfave/cli/v3"
) )
var appCmdCommand = cli.Command{ var appCmdCommand = cli.Command{
@ -43,32 +45,33 @@ EXAMPLE:
internal.ChaosFlag, internal.ChaosFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&appCmdListCommand, &appCmdListCommand,
}, },
BashComplete: func(ctx *cli.Context) { EnableShellCompletion: true,
args := ctx.Args() ShellComplete: func(ctx context.Context, cmd *cli.Command) {
args := cmd.Args()
switch args.Len() { switch args.Len() {
case 0: case 0:
autocomplete.AppNameComplete(ctx) autocomplete.AppNameComplete(ctx, cmd)
case 1: case 1:
autocomplete.ServiceNameComplete(args.Get(0)) autocomplete.ServiceNameComplete(args.Get(0))
case 2: case 2:
cmdNameComplete(args.Get(0)) cmdNameComplete(args.Get(0))
} }
}, },
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if internal.LocalCmd && internal.RemoteUser != "" { if internal.LocalCmd && internal.RemoteUser != "" {
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use --local & --user together")) internal.ShowSubcommandHelpAndError(cmd, errors.New("cannot use --local & --user together"))
} }
hasCmdArgs, parsedCmdArgs := parseCmdArgs(c.Args().Slice(), internal.LocalCmd) hasCmdArgs, parsedCmdArgs := parseCmdArgs(cmd.Args().Slice(), internal.LocalCmd)
if _, err := os.Stat(app.Recipe.AbraShPath); err != nil { if _, err := os.Stat(app.Recipe.AbraShPath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -78,11 +81,11 @@ EXAMPLE:
} }
if internal.LocalCmd { if internal.LocalCmd {
if !(c.Args().Len() >= 2) { if !(cmd.Args().Len() >= 2) {
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments")) internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments"))
} }
cmdName := c.Args().Get(1) cmdName := cmd.Args().Get(1)
if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil { if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -114,13 +117,13 @@ EXAMPLE:
log.Fatal(err) log.Fatal(err)
} }
} else { } else {
if !(c.Args().Len() >= 3) { if !(cmd.Args().Len() >= 3) {
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments")) internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments"))
} }
targetServiceName := c.Args().Get(1) targetServiceName := cmd.Args().Get(1)
cmdName := c.Args().Get(2) cmdName := cmd.Args().Get(2)
if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil { if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -208,8 +211,9 @@ var appCmdListCommand = cli.Command{
}, },
BashComplete: autocomplete.AppNameComplete, BashComplete: autocomplete.AppNameComplete,
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
r := recipe.Get(app.Recipe.Name)
if err := app.Recipe.EnsureExists(); err != nil { if err := app.Recipe.EnsureExists(); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,6 +1,7 @@
package app package app
import ( import (
"context"
"errors" "errors"
"os" "os"
"os/exec" "os/exec"
@ -10,7 +11,7 @@ import (
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appConfigCommand = cli.Command{ var appConfigCommand = cli.Command{
@ -21,13 +22,14 @@ var appConfigCommand = cli.Command{
Flags: []cli.Flag{ Flags: []cli.Flag{
internal.DebugFlag, internal.DebugFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
appName := c.Args().First() Action: func(ctx context.Context, cmd *cli.Command) error {
appName := cmd.Args().First()
if appName == "" { if appName == "" {
internal.ShowSubcommandHelpAndError(c, errors.New("no app provided")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
} }
files, err := appPkg.LoadAppFiles("") files, err := appPkg.LoadAppFiles("")
@ -51,11 +53,11 @@ var appConfigCommand = cli.Command{
} }
} }
cmd := exec.Command(ed, appFile.Path) c := exec.Command(ed, appFile.Path)
cmd.Stdin = os.Stdin c.Stdin = os.Stdin
cmd.Stdout = os.Stdout c.Stdout = os.Stdout
cmd.Stderr = os.Stderr c.Stderr = os.Stderr
if err := cmd.Run(); err != nil { if err := c.Run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -22,7 +22,7 @@ import (
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appCpCommand = cli.Command{ var appCpCommand = cli.Command{
@ -44,18 +44,17 @@ If you want to copy a myfile.txt to the root of the app service:
And if you want to copy that file back to your current working directory locally: And if you want to copy that file back to your current working directory locally:
abra app cp <domain> app:/myfile.txt . abra app cp <domain> app:/myfile.txt`,
`, EnableShellCompletion: true,
BashComplete: autocomplete.AppNameComplete, ShellComplete: autocomplete.AppNameComplete,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }
src := c.Args().Get(1) src := cmd.Args().Get(1)
dst := c.Args().Get(2) dst := cmd.Args().Get(2)
if src == "" { if src == "" {
log.Fatal("missing <src> argument") log.Fatal("missing <src> argument")
} }

View File

@ -15,7 +15,7 @@ import (
"coopcloud.tech/abra/pkg/lint" "coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/upstream/stack" "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appDeployCommand = cli.Command{ var appDeployCommand = cli.Command{
@ -45,15 +45,17 @@ EXAMPLE:
abra app deploy foo.example.com abra app deploy foo.example.com
abra app deploy foo.example.com 1.2.3+3.2.1 abra app deploy foo.example.com 1.2.3+3.2.1
abra app deploy foo.example.com 1e83340e`, abra app deploy foo.example.com 1e83340e`,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
stackName := app.StackName() stackName := app.StackName()
specificVersion := c.Args().Get(1) specificVersion := cmd.Args().Get(1)
if specificVersion == "" { if specificVersion == "" {
specificVersion = app.Recipe.Version specificVersion = app.Recipe.Version
} }
if specificVersion != "" && internal.Chaos { if specificVersion != "" && internal.Chaos {
log.Fatal("cannot use <version> and --chaos together") log.Fatal("cannot use <version> and --chaos together")
} }

View File

@ -1,6 +1,7 @@
package app package app
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sort" "sort"
@ -12,7 +13,7 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/tagcmp" "coopcloud.tech/tagcmp"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var ( var (
@ -89,7 +90,7 @@ can take some time.`,
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
appFiles, err := appPkg.LoadAppFiles(listAppServer) appFiles, err := appPkg.LoadAppFiles(listAppServer)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -19,7 +19,7 @@ import (
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appLogsCommand = cli.Command{ var appLogsCommand = cli.Command{
@ -32,10 +32,11 @@ var appLogsCommand = cli.Command{
internal.SinceLogsFlag, internal.SinceLogsFlag,
internal.DebugFlag, internal.DebugFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
stackName := app.StackName() stackName := app.StackName()
if err := app.Recipe.EnsureExists(); err != nil { if err := app.Recipe.EnsureExists(); err != nil {
@ -56,7 +57,7 @@ var appLogsCommand = cli.Command{
log.Fatalf("%s is not deployed?", app.Name) log.Fatalf("%s is not deployed?", app.Name)
} }
serviceName := c.Args().Get(1) serviceName := cmd.Args().Get(1)
serviceNames := []string{} serviceNames := []string{}
if serviceName != "" { if serviceName != "" {
serviceNames = []string{serviceName} serviceNames = []string{serviceName}

View File

@ -1,6 +1,7 @@
package app package app
import ( import (
"context"
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
@ -15,7 +16,7 @@ import (
"coopcloud.tech/abra/pkg/secret" "coopcloud.tech/abra/pkg/secret"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appNewDescription = ` var appNewDescription = `
@ -52,19 +53,20 @@ var appNewCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
internal.ChaosFlag, internal.ChaosFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
ArgsUsage: "[<recipe>] [<version>]", ArgsUsage: "[<recipe>] [<version>]",
BashComplete: func(ctx *cli.Context) { EnableShellCompletion: true,
args := ctx.Args() ShellComplete: func(ctx context.Context, cmd *cli.Command) {
args := cmd.Args()
switch args.Len() { switch args.Len() {
case 0: case 0:
autocomplete.RecipeNameComplete(ctx) autocomplete.RecipeNameComplete(ctx, cmd)
case 1: case 1:
autocomplete.RecipeVersionComplete(ctx.Args().Get(0)) autocomplete.RecipeVersionComplete(cmd.Args().Get(0))
} }
}, },
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipe(cmd)
if !internal.Chaos { if !internal.Chaos {
if err := recipe.EnsureIsClean(); err != nil { if err := recipe.EnsureIsClean(); err != nil {
@ -75,7 +77,7 @@ var appNewCommand = cli.Command{
log.Fatal(err) log.Fatal(err)
} }
} }
if c.Args().Get(1) == "" { if cmd.Args().Get(1) == "" {
var version string var version string
recipeVersions, err := recipe.GetRecipeVersions() recipeVersions, err := recipe.GetRecipeVersions()
@ -100,7 +102,7 @@ var appNewCommand = cli.Command{
} }
} }
} else { } else {
if _, err := recipe.EnsureVersion(c.Args().Get(1)); err != nil { if _, err := recipe.EnsureVersion(cmd.Args().Get(1)); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -17,7 +17,7 @@ import (
containerTypes "github.com/docker/docker/api/types/container" containerTypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appPsCommand = cli.Command{ var appPsCommand = cli.Command{
@ -30,10 +30,11 @@ var appPsCommand = cli.Command{
internal.MachineReadableFlag, internal.MachineReadableFlag,
internal.DebugFlag, internal.DebugFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(false, false); err != nil { if err := app.Recipe.Ensure(false, false); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -12,7 +12,7 @@ import (
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appRemoveCommand = cli.Command{ var appRemoveCommand = cli.Command{
@ -43,10 +43,11 @@ flag.`,
internal.NoInputFlag, internal.NoInputFlag,
internal.OfflineFlag, internal.OfflineFlag,
}, },
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Before: internal.SubCommandBefore, ShellComplete: autocomplete.AppNameComplete,
Action: func(c *cli.Context) error { Before: internal.SubCommandBefore,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if !internal.Force && !internal.NoInput { if !internal.Force && !internal.NoInput {
response := false response := false

View File

@ -12,7 +12,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
upstream "coopcloud.tech/abra/pkg/upstream/service" upstream "coopcloud.tech/abra/pkg/upstream/service"
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appRestartCommand = cli.Command{ var appRestartCommand = cli.Command{
@ -36,17 +36,18 @@ Pass "--all-services/-a" to restart all services.
EXAMPLE: EXAMPLE:
abra app restart example.com app`, abra app restart example.com app`,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(false, false); err != nil { if err := app.Recipe.Ensure(false, false); err != nil {
log.Fatal(err) log.Fatal(err)
} }
serviceName := c.Args().Get(1) serviceName := cmd.Args().Get(1)
if serviceName == "" && !internal.AllServices { if serviceName == "" && !internal.AllServices {
err := errors.New("missing <service>") err := errors.New("missing <service>")
internal.ShowSubcommandHelpAndError(c, err) internal.ShowSubcommandHelpAndError(cmd, err)
} }
if serviceName != "" && internal.AllServices { if serviceName != "" && internal.AllServices {

View File

@ -1,13 +1,14 @@
package app package app
import ( import (
"context"
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var targetPath string var targetPath string
@ -28,10 +29,11 @@ var appRestoreCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
targetPathFlag, targetPathFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -15,7 +15,7 @@ import (
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appRollbackCommand = cli.Command{ var appRollbackCommand = cli.Command{
@ -45,9 +45,10 @@ EXAMPLE:
abra app rollback foo.example.com abra app rollback foo.example.com
abra app rollback foo.example.com 1.2.3+3.2.1`, abra app rollback foo.example.com 1.2.3+3.2.1`,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
stackName := app.StackName() stackName := app.StackName()
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
@ -85,10 +86,11 @@ EXAMPLE:
log.Warnf("failed to determine deployed version of %s", app.Name) log.Warnf("failed to determine deployed version of %s", app.Name)
} }
specificVersion := c.Args().Get(1) specificVersion := cmd.Args().Get(1)
if specificVersion == "" { if specificVersion == "" {
specificVersion = app.Recipe.Version specificVersion = app.Recipe.Version
} }
if specificVersion != "" { if specificVersion != "" {
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version) parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
if err != nil { if err != nil {

View File

@ -14,7 +14,7 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var user string var user string
@ -40,19 +40,20 @@ var appRunCommand = cli.Command{
noTTYFlag, noTTYFlag,
userFlag, userFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
ArgsUsage: "<domain> <service> <args>...", ArgsUsage: "<domain> <service> <args>...",
Usage: "Run a command in a service container", Usage: "Run a command in a service container",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if c.Args().Len() < 2 { if cmd.Args().Len() < 2 {
internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no <service> provided?"))
} }
if c.Args().Len() < 3 { if cmd.Args().Len() < 3 {
internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no <args> provided?"))
} }
cl, err := client.New(app.Server) cl, err := client.New(app.Server)
@ -60,7 +61,7 @@ var appRunCommand = cli.Command{
log.Fatal(err) log.Fatal(err)
} }
serviceName := c.Args().Get(1) serviceName := cmd.Args().Get(1)
stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), serviceName) stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), serviceName)
filters := filters.NewArgs() filters := filters.NewArgs()
filters.Add("name", stackAndServiceName) filters.Add("name", stackAndServiceName)
@ -70,12 +71,12 @@ var appRunCommand = cli.Command{
log.Fatal(err) log.Fatal(err)
} }
cmd := c.Args().Slice()[2:] c := cmd.Args().Slice()[2:]
execCreateOpts := types.ExecConfig{ execCreateOpts := types.ExecConfig{
AttachStderr: true, AttachStderr: true,
AttachStdin: true, AttachStdin: true,
AttachStdout: true, AttachStdout: true,
Cmd: cmd, Cmd: c,
Detach: false, Detach: false,
Tty: true, Tty: true,
} }

View File

@ -17,7 +17,7 @@ import (
"coopcloud.tech/abra/pkg/secret" "coopcloud.tech/abra/pkg/secret"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var ( var (
@ -53,22 +53,23 @@ var appSecretGenerateCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
internal.ChaosFlag, internal.ChaosFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if c.Args().Len() == 1 && !allSecrets { if cmd.Args().Len() == 1 && !allSecrets {
err := errors.New("missing arguments <secret>/<version> or '--all'") err := errors.New("missing arguments <secret>/<version> or '--all'")
internal.ShowSubcommandHelpAndError(c, err) internal.ShowSubcommandHelpAndError(cmd, err)
} }
if c.Args().Get(1) != "" && allSecrets { if cmd.Args().Get(1) != "" && allSecrets {
err := errors.New("cannot use '<secret> <version>' and '--all' together") err := errors.New("cannot use '<secret> <version>' and '--all' together")
internal.ShowSubcommandHelpAndError(c, err) internal.ShowSubcommandHelpAndError(cmd, err)
} }
composeFiles, err := app.Recipe.GetComposeFiles(app.Env) composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
@ -82,8 +83,8 @@ var appSecretGenerateCommand = cli.Command{
} }
if !allSecrets { if !allSecrets {
secretName := c.Args().Get(1) secretName := cmd.Args().Get(1)
secretVersion := c.Args().Get(2) secretVersion := cmd.Args().Get(2)
s, ok := secrets[secretName] s, ok := secrets[secretName]
if !ok { if !ok {
log.Fatalf("%s doesn't exist in the env config?", secretName) log.Fatalf("%s doesn't exist in the env config?", secretName)
@ -144,9 +145,10 @@ var appSecretInsertCommand = cli.Command{
internal.FileFlag, internal.FileFlag,
internal.TrimFlag, internal.TrimFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
ArgsUsage: "<domain> <secret-name> <version> <data>", ArgsUsage: "<domain> <secret-name> <version> <data>",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
ShellComplete: autocomplete.AppNameComplete,
Description: ` Description: `
This command inserts a secret into an app environment. This command inserts a secret into an app environment.
@ -159,11 +161,11 @@ Example:
abra app secret insert myapp db_pass v1 mySecretPassword abra app secret insert myapp db_pass v1 mySecretPassword
`, `,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
if c.Args().Len() != 4 { if cmd.Args().Len() != 4 {
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?")) internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments?"))
} }
cl, err := client.New(app.Server) cl, err := client.New(app.Server)
@ -171,9 +173,9 @@ Example:
log.Fatal(err) log.Fatal(err)
} }
name := c.Args().Get(1) name := cmd.Args().Get(1)
version := c.Args().Get(2) version := cmd.Args().Get(2)
data := c.Args().Get(3) data := cmd.Args().Get(3)
if internal.File { if internal.File {
raw, err := os.ReadFile(data) raw, err := os.ReadFile(data)
@ -235,9 +237,10 @@ var appSecretRmCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
internal.ChaosFlag, internal.ChaosFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
ArgsUsage: "<domain> [<secret-name>]", ArgsUsage: "<domain> [<secret-name>]",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
ShellComplete: autocomplete.AppNameComplete,
Description: ` Description: `
This command removes app secrets. This command removes app secrets.
@ -245,8 +248,8 @@ Example:
abra app secret remove myapp db_pass abra app secret remove myapp db_pass
`, `,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -261,12 +264,12 @@ Example:
log.Fatal(err) log.Fatal(err)
} }
if c.Args().Get(1) != "" && rmAllSecrets { if cmd.Args().Get(1) != "" && rmAllSecrets {
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use '<secret-name>' and '--all' together")) internal.ShowSubcommandHelpAndError(cmd, errors.New("cannot use '<secret-name>' and '--all' together"))
} }
if c.Args().Get(1) == "" && !rmAllSecrets { if cmd.Args().Get(1) == "" && !rmAllSecrets {
internal.ShowSubcommandHelpAndError(c, errors.New("no secret(s) specified?")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no secret(s) specified?"))
} }
cl, err := client.New(app.Server) cl, err := client.New(app.Server)
@ -290,7 +293,7 @@ Example:
} }
match := false match := false
secretToRm := c.Args().Get(1) secretToRm := cmd.Args().Get(1)
for secretName, val := range secrets { for secretName, val := range secrets {
secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, val.Version) secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, val.Version)
if _, ok := remoteSecretNames[secretRemoteName]; ok { if _, ok := remoteSecretNames[secretRemoteName]; ok {
@ -333,11 +336,12 @@ var appSecretLsCommand = cli.Command{
internal.ChaosFlag, internal.ChaosFlag,
internal.MachineReadableFlag, internal.MachineReadableFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "List all secrets", Usage: "List all secrets",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -384,7 +388,7 @@ var appSecretCommand = cli.Command{
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Manage app secrets", Usage: "Manage app secrets",
ArgsUsage: "<domain>", ArgsUsage: "<domain>",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&appSecretGenerateCommand, &appSecretGenerateCommand,
&appSecretInsertCommand, &appSecretInsertCommand,
&appSecretRmCommand, &appSecretRmCommand,

View File

@ -13,7 +13,7 @@ import (
"coopcloud.tech/abra/pkg/service" "coopcloud.tech/abra/pkg/service"
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
containerTypes "github.com/docker/docker/api/types/container" containerTypes "github.com/docker/docker/api/types/container"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appServicesCommand = cli.Command{ var appServicesCommand = cli.Command{
@ -24,10 +24,11 @@ var appServicesCommand = cli.Command{
Flags: []cli.Flag{ Flags: []cli.Flag{
internal.DebugFlag, internal.DebugFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -13,7 +13,7 @@ import (
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var prune bool var prune bool
@ -70,9 +70,10 @@ var appUndeployCommand = cli.Command{
internal.NoInputFlag, internal.NoInputFlag,
pruneFlag, pruneFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "Undeploy an app", Usage: "Undeploy an app",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
ShellComplete: autocomplete.AppNameComplete,
Description: ` Description: `
This does not destroy any of the application data. This does not destroy any of the application data.
@ -80,8 +81,8 @@ However, you should remain vigilant, as your swarm installation will consider
any previously attached volumes as eligible for pruning once undeployed. any previously attached volumes as eligible for pruning once undeployed.
Passing "-p/--prune" does not remove those volumes.`, Passing "-p/--prune" does not remove those volumes.`,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(cmd)
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -14,7 +14,7 @@ import (
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
"coopcloud.tech/tagcmp" "coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appUpgradeCommand = cli.Command{ var appUpgradeCommand = cli.Command{
@ -45,9 +45,10 @@ EXAMPLE:
abra app upgrade foo.example.com abra app upgrade foo.example.com
abra app upgrade foo.example.com 1.2.3+3.2.1`, abra app upgrade foo.example.com 1.2.3+3.2.1`,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
stackName := app.StackName() stackName := app.StackName()
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
@ -85,7 +86,7 @@ EXAMPLE:
log.Warnf("failed to determine deployed version of %s", app.Name) log.Warnf("failed to determine deployed version of %s", app.Name)
} }
specificVersion := c.Args().Get(1) specificVersion := cmd.Args().Get(1)
if specificVersion != "" { if specificVersion != "" {
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version) parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
if err != nil { if err != nil {

View File

@ -10,7 +10,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/upstream/stack" "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var appVolumeListCommand = cli.Command{ var appVolumeListCommand = cli.Command{
@ -21,11 +21,12 @@ var appVolumeListCommand = cli.Command{
internal.DebugFlag, internal.DebugFlag,
internal.NoInputFlag, internal.NoInputFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "List volumes associated with an app", Usage: "List volumes associated with an app",
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
cl, err := client.New(app.Server) cl, err := client.New(app.Server)
if err != nil { if err != nil {
@ -81,10 +82,11 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
internal.NoInputFlag, internal.NoInputFlag,
internal.ForceFlag, internal.ForceFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.AppNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.AppNameComplete,
app := internal.ValidateApp(c) Action: func(ctx context.Context, cmd *cli.Command) error {
app := internal.ValidateApp(cmd)
cl, err := client.New(app.Server) cl, err := client.New(app.Server)
if err != nil { if err != nil {
@ -149,7 +151,7 @@ var appVolumeCommand = cli.Command{
Aliases: []string{"vl"}, Aliases: []string{"vl"},
Usage: "Manage app volumes", Usage: "Manage app volumes",
ArgsUsage: "<domain>", ArgsUsage: "<domain>",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&appVolumeListCommand, &appVolumeListCommand,
&appVolumeRemoveCommand, &appVolumeRemoveCommand,
}, },

View File

@ -1,6 +1,7 @@
package catalogue package catalogue
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -15,7 +16,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var catalogueGenerateCommand = cli.Command{ var catalogueGenerateCommand = cli.Command{
@ -45,14 +46,15 @@ If you have a Hub account you can have Abra log you in to avoid this. Pass
Push your new release to git.coopcloud.tech with "-p/--publish". This requires Push your new release to git.coopcloud.tech with "-p/--publish". This requires
that you have permission to git push to these repositories and have your SSH that you have permission to git push to these repositories and have your SSH
keys configured on your account.`, keys configured on your account.`,
ArgsUsage: "[<recipe>]", ArgsUsage: "[<recipe>]",
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipeName := c.Args().First() Action: func(ctx context.Context, cmd *cli.Command) error {
recipeName := cmd.Args().First()
r := recipe.Get(recipeName) r := recipe.Get(recipeName)
if recipeName != "" { if recipeName != "" {
internal.ValidateRecipe(c) internal.ValidateRecipe(cmd)
} }
if !internal.Chaos { if !internal.Chaos {
@ -209,7 +211,7 @@ var CatalogueCommand = cli.Command{
Usage: "Manage the recipe catalogue", Usage: "Manage the recipe catalogue",
Aliases: []string{"c"}, Aliases: []string{"c"},
ArgsUsage: "<recipe>", ArgsUsage: "<recipe>",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&catalogueGenerateCommand, &catalogueGenerateCommand,
}, },
} }

View File

@ -2,6 +2,7 @@
package cli package cli
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -18,7 +19,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/web" "coopcloud.tech/abra/pkg/web"
charmLog "github.com/charmbracelet/log" charmLog "github.com/charmbracelet/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// AutoCompleteCommand helps people set up auto-complete in their shells // AutoCompleteCommand helps people set up auto-complete in their shells
@ -38,11 +39,11 @@ EXAMPLE:
Flags: []cli.Flag{ Flags: []cli.Flag{
internal.DebugFlag, internal.DebugFlag,
}, },
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
shellType := c.Args().First() shellType := cmd.Args().First()
if shellType == "" { if shellType == "" {
internal.ShowSubcommandHelpAndError(c, errors.New("no shell provided")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no shell provided"))
} }
supportedShells := map[string]bool{ supportedShells := map[string]bool{
@ -125,18 +126,18 @@ EXAMPLE:
abra upgrade abra upgrade
abra upgrade --rc`, abra upgrade --rc`,
Flags: []cli.Flag{internal.RCFlag}, Flags: []cli.Flag{internal.RCFlag},
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
mainURL := "https://install.abra.coopcloud.tech" mainURL := "https://install.abra.coopcloud.tech"
cmd := exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash", mainURL)) c := exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash", mainURL))
if internal.RC { if internal.RC {
releaseCandidateURL := "https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer" releaseCandidateURL := "https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
cmd = exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash -s -- --rc", releaseCandidateURL)) c = exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash -s -- --rc", releaseCandidateURL))
} }
log.Debugf("attempting to run %s", cmd) log.Debugf("attempting to run %s", c)
if err := internal.RunCmd(cmd); err != nil { if err := internal.RunCmd(c); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -144,8 +145,8 @@ EXAMPLE:
}, },
} }
func newAbraApp(version, commit string) *cli.App { func newAbraApp(version, commit string) *cli.Command {
app := &cli.App{ app := &cli.Command{
Name: "abra", Name: "abra",
Usage: `the Co-op Cloud command-line utility belt 🎩🐇 Usage: `the Co-op Cloud command-line utility belt 🎩🐇
____ ____ _ _ ____ ____ _ _
@ -164,12 +165,11 @@ func newAbraApp(version, commit string) *cli.App {
&UpgradeCommand, &UpgradeCommand,
&AutoCompleteCommand, &AutoCompleteCommand,
}, },
BashComplete: autocomplete.SubcommandComplete, EnableShellCompletion: true,
ShellComplete: autocomplete.SubcommandComplete,
} }
app.EnableBashCompletion = true app.Before = func(ctx context.Context, cmd *cli.Command) error {
app.Before = func(c *cli.Context) error {
paths := []string{ paths := []string{
config.ABRA_DIR, config.ABRA_DIR,
config.SERVERS_DIR, config.SERVERS_DIR,
@ -200,7 +200,7 @@ func newAbraApp(version, commit string) *cli.App {
func RunApp(version, commit string) { func RunApp(version, commit string) {
app := newAbraApp(version, commit) app := newAbraApp(version, commit)
if err := app.Run(os.Args); err != nil { if err := app.Run(context.Background(), os.Args); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -1,10 +1,11 @@
package internal package internal
import ( import (
"context"
"os" "os"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// Secrets stores the variable from SecretsFlag // Secrets stores the variable from SecretsFlag
@ -319,7 +320,7 @@ var AllServicesFlag = &cli.BoolFlag{
} }
// SubCommandBefore wires up pre-action machinery (e.g. --debug handling). // SubCommandBefore wires up pre-action machinery (e.g. --debug handling).
func SubCommandBefore(c *cli.Context) error { func SubCommandBefore(ctx context.Context, cmd *cli.Command) error {
if Debug { if Debug {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
log.SetOutput(os.Stderr) log.SetOutput(os.Stderr)

View File

@ -4,13 +4,13 @@ import (
"os" "os"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// ShowSubcommandHelpAndError exits the program on error, logs the error to the // ShowSubcommandHelpAndError exits the program on error, logs the error to the
// terminal, and shows the help command. // terminal, and shows the help command.
func ShowSubcommandHelpAndError(c *cli.Context, err interface{}) { func ShowSubcommandHelpAndError(cmd *cli.Command, err interface{}) {
if err2 := cli.ShowSubcommandHelp(c); err2 != nil { if err2 := cli.ShowSubcommandHelp(cmd); err2 != nil {
log.Error(err2) log.Error(err2)
} }
log.Error(err) log.Error(err)

View File

@ -9,12 +9,12 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// ValidateRecipe ensures the recipe arg is valid. // ValidateRecipe ensures the recipe arg is valid.
func ValidateRecipe(c *cli.Context) recipe.Recipe { func ValidateRecipe(cmd *cli.Command) recipe.Recipe {
recipeName := c.Args().First() recipeName := cmd.Args().First()
if recipeName == "" && !NoInput { if recipeName == "" && !NoInput {
var recipes []string var recipes []string
@ -54,7 +54,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
} }
if recipeName == "" { if recipeName == "" {
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided")) ShowSubcommandHelpAndError(cmd, errors.New("no recipe name provided"))
} }
chosenRecipe := recipe.Get(recipeName) chosenRecipe := recipe.Get(recipeName)
@ -64,7 +64,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
} }
_, err = chosenRecipe.GetComposeConfig(nil) _, err = chosenRecipe.GetComposeConfig(nil)
if err != nil { if err != nil {
if c.Command.Name == "generate" { if cmd.Name == "generate" {
if strings.Contains(err.Error(), "missing a compose") { if strings.Contains(err.Error(), "missing a compose") {
log.Fatal(err) log.Fatal(err)
} }
@ -83,11 +83,11 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
} }
// ValidateApp ensures the app name arg is valid. // ValidateApp ensures the app name arg is valid.
func ValidateApp(c *cli.Context) app.App { func ValidateApp(cmd *cli.Command) app.App {
appName := c.Args().First() appName := cmd.Args().First()
if appName == "" { if appName == "" {
ShowSubcommandHelpAndError(c, errors.New("no app provided")) ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
} }
app, err := app.Get(appName) app, err := app.Get(appName)
@ -101,8 +101,8 @@ func ValidateApp(c *cli.Context) app.App {
} }
// ValidateDomain ensures the domain name arg is valid. // ValidateDomain ensures the domain name arg is valid.
func ValidateDomain(c *cli.Context) string { func ValidateDomain(cmd *cli.Command) string {
domainName := c.Args().First() domainName := cmd.Args().First()
if domainName == "" && !NoInput { if domainName == "" && !NoInput {
prompt := &survey.Input{ prompt := &survey.Input{
@ -115,7 +115,7 @@ func ValidateDomain(c *cli.Context) string {
} }
if domainName == "" { if domainName == "" {
ShowSubcommandHelpAndError(c, errors.New("no domain provided")) ShowSubcommandHelpAndError(cmd, errors.New("no domain provided"))
} }
log.Debugf("validated %s as domain argument", domainName) log.Debugf("validated %s as domain argument", domainName)
@ -124,10 +124,10 @@ func ValidateDomain(c *cli.Context) string {
} }
// ValidateSubCmdFlags ensures flag order conforms to correct order // ValidateSubCmdFlags ensures flag order conforms to correct order
func ValidateSubCmdFlags(c *cli.Context) bool { func ValidateSubCmdFlags(cmd *cli.Command) bool {
for argIdx, arg := range c.Args().Slice() { for argIdx, arg := range cmd.Args().Slice() {
if !strings.HasPrefix(arg, "--") { if !strings.HasPrefix(arg, "--") {
for _, flag := range c.Args().Slice()[argIdx:] { for _, flag := range cmd.Args().Slice()[argIdx:] {
if strings.HasPrefix(flag, "--") { if strings.HasPrefix(flag, "--") {
return false return false
} }
@ -138,8 +138,8 @@ func ValidateSubCmdFlags(c *cli.Context) bool {
} }
// ValidateServer ensures the server name arg is valid. // ValidateServer ensures the server name arg is valid.
func ValidateServer(c *cli.Context) string { func ValidateServer(cmd *cli.Command) string {
serverName := c.Args().First() serverName := cmd.Args().First()
serverNames, err := config.ReadServerNames() serverNames, err := config.ReadServerNames()
if err != nil { if err != nil {
@ -164,11 +164,11 @@ func ValidateServer(c *cli.Context) string {
} }
if serverName == "" { if serverName == "" {
ShowSubcommandHelpAndError(c, errors.New("no server provided")) ShowSubcommandHelpAndError(cmd, errors.New("no server provided"))
} }
if !matched { if !matched {
ShowSubcommandHelpAndError(c, errors.New("server doesn't exist?")) ShowSubcommandHelpAndError(cmd, errors.New("server doesn't exist?"))
} }
log.Debugf("validated %s as server argument", serverName) log.Debugf("validated %s as server argument", serverName)

View File

@ -1,11 +1,13 @@
package recipe package recipe
import ( import (
"context"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
gitPkg "coopcloud.tech/abra/pkg/git" gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeDiffCommand = cli.Command{ var recipeDiffCommand = cli.Command{
@ -18,10 +20,11 @@ var recipeDiffCommand = cli.Command{
internal.DebugFlag, internal.DebugFlag,
internal.NoInputFlag, internal.NoInputFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
r := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
r := internal.ValidateRecipe(cmd)
if err := gitPkg.DiffUnstaged(r.Dir); err != nil { if err := gitPkg.DiffUnstaged(r.Dir); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,12 +1,14 @@
package recipe package recipe
import ( import (
"context"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeFetchCommand = cli.Command{ var recipeFetchCommand = cli.Command{
@ -20,13 +22,14 @@ var recipeFetchCommand = cli.Command{
internal.NoInputFlag, internal.NoInputFlag,
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipeName := c.Args().First() Action: func(ctx context.Context, cmd *cli.Command) error {
recipeName := cmd.Args().First()
r := recipe.Get(recipeName) r := recipe.Get(recipeName)
if recipeName != "" { if recipeName != "" {
internal.ValidateRecipe(c) internal.ValidateRecipe(cmd)
if err := r.Ensure(false, false); err != nil { if err := r.Ensure(false, false); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"context"
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
@ -8,7 +9,7 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/lint" "coopcloud.tech/abra/pkg/lint"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeLintCommand = cli.Command{ var recipeLintCommand = cli.Command{
@ -23,10 +24,11 @@ var recipeLintCommand = cli.Command{
internal.NoInputFlag, internal.NoInputFlag,
internal.ChaosFlag, internal.ChaosFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipe := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(cmd)
if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"context"
"fmt" "fmt"
"sort" "sort"
"strconv" "strconv"
@ -10,7 +11,7 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var pattern string var pattern string
@ -33,7 +34,7 @@ var recipeListCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
catl, err := recipe.ReadRecipeCatalogue(internal.Offline) catl, err := recipe.ReadRecipeCatalogue(internal.Offline)
if err != nil { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())

View File

@ -2,6 +2,7 @@ package recipe
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -13,7 +14,7 @@ import (
"coopcloud.tech/abra/pkg/git" "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// recipeMetadata is the recipe metadata for the README.md // recipeMetadata is the recipe metadata for the README.md
@ -49,12 +50,12 @@ Create a new recipe.
Abra uses the built-in example repository which is available here: Abra uses the built-in example repository which is available here:
https://git.coopcloud.tech/coop-cloud/example`, https://git.coopcloud.tech/coop-cloud/example`,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
recipeName := c.Args().First() recipeName := cmd.Args().First()
r := recipe.Get(recipeName) r := recipe.Get(recipeName)
if recipeName == "" { if recipeName == "" {
internal.ShowSubcommandHelpAndError(c, errors.New("no recipe name provided")) internal.ShowSubcommandHelpAndError(cmd, errors.New("no recipe name provided"))
} }
if _, err := os.Stat(r.Dir); !os.IsNotExist(err) { if _, err := os.Stat(r.Dir); !os.IsNotExist(err) {

View File

@ -1,7 +1,7 @@
package recipe package recipe
import ( import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// RecipeCommand defines all recipe related sub-commands. // RecipeCommand defines all recipe related sub-commands.
@ -19,7 +19,7 @@ for you.
Anyone who uses a recipe can become a maintainer. Maintainers typically make Anyone who uses a recipe can become a maintainer. Maintainers typically make
sure the recipe is in good working order and the config upgraded in a timely sure the recipe is in good working order and the config upgraded in a timely
manner.`, manner.`,
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&recipeFetchCommand, &recipeFetchCommand,
&recipeLintCommand, &recipeLintCommand,
&recipeListCommand, &recipeListCommand,

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -18,7 +19,7 @@ import (
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/distribution/reference" "github.com/distribution/reference"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeReleaseCommand = cli.Command{ var recipeReleaseCommand = cli.Command{
@ -55,10 +56,11 @@ your SSH keys configured on your account.`,
internal.PublishFlag, internal.PublishFlag,
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipe := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(cmd)
imagesTmp, err := getImageVersions(recipe) imagesTmp, err := getImageVersions(recipe)
if err != nil { if err != nil {
@ -75,7 +77,7 @@ your SSH keys configured on your account.`,
log.Fatalf("main app service version for %s is empty?", recipe.Name) log.Fatalf("main app service version for %s is empty?", recipe.Name)
} }
tagString := c.Args().Get(1) tagString := cmd.Args().Get(1)
if tagString != "" { if tagString != "" {
if _, err := tagcmp.Parse(tagString); err != nil { if _, err := tagcmp.Parse(tagString); err != nil {
log.Fatalf("cannot parse %s, invalid tag specified?", tagString) log.Fatalf("cannot parse %s, invalid tag specified?", tagString)

View File

@ -1,12 +1,14 @@
package recipe package recipe
import ( import (
"context"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeResetCommand = cli.Command{ var recipeResetCommand = cli.Command{
@ -19,14 +21,15 @@ var recipeResetCommand = cli.Command{
internal.DebugFlag, internal.DebugFlag,
internal.NoInputFlag, internal.NoInputFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipeName := c.Args().First() Action: func(ctx context.Context, cmd *cli.Command) error {
recipeName := cmd.Args().First()
r := recipe.Get(recipeName) r := recipe.Get(recipeName)
if recipeName != "" { if recipeName != "" {
internal.ValidateRecipe(c) internal.ValidateRecipe(cmd)
} }
repo, err := git.PlainOpen(r.Dir) repo, err := git.PlainOpen(r.Dir)

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"context"
"fmt" "fmt"
"strconv" "strconv"
@ -12,7 +13,7 @@ import (
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var recipeSyncCommand = cli.Command{ var recipeSyncCommand = cli.Command{
@ -38,9 +39,10 @@ named "app") which corresponds to the following format:
Where <version> can be specifed on the command-line or Abra can attempt to Where <version> can be specifed on the command-line or Abra can attempt to
auto-generate it for you. The <recipe> configuration will be updated on the auto-generate it for you. The <recipe> configuration will be updated on the
local file system.`, local file system.`,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipe := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(cmd)
mainApp, err := internal.GetMainAppImage(recipe) mainApp, err := internal.GetMainAppImage(recipe)
if err != nil { if err != nil {
@ -59,7 +61,7 @@ local file system.`,
log.Fatal(err) log.Fatal(err)
} }
nextTag := c.Args().Get(1) nextTag := cmd.Args().Get(1)
if len(tags) == 0 && nextTag == "" { if len(tags) == 0 && nextTag == "" {
log.Warnf("no git tags found for %s", recipe.Name) log.Warnf("no git tags found for %s", recipe.Name)
if internal.NoInput { if internal.NoInput {

View File

@ -2,6 +2,7 @@ package recipe
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -19,7 +20,7 @@ import (
"coopcloud.tech/tagcmp" "coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/distribution/reference" "github.com/distribution/reference"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
type imgPin struct { type imgPin struct {
@ -68,10 +69,11 @@ EXAMPLE:
internal.MachineReadableFlag, internal.MachineReadableFlag,
internal.AllTagsFlag, internal.AllTagsFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipe := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(cmd)
if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil { if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,6 +1,7 @@
package recipe package recipe
import ( import (
"context"
"fmt" "fmt"
"sort" "sort"
@ -10,7 +11,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
recipePkg "coopcloud.tech/abra/pkg/recipe" recipePkg "coopcloud.tech/abra/pkg/recipe"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
func sortServiceByName(versions [][]string) func(i, j int) bool { func sortServiceByName(versions [][]string) func(i, j int) bool {
@ -34,10 +35,11 @@ var recipeVersionCommand = cli.Command{
internal.NoInputFlag, internal.NoInputFlag,
internal.MachineReadableFlag, internal.MachineReadableFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.RecipeNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.RecipeNameComplete,
recipe := internal.ValidateRecipe(c) Action: func(ctx context.Context, cmd *cli.Command) error {
recipe := internal.ValidateRecipe(cmd)
catl, err := recipePkg.ReadRecipeCatalogue(internal.Offline) catl, err := recipePkg.ReadRecipeCatalogue(internal.Offline)
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package server package server
import ( import (
"context"
"errors" "errors"
"os" "os"
"path/filepath" "path/filepath"
@ -13,7 +14,7 @@ import (
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/server" "coopcloud.tech/abra/pkg/server"
sshPkg "coopcloud.tech/abra/pkg/ssh" sshPkg "coopcloud.tech/abra/pkg/ssh"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var local bool var local bool
@ -131,17 +132,17 @@ of your ~/.ssh/config. Checks for a valid online domain will be skipped:
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
ArgsUsage: "<name>", ArgsUsage: "<name>",
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
if c.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(c) { if cmd.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(cmd) {
err := errors.New("cannot use <name> and --local together") err := errors.New("cannot use <name> and --local together")
internal.ShowSubcommandHelpAndError(c, err) internal.ShowSubcommandHelpAndError(cmd, err)
} }
var name string var name string
if local { if local {
name = "default" name = "default"
} else { } else {
name = internal.ValidateDomain(c) name = internal.ValidateDomain(cmd)
} }
// NOTE(d1): reasonable 5 second timeout for connections which can't // NOTE(d1): reasonable 5 second timeout for connections which can't

View File

@ -1,15 +1,16 @@
package server package server
import ( import (
"context"
"strings" "strings"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/context" contextPkg "coopcloud.tech/abra/pkg/context"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/docker/cli/cli/connhelper/ssh" "github.com/docker/cli/cli/connhelper/ssh"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var serverListCommand = cli.Command{ var serverListCommand = cli.Command{
@ -22,8 +23,8 @@ var serverListCommand = cli.Command{
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
dockerContextStore := context.NewDefaultDockerContextStore() dockerContextStore := contextPkg.NewDefaultDockerContextStore()
contexts, err := dockerContextStore.Store.List() contexts, err := dockerContextStore.Store.List()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -39,14 +40,14 @@ var serverListCommand = cli.Command{
for _, serverName := range serverNames { for _, serverName := range serverNames {
var row []string var row []string
for _, ctx := range contexts { for _, dockerCtx := range contexts {
endpoint, err := context.GetContextEndpoint(ctx) endpoint, err := contextPkg.GetContextEndpoint(dockerCtx)
if err != nil && strings.Contains(err.Error(), "does not exist") { if err != nil && strings.Contains(err.Error(), "does not exist") {
// No local context found, we can continue safely // No local context found, we can continue safely
continue continue
} }
if ctx.Name == serverName { if dockerCtx.Name == serverName {
sp, err := ssh.ParseURL(endpoint) sp, err := ssh.ParseURL(endpoint)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -9,7 +9,7 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var allFilter bool var allFilter bool
@ -47,10 +47,11 @@ app. This can result in unwanted data loss if not used carefully.`,
internal.OfflineFlag, internal.OfflineFlag,
internal.NoInputFlag, internal.NoInputFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.ServerNameComplete,
serverName := internal.ValidateServer(c) Action: func(ctx context.Context, cmd *cli.Command) error {
serverName := internal.ValidateServer(cmd)
cl, err := client.New(serverName) cl, err := client.New(serverName)
if err != nil { if err != nil {
@ -59,7 +60,6 @@ app. This can result in unwanted data loss if not used carefully.`,
var args filters.Args var args filters.Args
ctx := context.Background()
cr, err := cl.ContainersPrune(ctx, args) cr, err := cl.ContainersPrune(ctx, args)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,6 +1,7 @@
package server package server
import ( import (
"context"
"os" "os"
"path/filepath" "path/filepath"
@ -9,7 +10,7 @@ import (
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
var serverRemoveCommand = cli.Command{ var serverRemoveCommand = cli.Command{
@ -28,10 +29,11 @@ rain.`,
internal.NoInputFlag, internal.NoInputFlag,
internal.OfflineFlag, internal.OfflineFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete, EnableShellCompletion: true,
Action: func(c *cli.Context) error { ShellComplete: autocomplete.ServerNameComplete,
serverName := internal.ValidateServer(c) Action: func(ctx context.Context, cmd *cli.Command) error {
serverName := internal.ValidateServer(cmd)
if err := client.DeleteContext(serverName); err != nil { if err := client.DeleteContext(serverName); err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -1,7 +1,7 @@
package server package server
import ( import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// ServerCommand defines the `abra server` command and its subcommands // ServerCommand defines the `abra server` command and its subcommands
@ -9,7 +9,7 @@ var ServerCommand = cli.Command{
Name: "server", Name: "server",
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "Manage servers", Usage: "Manage servers",
Subcommands: []*cli.Command{ Commands: []*cli.Command{
&serverAddCommand, &serverAddCommand,
&serverListCommand, &serverListCommand,
&serverRemoveCommand, &serverRemoveCommand,

View File

@ -23,7 +23,7 @@ import (
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
const SERVER = "localhost" const SERVER = "localhost"
@ -62,7 +62,7 @@ catalogue.
If a new patch/minor version is available, a notification is printed. If a new patch/minor version is available, a notification is printed.
Use "--major" to include new major versions.`, Use "--major" to include new major versions.`,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
cl, err := client.New("default") cl, err := client.New("default")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -118,15 +118,15 @@ available, the app is upgraded.
To include major versions use the "--major" flag. You probably don't want that To include major versions use the "--major" flag. You probably don't want that
as it will break things. Only apps that are not deployed with "--chaos" are as it will break things. Only apps that are not deployed with "--chaos" are
upgraded, to update chaos deployments use the "--chaos" flag. Use it with care.`, upgraded, to update chaos deployments use the "--chaos" flag. Use it with care.`,
Action: func(c *cli.Context) error { Action: func(ctx context.Context, cmd *cli.Command) error {
cl, err := client.New("default") cl, err := client.New("default")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if !updateAll { if !updateAll {
stackName := c.Args().Get(0) stackName := cmd.Args().Get(0)
recipeName := c.Args().Get(1) recipeName := cmd.Args().Get(1)
err = tryUpgrade(cl, stackName, recipeName) err = tryUpgrade(cl, stackName, recipeName)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -470,8 +470,8 @@ func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion stri
return err return err
} }
func newAbraApp(version, commit string) *cli.App { func newAbraApp(version, commit string) *cli.Command {
app := &cli.App{ app := &cli.Command{
Name: "kadabra", Name: "kadabra",
Usage: `The Co-op Cloud auto-updater Usage: `The Co-op Cloud auto-updater
____ ____ _ _ ____ ____ _ _
@ -488,7 +488,7 @@ func newAbraApp(version, commit string) *cli.App {
}, },
} }
app.Before = func(c *cli.Context) error { app.Before = func(ctx context.Context, cmd *cli.Command) error {
charmLog.SetDefault(log.Logger) charmLog.SetDefault(log.Logger)
log.Debugf("kadabra version %s, commit %s", version, commit) log.Debugf("kadabra version %s, commit %s", version, commit)
return nil return nil
@ -501,7 +501,7 @@ func newAbraApp(version, commit string) *cli.App {
func RunApp(version, commit string) { func RunApp(version, commit string) {
app := newAbraApp(version, commit) app := newAbraApp(version, commit)
if err := app.Run(os.Args); err != nil { if err := app.Run(context.Background(), os.Args); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }

7
go.mod
View File

@ -2,6 +2,8 @@ module coopcloud.tech/abra
go 1.21 go 1.21
replace github.com/urfave/cli/v3 => github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42
require ( require (
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355 git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
@ -18,7 +20,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/schollz/progressbar/v3 v3.14.4 github.com/schollz/progressbar/v3 v3.14.4
github.com/urfave/cli/v2 v2.27.2 github.com/urfave/cli/v3 v3.0.0-alpha9
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.5.1 gotest.tools/v3 v3.5.1
) )
@ -37,7 +39,6 @@ require (
github.com/charmbracelet/x/ansi v0.1.2 // indirect github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/cloudflare/circl v1.3.9 // indirect github.com/cloudflare/circl v1.3.9 // indirect
github.com/containerd/log v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect
@ -85,14 +86,12 @@ require (
github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect github.com/skeema/knownhosts v1.2.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect

8
go.sum
View File

@ -273,7 +273,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -356,6 +355,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42 h1:yId1d3b2PHJ9vnYCxojs9NslXYVQ1iv7svK/CuDRoU0=
github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42/go.mod h1:Z1ItyMma7t6I7zHG9OpbExhHQOSkFf/96n+mAZ9MtVI=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -802,7 +803,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@ -886,8 +886,6 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
@ -909,8 +907,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=

View File

@ -1,22 +1,23 @@
package autocomplete package autocomplete
import ( import (
"context"
"fmt" "fmt"
"coopcloud.tech/abra/pkg/app" "coopcloud.tech/abra/pkg/app"
"coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v3"
) )
// AppNameComplete copletes app names. // AppNameComplete copletes app names.
func AppNameComplete(c *cli.Context) { func AppNameComplete(ctx context.Context, cmd *cli.Command) {
appNames, err := app.GetAppNames() appNames, err := app.GetAppNames()
if err != nil { if err != nil {
log.Warn(err) log.Warn(err)
} }
if c.NArg() > 0 { if cmd.NArg() > 0 {
return return
} }
@ -36,13 +37,13 @@ func ServiceNameComplete(appName string) {
} }
// RecipeNameComplete completes recipe names. // RecipeNameComplete completes recipe names.
func RecipeNameComplete(c *cli.Context) { func RecipeNameComplete(ctx context.Context, cmd *cli.Command) {
catl, err := recipe.ReadRecipeCatalogue(false) catl, err := recipe.ReadRecipeCatalogue(false)
if err != nil { if err != nil {
log.Warn(err) log.Warn(err)
} }
if c.NArg() > 0 { if cmd.NArg() > 0 {
return return
} }
@ -66,13 +67,13 @@ func RecipeVersionComplete(recipeName string) {
} }
// ServerNameComplete completes server names. // ServerNameComplete completes server names.
func ServerNameComplete(c *cli.Context) { func ServerNameComplete(ctx context.Context, cmd *cli.Command) {
files, err := app.LoadAppFiles("") files, err := app.LoadAppFiles("")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if c.NArg() > 0 { if cmd.NArg() > 0 {
return return
} }
@ -82,8 +83,8 @@ func ServerNameComplete(c *cli.Context) {
} }
// SubcommandComplete completes sub-commands. // SubcommandComplete completes sub-commands.
func SubcommandComplete(c *cli.Context) { func SubcommandComplete(ctx context.Context, cmd *cli.Command) {
if c.NArg() > 0 { if cmd.NArg() > 0 {
return return
} }