forked from toolshed/abra
		
	refactor: urfave v3
This commit is contained in:
		@ -1,15 +1,15 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AppCommand = cli.Command{
 | 
			
		||||
	Name:      "app",
 | 
			
		||||
	Aliases:   []string{"a"},
 | 
			
		||||
	Usage:     "Manage apps",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	Name:            "app",
 | 
			
		||||
	Aliases:         []string{"a"},
 | 
			
		||||
	Usage:           "Manage apps",
 | 
			
		||||
	UsageText:       "abra app [command] [options] [arguments]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&appBackupCommand,
 | 
			
		||||
		&appCheckCommand,
 | 
			
		||||
		&appCmdCommand,
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,14 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var snapshot string
 | 
			
		||||
@ -38,16 +39,16 @@ var appBackupListCommand = cli.Command{
 | 
			
		||||
	Name:    "list",
 | 
			
		||||
	Aliases: []string{"ls"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		snapshotFlag,
 | 
			
		||||
		includePathFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "List all backups",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "List all backups",
 | 
			
		||||
	UsageText:     "abra app backup list <domain> [options]",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -85,16 +86,16 @@ var appBackupDownloadCommand = cli.Command{
 | 
			
		||||
	Name:    "download",
 | 
			
		||||
	Aliases: []string{"d"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		snapshotFlag,
 | 
			
		||||
		includePathFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "Download a backup",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "Download a backup",
 | 
			
		||||
	UsageText:     "abra app backup download <domain> [options]",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.EnsureExists(); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -156,15 +157,15 @@ var appBackupCreateCommand = cli.Command{
 | 
			
		||||
	Name:    "create",
 | 
			
		||||
	Aliases: []string{"c"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		resticRepoFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "Create a new backup",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "Create a new backup",
 | 
			
		||||
	UsageText:     "abra app backup create <domain> [options]",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.EnsureExists(); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -214,15 +215,15 @@ var appBackupSnapshotsCommand = cli.Command{
 | 
			
		||||
	Name:    "snapshots",
 | 
			
		||||
	Aliases: []string{"s"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		snapshotFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "List backup snapshots",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "List backup snapshots",
 | 
			
		||||
	UsageText:     "abra app backup snapshots <domain> [options]",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.EnsureExists(); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -272,8 +273,8 @@ var appBackupCommand = cli.Command{
 | 
			
		||||
	Name:      "backup",
 | 
			
		||||
	Aliases:   []string{"b"},
 | 
			
		||||
	Usage:     "Manage app backups",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	UsageText: "abra app backup [command] [arguments] [options]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&appBackupListCommand,
 | 
			
		||||
		&appBackupSnapshotsCommand,
 | 
			
		||||
		&appBackupDownloadCommand,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
@ -9,16 +10,15 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/charmbracelet/lipgloss"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appCheckCommand = cli.Command{
 | 
			
		||||
	Name:    "check",
 | 
			
		||||
	Aliases: []string{"chk"},
 | 
			
		||||
	Usage:   "Ensure an app is well configured",
 | 
			
		||||
	Description: `
 | 
			
		||||
This command compares env vars in both the app ".env" and recipe ".env.sample"
 | 
			
		||||
file.
 | 
			
		||||
	Name:      "check",
 | 
			
		||||
	Aliases:   []string{"chk"},
 | 
			
		||||
	UsageText: "abra app check <domain> [options]",
 | 
			
		||||
	Usage:     "Ensure an app is well configured",
 | 
			
		||||
	Description: `Compare env vars in both the app ".env" and recipe ".env.sample" file.
 | 
			
		||||
 | 
			
		||||
The goal is to ensure that recipe ".env.sample" env vars are defined in your
 | 
			
		||||
app ".env" file. Only env var definitions in the ".env.sample" which are
 | 
			
		||||
@ -28,16 +28,15 @@ these env vars, then "check" will complain.
 | 
			
		||||
Recipe maintainers may or may not provide defaults for env vars within their
 | 
			
		||||
recipes regardless of commenting or not (e.g. through the use of
 | 
			
		||||
${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
@ -14,61 +15,53 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appCmdCommand = cli.Command{
 | 
			
		||||
	Name:    "command",
 | 
			
		||||
	Aliases: []string{"cmd"},
 | 
			
		||||
	Usage:   "Run app commands",
 | 
			
		||||
	Name:      "command",
 | 
			
		||||
	Aliases:   []string{"cmd"},
 | 
			
		||||
	Usage:     "Run app commands",
 | 
			
		||||
	UsageText: "abra app cmd <domain> [<service>] <cmd> [<cmd-args>] [options]",
 | 
			
		||||
	Description: `Run an app specific command.
 | 
			
		||||
 | 
			
		||||
These commands are bash functions, defined in the abra.sh of the recipe itself.
 | 
			
		||||
They can be run within the context of a service (e.g. app) or locally on your
 | 
			
		||||
work station by passing "--local". Arguments can be passed into these functions
 | 
			
		||||
using the "-- <args>" syntax.
 | 
			
		||||
 | 
			
		||||
**WARNING**: options must be passed directly after the sub-command "cmd".
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
  abra app cmd --local example.com app create_user -- me@example.com`,
 | 
			
		||||
	ArgsUsage: "<domain> [<service>] <command> [-- <args>]",
 | 
			
		||||
work station by passing "--local".`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.LocalCmdFlag,
 | 
			
		||||
		internal.RemoteUserFlag,
 | 
			
		||||
		internal.TtyFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&appCmdListCommand,
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: func(ctx *cli.Context) {
 | 
			
		||||
		args := ctx.Args()
 | 
			
		||||
	ShellComplete: func(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
		args := cmd.Args()
 | 
			
		||||
		switch args.Len() {
 | 
			
		||||
		case 0:
 | 
			
		||||
			autocomplete.AppNameComplete(ctx)
 | 
			
		||||
			autocomplete.AppNameComplete(ctx, cmd)
 | 
			
		||||
		case 1:
 | 
			
		||||
			autocomplete.ServiceNameComplete(args.Get(0))
 | 
			
		||||
		case 2:
 | 
			
		||||
			cmdNameComplete(args.Get(0))
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		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 {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 os.IsNotExist(err) {
 | 
			
		||||
@ -78,11 +71,11 @@ EXAMPLE:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if internal.LocalCmd {
 | 
			
		||||
			if !(c.Args().Len() >= 2) {
 | 
			
		||||
				internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments"))
 | 
			
		||||
			if !(cmd.Args().Len() >= 2) {
 | 
			
		||||
				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 {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
@ -114,13 +107,13 @@ EXAMPLE:
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if !(c.Args().Len() >= 3) {
 | 
			
		||||
				internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments"))
 | 
			
		||||
			if !(cmd.Args().Len() >= 3) {
 | 
			
		||||
				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 {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
@ -200,16 +193,16 @@ var appCmdListCommand = cli.Command{
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	Usage:     "List all available commands",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	UsageText: "abra app cmd ls <domain> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		r := recipe.Get(app.Recipe.Name)
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.EnsureExists(); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
@ -10,24 +11,22 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appConfigCommand = cli.Command{
 | 
			
		||||
	Name:      "config",
 | 
			
		||||
	Aliases:   []string{"cfg"},
 | 
			
		||||
	Usage:     "Edit app config",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		appName := c.Args().First()
 | 
			
		||||
	Name:          "config",
 | 
			
		||||
	Aliases:       []string{"cfg"},
 | 
			
		||||
	Usage:         "Edit app config",
 | 
			
		||||
	UsageText:     "abra app config <domain> [options]",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		appName := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
		if appName == "" {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no app provided"))
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		files, err := appPkg.LoadAppFiles("")
 | 
			
		||||
@ -51,11 +50,11 @@ var appConfigCommand = cli.Command{
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cmd := exec.Command(ed, appFile.Path)
 | 
			
		||||
		cmd.Stdin = os.Stdin
 | 
			
		||||
		cmd.Stdout = os.Stdout
 | 
			
		||||
		cmd.Stderr = os.Stderr
 | 
			
		||||
		if err := cmd.Run(); err != nil {
 | 
			
		||||
		c := exec.Command(ed, appFile.Path)
 | 
			
		||||
		c.Stdin = os.Stdin
 | 
			
		||||
		c.Stdout = os.Stdout
 | 
			
		||||
		c.Stderr = os.Stderr
 | 
			
		||||
		if err := c.Run(); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,21 +22,16 @@ import (
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/docker/docker/errdefs"
 | 
			
		||||
	"github.com/docker/docker/pkg/archive"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appCpCommand = cli.Command{
 | 
			
		||||
	Name:      "cp",
 | 
			
		||||
	Aliases:   []string{"c"},
 | 
			
		||||
	ArgsUsage: "<domain> <src> <dst>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Usage:  "Copy files to/from a deployed app service",
 | 
			
		||||
	Description: `
 | 
			
		||||
Copy files to and from any app service file system.
 | 
			
		||||
	Before:    internal.SubCommandBefore,
 | 
			
		||||
	Usage:     "Copy files to/from a deployed app service",
 | 
			
		||||
	UsageText: "abra app cp <domain> <src> <dst> [options]",
 | 
			
		||||
	Description: `Copy files to and from any app service file system.
 | 
			
		||||
 | 
			
		||||
If you want to copy a myfile.txt to the root of the app service:
 | 
			
		||||
 | 
			
		||||
@ -44,18 +39,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:
 | 
			
		||||
 | 
			
		||||
    abra app cp <domain> app:/myfile.txt .
 | 
			
		||||
`,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
 | 
			
		||||
    abra app cp <domain> app:/myfile.txt`,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		src := c.Args().Get(1)
 | 
			
		||||
		dst := c.Args().Get(2)
 | 
			
		||||
		src := cmd.Args().Get(1)
 | 
			
		||||
		dst := cmd.Args().Get(2)
 | 
			
		||||
		if src == "" {
 | 
			
		||||
			log.Fatal("missing <src> argument")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -17,22 +17,19 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/lint"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appDeployCommand = cli.Command{
 | 
			
		||||
	Name:      "deploy",
 | 
			
		||||
	Aliases:   []string{"d"},
 | 
			
		||||
	Usage:     "Deploy an app",
 | 
			
		||||
	ArgsUsage: "<domain> [<version>]",
 | 
			
		||||
	UsageText: "abra app deploy <domain> [<version>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.ForceFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		internal.NoDomainChecksFlag,
 | 
			
		||||
		internal.DontWaitConvergeFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `Deploy an app.
 | 
			
		||||
@ -40,21 +37,20 @@ var appDeployCommand = cli.Command{
 | 
			
		||||
This command supports chaos operations. Use "--chaos" to deploy your recipe
 | 
			
		||||
checkout as-is. Recipe commit hashes are also supported values for
 | 
			
		||||
"[<version>]". Please note, "upgrade"/"rollback" do not support chaos
 | 
			
		||||
operations.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra app deploy foo.example.com
 | 
			
		||||
    abra app deploy foo.example.com 1.2.3+3.2.1
 | 
			
		||||
    abra app deploy foo.example.com 1e83340e`,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
operations.`,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		var warnMessages []string
 | 
			
		||||
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
 | 
			
		||||
		specificVersion := c.Args().Get(1)
 | 
			
		||||
		specificVersion := cmd.Args().Get(1)
 | 
			
		||||
		if specificVersion == "" {
 | 
			
		||||
			specificVersion = app.Recipe.Version
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if specificVersion != "" && internal.Chaos {
 | 
			
		||||
			log.Fatal("cannot use <version> and --chaos together")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
@ -12,7 +13,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/tagcmp"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@ -70,26 +71,24 @@ type serverStatus struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var appListCommand = cli.Command{
 | 
			
		||||
	Name:    "list",
 | 
			
		||||
	Aliases: []string{"ls"},
 | 
			
		||||
	Usage:   "List all managed apps",
 | 
			
		||||
	Description: `
 | 
			
		||||
Read the local file system listing of apps and servers (e.g. ~/.abra/) to
 | 
			
		||||
generate a report of all your apps.
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	Usage:     "List all managed apps",
 | 
			
		||||
	UsageText: "abra app list [options]",
 | 
			
		||||
	Description: `Generate a report of all managed apps.
 | 
			
		||||
 | 
			
		||||
By passing the "--status/-S" flag, you can query all your servers for the
 | 
			
		||||
actual live deployment status. Depending on how many servers you manage, this
 | 
			
		||||
can take some time.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		statusFlag,
 | 
			
		||||
		listAppServerFlag,
 | 
			
		||||
		recipeFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
	Before:   internal.SubCommandBefore,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		appFiles, err := appPkg.LoadAppFiles(listAppServer)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -19,23 +19,23 @@ import (
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	"github.com/docker/docker/api/types/swarm"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appLogsCommand = cli.Command{
 | 
			
		||||
	Name:      "logs",
 | 
			
		||||
	Aliases:   []string{"l"},
 | 
			
		||||
	ArgsUsage: "<domain> [<service>]",
 | 
			
		||||
	Usage:     "Tail app logs",
 | 
			
		||||
	UsageText: "abra app logs <domain> [<service>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.StdErrOnlyFlag,
 | 
			
		||||
		internal.SinceLogsFlag,
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
 | 
			
		||||
		if err := app.Recipe.EnsureExists(); err != nil {
 | 
			
		||||
@ -56,7 +56,7 @@ var appLogsCommand = cli.Command{
 | 
			
		||||
			log.Fatalf("%s is not deployed?", app.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		serviceName := c.Args().Get(1)
 | 
			
		||||
		serviceName := cmd.Args().Get(1)
 | 
			
		||||
		serviceNames := []string{}
 | 
			
		||||
		if serviceName != "" {
 | 
			
		||||
			serviceNames = []string{serviceName}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
@ -16,12 +17,13 @@ import (
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/charmbracelet/lipgloss/table"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appNewDescription = `
 | 
			
		||||
Creates a new app from a default recipe. This new app configuration is stored
 | 
			
		||||
in your $ABRA_DIR directory under the appropriate server.
 | 
			
		||||
var appNewDescription = `Creates a new app from a default recipe.
 | 
			
		||||
 | 
			
		||||
This new app configuration is stored in your $ABRA_DIR directory under the
 | 
			
		||||
appropriate server.
 | 
			
		||||
 | 
			
		||||
This command does not deploy your app for you. You will need to run "abra app
 | 
			
		||||
deploy <domain>" to do so.
 | 
			
		||||
@ -44,30 +46,28 @@ var appNewCommand = cli.Command{
 | 
			
		||||
	Name:        "new",
 | 
			
		||||
	Aliases:     []string{"n"},
 | 
			
		||||
	Usage:       "Create a new app",
 | 
			
		||||
	UsageText:   "abra app new [<recipe>] [<version>] [options]",
 | 
			
		||||
	Description: appNewDescription,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.NewAppServerFlag,
 | 
			
		||||
		internal.DomainFlag,
 | 
			
		||||
		internal.PassFlag,
 | 
			
		||||
		internal.SecretsFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:    internal.SubCommandBefore,
 | 
			
		||||
	ArgsUsage: "[<recipe>] [<version>]",
 | 
			
		||||
	BashComplete: func(ctx *cli.Context) {
 | 
			
		||||
		args := ctx.Args()
 | 
			
		||||
	Before:   internal.SubCommandBefore,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	ShellComplete: func(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
		args := cmd.Args()
 | 
			
		||||
		switch args.Len() {
 | 
			
		||||
		case 0:
 | 
			
		||||
			autocomplete.RecipeNameComplete(ctx)
 | 
			
		||||
			autocomplete.RecipeNameComplete(ctx, cmd)
 | 
			
		||||
		case 1:
 | 
			
		||||
			autocomplete.RecipeVersionComplete(ctx.Args().Get(0))
 | 
			
		||||
			autocomplete.RecipeVersionComplete(cmd.Args().Get(0))
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		var version string
 | 
			
		||||
		if !internal.Chaos {
 | 
			
		||||
@ -80,7 +80,7 @@ var appNewCommand = cli.Command{
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if c.Args().Get(1) == "" {
 | 
			
		||||
			if cmd.Args().Get(1) == "" {
 | 
			
		||||
				recipeVersions, err := recipe.GetRecipeVersions()
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Fatal(err)
 | 
			
		||||
@ -101,7 +101,7 @@ var appNewCommand = cli.Command{
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				version = c.Args().Get(1)
 | 
			
		||||
				version = cmd.Args().Get(1)
 | 
			
		||||
				if _, err := recipe.EnsureVersion(version); err != nil {
 | 
			
		||||
					log.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@ -18,25 +18,25 @@ import (
 | 
			
		||||
	containerTypes "github.com/docker/docker/api/types/container"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appPsCommand = cli.Command{
 | 
			
		||||
	Name:        "ps",
 | 
			
		||||
	Aliases:     []string{"p"},
 | 
			
		||||
	Usage:       "Check app status",
 | 
			
		||||
	ArgsUsage:   "<domain>",
 | 
			
		||||
	UsageText:   "abra app ps <domain> [options]",
 | 
			
		||||
	Description: "Show status of a deployed app.",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -12,16 +12,15 @@ import (
 | 
			
		||||
	stack "coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appRemoveCommand = cli.Command{
 | 
			
		||||
	Name:      "remove",
 | 
			
		||||
	Aliases:   []string{"rm"},
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	UsageText: "abra app remove <domain> [options]",
 | 
			
		||||
	Usage:     "Remove all app data, locally and remotely",
 | 
			
		||||
	Description: `
 | 
			
		||||
This command removes everything related to an app which is already undeployed.
 | 
			
		||||
	Description: `Remove everything related to an app which is already undeployed.
 | 
			
		||||
 | 
			
		||||
By default, it will prompt for confirmation before proceeding. All secrets,
 | 
			
		||||
volumes and the local app env file will be deleted.
 | 
			
		||||
@ -39,14 +38,12 @@ To delete everything without prompt, use the "--force/-f" or the "--no-input/n"
 | 
			
		||||
flag.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.ForceFlag,
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if !internal.Force && !internal.NoInput {
 | 
			
		||||
			log.Warnf("ALERTA ALERTA: this will completely remove %s data and config locally and remotely", app.Name)
 | 
			
		||||
 | 
			
		||||
@ -12,41 +12,35 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	upstream "coopcloud.tech/abra/pkg/upstream/service"
 | 
			
		||||
	stack "coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appRestartCommand = cli.Command{
 | 
			
		||||
	Name:      "restart",
 | 
			
		||||
	Aliases:   []string{"re"},
 | 
			
		||||
	Usage:     "Restart an app",
 | 
			
		||||
	ArgsUsage: "<domain> [<service>]",
 | 
			
		||||
	UsageText: "abra app restart <domain> [<service>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.AllServicesFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
This command restarts services within a deployed app.
 | 
			
		||||
	Description: `This command restarts services within a deployed app.
 | 
			
		||||
 | 
			
		||||
Run "abra app ps <domain>" to see a list of service names.
 | 
			
		||||
 | 
			
		||||
Pass "--all-services/-a" to restart all services.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra app restart example.com app`,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
Pass "--all-services/-a" to restart all services.`,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(false, false); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		serviceName := c.Args().Get(1)
 | 
			
		||||
		serviceName := cmd.Args().Get(1)
 | 
			
		||||
		if serviceName == "" && !internal.AllServices {
 | 
			
		||||
			err := errors.New("missing <service>")
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, err)
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if serviceName != "" && internal.AllServices {
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,14 @@
 | 
			
		||||
package app
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var targetPath string
 | 
			
		||||
@ -22,16 +23,15 @@ var appRestoreCommand = cli.Command{
 | 
			
		||||
	Name:      "restore",
 | 
			
		||||
	Aliases:   []string{"rs"},
 | 
			
		||||
	Usage:     "Restore an app backup",
 | 
			
		||||
	ArgsUsage: "<domain> <service>",
 | 
			
		||||
	UsageText: "abra app restore <domain> <service> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		targetPathFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -16,44 +16,36 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appRollbackCommand = cli.Command{
 | 
			
		||||
	Name:      "rollback",
 | 
			
		||||
	Aliases:   []string{"rl"},
 | 
			
		||||
	Usage:     "Roll an app back to a previous version",
 | 
			
		||||
	ArgsUsage: "<domain> [<version>]",
 | 
			
		||||
	UsageText: "abra app rollback <domain> [<version>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.ForceFlag,
 | 
			
		||||
		internal.NoDomainChecksFlag,
 | 
			
		||||
		internal.DontWaitConvergeFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
This command rolls an app back to a previous version.
 | 
			
		||||
	Description: `This command rolls an app back to a previous version.
 | 
			
		||||
 | 
			
		||||
Unlike "deploy", chaos operations are not supported here. Only recipe versions
 | 
			
		||||
are supported values for "[<version>]".
 | 
			
		||||
 | 
			
		||||
A rollback can be destructive, please ensure you have a copy of your app data
 | 
			
		||||
beforehand.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra app rollback foo.example.com
 | 
			
		||||
    abra app rollback foo.example.com 1.2.3+3.2.1`,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
beforehand.`,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		var warnMessages []string
 | 
			
		||||
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
 | 
			
		||||
		specificVersion := c.Args().Get(1)
 | 
			
		||||
		specificVersion := cmd.Args().Get(1)
 | 
			
		||||
		if specificVersion != "" {
 | 
			
		||||
			log.Debugf("overriding env file version (%s) with %s", app.Recipe.Version, specificVersion)
 | 
			
		||||
			app.Recipe.Version = specificVersion
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ import (
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var user string
 | 
			
		||||
@ -36,23 +36,23 @@ var appRunCommand = cli.Command{
 | 
			
		||||
	Name:    "run",
 | 
			
		||||
	Aliases: []string{"r"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		noTTYFlag,
 | 
			
		||||
		userFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	ArgsUsage:    "<domain> <service> <args>...",
 | 
			
		||||
	Usage:        "Run a command in a service container",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "Run a command in an app service",
 | 
			
		||||
	UsageText:     "abra app run <domain> <service> <args> [options]",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		if c.Args().Len() < 2 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
 | 
			
		||||
		if cmd.Args().Len() < 2 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("no <service> provided?"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Args().Len() < 3 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?"))
 | 
			
		||||
		if cmd.Args().Len() < 3 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("no <args> provided?"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
@ -60,7 +60,7 @@ var appRunCommand = cli.Command{
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		serviceName := c.Args().Get(1)
 | 
			
		||||
		serviceName := cmd.Args().Get(1)
 | 
			
		||||
		stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), serviceName)
 | 
			
		||||
		filters := filters.NewArgs()
 | 
			
		||||
		filters.Add("name", stackAndServiceName)
 | 
			
		||||
@ -70,12 +70,12 @@ var appRunCommand = cli.Command{
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cmd := c.Args().Slice()[2:]
 | 
			
		||||
		c := cmd.Args().Slice()[2:]
 | 
			
		||||
		execCreateOpts := types.ExecConfig{
 | 
			
		||||
			AttachStderr: true,
 | 
			
		||||
			AttachStdin:  true,
 | 
			
		||||
			AttachStdout: true,
 | 
			
		||||
			Cmd:          cmd,
 | 
			
		||||
			Cmd:          c,
 | 
			
		||||
			Detach:       false,
 | 
			
		||||
			Tty:          true,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/secret"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@ -44,31 +44,30 @@ var appSecretGenerateCommand = cli.Command{
 | 
			
		||||
	Name:      "generate",
 | 
			
		||||
	Aliases:   []string{"g"},
 | 
			
		||||
	Usage:     "Generate secrets",
 | 
			
		||||
	ArgsUsage: "<domain> <secret> <version>",
 | 
			
		||||
	UsageText: "abra app secret generate <domain> <secret> <version> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		allSecretsFlag,
 | 
			
		||||
		internal.PassFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Args().Len() == 1 && !allSecrets {
 | 
			
		||||
		if cmd.Args().Len() == 1 && !allSecrets {
 | 
			
		||||
			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")
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, err)
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
 | 
			
		||||
@ -82,8 +81,8 @@ var appSecretGenerateCommand = cli.Command{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !allSecrets {
 | 
			
		||||
			secretName := c.Args().Get(1)
 | 
			
		||||
			secretVersion := c.Args().Get(2)
 | 
			
		||||
			secretName := cmd.Args().Get(1)
 | 
			
		||||
			secretVersion := cmd.Args().Get(2)
 | 
			
		||||
			s, ok := secrets[secretName]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				log.Fatalf("%s doesn't exist in the env config?", secretName)
 | 
			
		||||
@ -154,39 +153,32 @@ var appSecretGenerateCommand = cli.Command{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var appSecretInsertCommand = cli.Command{
 | 
			
		||||
	Name:    "insert",
 | 
			
		||||
	Aliases: []string{"i"},
 | 
			
		||||
	Usage:   "Insert secret",
 | 
			
		||||
	Name:      "insert",
 | 
			
		||||
	Aliases:   []string{"i"},
 | 
			
		||||
	Usage:     "Insert secret",
 | 
			
		||||
	UsageText: "abra app secret insert <domain> <secret> <version> <data> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.PassFlag,
 | 
			
		||||
		internal.FileFlag,
 | 
			
		||||
		internal.TrimFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	ArgsUsage:    "<domain> <secret-name> <version> <data>",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Description: `
 | 
			
		||||
This command inserts a secret into an app environment.
 | 
			
		||||
	Before:          internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete:   autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelpCommand: true,
 | 
			
		||||
	Description: `This command inserts a secret into an app environment.
 | 
			
		||||
 | 
			
		||||
This can be useful when you want to manually generate secrets for an app
 | 
			
		||||
environment. Typically, you can let Abra generate them for you on app creation
 | 
			
		||||
(see "abra app new --secrets" for more).
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
    abra app secret insert myapp db_pass v1 mySecretPassword
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
(see "abra app new --secrets" for more).`,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Args().Len() != 4 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?"))
 | 
			
		||||
		if cmd.Args().Len() != 4 {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments?"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
@ -194,9 +186,9 @@ Example:
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name := c.Args().Get(1)
 | 
			
		||||
		version := c.Args().Get(2)
 | 
			
		||||
		data := c.Args().Get(3)
 | 
			
		||||
		name := cmd.Args().Get(1)
 | 
			
		||||
		version := cmd.Args().Get(2)
 | 
			
		||||
		data := cmd.Args().Get(3)
 | 
			
		||||
 | 
			
		||||
		if internal.File {
 | 
			
		||||
			raw, err := os.ReadFile(data)
 | 
			
		||||
@ -247,29 +239,28 @@ func secretRm(cl *dockerClient.Client, app appPkg.App, secretName, parsed string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var appSecretRmCommand = cli.Command{
 | 
			
		||||
	Name:    "remove",
 | 
			
		||||
	Aliases: []string{"rm"},
 | 
			
		||||
	Usage:   "Remove a secret",
 | 
			
		||||
	Name:      "remove",
 | 
			
		||||
	Aliases:   []string{"rm"},
 | 
			
		||||
	Usage:     "Remove a secret",
 | 
			
		||||
	UsageText: "abra app remove <domainabra app remove <domain> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		rmAllSecretsFlag,
 | 
			
		||||
		internal.PassRemoveFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	ArgsUsage:    "<domain> [<secret-name>]",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Description: `
 | 
			
		||||
This command removes app secrets.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
    abra app secret remove myapp db_pass
 | 
			
		||||
`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
    abra app secret remove myapp db_pass`,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
@ -284,12 +275,12 @@ Example:
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Args().Get(1) != "" && rmAllSecrets {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("cannot use '<secret-name>' and '--all' together"))
 | 
			
		||||
		if cmd.Args().Get(1) != "" && rmAllSecrets {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("cannot use '<secret-name>' and '--all' together"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if c.Args().Get(1) == "" && !rmAllSecrets {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no secret(s) specified?"))
 | 
			
		||||
		if cmd.Args().Get(1) == "" && !rmAllSecrets {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("no secret(s) specified?"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
@ -313,7 +304,7 @@ Example:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		match := false
 | 
			
		||||
		secretToRm := c.Args().Get(1)
 | 
			
		||||
		secretToRm := cmd.Args().Get(1)
 | 
			
		||||
		for secretName, val := range secrets {
 | 
			
		||||
			secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, val.Version)
 | 
			
		||||
			if _, ok := remoteSecretNames[secretRemoteName]; ok {
 | 
			
		||||
@ -351,16 +342,17 @@ var appSecretLsCommand = cli.Command{
 | 
			
		||||
	Name:    "list",
 | 
			
		||||
	Aliases: []string{"ls"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "List all secrets",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "List all secrets",
 | 
			
		||||
	UsageText:     "abra app secret list [options]",
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
@ -420,8 +412,8 @@ var appSecretCommand = cli.Command{
 | 
			
		||||
	Name:      "secret",
 | 
			
		||||
	Aliases:   []string{"s"},
 | 
			
		||||
	Usage:     "Manage app secrets",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	UsageText: "abra app secret [command] [arguments] [options]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&appSecretGenerateCommand,
 | 
			
		||||
		&appSecretInsertCommand,
 | 
			
		||||
		&appSecretRmCommand,
 | 
			
		||||
 | 
			
		||||
@ -13,21 +13,19 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/service"
 | 
			
		||||
	stack "coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	containerTypes "github.com/docker/docker/api/types/container"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appServicesCommand = cli.Command{
 | 
			
		||||
	Name:      "services",
 | 
			
		||||
	Aliases:   []string{"sr"},
 | 
			
		||||
	Usage:     "Display all services of an app",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Name:          "services",
 | 
			
		||||
	Aliases:       []string{"sr"},
 | 
			
		||||
	Usage:         "Display all services of an app",
 | 
			
		||||
	UsageText:     "abra app services <domain> [options]",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ import (
 | 
			
		||||
	stack "coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var prune bool
 | 
			
		||||
@ -65,25 +65,24 @@ func pruneApp(cl *dockerClient.Client, app appPkg.App) error {
 | 
			
		||||
var appUndeployCommand = cli.Command{
 | 
			
		||||
	Name:      "undeploy",
 | 
			
		||||
	Aliases:   []string{"un"},
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	UsageText: "abra app undeploy <domain> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		pruneFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "Undeploy an app",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Description: `
 | 
			
		||||
This does not destroy any of the application data.
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "Undeploy an app",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Description: `This does not destroy any of the application data.
 | 
			
		||||
 | 
			
		||||
However, you should remain vigilant, as your swarm installation will consider
 | 
			
		||||
any previously attached volumes as eligible for pruning once undeployed.
 | 
			
		||||
 | 
			
		||||
Passing "-p/--prune" does not remove those volumes.`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
 | 
			
		||||
@ -15,45 +15,37 @@ import (
 | 
			
		||||
	stack "coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"coopcloud.tech/tagcmp"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appUpgradeCommand = cli.Command{
 | 
			
		||||
	Name:      "upgrade",
 | 
			
		||||
	Aliases:   []string{"up"},
 | 
			
		||||
	Usage:     "Upgrade an app",
 | 
			
		||||
	ArgsUsage: "<domain> [<version>]",
 | 
			
		||||
	UsageText: "abra app upgrade <domain> [<version>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.ForceFlag,
 | 
			
		||||
		internal.NoDomainChecksFlag,
 | 
			
		||||
		internal.DontWaitConvergeFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ReleaseNotesFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Upgrade an app.
 | 
			
		||||
	Description: `Upgrade an app.
 | 
			
		||||
 | 
			
		||||
Unlike "deploy", chaos operations are not supported here. Only recipe versions
 | 
			
		||||
are supported values for "[<version>]".
 | 
			
		||||
 | 
			
		||||
An upgrade can be destructive, please ensure you have a copy of your app data
 | 
			
		||||
beforehand.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra app upgrade foo.example.com
 | 
			
		||||
    abra app upgrade foo.example.com 1.2.3+3.2.1`,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
beforehand.`,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		var warnMessages []string
 | 
			
		||||
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
		stackName := app.StackName()
 | 
			
		||||
 | 
			
		||||
		specificVersion := c.Args().Get(1)
 | 
			
		||||
		specificVersion := cmd.Args().Get(1)
 | 
			
		||||
		if specificVersion != "" {
 | 
			
		||||
			log.Debugf("overriding env file version (%s) with %s", app.Recipe.Version, specificVersion)
 | 
			
		||||
			app.Recipe.Version = specificVersion
 | 
			
		||||
 | 
			
		||||
@ -11,22 +11,19 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/upstream/stack"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appVolumeListCommand = cli.Command{
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Usage:        "List volumes associated with an app",
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Name:          "list",
 | 
			
		||||
	Aliases:       []string{"ls"},
 | 
			
		||||
	UsageText:     "abra app volume list <domain> [options]",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	Usage:         "List volumes associated with an app",
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -74,27 +71,26 @@ var appVolumeListCommand = cli.Command{
 | 
			
		||||
var appVolumeRemoveCommand = cli.Command{
 | 
			
		||||
	Name:  "remove",
 | 
			
		||||
	Usage: "Remove volume(s) associated with an app",
 | 
			
		||||
	Description: `
 | 
			
		||||
This command supports removing volumes associated with an app. The app in
 | 
			
		||||
question must be undeployed before you try to remove volumes. See "abra app
 | 
			
		||||
undeploy <domain>" for more.
 | 
			
		||||
	Description: `Remove volumes associated with an app.
 | 
			
		||||
 | 
			
		||||
The app in question must be undeployed before you try to remove volumes. See
 | 
			
		||||
"abra app undeploy <domain>" for more.
 | 
			
		||||
 | 
			
		||||
The command is interactive and will show a multiple select input which allows
 | 
			
		||||
you to make a seclection. Use the "?" key to see more help on navigating this
 | 
			
		||||
interface.
 | 
			
		||||
 | 
			
		||||
Passing "--force/-f" will select all volumes for removal. Be careful.`,
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	UsageText: "abra app volume remove [options] <domain>",
 | 
			
		||||
	Aliases:   []string{"rm"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.ForceFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		app := internal.ValidateApp(cmd)
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(app.Server)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -158,8 +154,8 @@ var appVolumeCommand = cli.Command{
 | 
			
		||||
	Name:      "volume",
 | 
			
		||||
	Aliases:   []string{"vl"},
 | 
			
		||||
	Usage:     "Manage app volumes",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	UsageText: "abra app volume [command] [options] [arguments]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&appVolumeListCommand,
 | 
			
		||||
		&appVolumeRemoveCommand,
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package catalogue
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
@ -15,25 +16,22 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var catalogueGenerateCommand = cli.Command{
 | 
			
		||||
	Name:    "generate",
 | 
			
		||||
	Aliases: []string{"g"},
 | 
			
		||||
	Usage:   "Generate the recipe catalogue",
 | 
			
		||||
	Name:      "generate",
 | 
			
		||||
	Aliases:   []string{"g"},
 | 
			
		||||
	Usage:     "Generate the recipe catalogue",
 | 
			
		||||
	UsageText: "abra catalogue generate [<recipe>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.PublishFlag,
 | 
			
		||||
		internal.DryFlag,
 | 
			
		||||
		internal.SkipUpdatesFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Generate a new copy of the recipe catalogue.
 | 
			
		||||
	Description: `Generate a new copy of the recipe catalogue.
 | 
			
		||||
 | 
			
		||||
It is possible to generate new metadata for a single recipe by passing
 | 
			
		||||
<recipe>. The existing local catalogue will be updated, not overwritten.
 | 
			
		||||
@ -45,14 +43,14 @@ 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
 | 
			
		||||
that you have permission to git push to these repositories and have your SSH
 | 
			
		||||
keys configured on your account.`,
 | 
			
		||||
	ArgsUsage:    "[<recipe>]",
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipeName := cmd.Args().First()
 | 
			
		||||
		r := recipe.Get(recipeName)
 | 
			
		||||
 | 
			
		||||
		if recipeName != "" {
 | 
			
		||||
			internal.ValidateRecipe(c)
 | 
			
		||||
			internal.ValidateRecipe(cmd)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !internal.Chaos {
 | 
			
		||||
@ -208,8 +206,8 @@ var CatalogueCommand = cli.Command{
 | 
			
		||||
	Name:      "catalogue",
 | 
			
		||||
	Usage:     "Manage the recipe catalogue",
 | 
			
		||||
	Aliases:   []string{"c"},
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	UsageText: "abra catalogue [command] [options] [arguments]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&catalogueGenerateCommand,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										101
									
								
								cli/cli.go
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								cli/cli.go
									
									
									
									
									
								
							@ -2,6 +2,7 @@
 | 
			
		||||
package cli
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
@ -18,31 +19,24 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/web"
 | 
			
		||||
	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
 | 
			
		||||
var AutoCompleteCommand = cli.Command{
 | 
			
		||||
	Name:    "autocomplete",
 | 
			
		||||
	Aliases: []string{"ac"},
 | 
			
		||||
	Usage:   "Configure shell autocompletion",
 | 
			
		||||
	Description: `
 | 
			
		||||
Set up shell auto-completion.
 | 
			
		||||
	Name:      "autocomplete",
 | 
			
		||||
	Aliases:   []string{"ac"},
 | 
			
		||||
	Usage:     "Configure shell autocompletion",
 | 
			
		||||
	UsageText: "abra autocomplete <shell> [options]",
 | 
			
		||||
	Description: `Set up shell auto-completion.
 | 
			
		||||
 | 
			
		||||
Supported shells are: bash, fish, fizsh & zsh.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra autocomplete bash`,
 | 
			
		||||
	ArgsUsage: "<shell>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		shellType := c.Args().First()
 | 
			
		||||
Supported shells are: bash, fish, fizsh & zsh.`,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		shellType := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
		if shellType == "" {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no shell provided"))
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, errors.New("no shell provided"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		supportedShells := map[string]bool{
 | 
			
		||||
@ -113,33 +107,29 @@ source /etc/fish/completions/abra
 | 
			
		||||
 | 
			
		||||
// UpgradeCommand upgrades abra in-place.
 | 
			
		||||
var UpgradeCommand = cli.Command{
 | 
			
		||||
	Name:    "upgrade",
 | 
			
		||||
	Aliases: []string{"u"},
 | 
			
		||||
	Usage:   "Upgrade abra",
 | 
			
		||||
	Description: `
 | 
			
		||||
Upgrade abra in-place with the latest stable or release candidate.
 | 
			
		||||
	Name:      "upgrade",
 | 
			
		||||
	Aliases:   []string{"u"},
 | 
			
		||||
	Usage:     "Upgrade abra",
 | 
			
		||||
	UsageText: "abra upgrade [options]",
 | 
			
		||||
	Description: `Upgrade abra in-place with the latest stable or release candidate.
 | 
			
		||||
 | 
			
		||||
Use "-r/--rc" to install the latest release candidate. Please bear in mind that
 | 
			
		||||
Use "--rc/-r" to install the latest release candidate. Please bear in mind that
 | 
			
		||||
it may contain absolutely catastrophic deal-breaker bugs. Thank you very much
 | 
			
		||||
for the testing efforts 💗
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra upgrade
 | 
			
		||||
		abra upgrade --rc`,
 | 
			
		||||
	Flags: []cli.Flag{internal.RCFlag},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
for the testing efforts 💗`,
 | 
			
		||||
	Flags:    []cli.Flag{internal.RCFlag},
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		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 {
 | 
			
		||||
			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)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -147,18 +137,16 @@ EXAMPLE:
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
	app := &cli.App{
 | 
			
		||||
		Name: "abra",
 | 
			
		||||
		Usage: `the Co-op Cloud command-line utility belt 🎩🐇
 | 
			
		||||
    ____                           ____ _                 _
 | 
			
		||||
   / ___|___         ___  _ __    / ___| | ___  _   _  __| |
 | 
			
		||||
  | |   / _ \ _____ / _ \| '_ \  | |   | |/ _ \| | | |/ _' |
 | 
			
		||||
  | |__| (_) |_____| (_) | |_) | | |___| | (_) | |_| | (_| |
 | 
			
		||||
   \____\___/       \___/| .__/   \____|_|\___/ \__,_|\__,_|
 | 
			
		||||
                         |_|
 | 
			
		||||
`,
 | 
			
		||||
		Version: fmt.Sprintf("%s-%s", version, commit[:7]),
 | 
			
		||||
func newAbraApp(version, commit string) *cli.Command {
 | 
			
		||||
	app := &cli.Command{
 | 
			
		||||
		Name:      "abra",
 | 
			
		||||
		Usage:     "The Co-op Cloud command-line utility belt 🎩🐇",
 | 
			
		||||
		UsageText: "abra [command] [arguments] [options]",
 | 
			
		||||
		Version:   fmt.Sprintf("%s-%s", version, commit[:7]),
 | 
			
		||||
		Flags: []cli.Flag{
 | 
			
		||||
			// NOTE(d1): "GLOBAL OPTIONS" flags
 | 
			
		||||
			internal.DebugFlag,
 | 
			
		||||
		},
 | 
			
		||||
		Commands: []*cli.Command{
 | 
			
		||||
			&app.AppCommand,
 | 
			
		||||
			&server.ServerCommand,
 | 
			
		||||
@ -167,12 +155,13 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
			&UpgradeCommand,
 | 
			
		||||
			&AutoCompleteCommand,
 | 
			
		||||
		},
 | 
			
		||||
		BashComplete: autocomplete.SubcommandComplete,
 | 
			
		||||
		EnableShellCompletion:  true,
 | 
			
		||||
		UseShortOptionHandling: true,
 | 
			
		||||
		HideHelpCommand:        true,
 | 
			
		||||
		ShellComplete:          autocomplete.SubcommandComplete,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app.EnableBashCompletion = true
 | 
			
		||||
 | 
			
		||||
	app.Before = func(c *cli.Context) error {
 | 
			
		||||
	app.Before = func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		paths := []string{
 | 
			
		||||
			config.ABRA_DIR,
 | 
			
		||||
			config.SERVERS_DIR,
 | 
			
		||||
@ -198,6 +187,12 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cli.HelpFlag = &cli.BoolFlag{
 | 
			
		||||
		Name:    "help",
 | 
			
		||||
		Aliases: []string{"h, H"},
 | 
			
		||||
		Usage:   "Show help",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -205,7 +200,7 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
func RunApp(version, commit string) {
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Secrets stores the variable from SecretsFlag
 | 
			
		||||
@ -74,7 +75,7 @@ var Chaos bool
 | 
			
		||||
var ChaosFlag = &cli.BoolFlag{
 | 
			
		||||
	Name:        "chaos",
 | 
			
		||||
	Aliases:     []string{"C"},
 | 
			
		||||
	Usage:       "Proceed with uncommitted recipes changes. Use with care!",
 | 
			
		||||
	Usage:       "Ignore uncommitted recipes changes. Use with care!",
 | 
			
		||||
	Destination: &Chaos,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -116,7 +117,7 @@ var OfflineFlag = &cli.BoolFlag{
 | 
			
		||||
	Name:        "offline",
 | 
			
		||||
	Aliases:     []string{"o"},
 | 
			
		||||
	Destination: &Offline,
 | 
			
		||||
	Usage:       "Prefer offline & filesystem access when possible",
 | 
			
		||||
	Usage:       "Prefer offline & filesystem access",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseNotes stores the variable from ReleaseNotesFlag.
 | 
			
		||||
@ -138,7 +139,7 @@ var MachineReadableFlag = &cli.BoolFlag{
 | 
			
		||||
	Name:        "machine",
 | 
			
		||||
	Aliases:     []string{"m"},
 | 
			
		||||
	Destination: &MachineReadable,
 | 
			
		||||
	Usage:       "Output in a machine-readable format (where supported)",
 | 
			
		||||
	Usage:       "Machine-readable output",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RC signifies the latest release candidate
 | 
			
		||||
@ -319,7 +320,7 @@ var AllServicesFlag = &cli.BoolFlag{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
		log.SetLevel(log.DebugLevel)
 | 
			
		||||
		log.SetOutput(os.Stderr)
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,13 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"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
 | 
			
		||||
// terminal, and shows the help command.
 | 
			
		||||
func ShowSubcommandHelpAndError(c *cli.Context, err interface{}) {
 | 
			
		||||
	if err2 := cli.ShowSubcommandHelp(c); err2 != nil {
 | 
			
		||||
func ShowSubcommandHelpAndError(cmd *cli.Command, err interface{}) {
 | 
			
		||||
	if err2 := cli.ShowSubcommandHelp(cmd); err2 != nil {
 | 
			
		||||
		log.Error(err2)
 | 
			
		||||
	}
 | 
			
		||||
	log.Error(err)
 | 
			
		||||
 | 
			
		||||
@ -9,12 +9,12 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ValidateRecipe ensures the recipe arg is valid.
 | 
			
		||||
func ValidateRecipe(c *cli.Context) recipe.Recipe {
 | 
			
		||||
	recipeName := c.Args().First()
 | 
			
		||||
func ValidateRecipe(cmd *cli.Command) recipe.Recipe {
 | 
			
		||||
	recipeName := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
	if recipeName == "" && !NoInput {
 | 
			
		||||
		var recipes []string
 | 
			
		||||
@ -54,7 +54,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if recipeName == "" {
 | 
			
		||||
		ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
 | 
			
		||||
		ShowSubcommandHelpAndError(cmd, errors.New("no recipe name provided"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chosenRecipe := recipe.Get(recipeName)
 | 
			
		||||
@ -64,7 +64,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
 | 
			
		||||
	}
 | 
			
		||||
	_, err = chosenRecipe.GetComposeConfig(nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if c.Command.Name == "generate" {
 | 
			
		||||
		if cmd.Name == "generate" {
 | 
			
		||||
			if strings.Contains(err.Error(), "missing a compose") {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
@ -83,11 +83,11 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateApp ensures the app name arg is valid.
 | 
			
		||||
func ValidateApp(c *cli.Context) app.App {
 | 
			
		||||
	appName := c.Args().First()
 | 
			
		||||
func ValidateApp(cmd *cli.Command) app.App {
 | 
			
		||||
	appName := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
	if appName == "" {
 | 
			
		||||
		ShowSubcommandHelpAndError(c, errors.New("no app provided"))
 | 
			
		||||
		ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app, err := app.Get(appName)
 | 
			
		||||
@ -101,8 +101,8 @@ func ValidateApp(c *cli.Context) app.App {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateDomain ensures the domain name arg is valid.
 | 
			
		||||
func ValidateDomain(c *cli.Context) string {
 | 
			
		||||
	domainName := c.Args().First()
 | 
			
		||||
func ValidateDomain(cmd *cli.Command) string {
 | 
			
		||||
	domainName := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
	if domainName == "" && !NoInput {
 | 
			
		||||
		prompt := &survey.Input{
 | 
			
		||||
@ -115,7 +115,7 @@ func ValidateDomain(c *cli.Context) string {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if domainName == "" {
 | 
			
		||||
		ShowSubcommandHelpAndError(c, errors.New("no domain provided"))
 | 
			
		||||
		ShowSubcommandHelpAndError(cmd, errors.New("no domain provided"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
func ValidateSubCmdFlags(c *cli.Context) bool {
 | 
			
		||||
	for argIdx, arg := range c.Args().Slice() {
 | 
			
		||||
func ValidateSubCmdFlags(cmd *cli.Command) bool {
 | 
			
		||||
	for argIdx, arg := range cmd.Args().Slice() {
 | 
			
		||||
		if !strings.HasPrefix(arg, "--") {
 | 
			
		||||
			for _, flag := range c.Args().Slice()[argIdx:] {
 | 
			
		||||
			for _, flag := range cmd.Args().Slice()[argIdx:] {
 | 
			
		||||
				if strings.HasPrefix(flag, "--") {
 | 
			
		||||
					return false
 | 
			
		||||
				}
 | 
			
		||||
@ -138,8 +138,8 @@ func ValidateSubCmdFlags(c *cli.Context) bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateServer ensures the server name arg is valid.
 | 
			
		||||
func ValidateServer(c *cli.Context) string {
 | 
			
		||||
	serverName := c.Args().First()
 | 
			
		||||
func ValidateServer(cmd *cli.Command) string {
 | 
			
		||||
	serverName := cmd.Args().First()
 | 
			
		||||
 | 
			
		||||
	serverNames, err := config.ReadServerNames()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -164,11 +164,11 @@ func ValidateServer(c *cli.Context) string {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if serverName == "" {
 | 
			
		||||
		ShowSubcommandHelpAndError(c, errors.New("no server provided"))
 | 
			
		||||
		ShowSubcommandHelpAndError(cmd, errors.New("no server provided"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,26 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	gitPkg "coopcloud.tech/abra/pkg/git"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeDiffCommand = cli.Command{
 | 
			
		||||
	Name:        "diff",
 | 
			
		||||
	Usage:       "Show unstaged changes in recipe config",
 | 
			
		||||
	Description: "This command requires /usr/bin/git.",
 | 
			
		||||
	Aliases:     []string{"d"},
 | 
			
		||||
	ArgsUsage:   "<recipe>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		r := internal.ValidateRecipe(c)
 | 
			
		||||
	Name:          "diff",
 | 
			
		||||
	Usage:         "Show unstaged changes in recipe config",
 | 
			
		||||
	Description:   "This command requires /usr/bin/git.",
 | 
			
		||||
	Aliases:       []string{"d"},
 | 
			
		||||
	UsageText:     "abra recipe diff <recipe> [options]",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		r := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := gitPkg.DiffUnstaged(r.Dir); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,32 +1,30 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeFetchCommand = cli.Command{
 | 
			
		||||
	Name:        "fetch",
 | 
			
		||||
	Usage:       "Fetch recipe(s)",
 | 
			
		||||
	Aliases:     []string{"f"},
 | 
			
		||||
	ArgsUsage:   "[<recipe>]",
 | 
			
		||||
	Description: "Retrieves all recipes if no <recipe> argument is passed",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
	Name:          "fetch",
 | 
			
		||||
	Usage:         "Fetch recipe(s)",
 | 
			
		||||
	Aliases:       []string{"f"},
 | 
			
		||||
	UsageText:     "abra recipe fetch [<recipe>] [options]",
 | 
			
		||||
	Description:   "Retrieves all recipes if no <recipe> argument is passed",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipeName := cmd.Args().First()
 | 
			
		||||
		r := recipe.Get(recipeName)
 | 
			
		||||
		if recipeName != "" {
 | 
			
		||||
			internal.ValidateRecipe(c)
 | 
			
		||||
			internal.ValidateRecipe(cmd)
 | 
			
		||||
			if err := r.Ensure(false, false); err != nil {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
@ -8,25 +9,23 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/lint"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeLintCommand = cli.Command{
 | 
			
		||||
	Name:      "lint",
 | 
			
		||||
	Usage:     "Lint a recipe",
 | 
			
		||||
	Aliases:   []string{"l"},
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
	UsageText: "abra recipe lint <recipe> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OnlyErrorFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
@ -10,7 +11,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pattern string
 | 
			
		||||
@ -23,17 +24,17 @@ var patternFlag = &cli.StringFlag{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var recipeListCommand = cli.Command{
 | 
			
		||||
	Name:    "list",
 | 
			
		||||
	Usage:   "List available recipes",
 | 
			
		||||
	Aliases: []string{"ls"},
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Usage:     "List recipes",
 | 
			
		||||
	UsageText: "abra recipe list [options]",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		patternFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
	Before:   internal.SubCommandBefore,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		catl, err := recipe.ReadRecipeCatalogue(internal.Offline)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err.Error())
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
@ -13,7 +14,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/git"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// recipeMetadata is the recipe metadata for the README.md
 | 
			
		||||
@ -34,27 +35,24 @@ var recipeNewCommand = cli.Command{
 | 
			
		||||
	Name:    "new",
 | 
			
		||||
	Aliases: []string{"n"},
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.GitNameFlag,
 | 
			
		||||
		internal.GitEmailFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:    internal.SubCommandBefore,
 | 
			
		||||
	Usage:     "Create a new recipe",
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
	Description: `
 | 
			
		||||
Create a new recipe.
 | 
			
		||||
	UsageText: "abra recipe new <recipe> [options]",
 | 
			
		||||
	Description: `Create a new recipe.
 | 
			
		||||
 | 
			
		||||
Abra uses the built-in example repository which is available here:
 | 
			
		||||
 | 
			
		||||
    https://git.coopcloud.tech/coop-cloud/example`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipeName := cmd.Args().First()
 | 
			
		||||
		r := recipe.Get(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) {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RecipeCommand defines all recipe related sub-commands.
 | 
			
		||||
@ -9,17 +9,17 @@ var RecipeCommand = cli.Command{
 | 
			
		||||
	Name:      "recipe",
 | 
			
		||||
	Aliases:   []string{"r"},
 | 
			
		||||
	Usage:     "Manage recipes",
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
	Description: `
 | 
			
		||||
A recipe is a blueprint for an app. It is a bunch of config files which
 | 
			
		||||
describe how to deploy and maintain an app. Recipes are maintained by the Co-op
 | 
			
		||||
Cloud community and you can use Abra to read them, deploy them and create apps
 | 
			
		||||
for you.
 | 
			
		||||
	UsageText: "abra recipe [command] [arguments] [options]",
 | 
			
		||||
	Description: `A recipe is a blueprint for an app.
 | 
			
		||||
 | 
			
		||||
It is a bunch of config files which describe how to deploy and maintain an app.
 | 
			
		||||
Recipes are maintained by the Co-op Cloud community and you can use Abra to
 | 
			
		||||
read them, deploy them and create apps for you.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
manner.`,
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&recipeFetchCommand,
 | 
			
		||||
		&recipeLintCommand,
 | 
			
		||||
		&recipeListCommand,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
@ -18,17 +19,18 @@ import (
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeReleaseCommand = cli.Command{
 | 
			
		||||
	Name:      "release",
 | 
			
		||||
	Aliases:   []string{"rl"},
 | 
			
		||||
	Usage:     "Release a new recipe version",
 | 
			
		||||
	ArgsUsage: "<recipe> [<version>]",
 | 
			
		||||
	Description: `
 | 
			
		||||
Create a new version of a recipe. These versions are then published on the
 | 
			
		||||
Co-op Cloud recipe catalogue. These versions take the following form:
 | 
			
		||||
	UsageText: "abra recipe release <recipe> [<version>] [options]",
 | 
			
		||||
	Description: `Create a new version of a recipe.
 | 
			
		||||
 | 
			
		||||
These versions are then published on the Co-op Cloud recipe catalogue. These
 | 
			
		||||
versions take the following form:
 | 
			
		||||
 | 
			
		||||
    a.b.c+x.y.z
 | 
			
		||||
 | 
			
		||||
@ -46,19 +48,17 @@ Publish 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 keys configured on your account.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.DryFlag,
 | 
			
		||||
		internal.MajorFlag,
 | 
			
		||||
		internal.MinorFlag,
 | 
			
		||||
		internal.PatchFlag,
 | 
			
		||||
		internal.PublishFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		imagesTmp, err := getImageVersions(recipe)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -75,7 +75,7 @@ your SSH keys configured on your account.`,
 | 
			
		||||
			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 _, err := tagcmp.Parse(tagString); err != nil {
 | 
			
		||||
				log.Fatalf("cannot parse %s, invalid tag specified?", tagString)
 | 
			
		||||
 | 
			
		||||
@ -1,32 +1,31 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeResetCommand = cli.Command{
 | 
			
		||||
	Name:        "reset",
 | 
			
		||||
	Usage:       "Remove all unstaged changes from recipe config",
 | 
			
		||||
	Description: "WARNING: this will delete your changes. Be Careful.",
 | 
			
		||||
	Aliases:     []string{"rs"},
 | 
			
		||||
	ArgsUsage:   "<recipe>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
	Name:          "reset",
 | 
			
		||||
	Usage:         "Remove all unstaged changes from recipe config",
 | 
			
		||||
	Description:   "WARNING: this will delete your changes. Be Careful.",
 | 
			
		||||
	Aliases:       []string{"rs"},
 | 
			
		||||
	UsageText:     "abra recipe reset <recipe> [options]",
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipeName := cmd.Args().First()
 | 
			
		||||
		r := recipe.Get(recipeName)
 | 
			
		||||
 | 
			
		||||
		if recipeName != "" {
 | 
			
		||||
			internal.ValidateRecipe(c)
 | 
			
		||||
			internal.ValidateRecipe(cmd)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		repo, err := git.PlainOpen(r.Dir)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
@ -12,35 +13,34 @@ import (
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/go-git/go-git/v5/plumbing"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeSyncCommand = cli.Command{
 | 
			
		||||
	Name:      "sync",
 | 
			
		||||
	Aliases:   []string{"s"},
 | 
			
		||||
	Usage:     "Sync recipe version label",
 | 
			
		||||
	ArgsUsage: "<recipe> [<version>]",
 | 
			
		||||
	UsageText: "abra recipe lint <recipe> [<version>] [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.DryFlag,
 | 
			
		||||
		internal.MajorFlag,
 | 
			
		||||
		internal.MinorFlag,
 | 
			
		||||
		internal.PatchFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Generate labels for the main recipe service (i.e. by convention, the service
 | 
			
		||||
named "app") which corresponds to the following format:
 | 
			
		||||
	Description: `Generate labels for the main recipe service.
 | 
			
		||||
 | 
			
		||||
By convention, the service named "app" using the following format:
 | 
			
		||||
 | 
			
		||||
    coop-cloud.${STACK_NAME}.version=<version>
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
local file system.`,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		mainApp, err := internal.GetMainAppImage(recipe)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -59,7 +59,7 @@ local file system.`,
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nextTag := c.Args().Get(1)
 | 
			
		||||
		nextTag := cmd.Args().Get(1)
 | 
			
		||||
		if len(tags) == 0 && nextTag == "" {
 | 
			
		||||
			log.Warnf("no git tags found for %s", recipe.Name)
 | 
			
		||||
			if internal.NoInput {
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
@ -19,7 +20,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/tagcmp"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type imgPin struct {
 | 
			
		||||
@ -27,8 +28,8 @@ type imgPin struct {
 | 
			
		||||
	version tagcmp.Tag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// anUpgrade represents a single service upgrade (as within a recipe), and the list of tags that it can be upgraded to,
 | 
			
		||||
// for serialization purposes.
 | 
			
		||||
// anUpgrade represents a single service upgrade (as within a recipe), and the
 | 
			
		||||
// list of tags that it can be upgraded to, for serialization purposes.
 | 
			
		||||
type anUpgrade struct {
 | 
			
		||||
	Service     string   `json:"service"`
 | 
			
		||||
	Image       string   `json:"image"`
 | 
			
		||||
@ -37,13 +38,13 @@ type anUpgrade struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var recipeUpgradeCommand = cli.Command{
 | 
			
		||||
	Name:    "upgrade",
 | 
			
		||||
	Aliases: []string{"u"},
 | 
			
		||||
	Usage:   "Upgrade recipe image tags",
 | 
			
		||||
	Description: `
 | 
			
		||||
Parse all image tags within the given <recipe> configuration and prompt with
 | 
			
		||||
more recent tags to upgrade to. It will update the relevant compose file tags
 | 
			
		||||
on the local file system.
 | 
			
		||||
	Name:      "upgrade",
 | 
			
		||||
	Aliases:   []string{"u"},
 | 
			
		||||
	Usage:     "Upgrade recipe image tags",
 | 
			
		||||
	UsageText: "abra recipe upgrade [<recipe>] [options]",
 | 
			
		||||
	Description: `Upgrade a given <recipe> configuration.
 | 
			
		||||
 | 
			
		||||
It will update the relevant compose file tags on the local file system.
 | 
			
		||||
 | 
			
		||||
Some image tags cannot be parsed because they do not follow some sort of
 | 
			
		||||
semver-like convention. In this case, all possible tags will be listed and it
 | 
			
		||||
@ -53,25 +54,19 @@ 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.
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
 | 
			
		||||
    abra recipe upgrade`,
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
You may invoke this command in "wizard" mode and be prompted for input.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.PatchFlag,
 | 
			
		||||
		internal.MinorFlag,
 | 
			
		||||
		internal.MajorFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		internal.AllTagsFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
@ -9,7 +10,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	recipePkg "coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func sortServiceByName(versions [][]string) func(i, j int) bool {
 | 
			
		||||
@ -26,19 +27,17 @@ var recipeVersionCommand = cli.Command{
 | 
			
		||||
	Name:      "versions",
 | 
			
		||||
	Aliases:   []string{"v"},
 | 
			
		||||
	Usage:     "List recipe versions",
 | 
			
		||||
	ArgsUsage: "<recipe>",
 | 
			
		||||
	UsageText: "abra recipe version <recipe> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		var warnMessages []string
 | 
			
		||||
 | 
			
		||||
		recipe := internal.ValidateRecipe(c)
 | 
			
		||||
		recipe := internal.ValidateRecipe(cmd)
 | 
			
		||||
 | 
			
		||||
		catl, err := recipePkg.ReadRecipeCatalogue(internal.Offline)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
@ -13,7 +14,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/server"
 | 
			
		||||
	sshPkg "coopcloud.tech/abra/pkg/ssh"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var local bool
 | 
			
		||||
@ -93,15 +94,15 @@ func createServerDir(name string) (bool, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var serverAddCommand = cli.Command{
 | 
			
		||||
	Name:    "add",
 | 
			
		||||
	Aliases: []string{"a"},
 | 
			
		||||
	Usage:   "Add a new server to your configuration",
 | 
			
		||||
	Description: `
 | 
			
		||||
Add a new server to your configuration so that it can be managed by Abra.
 | 
			
		||||
	Name:      "add",
 | 
			
		||||
	Aliases:   []string{"a"},
 | 
			
		||||
	Usage:     "Add a new server",
 | 
			
		||||
	UsageText: "abra server add <domain> [options]",
 | 
			
		||||
	Description: `Add a new server to your configuration so that it can be managed by Abra.
 | 
			
		||||
 | 
			
		||||
Abra relies on the standard SSH command-line and ~/.ssh/config for client
 | 
			
		||||
connection details. You must configure an entry per-host in your ~/.ssh/config
 | 
			
		||||
for each server. For example:
 | 
			
		||||
for each server:
 | 
			
		||||
 | 
			
		||||
  Host example.com example
 | 
			
		||||
    Hostname example.com
 | 
			
		||||
@ -109,10 +110,6 @@ for each server. For example:
 | 
			
		||||
    Port 12345
 | 
			
		||||
    IdentityFile ~/.ssh/example@somewhere
 | 
			
		||||
 | 
			
		||||
You can then add a server like so:
 | 
			
		||||
 | 
			
		||||
  abra server add example.com
 | 
			
		||||
 | 
			
		||||
If "--local" is passed, then Abra assumes that the current local server is
 | 
			
		||||
intended as the target server. This is useful when you want to have your entire
 | 
			
		||||
Co-op Cloud config located on the server itself, and not on your local
 | 
			
		||||
@ -120,28 +117,24 @@ developer machine. The domain is then set to "default".
 | 
			
		||||
 | 
			
		||||
You can also pass "--no-domain-checks/-D" flag to use any arbitrary name
 | 
			
		||||
instead of a real domain. The host will be resolved with the "Hostname" entry
 | 
			
		||||
of your ~/.ssh/config. Checks for a valid online domain will be skipped:
 | 
			
		||||
 | 
			
		||||
  abra server add -D example`,
 | 
			
		||||
of your ~/.ssh/config. Checks for a valid online domain will be skipped.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.NoDomainChecksFlag,
 | 
			
		||||
		localFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:    internal.SubCommandBefore,
 | 
			
		||||
	ArgsUsage: "<name>",
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		if c.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(c) {
 | 
			
		||||
	Before:   internal.SubCommandBefore,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		if cmd.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(cmd) {
 | 
			
		||||
			err := errors.New("cannot use <name> and --local together")
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, err)
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(cmd, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var name string
 | 
			
		||||
		if local {
 | 
			
		||||
			name = "default"
 | 
			
		||||
		} else {
 | 
			
		||||
			name = internal.ValidateDomain(c)
 | 
			
		||||
			name = internal.ValidateDomain(cmd)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// NOTE(d1): reasonable 5 second timeout for connections which can't
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,31 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"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/log"
 | 
			
		||||
	"github.com/docker/cli/cli/connhelper/ssh"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var serverListCommand = cli.Command{
 | 
			
		||||
	Name:    "list",
 | 
			
		||||
	Aliases: []string{"ls"},
 | 
			
		||||
	Usage:   "List managed servers",
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	Usage:     "List managed servers",
 | 
			
		||||
	UsageText: "abra server list [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.MachineReadableFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		dockerContextStore := context.NewDefaultDockerContextStore()
 | 
			
		||||
	Before:   internal.SubCommandBefore,
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		dockerContextStore := contextPkg.NewDefaultDockerContextStore()
 | 
			
		||||
		contexts, err := dockerContextStore.Store.List()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -46,14 +47,14 @@ var serverListCommand = cli.Command{
 | 
			
		||||
		var rows [][]string
 | 
			
		||||
		for _, serverName := range serverNames {
 | 
			
		||||
			var row []string
 | 
			
		||||
			for _, ctx := range contexts {
 | 
			
		||||
				endpoint, err := context.GetContextEndpoint(ctx)
 | 
			
		||||
			for _, dockerCtx := range contexts {
 | 
			
		||||
				endpoint, err := contextPkg.GetContextEndpoint(dockerCtx)
 | 
			
		||||
				if err != nil && strings.Contains(err.Error(), "does not exist") {
 | 
			
		||||
					// No local context found, we can continue safely
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ctx.Name == serverName {
 | 
			
		||||
				if dockerCtx.Name == serverName {
 | 
			
		||||
					sp, err := ssh.ParseURL(endpoint)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var allFilter bool
 | 
			
		||||
@ -31,26 +31,23 @@ var volumesFilterFlag = &cli.BoolFlag{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var serverPruneCommand = cli.Command{
 | 
			
		||||
	Name:    "prune",
 | 
			
		||||
	Aliases: []string{"p"},
 | 
			
		||||
	Usage:   "Prune resources on a server",
 | 
			
		||||
	Description: `
 | 
			
		||||
Prunes unused containers, networks, and dangling images.
 | 
			
		||||
	Name:      "prune",
 | 
			
		||||
	Aliases:   []string{"p"},
 | 
			
		||||
	Usage:     "Prune resources on a server",
 | 
			
		||||
	UsageText: "abra server prune <server> [options]",
 | 
			
		||||
	Description: `Prunes unused containers, networks, and dangling images.
 | 
			
		||||
 | 
			
		||||
Use "-v/--volumes" to remove volumes that are not associated with a deployed
 | 
			
		||||
app. This can result in unwanted data loss if not used carefully.`,
 | 
			
		||||
	ArgsUsage: "[<server>]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		allFilterFlag,
 | 
			
		||||
		volumesFilterFlag,
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		serverName := internal.ValidateServer(c)
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		serverName := internal.ValidateServer(cmd)
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New(serverName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -59,7 +56,6 @@ app. This can result in unwanted data loss if not used carefully.`,
 | 
			
		||||
 | 
			
		||||
		var args filters.Args
 | 
			
		||||
 | 
			
		||||
		ctx := context.Background()
 | 
			
		||||
		cr, err := cl.ContainersPrune(ctx, args)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
@ -9,29 +10,24 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/config"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var serverRemoveCommand = cli.Command{
 | 
			
		||||
	Name:      "remove",
 | 
			
		||||
	Aliases:   []string{"rm"},
 | 
			
		||||
	ArgsUsage: "<server>",
 | 
			
		||||
	UsageText: "abra server remove <domain> [options]",
 | 
			
		||||
	Usage:     "Remove a managed server",
 | 
			
		||||
	Description: `
 | 
			
		||||
Remove a managed server.
 | 
			
		||||
	Description: `Remove a managed server.
 | 
			
		||||
 | 
			
		||||
Abra will remove the internal bookkeeping (~/.abra/servers/...) and underlying
 | 
			
		||||
client connection context. This server will then be lost in time, like tears in
 | 
			
		||||
rain.`,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		serverName := internal.ValidateServer(c)
 | 
			
		||||
Abra will remove the internal bookkeeping ($ABRA_DIR/servers/...) and
 | 
			
		||||
underlying client connection context. This server will then be lost in time,
 | 
			
		||||
like tears in rain.`,
 | 
			
		||||
	Before:        internal.SubCommandBefore,
 | 
			
		||||
	ShellComplete: autocomplete.ServerNameComplete,
 | 
			
		||||
	HideHelp:      true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		serverName := internal.ValidateServer(cmd)
 | 
			
		||||
 | 
			
		||||
		if err := client.DeleteContext(serverName); err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,16 @@
 | 
			
		||||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ServerCommand defines the `abra server` command and its subcommands
 | 
			
		||||
var ServerCommand = cli.Command{
 | 
			
		||||
	Name:    "server",
 | 
			
		||||
	Aliases: []string{"s"},
 | 
			
		||||
	Usage:   "Manage servers",
 | 
			
		||||
	Subcommands: []*cli.Command{
 | 
			
		||||
	Name:      "server",
 | 
			
		||||
	Aliases:   []string{"s"},
 | 
			
		||||
	Usage:     "Manage servers",
 | 
			
		||||
	UsageText: "abra server [command] [arguments] [options]",
 | 
			
		||||
	Commands: []*cli.Command{
 | 
			
		||||
		&serverAddCommand,
 | 
			
		||||
		&serverListCommand,
 | 
			
		||||
		&serverRemoveCommand,
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ import (
 | 
			
		||||
	dockerclient "github.com/docker/docker/client"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const SERVER = "localhost"
 | 
			
		||||
@ -46,23 +46,21 @@ var allFlag = &cli.BoolFlag{
 | 
			
		||||
 | 
			
		||||
// Notify checks for available upgrades
 | 
			
		||||
var Notify = cli.Command{
 | 
			
		||||
	Name:    "notify",
 | 
			
		||||
	Aliases: []string{"n"},
 | 
			
		||||
	Usage:   "Check for available upgrades",
 | 
			
		||||
	Name:      "notify",
 | 
			
		||||
	Aliases:   []string{"n"},
 | 
			
		||||
	Usage:     "Check for available upgrades",
 | 
			
		||||
	UsageText: "kadabra notify [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		majorFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Read the deployed app versions and look for new versions in the recipe
 | 
			
		||||
catalogue.
 | 
			
		||||
	Description: `Notify on new versions for deployed apps.
 | 
			
		||||
 | 
			
		||||
If a new patch/minor version is available, a notification is printed.
 | 
			
		||||
 | 
			
		||||
Use "--major" to include new major versions.`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		cl, err := client.New("default")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
@ -97,17 +95,14 @@ var UpgradeApp = cli.Command{
 | 
			
		||||
	Name:      "upgrade",
 | 
			
		||||
	Aliases:   []string{"u"},
 | 
			
		||||
	Usage:     "Upgrade apps",
 | 
			
		||||
	ArgsUsage: "<stack-name> <recipe>",
 | 
			
		||||
	UsageText: "kadabra notify <stack> <recipe> [options]",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		majorFlag,
 | 
			
		||||
		allFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Upgrade an app by specifying stack name and recipe. 
 | 
			
		||||
	Description: `Upgrade an app by specifying stack name and recipe. 
 | 
			
		||||
 | 
			
		||||
Use "--all" to upgrade every deployed app.
 | 
			
		||||
 | 
			
		||||
@ -118,15 +113,16 @@ available, the app is upgraded.
 | 
			
		||||
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
 | 
			
		||||
upgraded, to update chaos deployments use the "--chaos" flag. Use it with care.`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
	HideHelp: true,
 | 
			
		||||
	Action: func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		cl, err := client.New("default")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !updateAll {
 | 
			
		||||
			stackName := c.Args().Get(0)
 | 
			
		||||
			recipeName := c.Args().Get(1)
 | 
			
		||||
			stackName := cmd.Args().Get(0)
 | 
			
		||||
			recipeName := cmd.Args().Get(1)
 | 
			
		||||
			err = tryUpgrade(cl, stackName, recipeName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
@ -470,25 +466,25 @@ func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion stri
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
	app := &cli.App{
 | 
			
		||||
		Name: "kadabra",
 | 
			
		||||
		Usage: `The Co-op Cloud auto-updater
 | 
			
		||||
    ____                           ____ _                 _
 | 
			
		||||
   / ___|___         ___  _ __    / ___| | ___  _   _  __| |
 | 
			
		||||
  | |   / _ \ _____ / _ \| '_ \  | |   | |/ _ \| | | |/ _' |
 | 
			
		||||
  | |__| (_) |_____| (_) | |_) | | |___| | (_) | |_| | (_| |
 | 
			
		||||
   \____\___/       \___/| .__/   \____|_|\___/ \__,_|\__,_|
 | 
			
		||||
                         |_|
 | 
			
		||||
`,
 | 
			
		||||
		Version: fmt.Sprintf("%s-%s", version, commit[:7]),
 | 
			
		||||
func newKadabraApp(version, commit string) *cli.Command {
 | 
			
		||||
	app := &cli.Command{
 | 
			
		||||
		Name:                   "kadabra",
 | 
			
		||||
		Version:                fmt.Sprintf("%s-%s", version, commit[:7]),
 | 
			
		||||
		Usage:                  "The Co-op Cloud auto-updater 🤖 🚀",
 | 
			
		||||
		UsageText:              "kadabra [command] [options]",
 | 
			
		||||
		UseShortOptionHandling: true,
 | 
			
		||||
		HideHelpCommand:        true,
 | 
			
		||||
		Flags: []cli.Flag{
 | 
			
		||||
			// NOTE(d1): "GLOBAL OPTIONS" flags
 | 
			
		||||
			internal.DebugFlag,
 | 
			
		||||
		},
 | 
			
		||||
		Commands: []*cli.Command{
 | 
			
		||||
			&Notify,
 | 
			
		||||
			&UpgradeApp,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app.Before = func(c *cli.Context) error {
 | 
			
		||||
	app.Before = func(ctx context.Context, cmd *cli.Command) error {
 | 
			
		||||
		log.Logger.SetStyles(log.Styles())
 | 
			
		||||
		charmLog.SetDefault(log.Logger)
 | 
			
		||||
 | 
			
		||||
@ -497,14 +493,20 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cli.HelpFlag = &cli.BoolFlag{
 | 
			
		||||
		Name:    "help",
 | 
			
		||||
		Aliases: []string{"h, H"},
 | 
			
		||||
		Usage:   "Show help",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunApp runs CLI abra app.
 | 
			
		||||
func RunApp(version, commit string) {
 | 
			
		||||
	app := newAbraApp(version, commit)
 | 
			
		||||
	app := newKadabraApp(version, commit)
 | 
			
		||||
 | 
			
		||||
	if err := app.Run(os.Args); err != nil {
 | 
			
		||||
	if err := app.Run(context.Background(), os.Args); err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
								
							@ -2,6 +2,8 @@ module coopcloud.tech/abra
 | 
			
		||||
 | 
			
		||||
go 1.21
 | 
			
		||||
 | 
			
		||||
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
 | 
			
		||||
	git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
 | 
			
		||||
@ -18,7 +20,7 @@ require (
 | 
			
		||||
	github.com/moby/term v0.5.0
 | 
			
		||||
	github.com/pkg/errors v0.9.1
 | 
			
		||||
	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
 | 
			
		||||
	golang.org/x/term v0.22.0
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1
 | 
			
		||||
	gotest.tools/v3 v3.5.1
 | 
			
		||||
@ -37,7 +39,6 @@ require (
 | 
			
		||||
	github.com/charmbracelet/x/ansi v0.1.3 // indirect
 | 
			
		||||
	github.com/cloudflare/circl v1.3.9 // 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/davecgh/go-spew v1.1.1 // 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/procfs v0.15.1 // 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/skeema/knownhosts v1.2.2 // indirect
 | 
			
		||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
			
		||||
	github.com/xanzy/ssh-agent v0.3.3 // indirect
 | 
			
		||||
	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // 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/otel v1.28.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							@ -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/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.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
 | 
			
		||||
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.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
			
		||||
@ -799,7 +798,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/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.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 | 
			
		||||
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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 | 
			
		||||
@ -883,8 +881,8 @@ 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.2/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/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44 h1:BeSTAZEDkDVNv9EOrycIGCkEg+6EhRRgSsbdc93Q3OM=
 | 
			
		||||
github.com/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
 | 
			
		||||
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 v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
 | 
			
		||||
@ -906,8 +904,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/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/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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 | 
			
		||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,23 @@
 | 
			
		||||
package autocomplete
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/pkg/app"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/log"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
	"github.com/urfave/cli/v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AppNameComplete copletes app names.
 | 
			
		||||
func AppNameComplete(c *cli.Context) {
 | 
			
		||||
func AppNameComplete(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
	appNames, err := app.GetAppNames()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.NArg() > 0 {
 | 
			
		||||
	if cmd.NArg() > 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -36,13 +37,13 @@ func ServiceNameComplete(appName string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RecipeNameComplete completes recipe names.
 | 
			
		||||
func RecipeNameComplete(c *cli.Context) {
 | 
			
		||||
func RecipeNameComplete(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
	catl, err := recipe.ReadRecipeCatalogue(false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.NArg() > 0 {
 | 
			
		||||
	if cmd.NArg() > 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -66,13 +67,13 @@ func RecipeVersionComplete(recipeName string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServerNameComplete completes server names.
 | 
			
		||||
func ServerNameComplete(c *cli.Context) {
 | 
			
		||||
func ServerNameComplete(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
	files, err := app.LoadAppFiles("")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.NArg() > 0 {
 | 
			
		||||
	if cmd.NArg() > 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -82,8 +83,8 @@ func ServerNameComplete(c *cli.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SubcommandComplete completes sub-commands.
 | 
			
		||||
func SubcommandComplete(c *cli.Context) {
 | 
			
		||||
	if c.NArg() > 0 {
 | 
			
		||||
func SubcommandComplete(ctx context.Context, cmd *cli.Command) {
 | 
			
		||||
	if cmd.NArg() > 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,17 +2,31 @@
 | 
			
		||||
 | 
			
		||||
: ${PROG:=$(basename ${BASH_SOURCE})}
 | 
			
		||||
 | 
			
		||||
# Macs have bash3 for which the bash-completion package doesn't include
 | 
			
		||||
# _init_completion. This is a minimal version of that function.
 | 
			
		||||
_cli_init_completion() {
 | 
			
		||||
  COMPREPLY=()
 | 
			
		||||
  _get_comp_words_by_ref "$@" cur prev words cword
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_cli_bash_autocomplete() {
 | 
			
		||||
  if [[ "${COMP_WORDS[0]}" != "source" ]]; then
 | 
			
		||||
    local cur opts base
 | 
			
		||||
    local cur opts base words
 | 
			
		||||
    COMPREPLY=()
 | 
			
		||||
    cur="${COMP_WORDS[COMP_CWORD]}"
 | 
			
		||||
    if [[ "$cur" == "-"* ]]; then
 | 
			
		||||
      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
 | 
			
		||||
    if declare -F _init_completion >/dev/null 2>&1; then
 | 
			
		||||
      _init_completion -n "=:" || return
 | 
			
		||||
    else
 | 
			
		||||
      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
 | 
			
		||||
      _cli_init_completion -n "=:" || return
 | 
			
		||||
    fi
 | 
			
		||||
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
 | 
			
		||||
    words=("${words[@]:0:$cword}")
 | 
			
		||||
    if [[ "$cur" == "-"* ]]; then
 | 
			
		||||
      requestComp="${words[*]} ${cur} --generate-shell-completion"
 | 
			
		||||
    else
 | 
			
		||||
      requestComp="${words[*]} --generate-shell-completion"
 | 
			
		||||
    fi
 | 
			
		||||
    opts=$(eval "${requestComp}" 2>/dev/null)
 | 
			
		||||
    COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
function complete_abra_args
 | 
			
		||||
    set -l cmd (commandline -poc) --generate-bash-completion
 | 
			
		||||
    set -l cmd (commandline -poc) --generate-shell-completion
 | 
			
		||||
    $cmd
 | 
			
		||||
end
 | 
			
		||||
complete -c abra -f -n "not __fish_seen_subcommand_from -h --help -v --version complete_abra_args" -a "(complete_abra_args)"
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ $fn = $($MyInvocation.MyCommand.Name)
 | 
			
		||||
$name = $fn -replace "(.*)\.ps1$", '$1'
 | 
			
		||||
Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock {
 | 
			
		||||
     param($commandName, $wordToComplete, $cursorPosition)
 | 
			
		||||
     $other = "$wordToComplete --generate-bash-completion"
 | 
			
		||||
     $other = "$wordToComplete --generate-shell-completion"
 | 
			
		||||
         Invoke-Expression $other | ForEach-Object {
 | 
			
		||||
            [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
 | 
			
		||||
         }
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,26 @@
 | 
			
		||||
#compdef $PROG
 | 
			
		||||
#compdef abra
 | 
			
		||||
compdef _abra abra
 | 
			
		||||
 | 
			
		||||
_cli_zsh_autocomplete() {
 | 
			
		||||
# https://github.com/urfave/cli/blob/main/autocomplete/zsh_autocomplete
 | 
			
		||||
 | 
			
		||||
  local -a opts
 | 
			
		||||
  local cur
 | 
			
		||||
  cur=${words[-1]}
 | 
			
		||||
  if [[ "$cur" == "-"* ]]; then
 | 
			
		||||
    opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
 | 
			
		||||
  else
 | 
			
		||||
    opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
 | 
			
		||||
  fi
 | 
			
		||||
_abra() {
 | 
			
		||||
	local -a opts
 | 
			
		||||
	local cur
 | 
			
		||||
	cur=${words[-1]}
 | 
			
		||||
	if [[ "$cur" == "-"* ]]; then
 | 
			
		||||
		opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-shell-completion)}")
 | 
			
		||||
	else
 | 
			
		||||
		opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-shell-completion)}")
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
  if [[ "${opts[1]}" != "" ]]; then
 | 
			
		||||
    _describe 'values' opts
 | 
			
		||||
  else
 | 
			
		||||
    _files
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  return
 | 
			
		||||
	if [[ "${opts[1]}" != "" ]]; then
 | 
			
		||||
		_describe 'values' opts
 | 
			
		||||
	else
 | 
			
		||||
		_files
 | 
			
		||||
	fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
compdef _cli_zsh_autocomplete $PROG
 | 
			
		||||
# don't run the completion function when being source-ed or eval-ed
 | 
			
		||||
if [ "$funcstack[1]" = "_abra" ]; then
 | 
			
		||||
	_abra
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/api.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/api.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winterm
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -259,7 +259,7 @@ func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) er
 | 
			
		||||
	var keysToEncrypt []*packet.PrivateKey
 | 
			
		||||
	// Add entity private key to encrypt.
 | 
			
		||||
	if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
 | 
			
		||||
		keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
 | 
			
		||||
		keysToEncrypt = append(keysToEncrypt,  e.PrivateKey)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add subkeys to encrypt.
 | 
			
		||||
@ -284,7 +284,7 @@ func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
 | 
			
		||||
	// Add subkeys to decrypt.
 | 
			
		||||
	for _, sub := range e.Subkeys {
 | 
			
		||||
		if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
 | 
			
		||||
			keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
 | 
			
		||||
			keysToDecrypt = append(keysToDecrypt,  sub.PrivateKey)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -458,7 +458,7 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecryptPrivateKeys decrypts all encrypted keys with the given config and passphrase.
 | 
			
		||||
// Avoids recomputation of similar s2k key derivations.
 | 
			
		||||
// Avoids recomputation of similar s2k key derivations. 
 | 
			
		||||
func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
 | 
			
		||||
	// Create a cache to avoid recomputation of key derviations for the same passphrase.
 | 
			
		||||
	s2kCache := &s2k.Cache{}
 | 
			
		||||
@ -485,7 +485,7 @@ func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction Cip
 | 
			
		||||
	if len(key) != cipherFunction.KeySize() {
 | 
			
		||||
		return errors.InvalidArgumentError("supplied encryption key has the wrong size")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	priv := bytes.NewBuffer(nil)
 | 
			
		||||
	err := pk.serializePrivateKey(priv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -497,7 +497,7 @@ func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction Cip
 | 
			
		||||
	pk.s2k, err = pk.s2kParams.Function()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	privateKeyBytes := priv.Bytes()
 | 
			
		||||
	pk.sha1Checksum = true
 | 
			
		||||
@ -581,7 +581,7 @@ func (pk *PrivateKey) Encrypt(passphrase []byte) error {
 | 
			
		||||
			S2KMode:  s2k.IteratedSaltedS2K,
 | 
			
		||||
			S2KCount: 65536,
 | 
			
		||||
			Hash:     crypto.SHA256,
 | 
			
		||||
		},
 | 
			
		||||
		} ,
 | 
			
		||||
		DefaultCipher: CipherAES256,
 | 
			
		||||
	}
 | 
			
		||||
	return pk.EncryptWithConfig(passphrase, config)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -87,10 +87,10 @@ func decodeCount(c uint8) int {
 | 
			
		||||
// encodeMemory converts the Argon2 "memory" in the range parallelism*8 to
 | 
			
		||||
// 2**31, inclusive, to an encoded memory. The return value is the
 | 
			
		||||
// octet that is actually stored in the GPG file. encodeMemory panics
 | 
			
		||||
// if is not in the above range
 | 
			
		||||
// if is not in the above range 
 | 
			
		||||
// See OpenPGP crypto refresh Section 3.7.1.4.
 | 
			
		||||
func encodeMemory(memory uint32, parallelism uint8) uint8 {
 | 
			
		||||
	if memory < (8*uint32(parallelism)) || memory > uint32(2147483648) {
 | 
			
		||||
	if memory < (8 * uint32(parallelism)) || memory > uint32(2147483648) {
 | 
			
		||||
		panic("Memory argument memory is outside the required range")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -199,8 +199,8 @@ func Generate(rand io.Reader, c *Config) (*Params, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		params = &Params{
 | 
			
		||||
			mode:   SaltedS2K,
 | 
			
		||||
			hashId: hashId,
 | 
			
		||||
			mode:      SaltedS2K,
 | 
			
		||||
			hashId:    hashId,
 | 
			
		||||
		}
 | 
			
		||||
	} else { // Enforce IteratedSaltedS2K method otherwise
 | 
			
		||||
		hashId, ok := algorithm.HashToHashId(c.hash())
 | 
			
		||||
@ -211,7 +211,7 @@ func Generate(rand io.Reader, c *Config) (*Params, error) {
 | 
			
		||||
			c.S2KMode = IteratedSaltedS2K
 | 
			
		||||
		}
 | 
			
		||||
		params = &Params{
 | 
			
		||||
			mode:      IteratedSaltedS2K,
 | 
			
		||||
			mode:      IteratedSaltedS2K, 
 | 
			
		||||
			hashId:    hashId,
 | 
			
		||||
			countByte: c.EncodedCount(),
 | 
			
		||||
		}
 | 
			
		||||
@ -306,12 +306,9 @@ func (params *Params) Dummy() bool {
 | 
			
		||||
 | 
			
		||||
func (params *Params) salt() []byte {
 | 
			
		||||
	switch params.mode {
 | 
			
		||||
	case SaltedS2K, IteratedSaltedS2K:
 | 
			
		||||
		return params.saltBytes[:8]
 | 
			
		||||
	case Argon2S2K:
 | 
			
		||||
		return params.saltBytes[:Argon2SaltSize]
 | 
			
		||||
	default:
 | 
			
		||||
		return nil
 | 
			
		||||
		case SaltedS2K, IteratedSaltedS2K: return params.saltBytes[:8]
 | 
			
		||||
		case Argon2S2K: return params.saltBytes[:Argon2SaltSize]
 | 
			
		||||
		default: return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -5,7 +5,7 @@ package s2k
 | 
			
		||||
// the same parameters.
 | 
			
		||||
type Cache map[Params][]byte
 | 
			
		||||
 | 
			
		||||
// GetOrComputeDerivedKey tries to retrieve the key
 | 
			
		||||
// GetOrComputeDerivedKey tries to retrieve the key 
 | 
			
		||||
// for the given s2k parameters from the cache.
 | 
			
		||||
// If there is no hit, it derives the key with the s2k function from the passphrase,
 | 
			
		||||
// updates the cache, and returns the key.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -50,9 +50,9 @@ type Config struct {
 | 
			
		||||
type Argon2Config struct {
 | 
			
		||||
	NumberOfPasses      uint8
 | 
			
		||||
	DegreeOfParallelism uint8
 | 
			
		||||
	// The memory parameter for Argon2 specifies desired memory usage in kibibytes.
 | 
			
		||||
	// The memory parameter for Argon2 specifies desired memory usage in kibibytes. 
 | 
			
		||||
	// For example memory=64*1024 sets the memory cost to ~64 MB.
 | 
			
		||||
	Memory uint32
 | 
			
		||||
	Memory      	    uint32 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) Mode() Mode {
 | 
			
		||||
@ -115,7 +115,7 @@ func (c *Argon2Config) EncodedMemory() uint8 {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memory := c.Memory
 | 
			
		||||
	lowerBound := uint32(c.Parallelism()) * 8
 | 
			
		||||
	lowerBound := uint32(c.Parallelism())*8
 | 
			
		||||
	upperBound := uint32(2147483648)
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/beorn7/perks/quantile/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/beorn7/perks/quantile/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -9,7 +9,7 @@
 | 
			
		||||
//
 | 
			
		||||
// For more detailed information about the algorithm used, see:
 | 
			
		||||
//
 | 
			
		||||
// # Effective Computation of Biased Quantiles over Data Streams
 | 
			
		||||
// Effective Computation of Biased Quantiles over Data Streams
 | 
			
		||||
//
 | 
			
		||||
// http://www.cs.rutgers.edu/~muthu/bquant.pdf
 | 
			
		||||
package quantile
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/github.com/cenkalti/backoff/v4/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/cenkalti/backoff/v4/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -11,17 +11,17 @@ period for each retry attempt using a randomization function that grows exponent
 | 
			
		||||
 | 
			
		||||
NextBackOff() is calculated using the following formula:
 | 
			
		||||
 | 
			
		||||
	randomized interval =
 | 
			
		||||
	    RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
 | 
			
		||||
 randomized interval =
 | 
			
		||||
     RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
 | 
			
		||||
 | 
			
		||||
In other words NextBackOff() will range between the randomization factor
 | 
			
		||||
percentage below and above the retry interval.
 | 
			
		||||
 | 
			
		||||
For example, given the following parameters:
 | 
			
		||||
 | 
			
		||||
	RetryInterval = 2
 | 
			
		||||
	RandomizationFactor = 0.5
 | 
			
		||||
	Multiplier = 2
 | 
			
		||||
 RetryInterval = 2
 | 
			
		||||
 RandomizationFactor = 0.5
 | 
			
		||||
 Multiplier = 2
 | 
			
		||||
 | 
			
		||||
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
 | 
			
		||||
multiplied by the exponential, that is, between 2 and 6 seconds.
 | 
			
		||||
@ -36,18 +36,18 @@ The elapsed time can be reset by calling Reset().
 | 
			
		||||
Example: Given the following default arguments, for 10 tries the sequence will be,
 | 
			
		||||
and assuming we go over the MaxElapsedTime on the 10th try:
 | 
			
		||||
 | 
			
		||||
	Request #  RetryInterval (seconds)  Randomized Interval (seconds)
 | 
			
		||||
 Request #  RetryInterval (seconds)  Randomized Interval (seconds)
 | 
			
		||||
 | 
			
		||||
	 1          0.5                     [0.25,   0.75]
 | 
			
		||||
	 2          0.75                    [0.375,  1.125]
 | 
			
		||||
	 3          1.125                   [0.562,  1.687]
 | 
			
		||||
	 4          1.687                   [0.8435, 2.53]
 | 
			
		||||
	 5          2.53                    [1.265,  3.795]
 | 
			
		||||
	 6          3.795                   [1.897,  5.692]
 | 
			
		||||
	 7          5.692                   [2.846,  8.538]
 | 
			
		||||
	 8          8.538                   [4.269, 12.807]
 | 
			
		||||
	 9         12.807                   [6.403, 19.210]
 | 
			
		||||
	10         19.210                   backoff.Stop
 | 
			
		||||
  1          0.5                     [0.25,   0.75]
 | 
			
		||||
  2          0.75                    [0.375,  1.125]
 | 
			
		||||
  3          1.125                   [0.562,  1.687]
 | 
			
		||||
  4          1.687                   [0.8435, 2.53]
 | 
			
		||||
  5          2.53                    [1.265,  3.795]
 | 
			
		||||
  6          3.795                   [1.897,  5.692]
 | 
			
		||||
  7          5.692                   [2.846,  8.538]
 | 
			
		||||
  8          8.538                   [4.269, 12.807]
 | 
			
		||||
  9         12.807                   [6.403, 19.210]
 | 
			
		||||
 10         19.210                   backoff.Stop
 | 
			
		||||
 | 
			
		||||
Note: Implementation is not thread-safe.
 | 
			
		||||
*/
 | 
			
		||||
@ -167,8 +167,7 @@ func (b *ExponentialBackOff) Reset() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextBackOff calculates the next backoff interval using the formula:
 | 
			
		||||
//
 | 
			
		||||
//	Randomized interval = RetryInterval * (1 ± RandomizationFactor)
 | 
			
		||||
// 	Randomized interval = RetryInterval * (1 ± RandomizationFactor)
 | 
			
		||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
 | 
			
		||||
	// Make sure we have not gone over the maximum elapsed time.
 | 
			
		||||
	elapsed := b.GetElapsedTime()
 | 
			
		||||
@ -201,8 +200,7 @@ func (b *ExponentialBackOff) incrementCurrentInterval() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a random value from the following interval:
 | 
			
		||||
//
 | 
			
		||||
//	[currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
 | 
			
		||||
// 	[currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
 | 
			
		||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
 | 
			
		||||
	if randomizationFactor == 0 {
 | 
			
		||||
		return currentInterval // make sure no randomness is used when randomizationFactor is 0.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/containers/image/docker/reference/reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containers/image/docker/reference/reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -3,13 +3,13 @@
 | 
			
		||||
//
 | 
			
		||||
// Grammar
 | 
			
		||||
//
 | 
			
		||||
//	reference                       := name [ ":" tag ] [ "@" digest ]
 | 
			
		||||
// 	reference                       := name [ ":" tag ] [ "@" digest ]
 | 
			
		||||
//	name                            := [domain '/'] path-component ['/' path-component]*
 | 
			
		||||
//	domain                          := domain-component ['.' domain-component]* [':' port-number]
 | 
			
		||||
//	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
 | 
			
		||||
//	port-number                     := /[0-9]+/
 | 
			
		||||
//	path-component                  := alpha-numeric [separator alpha-numeric]*
 | 
			
		||||
//	alpha-numeric                   := /[a-z0-9]+/
 | 
			
		||||
// 	alpha-numeric                   := /[a-z0-9]+/
 | 
			
		||||
//	separator                       := /[_.]|__|[-]*/
 | 
			
		||||
//
 | 
			
		||||
//	tag                             := /[\w][\w.-]{0,127}/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
//go:build !linux && (!386 || !amd64)
 | 
			
		||||
// +build !linux
 | 
			
		||||
// +build !386 !amd64
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/key.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/key.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -2,7 +2,6 @@
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build linux
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
package keyctl
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -2,7 +2,6 @@
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build linux
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
// Package keyctl is a Go interface to linux kernel keyrings (keyctl interface)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/perm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/perm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -2,7 +2,6 @@
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build linux
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
package keyctl
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -2,7 +2,6 @@
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
//go:build linux
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
package keyctl
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/containers/image/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containers/image/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -131,25 +131,24 @@ type BICReplacementCandidate struct {
 | 
			
		||||
// BlobInfoCache records data useful for reusing blobs, or substituing equivalent ones, to avoid unnecessary blob copies.
 | 
			
		||||
//
 | 
			
		||||
// It records two kinds of data:
 | 
			
		||||
// - Sets of corresponding digest vs. uncompressed digest ("DiffID") pairs:
 | 
			
		||||
//   One of the two digests is known to be uncompressed, and a single uncompressed digest may correspond to more than one compressed digest.
 | 
			
		||||
//   This allows matching compressed layer blobs to existing local uncompressed layers (to avoid unnecessary download and decompresssion),
 | 
			
		||||
//   or uncompressed layer blobs to existing remote compressed layers (to avoid unnecessary compression and upload)/
 | 
			
		||||
//
 | 
			
		||||
//   - Sets of corresponding digest vs. uncompressed digest ("DiffID") pairs:
 | 
			
		||||
//     One of the two digests is known to be uncompressed, and a single uncompressed digest may correspond to more than one compressed digest.
 | 
			
		||||
//     This allows matching compressed layer blobs to existing local uncompressed layers (to avoid unnecessary download and decompresssion),
 | 
			
		||||
//     or uncompressed layer blobs to existing remote compressed layers (to avoid unnecessary compression and upload)/
 | 
			
		||||
//   It is allowed to record an (uncompressed digest, the same uncompressed digest) correspondence, to express that the digest is known
 | 
			
		||||
//   to be uncompressed (i.e. that a conversion from schema1 does not have to decompress the blob to compute a DiffID value).
 | 
			
		||||
//
 | 
			
		||||
//     It is allowed to record an (uncompressed digest, the same uncompressed digest) correspondence, to express that the digest is known
 | 
			
		||||
//     to be uncompressed (i.e. that a conversion from schema1 does not have to decompress the blob to compute a DiffID value).
 | 
			
		||||
//   This mapping is primarily maintained in generic copy.Image code, but transports may want to contribute more data points if they independently
 | 
			
		||||
//   compress/decompress blobs for their own purposes.
 | 
			
		||||
//
 | 
			
		||||
//     This mapping is primarily maintained in generic copy.Image code, but transports may want to contribute more data points if they independently
 | 
			
		||||
//     compress/decompress blobs for their own purposes.
 | 
			
		||||
// - Known blob locations, managed by individual transports:
 | 
			
		||||
//   The transports call RecordKnownLocation when encountering a blob that could possibly be reused (typically in GetBlob/PutBlob/TryReusingBlob),
 | 
			
		||||
//   recording transport-specific information that allows the transport to reuse the blob in the future;
 | 
			
		||||
//   then, TryReusingBlob implementations can call CandidateLocations to look up previously recorded blob locations that could be reused.
 | 
			
		||||
//
 | 
			
		||||
//   - Known blob locations, managed by individual transports:
 | 
			
		||||
//     The transports call RecordKnownLocation when encountering a blob that could possibly be reused (typically in GetBlob/PutBlob/TryReusingBlob),
 | 
			
		||||
//     recording transport-specific information that allows the transport to reuse the blob in the future;
 | 
			
		||||
//     then, TryReusingBlob implementations can call CandidateLocations to look up previously recorded blob locations that could be reused.
 | 
			
		||||
//
 | 
			
		||||
//     Each transport defines its own “scopes” within which blob reuse is possible (e.g. in, the docker/distribution case, blobs
 | 
			
		||||
//     can be directly reused within a registry, or mounted across registries within a registry server.)
 | 
			
		||||
//   Each transport defines its own “scopes” within which blob reuse is possible (e.g. in, the docker/distribution case, blobs
 | 
			
		||||
//   can be directly reused within a registry, or mounted across registries within a registry server.)
 | 
			
		||||
//
 | 
			
		||||
// None of the methods return an error indication: errors when neither reading from, nor writing to, the cache, should be fatal;
 | 
			
		||||
// users of the cahce should just fall back to copying the blobs the usual way.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,21 +0,0 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2014 Brian Goff
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,16 +0,0 @@
 | 
			
		||||
package md2man
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/russross/blackfriday/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Render converts a markdown document into a roff formatted document.
 | 
			
		||||
func Render(doc []byte) []byte {
 | 
			
		||||
	renderer := NewRoffRenderer()
 | 
			
		||||
 | 
			
		||||
	return blackfriday.Run(doc,
 | 
			
		||||
		[]blackfriday.Option{
 | 
			
		||||
			blackfriday.WithRenderer(renderer),
 | 
			
		||||
			blackfriday.WithExtensions(renderer.GetExtensions()),
 | 
			
		||||
		}...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										382
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										382
									
								
								vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,382 +0,0 @@
 | 
			
		||||
package md2man
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/russross/blackfriday/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// roffRenderer implements the blackfriday.Renderer interface for creating
 | 
			
		||||
// roff format (manpages) from markdown text
 | 
			
		||||
type roffRenderer struct {
 | 
			
		||||
	extensions   blackfriday.Extensions
 | 
			
		||||
	listCounters []int
 | 
			
		||||
	firstHeader  bool
 | 
			
		||||
	firstDD      bool
 | 
			
		||||
	listDepth    int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	titleHeader       = ".TH "
 | 
			
		||||
	topLevelHeader    = "\n\n.SH "
 | 
			
		||||
	secondLevelHdr    = "\n.SH "
 | 
			
		||||
	otherHeader       = "\n.SS "
 | 
			
		||||
	crTag             = "\n"
 | 
			
		||||
	emphTag           = "\\fI"
 | 
			
		||||
	emphCloseTag      = "\\fP"
 | 
			
		||||
	strongTag         = "\\fB"
 | 
			
		||||
	strongCloseTag    = "\\fP"
 | 
			
		||||
	breakTag          = "\n.br\n"
 | 
			
		||||
	paraTag           = "\n.PP\n"
 | 
			
		||||
	hruleTag          = "\n.ti 0\n\\l'\\n(.lu'\n"
 | 
			
		||||
	linkTag           = "\n\\[la]"
 | 
			
		||||
	linkCloseTag      = "\\[ra]"
 | 
			
		||||
	codespanTag       = "\\fB"
 | 
			
		||||
	codespanCloseTag  = "\\fR"
 | 
			
		||||
	codeTag           = "\n.EX\n"
 | 
			
		||||
	codeCloseTag      = ".EE\n" // Do not prepend a newline character since code blocks, by definition, include a newline already (or at least as how blackfriday gives us on).
 | 
			
		||||
	quoteTag          = "\n.PP\n.RS\n"
 | 
			
		||||
	quoteCloseTag     = "\n.RE\n"
 | 
			
		||||
	listTag           = "\n.RS\n"
 | 
			
		||||
	listCloseTag      = "\n.RE\n"
 | 
			
		||||
	dtTag             = "\n.TP\n"
 | 
			
		||||
	dd2Tag            = "\n"
 | 
			
		||||
	tableStart        = "\n.TS\nallbox;\n"
 | 
			
		||||
	tableEnd          = ".TE\n"
 | 
			
		||||
	tableCellStart    = "T{\n"
 | 
			
		||||
	tableCellEnd      = "\nT}\n"
 | 
			
		||||
	tablePreprocessor = `'\" t`
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
 | 
			
		||||
// from markdown
 | 
			
		||||
func NewRoffRenderer() *roffRenderer { // nolint: golint
 | 
			
		||||
	var extensions blackfriday.Extensions
 | 
			
		||||
 | 
			
		||||
	extensions |= blackfriday.NoIntraEmphasis
 | 
			
		||||
	extensions |= blackfriday.Tables
 | 
			
		||||
	extensions |= blackfriday.FencedCode
 | 
			
		||||
	extensions |= blackfriday.SpaceHeadings
 | 
			
		||||
	extensions |= blackfriday.Footnotes
 | 
			
		||||
	extensions |= blackfriday.Titleblock
 | 
			
		||||
	extensions |= blackfriday.DefinitionLists
 | 
			
		||||
	return &roffRenderer{
 | 
			
		||||
		extensions: extensions,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetExtensions returns the list of extensions used by this renderer implementation
 | 
			
		||||
func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
 | 
			
		||||
	return r.extensions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderHeader handles outputting the header at document start
 | 
			
		||||
func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) {
 | 
			
		||||
	// We need to walk the tree to check if there are any tables.
 | 
			
		||||
	// If there are, we need to enable the roff table preprocessor.
 | 
			
		||||
	ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
 | 
			
		||||
		if node.Type == blackfriday.Table {
 | 
			
		||||
			out(w, tablePreprocessor+"\n")
 | 
			
		||||
			return blackfriday.Terminate
 | 
			
		||||
		}
 | 
			
		||||
		return blackfriday.GoToNext
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// disable hyphenation
 | 
			
		||||
	out(w, ".nh\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderFooter handles outputting the footer at the document end; the roff
 | 
			
		||||
// renderer has no footer information
 | 
			
		||||
func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderNode is called for each node in a markdown document; based on the node
 | 
			
		||||
// type the equivalent roff output is sent to the writer
 | 
			
		||||
func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
 | 
			
		||||
	walkAction := blackfriday.GoToNext
 | 
			
		||||
 | 
			
		||||
	switch node.Type {
 | 
			
		||||
	case blackfriday.Text:
 | 
			
		||||
		escapeSpecialChars(w, node.Literal)
 | 
			
		||||
	case blackfriday.Softbreak:
 | 
			
		||||
		out(w, crTag)
 | 
			
		||||
	case blackfriday.Hardbreak:
 | 
			
		||||
		out(w, breakTag)
 | 
			
		||||
	case blackfriday.Emph:
 | 
			
		||||
		if entering {
 | 
			
		||||
			out(w, emphTag)
 | 
			
		||||
		} else {
 | 
			
		||||
			out(w, emphCloseTag)
 | 
			
		||||
		}
 | 
			
		||||
	case blackfriday.Strong:
 | 
			
		||||
		if entering {
 | 
			
		||||
			out(w, strongTag)
 | 
			
		||||
		} else {
 | 
			
		||||
			out(w, strongCloseTag)
 | 
			
		||||
		}
 | 
			
		||||
	case blackfriday.Link:
 | 
			
		||||
		// Don't render the link text for automatic links, because this
 | 
			
		||||
		// will only duplicate the URL in the roff output.
 | 
			
		||||
		// See https://daringfireball.net/projects/markdown/syntax#autolink
 | 
			
		||||
		if !bytes.Equal(node.LinkData.Destination, node.FirstChild.Literal) {
 | 
			
		||||
			out(w, string(node.FirstChild.Literal))
 | 
			
		||||
		}
 | 
			
		||||
		// Hyphens in a link must be escaped to avoid word-wrap in the rendered man page.
 | 
			
		||||
		escapedLink := strings.ReplaceAll(string(node.LinkData.Destination), "-", "\\-")
 | 
			
		||||
		out(w, linkTag+escapedLink+linkCloseTag)
 | 
			
		||||
		walkAction = blackfriday.SkipChildren
 | 
			
		||||
	case blackfriday.Image:
 | 
			
		||||
		// ignore images
 | 
			
		||||
		walkAction = blackfriday.SkipChildren
 | 
			
		||||
	case blackfriday.Code:
 | 
			
		||||
		out(w, codespanTag)
 | 
			
		||||
		escapeSpecialChars(w, node.Literal)
 | 
			
		||||
		out(w, codespanCloseTag)
 | 
			
		||||
	case blackfriday.Document:
 | 
			
		||||
		break
 | 
			
		||||
	case blackfriday.Paragraph:
 | 
			
		||||
		// roff .PP markers break lists
 | 
			
		||||
		if r.listDepth > 0 {
 | 
			
		||||
			return blackfriday.GoToNext
 | 
			
		||||
		}
 | 
			
		||||
		if entering {
 | 
			
		||||
			out(w, paraTag)
 | 
			
		||||
		} else {
 | 
			
		||||
			out(w, crTag)
 | 
			
		||||
		}
 | 
			
		||||
	case blackfriday.BlockQuote:
 | 
			
		||||
		if entering {
 | 
			
		||||
			out(w, quoteTag)
 | 
			
		||||
		} else {
 | 
			
		||||
			out(w, quoteCloseTag)
 | 
			
		||||
		}
 | 
			
		||||
	case blackfriday.Heading:
 | 
			
		||||
		r.handleHeading(w, node, entering)
 | 
			
		||||
	case blackfriday.HorizontalRule:
 | 
			
		||||
		out(w, hruleTag)
 | 
			
		||||
	case blackfriday.List:
 | 
			
		||||
		r.handleList(w, node, entering)
 | 
			
		||||
	case blackfriday.Item:
 | 
			
		||||
		r.handleItem(w, node, entering)
 | 
			
		||||
	case blackfriday.CodeBlock:
 | 
			
		||||
		out(w, codeTag)
 | 
			
		||||
		escapeSpecialChars(w, node.Literal)
 | 
			
		||||
		out(w, codeCloseTag)
 | 
			
		||||
	case blackfriday.Table:
 | 
			
		||||
		r.handleTable(w, node, entering)
 | 
			
		||||
	case blackfriday.TableHead:
 | 
			
		||||
	case blackfriday.TableBody:
 | 
			
		||||
	case blackfriday.TableRow:
 | 
			
		||||
		// no action as cell entries do all the nroff formatting
 | 
			
		||||
		return blackfriday.GoToNext
 | 
			
		||||
	case blackfriday.TableCell:
 | 
			
		||||
		r.handleTableCell(w, node, entering)
 | 
			
		||||
	case blackfriday.HTMLSpan:
 | 
			
		||||
		// ignore other HTML tags
 | 
			
		||||
	case blackfriday.HTMLBlock:
 | 
			
		||||
		if bytes.HasPrefix(node.Literal, []byte("<!--")) {
 | 
			
		||||
			break // ignore comments, no warning
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
 | 
			
		||||
	}
 | 
			
		||||
	return walkAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) {
 | 
			
		||||
	if entering {
 | 
			
		||||
		switch node.Level {
 | 
			
		||||
		case 1:
 | 
			
		||||
			if !r.firstHeader {
 | 
			
		||||
				out(w, titleHeader)
 | 
			
		||||
				r.firstHeader = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			out(w, topLevelHeader)
 | 
			
		||||
		case 2:
 | 
			
		||||
			out(w, secondLevelHdr)
 | 
			
		||||
		default:
 | 
			
		||||
			out(w, otherHeader)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
 | 
			
		||||
	openTag := listTag
 | 
			
		||||
	closeTag := listCloseTag
 | 
			
		||||
	if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
 | 
			
		||||
		// tags for definition lists handled within Item node
 | 
			
		||||
		openTag = ""
 | 
			
		||||
		closeTag = ""
 | 
			
		||||
	}
 | 
			
		||||
	if entering {
 | 
			
		||||
		r.listDepth++
 | 
			
		||||
		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
 | 
			
		||||
			r.listCounters = append(r.listCounters, 1)
 | 
			
		||||
		}
 | 
			
		||||
		out(w, openTag)
 | 
			
		||||
	} else {
 | 
			
		||||
		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
 | 
			
		||||
			r.listCounters = r.listCounters[:len(r.listCounters)-1]
 | 
			
		||||
		}
 | 
			
		||||
		out(w, closeTag)
 | 
			
		||||
		r.listDepth--
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) {
 | 
			
		||||
	if entering {
 | 
			
		||||
		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
 | 
			
		||||
			out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1]))
 | 
			
		||||
			r.listCounters[len(r.listCounters)-1]++
 | 
			
		||||
		} else if node.ListFlags&blackfriday.ListTypeTerm != 0 {
 | 
			
		||||
			// DT (definition term): line just before DD (see below).
 | 
			
		||||
			out(w, dtTag)
 | 
			
		||||
			r.firstDD = true
 | 
			
		||||
		} else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
 | 
			
		||||
			// DD (definition description): line that starts with ": ".
 | 
			
		||||
			//
 | 
			
		||||
			// We have to distinguish between the first DD and the
 | 
			
		||||
			// subsequent ones, as there should be no vertical
 | 
			
		||||
			// whitespace between the DT and the first DD.
 | 
			
		||||
			if r.firstDD {
 | 
			
		||||
				r.firstDD = false
 | 
			
		||||
			} else {
 | 
			
		||||
				out(w, dd2Tag)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			out(w, ".IP \\(bu 2\n")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		out(w, "\n")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) {
 | 
			
		||||
	if entering {
 | 
			
		||||
		out(w, tableStart)
 | 
			
		||||
		// call walker to count cells (and rows?) so format section can be produced
 | 
			
		||||
		columns := countColumns(node)
 | 
			
		||||
		out(w, strings.Repeat("l ", columns)+"\n")
 | 
			
		||||
		out(w, strings.Repeat("l ", columns)+".\n")
 | 
			
		||||
	} else {
 | 
			
		||||
		out(w, tableEnd)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) {
 | 
			
		||||
	if entering {
 | 
			
		||||
		var start string
 | 
			
		||||
		if node.Prev != nil && node.Prev.Type == blackfriday.TableCell {
 | 
			
		||||
			start = "\t"
 | 
			
		||||
		}
 | 
			
		||||
		if node.IsHeader {
 | 
			
		||||
			start += strongTag
 | 
			
		||||
		} else if nodeLiteralSize(node) > 30 {
 | 
			
		||||
			start += tableCellStart
 | 
			
		||||
		}
 | 
			
		||||
		out(w, start)
 | 
			
		||||
	} else {
 | 
			
		||||
		var end string
 | 
			
		||||
		if node.IsHeader {
 | 
			
		||||
			end = strongCloseTag
 | 
			
		||||
		} else if nodeLiteralSize(node) > 30 {
 | 
			
		||||
			end = tableCellEnd
 | 
			
		||||
		}
 | 
			
		||||
		if node.Next == nil && end != tableCellEnd {
 | 
			
		||||
			// Last cell: need to carriage return if we are at the end of the
 | 
			
		||||
			// header row and content isn't wrapped in a "tablecell"
 | 
			
		||||
			end += crTag
 | 
			
		||||
		}
 | 
			
		||||
		out(w, end)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nodeLiteralSize(node *blackfriday.Node) int {
 | 
			
		||||
	total := 0
 | 
			
		||||
	for n := node.FirstChild; n != nil; n = n.FirstChild {
 | 
			
		||||
		total += len(n.Literal)
 | 
			
		||||
	}
 | 
			
		||||
	return total
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// because roff format requires knowing the column count before outputting any table
 | 
			
		||||
// data we need to walk a table tree and count the columns
 | 
			
		||||
func countColumns(node *blackfriday.Node) int {
 | 
			
		||||
	var columns int
 | 
			
		||||
 | 
			
		||||
	node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
 | 
			
		||||
		switch node.Type {
 | 
			
		||||
		case blackfriday.TableRow:
 | 
			
		||||
			if !entering {
 | 
			
		||||
				return blackfriday.Terminate
 | 
			
		||||
			}
 | 
			
		||||
		case blackfriday.TableCell:
 | 
			
		||||
			if entering {
 | 
			
		||||
				columns++
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
		return blackfriday.GoToNext
 | 
			
		||||
	})
 | 
			
		||||
	return columns
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func out(w io.Writer, output string) {
 | 
			
		||||
	io.WriteString(w, output) // nolint: errcheck
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func escapeSpecialChars(w io.Writer, text []byte) {
 | 
			
		||||
	scanner := bufio.NewScanner(bytes.NewReader(text))
 | 
			
		||||
 | 
			
		||||
	// count the number of lines in the text
 | 
			
		||||
	// we need to know this to avoid adding a newline after the last line
 | 
			
		||||
	n := bytes.Count(text, []byte{'\n'})
 | 
			
		||||
	idx := 0
 | 
			
		||||
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		dt := scanner.Bytes()
 | 
			
		||||
		if idx < n {
 | 
			
		||||
			idx++
 | 
			
		||||
			dt = append(dt, '\n')
 | 
			
		||||
		}
 | 
			
		||||
		escapeSpecialCharsLine(w, dt)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := scanner.Err(); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func escapeSpecialCharsLine(w io.Writer, text []byte) {
 | 
			
		||||
	for i := 0; i < len(text); i++ {
 | 
			
		||||
		// escape initial apostrophe or period
 | 
			
		||||
		if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {
 | 
			
		||||
			out(w, "\\&")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// directly copy normal characters
 | 
			
		||||
		org := i
 | 
			
		||||
 | 
			
		||||
		for i < len(text) && text[i] != '\\' {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
		if i > org {
 | 
			
		||||
			w.Write(text[org:i]) // nolint: errcheck
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// escape a character
 | 
			
		||||
		if i >= len(text) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		w.Write([]byte{'\\', text[i]}) // nolint: errcheck
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/davecgh/go-spew/spew/bypass.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/davecgh/go-spew/spew/bypass.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -18,7 +18,6 @@
 | 
			
		||||
// tag is deprecated and thus should not be used.
 | 
			
		||||
// Go versions prior to 1.4 are disabled because they use a different layout
 | 
			
		||||
// for interfaces which make the implementation of unsafeReflectValue more complex.
 | 
			
		||||
//go:build !js && !appengine && !safe && !disableunsafe && go1.4
 | 
			
		||||
// +build !js,!appengine,!safe,!disableunsafe,go1.4
 | 
			
		||||
 | 
			
		||||
package spew
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -16,7 +16,6 @@
 | 
			
		||||
// when the code is running on Google App Engine, compiled by GopherJS, or
 | 
			
		||||
// "-tags safe" is added to the go build command line.  The "disableunsafe"
 | 
			
		||||
// tag is deprecated and thus should not be used.
 | 
			
		||||
//go:build js || appengine || safe || disableunsafe || !go1.4
 | 
			
		||||
// +build js appengine safe disableunsafe !go1.4
 | 
			
		||||
 | 
			
		||||
package spew
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/github.com/davecgh/go-spew/spew/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/davecgh/go-spew/spew/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -254,15 +254,15 @@ pointer addresses used to indirect to the final value.  It provides the
 | 
			
		||||
following features over the built-in printing facilities provided by the fmt
 | 
			
		||||
package:
 | 
			
		||||
 | 
			
		||||
  - Pointers are dereferenced and followed
 | 
			
		||||
  - Circular data structures are detected and handled properly
 | 
			
		||||
  - Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
    on unexported types
 | 
			
		||||
  - Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
    a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
    variables
 | 
			
		||||
  - Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
    includes offsets, byte values in hex, and ASCII output
 | 
			
		||||
	* Pointers are dereferenced and followed
 | 
			
		||||
	* Circular data structures are detected and handled properly
 | 
			
		||||
	* Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
	  on unexported types
 | 
			
		||||
	* Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
	  a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
	  variables
 | 
			
		||||
	* Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
	  includes offsets, byte values in hex, and ASCII output
 | 
			
		||||
 | 
			
		||||
The configuration options are controlled by modifying the public members
 | 
			
		||||
of c.  See ConfigState for options documentation.
 | 
			
		||||
@ -295,12 +295,12 @@ func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{})
 | 
			
		||||
 | 
			
		||||
// NewDefaultConfig returns a ConfigState with the following default settings.
 | 
			
		||||
//
 | 
			
		||||
//	Indent: " "
 | 
			
		||||
//	MaxDepth: 0
 | 
			
		||||
//	DisableMethods: false
 | 
			
		||||
//	DisablePointerMethods: false
 | 
			
		||||
//	ContinueOnMethod: false
 | 
			
		||||
//	SortKeys: false
 | 
			
		||||
// 	Indent: " "
 | 
			
		||||
// 	MaxDepth: 0
 | 
			
		||||
// 	DisableMethods: false
 | 
			
		||||
// 	DisablePointerMethods: false
 | 
			
		||||
// 	ContinueOnMethod: false
 | 
			
		||||
// 	SortKeys: false
 | 
			
		||||
func NewDefaultConfig() *ConfigState {
 | 
			
		||||
	return &ConfigState{Indent: " "}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/davecgh/go-spew/spew/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/davecgh/go-spew/spew/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -21,36 +21,35 @@ debugging.
 | 
			
		||||
A quick overview of the additional features spew provides over the built-in
 | 
			
		||||
printing facilities for Go data types are as follows:
 | 
			
		||||
 | 
			
		||||
  - Pointers are dereferenced and followed
 | 
			
		||||
  - Circular data structures are detected and handled properly
 | 
			
		||||
  - Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
    on unexported types
 | 
			
		||||
  - Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
    a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
    variables
 | 
			
		||||
  - Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
    includes offsets, byte values in hex, and ASCII output (only when using
 | 
			
		||||
    Dump style)
 | 
			
		||||
	* Pointers are dereferenced and followed
 | 
			
		||||
	* Circular data structures are detected and handled properly
 | 
			
		||||
	* Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
	  on unexported types
 | 
			
		||||
	* Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
	  a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
	  variables
 | 
			
		||||
	* Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
	  includes offsets, byte values in hex, and ASCII output (only when using
 | 
			
		||||
	  Dump style)
 | 
			
		||||
 | 
			
		||||
There are two different approaches spew allows for dumping Go data structures:
 | 
			
		||||
 | 
			
		||||
  - Dump style which prints with newlines, customizable indentation,
 | 
			
		||||
    and additional debug information such as types and all pointer addresses
 | 
			
		||||
    used to indirect to the final value
 | 
			
		||||
  - A custom Formatter interface that integrates cleanly with the standard fmt
 | 
			
		||||
    package and replaces %v, %+v, %#v, and %#+v to provide inline printing
 | 
			
		||||
    similar to the default %v while providing the additional functionality
 | 
			
		||||
    outlined above and passing unsupported format verbs such as %x and %q
 | 
			
		||||
    along to fmt
 | 
			
		||||
	* Dump style which prints with newlines, customizable indentation,
 | 
			
		||||
	  and additional debug information such as types and all pointer addresses
 | 
			
		||||
	  used to indirect to the final value
 | 
			
		||||
	* A custom Formatter interface that integrates cleanly with the standard fmt
 | 
			
		||||
	  package and replaces %v, %+v, %#v, and %#+v to provide inline printing
 | 
			
		||||
	  similar to the default %v while providing the additional functionality
 | 
			
		||||
	  outlined above and passing unsupported format verbs such as %x and %q
 | 
			
		||||
	  along to fmt
 | 
			
		||||
 | 
			
		||||
# Quick Start
 | 
			
		||||
Quick Start
 | 
			
		||||
 | 
			
		||||
This section demonstrates how to quickly get started with spew.  See the
 | 
			
		||||
sections below for further details on formatting and configuration options.
 | 
			
		||||
 | 
			
		||||
To dump a variable with full newlines, indentation, type, and pointer
 | 
			
		||||
information use Dump, Fdump, or Sdump:
 | 
			
		||||
 | 
			
		||||
	spew.Dump(myVar1, myVar2, ...)
 | 
			
		||||
	spew.Fdump(someWriter, myVar1, myVar2, ...)
 | 
			
		||||
	str := spew.Sdump(myVar1, myVar2, ...)
 | 
			
		||||
@ -59,13 +58,12 @@ Alternatively, if you would prefer to use format strings with a compacted inline
 | 
			
		||||
printing style, use the convenience wrappers Printf, Fprintf, etc with
 | 
			
		||||
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
 | 
			
		||||
%#+v (adds types and pointer addresses):
 | 
			
		||||
 | 
			
		||||
	spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
 | 
			
		||||
	spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
 | 
			
		||||
	spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
 | 
			
		||||
	spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
 | 
			
		||||
 | 
			
		||||
# Configuration Options
 | 
			
		||||
Configuration Options
 | 
			
		||||
 | 
			
		||||
Configuration of spew is handled by fields in the ConfigState type.  For
 | 
			
		||||
convenience, all of the top-level functions use a global state available
 | 
			
		||||
@ -76,52 +74,51 @@ equivalent to the top-level functions.  This allows concurrent configuration
 | 
			
		||||
options.  See the ConfigState documentation for more details.
 | 
			
		||||
 | 
			
		||||
The following configuration options are available:
 | 
			
		||||
	* Indent
 | 
			
		||||
		String to use for each indentation level for Dump functions.
 | 
			
		||||
		It is a single space by default.  A popular alternative is "\t".
 | 
			
		||||
 | 
			
		||||
  - Indent
 | 
			
		||||
    String to use for each indentation level for Dump functions.
 | 
			
		||||
    It is a single space by default.  A popular alternative is "\t".
 | 
			
		||||
	* MaxDepth
 | 
			
		||||
		Maximum number of levels to descend into nested data structures.
 | 
			
		||||
		There is no limit by default.
 | 
			
		||||
 | 
			
		||||
  - MaxDepth
 | 
			
		||||
    Maximum number of levels to descend into nested data structures.
 | 
			
		||||
    There is no limit by default.
 | 
			
		||||
	* DisableMethods
 | 
			
		||||
		Disables invocation of error and Stringer interface methods.
 | 
			
		||||
		Method invocation is enabled by default.
 | 
			
		||||
 | 
			
		||||
  - DisableMethods
 | 
			
		||||
    Disables invocation of error and Stringer interface methods.
 | 
			
		||||
    Method invocation is enabled by default.
 | 
			
		||||
	* DisablePointerMethods
 | 
			
		||||
		Disables invocation of error and Stringer interface methods on types
 | 
			
		||||
		which only accept pointer receivers from non-pointer variables.
 | 
			
		||||
		Pointer method invocation is enabled by default.
 | 
			
		||||
 | 
			
		||||
  - DisablePointerMethods
 | 
			
		||||
    Disables invocation of error and Stringer interface methods on types
 | 
			
		||||
    which only accept pointer receivers from non-pointer variables.
 | 
			
		||||
    Pointer method invocation is enabled by default.
 | 
			
		||||
	* DisablePointerAddresses
 | 
			
		||||
		DisablePointerAddresses specifies whether to disable the printing of
 | 
			
		||||
		pointer addresses. This is useful when diffing data structures in tests.
 | 
			
		||||
 | 
			
		||||
  - DisablePointerAddresses
 | 
			
		||||
    DisablePointerAddresses specifies whether to disable the printing of
 | 
			
		||||
    pointer addresses. This is useful when diffing data structures in tests.
 | 
			
		||||
	* DisableCapacities
 | 
			
		||||
		DisableCapacities specifies whether to disable the printing of
 | 
			
		||||
		capacities for arrays, slices, maps and channels. This is useful when
 | 
			
		||||
		diffing data structures in tests.
 | 
			
		||||
 | 
			
		||||
  - DisableCapacities
 | 
			
		||||
    DisableCapacities specifies whether to disable the printing of
 | 
			
		||||
    capacities for arrays, slices, maps and channels. This is useful when
 | 
			
		||||
    diffing data structures in tests.
 | 
			
		||||
	* ContinueOnMethod
 | 
			
		||||
		Enables recursion into types after invoking error and Stringer interface
 | 
			
		||||
		methods. Recursion after method invocation is disabled by default.
 | 
			
		||||
 | 
			
		||||
  - ContinueOnMethod
 | 
			
		||||
    Enables recursion into types after invoking error and Stringer interface
 | 
			
		||||
    methods. Recursion after method invocation is disabled by default.
 | 
			
		||||
	* SortKeys
 | 
			
		||||
		Specifies map keys should be sorted before being printed. Use
 | 
			
		||||
		this to have a more deterministic, diffable output.  Note that
 | 
			
		||||
		only native types (bool, int, uint, floats, uintptr and string)
 | 
			
		||||
		and types which implement error or Stringer interfaces are
 | 
			
		||||
		supported with other types sorted according to the
 | 
			
		||||
		reflect.Value.String() output which guarantees display
 | 
			
		||||
		stability.  Natural map order is used by default.
 | 
			
		||||
 | 
			
		||||
  - SortKeys
 | 
			
		||||
    Specifies map keys should be sorted before being printed. Use
 | 
			
		||||
    this to have a more deterministic, diffable output.  Note that
 | 
			
		||||
    only native types (bool, int, uint, floats, uintptr and string)
 | 
			
		||||
    and types which implement error or Stringer interfaces are
 | 
			
		||||
    supported with other types sorted according to the
 | 
			
		||||
    reflect.Value.String() output which guarantees display
 | 
			
		||||
    stability.  Natural map order is used by default.
 | 
			
		||||
	* SpewKeys
 | 
			
		||||
		Specifies that, as a last resort attempt, map keys should be
 | 
			
		||||
		spewed to strings and sorted by those strings.  This is only
 | 
			
		||||
		considered if SortKeys is true.
 | 
			
		||||
 | 
			
		||||
  - SpewKeys
 | 
			
		||||
    Specifies that, as a last resort attempt, map keys should be
 | 
			
		||||
    spewed to strings and sorted by those strings.  This is only
 | 
			
		||||
    considered if SortKeys is true.
 | 
			
		||||
 | 
			
		||||
# Dump Usage
 | 
			
		||||
Dump Usage
 | 
			
		||||
 | 
			
		||||
Simply call spew.Dump with a list of variables you want to dump:
 | 
			
		||||
 | 
			
		||||
@ -136,7 +133,7 @@ A third option is to call spew.Sdump to get the formatted output as a string:
 | 
			
		||||
 | 
			
		||||
	str := spew.Sdump(myVar1, myVar2, ...)
 | 
			
		||||
 | 
			
		||||
# Sample Dump Output
 | 
			
		||||
Sample Dump Output
 | 
			
		||||
 | 
			
		||||
See the Dump example for details on the setup of the types and variables being
 | 
			
		||||
shown here.
 | 
			
		||||
@ -153,14 +150,13 @@ shown here.
 | 
			
		||||
 | 
			
		||||
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
 | 
			
		||||
command as shown.
 | 
			
		||||
 | 
			
		||||
	([]uint8) (len=32 cap=32) {
 | 
			
		||||
	 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
 | 
			
		||||
	 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
 | 
			
		||||
	 00000020  31 32                                             |12|
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
# Custom Formatter
 | 
			
		||||
Custom Formatter
 | 
			
		||||
 | 
			
		||||
Spew provides a custom formatter that implements the fmt.Formatter interface
 | 
			
		||||
so that it integrates cleanly with standard fmt package printing functions. The
 | 
			
		||||
@ -174,7 +170,7 @@ standard fmt package for formatting.  In addition, the custom formatter ignores
 | 
			
		||||
the width and precision arguments (however they will still work on the format
 | 
			
		||||
specifiers not handled by the custom formatter).
 | 
			
		||||
 | 
			
		||||
# Custom Formatter Usage
 | 
			
		||||
Custom Formatter Usage
 | 
			
		||||
 | 
			
		||||
The simplest way to make use of the spew custom formatter is to call one of the
 | 
			
		||||
convenience functions such as spew.Printf, spew.Println, or spew.Printf.  The
 | 
			
		||||
@ -188,17 +184,15 @@ functions have syntax you are most likely already familiar with:
 | 
			
		||||
 | 
			
		||||
See the Index for the full list convenience functions.
 | 
			
		||||
 | 
			
		||||
# Sample Formatter Output
 | 
			
		||||
Sample Formatter Output
 | 
			
		||||
 | 
			
		||||
Double pointer to a uint8:
 | 
			
		||||
 | 
			
		||||
	  %v: <**>5
 | 
			
		||||
	 %+v: <**>(0xf8400420d0->0xf8400420c8)5
 | 
			
		||||
	 %#v: (**uint8)5
 | 
			
		||||
	%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
 | 
			
		||||
 | 
			
		||||
Pointer to circular struct with a uint8 field and a pointer to itself:
 | 
			
		||||
 | 
			
		||||
	  %v: <*>{1 <*><shown>}
 | 
			
		||||
	 %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
 | 
			
		||||
	 %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
 | 
			
		||||
@ -207,7 +201,7 @@ Pointer to circular struct with a uint8 field and a pointer to itself:
 | 
			
		||||
See the Printf example for details on the setup of variables being shown
 | 
			
		||||
here.
 | 
			
		||||
 | 
			
		||||
# Errors
 | 
			
		||||
Errors
 | 
			
		||||
 | 
			
		||||
Since it is possible for custom Stringer/error interfaces to panic, spew
 | 
			
		||||
detects them and handles them internally by printing the panic information
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								vendor/github.com/davecgh/go-spew/spew/dump.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/davecgh/go-spew/spew/dump.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -488,15 +488,15 @@ pointer addresses used to indirect to the final value.  It provides the
 | 
			
		||||
following features over the built-in printing facilities provided by the fmt
 | 
			
		||||
package:
 | 
			
		||||
 | 
			
		||||
  - Pointers are dereferenced and followed
 | 
			
		||||
  - Circular data structures are detected and handled properly
 | 
			
		||||
  - Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
    on unexported types
 | 
			
		||||
  - Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
    a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
    variables
 | 
			
		||||
  - Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
    includes offsets, byte values in hex, and ASCII output
 | 
			
		||||
	* Pointers are dereferenced and followed
 | 
			
		||||
	* Circular data structures are detected and handled properly
 | 
			
		||||
	* Custom Stringer/error interfaces are optionally invoked, including
 | 
			
		||||
	  on unexported types
 | 
			
		||||
	* Custom types which only implement the Stringer/error interfaces via
 | 
			
		||||
	  a pointer receiver are optionally invoked when passing non-pointer
 | 
			
		||||
	  variables
 | 
			
		||||
	* Byte arrays and slices are dumped like the hexdump -C command which
 | 
			
		||||
	  includes offsets, byte values in hex, and ASCII output
 | 
			
		||||
 | 
			
		||||
The configuration options are controlled by an exported package global,
 | 
			
		||||
spew.Config.  See ConfigState for options documentation.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/go-metrics/namespace.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/go-metrics/namespace.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -37,8 +37,8 @@ type Namespace struct {
 | 
			
		||||
// WithConstLabels returns a namespace with the provided set of labels merged
 | 
			
		||||
// with the existing constant labels on the namespace.
 | 
			
		||||
//
 | 
			
		||||
//	Only metrics created with the returned namespace will get the new constant
 | 
			
		||||
//	labels.  The returned namespace must be registered separately.
 | 
			
		||||
//  Only metrics created with the returned namespace will get the new constant
 | 
			
		||||
//  labels.  The returned namespace must be registered separately.
 | 
			
		||||
func (n *Namespace) WithConstLabels(labels Labels) *Namespace {
 | 
			
		||||
	n.mu.Lock()
 | 
			
		||||
	ns := &Namespace{
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/docker/go/canonical/json/decode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/docker/go/canonical/json/decode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -74,13 +74,14 @@ import (
 | 
			
		||||
//
 | 
			
		||||
// The JSON null value unmarshals into an interface, map, pointer, or slice
 | 
			
		||||
// by setting that Go value to nil. Because null is often used in JSON to mean
 | 
			
		||||
// “not present,” unmarshaling a JSON null into any other Go type has no effect
 | 
			
		||||
// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
 | 
			
		||||
// on the value and produces no error.
 | 
			
		||||
//
 | 
			
		||||
// When unmarshaling quoted strings, invalid UTF-8 or
 | 
			
		||||
// invalid UTF-16 surrogate pairs are not treated as an error.
 | 
			
		||||
// Instead, they are replaced by the Unicode replacement
 | 
			
		||||
// character U+FFFD.
 | 
			
		||||
//
 | 
			
		||||
func Unmarshal(data []byte, v interface{}) error {
 | 
			
		||||
	// Check for well-formedness.
 | 
			
		||||
	// Avoids filling out half a data structure
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/docker/go/canonical/json/encode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/docker/go/canonical/json/encode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -58,7 +58,6 @@ import (
 | 
			
		||||
// becomes a member of the object unless
 | 
			
		||||
//   - the field's tag is "-", or
 | 
			
		||||
//   - the field is empty and its tag specifies the "omitempty" option.
 | 
			
		||||
//
 | 
			
		||||
// The empty values are false, 0, any
 | 
			
		||||
// nil pointer or interface value, and any array, slice, map, or string of
 | 
			
		||||
// length zero. The object's default key string is the struct field name
 | 
			
		||||
@ -66,28 +65,28 @@ import (
 | 
			
		||||
// the struct field's tag value is the key name, followed by an optional comma
 | 
			
		||||
// and options. Examples:
 | 
			
		||||
//
 | 
			
		||||
//	// Field is ignored by this package.
 | 
			
		||||
//	Field int `json:"-"`
 | 
			
		||||
//   // Field is ignored by this package.
 | 
			
		||||
//   Field int `json:"-"`
 | 
			
		||||
//
 | 
			
		||||
//	// Field appears in JSON as key "myName".
 | 
			
		||||
//	Field int `json:"myName"`
 | 
			
		||||
//   // Field appears in JSON as key "myName".
 | 
			
		||||
//   Field int `json:"myName"`
 | 
			
		||||
//
 | 
			
		||||
//	// Field appears in JSON as key "myName" and
 | 
			
		||||
//	// the field is omitted from the object if its value is empty,
 | 
			
		||||
//	// as defined above.
 | 
			
		||||
//	Field int `json:"myName,omitempty"`
 | 
			
		||||
//   // Field appears in JSON as key "myName" and
 | 
			
		||||
//   // the field is omitted from the object if its value is empty,
 | 
			
		||||
//   // as defined above.
 | 
			
		||||
//   Field int `json:"myName,omitempty"`
 | 
			
		||||
//
 | 
			
		||||
//	// Field appears in JSON as key "Field" (the default), but
 | 
			
		||||
//	// the field is skipped if empty.
 | 
			
		||||
//	// Note the leading comma.
 | 
			
		||||
//	Field int `json:",omitempty"`
 | 
			
		||||
//   // Field appears in JSON as key "Field" (the default), but
 | 
			
		||||
//   // the field is skipped if empty.
 | 
			
		||||
//   // Note the leading comma.
 | 
			
		||||
//   Field int `json:",omitempty"`
 | 
			
		||||
//
 | 
			
		||||
// The "string" option signals that a field is stored as JSON inside a
 | 
			
		||||
// JSON-encoded string. It applies only to fields of string, floating point,
 | 
			
		||||
// integer, or boolean types. This extra level of encoding is sometimes used
 | 
			
		||||
// when communicating with JavaScript programs:
 | 
			
		||||
//
 | 
			
		||||
//	Int64String int64 `json:",string"`
 | 
			
		||||
//    Int64String int64 `json:",string"`
 | 
			
		||||
//
 | 
			
		||||
// The key name will be used if it's a non-empty string consisting of
 | 
			
		||||
// only Unicode letters, digits, dollar signs, percent signs, hyphens,
 | 
			
		||||
@ -134,6 +133,7 @@ import (
 | 
			
		||||
// JSON cannot represent cyclic data structures and Marshal does not
 | 
			
		||||
// handle them.  Passing cyclic structures to Marshal will result in
 | 
			
		||||
// an infinite recursion.
 | 
			
		||||
//
 | 
			
		||||
func Marshal(v interface{}) ([]byte, error) {
 | 
			
		||||
	return marshal(v, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/docker/go/canonical/json/fold.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/docker/go/canonical/json/fold.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -24,9 +24,8 @@ const (
 | 
			
		||||
// 4) simpleLetterEqualFold, no specials, no non-letters.
 | 
			
		||||
//
 | 
			
		||||
// The letters S and K are special because they map to 3 runes, not just 2:
 | 
			
		||||
//   - S maps to s and to U+017F 'ſ' Latin small letter long s
 | 
			
		||||
//   - k maps to K and to U+212A 'K' Kelvin sign
 | 
			
		||||
//
 | 
			
		||||
//  * S maps to s and to U+017F 'ſ' Latin small letter long s
 | 
			
		||||
//  * k maps to K and to U+212A 'K' Kelvin sign
 | 
			
		||||
// See https://play.golang.org/p/tTxjOc0OGo
 | 
			
		||||
//
 | 
			
		||||
// The returned function is specialized for matching against s and
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/docker/go/canonical/json/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/docker/go/canonical/json/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -242,6 +242,7 @@ var _ Unmarshaler = (*RawMessage)(nil)
 | 
			
		||||
//	Number, for JSON numbers
 | 
			
		||||
//	string, for JSON string literals
 | 
			
		||||
//	nil, for JSON null
 | 
			
		||||
//
 | 
			
		||||
type Token interface{}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/emirpasic/gods/containers/iterator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/emirpasic/gods/containers/iterator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -72,7 +72,7 @@ type IteratorWithKey interface {
 | 
			
		||||
//
 | 
			
		||||
// Essentially it is the same as IteratorWithIndex, but provides additional:
 | 
			
		||||
//
 | 
			
		||||
// # Prev() function to enable traversal in reverse
 | 
			
		||||
// Prev() function to enable traversal in reverse
 | 
			
		||||
//
 | 
			
		||||
// Last() function to move the iterator to the last element.
 | 
			
		||||
//
 | 
			
		||||
@ -105,7 +105,7 @@ type ReverseIteratorWithIndex interface {
 | 
			
		||||
//
 | 
			
		||||
// Essentially it is the same as IteratorWithKey, but provides additional:
 | 
			
		||||
//
 | 
			
		||||
// # Prev() function to enable traversal in reverse
 | 
			
		||||
// Prev() function to enable traversal in reverse
 | 
			
		||||
//
 | 
			
		||||
// Last() function to move the iterator to the last element.
 | 
			
		||||
type ReverseIteratorWithKey interface {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/emirpasic/gods/lists/arraylist/arraylist.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/emirpasic/gods/lists/arraylist/arraylist.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -102,7 +102,7 @@ func (list *List) Values() []interface{} {
 | 
			
		||||
	return newElements
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IndexOf returns index of provided element
 | 
			
		||||
//IndexOf returns index of provided element
 | 
			
		||||
func (list *List) IndexOf(value interface{}) int {
 | 
			
		||||
	if list.size == 0 {
 | 
			
		||||
		return -1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/emirpasic/gods/utils/comparator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/emirpasic/gods/utils/comparator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -10,10 +10,9 @@ import "time"
 | 
			
		||||
// which will panic if a or b are not of the asserted type.
 | 
			
		||||
//
 | 
			
		||||
// Should return a number:
 | 
			
		||||
//
 | 
			
		||||
//	negative , if a < b
 | 
			
		||||
//	zero     , if a == b
 | 
			
		||||
//	positive , if a > b
 | 
			
		||||
//    negative , if a < b
 | 
			
		||||
//    zero     , if a == b
 | 
			
		||||
//    positive , if a > b
 | 
			
		||||
type Comparator func(a, b interface{}) int
 | 
			
		||||
 | 
			
		||||
// StringComparator provides a fast comparison on strings
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,6 +1,4 @@
 | 
			
		||||
//go:build go1.8
 | 
			
		||||
// +build go1.8
 | 
			
		||||
 | 
			
		||||
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package httpsnoop
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -1,6 +1,4 @@
 | 
			
		||||
//go:build !go1.8
 | 
			
		||||
// +build !go1.8
 | 
			
		||||
 | 
			
		||||
// Code generated by "httpsnoop/codegen"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package httpsnoop
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/ghodss/yaml/fields.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/ghodss/yaml/fields.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -347,9 +347,8 @@ const (
 | 
			
		||||
// 4) simpleLetterEqualFold, no specials, no non-letters.
 | 
			
		||||
//
 | 
			
		||||
// The letters S and K are special because they map to 3 runes, not just 2:
 | 
			
		||||
//   - S maps to s and to U+017F 'ſ' Latin small letter long s
 | 
			
		||||
//   - k maps to K and to U+212A 'K' Kelvin sign
 | 
			
		||||
//
 | 
			
		||||
//  * S maps to s and to U+017F 'ſ' Latin small letter long s
 | 
			
		||||
//  * k maps to K and to U+212A 'K' Kelvin sign
 | 
			
		||||
// See http://play.golang.org/p/tTxjOc0OGo
 | 
			
		||||
//
 | 
			
		||||
// The returned function is specialized for matching against s and
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/github.com/ghodss/yaml/yaml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/ghodss/yaml/yaml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -64,12 +64,12 @@ func JSONToYAML(j []byte) ([]byte, error) {
 | 
			
		||||
// this method should be a no-op.
 | 
			
		||||
//
 | 
			
		||||
// Things YAML can do that are not supported by JSON:
 | 
			
		||||
//   - In YAML you can have binary and null keys in your maps. These are invalid
 | 
			
		||||
//     in JSON. (int and float keys are converted to strings.)
 | 
			
		||||
//   - Binary data in YAML with the !!binary tag is not supported. If you want to
 | 
			
		||||
//     use binary data with this library, encode the data as base64 as usual but do
 | 
			
		||||
//     not use the !!binary tag in your YAML. This will ensure the original base64
 | 
			
		||||
//     encoded data makes it all the way through to the JSON.
 | 
			
		||||
// * In YAML you can have binary and null keys in your maps. These are invalid
 | 
			
		||||
//   in JSON. (int and float keys are converted to strings.)
 | 
			
		||||
// * Binary data in YAML with the !!binary tag is not supported. If you want to
 | 
			
		||||
//   use binary data with this library, encode the data as base64 as usual but do
 | 
			
		||||
//   not use the !!binary tag in your YAML. This will ensure the original base64
 | 
			
		||||
//   encoded data makes it all the way through to the JSON.
 | 
			
		||||
func YAMLToJSON(y []byte) ([]byte, error) {
 | 
			
		||||
	return yamlToJSON(y, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										89
									
								
								vendor/github.com/go-git/gcfg/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/go-git/gcfg/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -4,29 +4,29 @@
 | 
			
		||||
// This package is still a work in progress; see the sections below for planned
 | 
			
		||||
// changes.
 | 
			
		||||
//
 | 
			
		||||
// # Syntax
 | 
			
		||||
// Syntax
 | 
			
		||||
//
 | 
			
		||||
// The syntax is based on that used by git config:
 | 
			
		||||
// http://git-scm.com/docs/git-config#_syntax .
 | 
			
		||||
// There are some (planned) differences compared to the git config format:
 | 
			
		||||
//   - improve data portability:
 | 
			
		||||
//   - must be encoded in UTF-8 (for now) and must not contain the 0 byte
 | 
			
		||||
//   - include and "path" type is not supported
 | 
			
		||||
//     (path type may be implementable as a user-defined type)
 | 
			
		||||
//   - internationalization
 | 
			
		||||
//   - section and variable names can contain unicode letters, unicode digits
 | 
			
		||||
//     (as defined in http://golang.org/ref/spec#Characters ) and hyphens
 | 
			
		||||
//     (U+002D), starting with a unicode letter
 | 
			
		||||
//   - disallow potentially ambiguous or misleading definitions:
 | 
			
		||||
//   - `[sec.sub]` format is not allowed (deprecated in gitconfig)
 | 
			
		||||
//   - `[sec ""]` is not allowed
 | 
			
		||||
//   - use `[sec]` for section name "sec" and empty subsection name
 | 
			
		||||
//   - (planned) within a single file, definitions must be contiguous for each:
 | 
			
		||||
//   - section: '[secA]' -> '[secB]' -> '[secA]' is an error
 | 
			
		||||
//   - subsection: '[sec "A"]' -> '[sec "B"]' -> '[sec "A"]' is an error
 | 
			
		||||
//   - multivalued variable: 'multi=a' -> 'other=x' -> 'multi=b' is an error
 | 
			
		||||
//  - improve data portability:
 | 
			
		||||
//    - must be encoded in UTF-8 (for now) and must not contain the 0 byte
 | 
			
		||||
//    - include and "path" type is not supported
 | 
			
		||||
//      (path type may be implementable as a user-defined type)
 | 
			
		||||
//  - internationalization
 | 
			
		||||
//    - section and variable names can contain unicode letters, unicode digits
 | 
			
		||||
//      (as defined in http://golang.org/ref/spec#Characters ) and hyphens
 | 
			
		||||
//      (U+002D), starting with a unicode letter
 | 
			
		||||
//  - disallow potentially ambiguous or misleading definitions:
 | 
			
		||||
//    - `[sec.sub]` format is not allowed (deprecated in gitconfig)
 | 
			
		||||
//    - `[sec ""]` is not allowed
 | 
			
		||||
//      - use `[sec]` for section name "sec" and empty subsection name
 | 
			
		||||
//    - (planned) within a single file, definitions must be contiguous for each:
 | 
			
		||||
//      - section: '[secA]' -> '[secB]' -> '[secA]' is an error
 | 
			
		||||
//      - subsection: '[sec "A"]' -> '[sec "B"]' -> '[sec "A"]' is an error
 | 
			
		||||
//      - multivalued variable: 'multi=a' -> 'other=x' -> 'multi=b' is an error
 | 
			
		||||
//
 | 
			
		||||
// # Data structure
 | 
			
		||||
// Data structure
 | 
			
		||||
//
 | 
			
		||||
// The functions in this package read values into a user-defined struct.
 | 
			
		||||
// Each section corresponds to a struct field in the config struct, and each
 | 
			
		||||
@ -56,7 +56,7 @@
 | 
			
		||||
// or when a field is not of a suitable type (either a struct or a map with
 | 
			
		||||
// string keys and pointer-to-struct values).
 | 
			
		||||
//
 | 
			
		||||
// # Parsing of values
 | 
			
		||||
// Parsing of values
 | 
			
		||||
//
 | 
			
		||||
// The section structs in the config struct may contain single-valued or
 | 
			
		||||
// multi-valued variables. Variables of unnamed slice type (that is, a type
 | 
			
		||||
@ -98,17 +98,17 @@
 | 
			
		||||
// The types subpackage for provides helpers for parsing "enum-like" and integer
 | 
			
		||||
// types.
 | 
			
		||||
//
 | 
			
		||||
// # Error handling
 | 
			
		||||
// Error handling
 | 
			
		||||
//
 | 
			
		||||
// There are 3 types of errors:
 | 
			
		||||
//
 | 
			
		||||
//   - programmer errors / panics:
 | 
			
		||||
//   - invalid configuration structure
 | 
			
		||||
//   - data errors:
 | 
			
		||||
//   - fatal errors:
 | 
			
		||||
//   - invalid configuration syntax
 | 
			
		||||
//   - warnings:
 | 
			
		||||
//   - data that doesn't belong to any part of the config structure
 | 
			
		||||
//  - programmer errors / panics:
 | 
			
		||||
//    - invalid configuration structure
 | 
			
		||||
//  - data errors:
 | 
			
		||||
//    - fatal errors:
 | 
			
		||||
//      - invalid configuration syntax
 | 
			
		||||
//    - warnings:
 | 
			
		||||
//      - data that doesn't belong to any part of the config structure
 | 
			
		||||
//
 | 
			
		||||
// Programmer errors trigger panics. These are should be fixed by the programmer
 | 
			
		||||
// before releasing code that uses gcfg.
 | 
			
		||||
@ -122,23 +122,24 @@
 | 
			
		||||
// filtered out programmatically. To ignore extra data warnings, wrap the
 | 
			
		||||
// gcfg.Read*Into invocation into a call to gcfg.FatalOnly.
 | 
			
		||||
//
 | 
			
		||||
// # TODO
 | 
			
		||||
// TODO
 | 
			
		||||
//
 | 
			
		||||
// The following is a list of changes under consideration:
 | 
			
		||||
//   - documentation
 | 
			
		||||
//   - self-contained syntax documentation
 | 
			
		||||
//   - more practical examples
 | 
			
		||||
//   - move TODOs to issue tracker (eventually)
 | 
			
		||||
//   - syntax
 | 
			
		||||
//   - reconsider valid escape sequences
 | 
			
		||||
//     (gitconfig doesn't support \r in value, \t in subsection name, etc.)
 | 
			
		||||
//   - reading / parsing gcfg files
 | 
			
		||||
//   - define internal representation structure
 | 
			
		||||
//   - support multiple inputs (readers, strings, files)
 | 
			
		||||
//   - support declaring encoding (?)
 | 
			
		||||
//   - support varying fields sets for subsections (?)
 | 
			
		||||
//   - writing gcfg files
 | 
			
		||||
//   - error handling
 | 
			
		||||
//   - make error context accessible programmatically?
 | 
			
		||||
//   - limit input size?
 | 
			
		||||
//  - documentation
 | 
			
		||||
//    - self-contained syntax documentation
 | 
			
		||||
//    - more practical examples
 | 
			
		||||
//    - move TODOs to issue tracker (eventually)
 | 
			
		||||
//  - syntax
 | 
			
		||||
//    - reconsider valid escape sequences
 | 
			
		||||
//      (gitconfig doesn't support \r in value, \t in subsection name, etc.)
 | 
			
		||||
//  - reading / parsing gcfg files
 | 
			
		||||
//    - define internal representation structure
 | 
			
		||||
//    - support multiple inputs (readers, strings, files)
 | 
			
		||||
//    - support declaring encoding (?)
 | 
			
		||||
//    - support varying fields sets for subsections (?)
 | 
			
		||||
//  - writing gcfg files
 | 
			
		||||
//  - error handling
 | 
			
		||||
//    - make error context accessible programmatically?
 | 
			
		||||
//    - limit input size?
 | 
			
		||||
//
 | 
			
		||||
package gcfg // import "github.com/go-git/gcfg"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/go-git/gcfg/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/go-git/gcfg/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -8,9 +8,10 @@ import (
 | 
			
		||||
// fatal errors. That is, errors (warnings) indicating data for unknown
 | 
			
		||||
// sections / variables is ignored. Example invocation:
 | 
			
		||||
//
 | 
			
		||||
//	err := gcfg.FatalOnly(gcfg.ReadFileInto(&cfg, configFile))
 | 
			
		||||
//	if err != nil {
 | 
			
		||||
//	    ...
 | 
			
		||||
//  err := gcfg.FatalOnly(gcfg.ReadFileInto(&cfg, configFile))
 | 
			
		||||
//  if err != nil {
 | 
			
		||||
//      ...
 | 
			
		||||
//
 | 
			
		||||
func FatalOnly(err error) error {
 | 
			
		||||
	return warnings.FatalOnly(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/go-git/gcfg/scanner/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/go-git/gcfg/scanner/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -18,6 +18,7 @@ import (
 | 
			
		||||
// The position Pos, if valid, points to the beginning of
 | 
			
		||||
// the offending token, and the error condition is described
 | 
			
		||||
// by Msg.
 | 
			
		||||
//
 | 
			
		||||
type Error struct {
 | 
			
		||||
	Pos token.Position
 | 
			
		||||
	Msg string
 | 
			
		||||
@ -35,6 +36,7 @@ func (e Error) Error() string {
 | 
			
		||||
 | 
			
		||||
// ErrorList is a list of *Errors.
 | 
			
		||||
// The zero value for an ErrorList is an empty ErrorList ready to use.
 | 
			
		||||
//
 | 
			
		||||
type ErrorList []*Error
 | 
			
		||||
 | 
			
		||||
// Add adds an Error with given position and error message to an ErrorList.
 | 
			
		||||
@ -64,6 +66,7 @@ func (p ErrorList) Less(i, j int) bool {
 | 
			
		||||
// Sort sorts an ErrorList. *Error entries are sorted by position,
 | 
			
		||||
// other errors are sorted by error message, and before any *Error
 | 
			
		||||
// entry.
 | 
			
		||||
//
 | 
			
		||||
func (p ErrorList) Sort() {
 | 
			
		||||
	sort.Sort(p)
 | 
			
		||||
}
 | 
			
		||||
@ -106,6 +109,7 @@ func (p ErrorList) Err() error {
 | 
			
		||||
// PrintError is a utility function that prints a list of errors to w,
 | 
			
		||||
// one error per line, if the err parameter is an ErrorList. Otherwise
 | 
			
		||||
// it prints the err string.
 | 
			
		||||
//
 | 
			
		||||
func PrintError(w io.Writer, err error) {
 | 
			
		||||
	if list, ok := err.(ErrorList); ok {
 | 
			
		||||
		for _, e := range list {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/go-git/gcfg/set.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-git/gcfg/set.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -216,7 +216,7 @@ func newValue(c *warnings.Collector, sect string, vCfg reflect.Value,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func set(c *warnings.Collector, cfg interface{}, sect, sub, name string,
 | 
			
		||||
	value string, blankValue bool, subsectPass bool) error {
 | 
			
		||||
	 value string, blankValue bool, subsectPass bool) error {
 | 
			
		||||
	//
 | 
			
		||||
	vPCfg := reflect.ValueOf(cfg)
 | 
			
		||||
	if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/go-git/gcfg/token/position.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/go-git/gcfg/token/position.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -18,6 +18,7 @@ import (
 | 
			
		||||
// Position describes an arbitrary source position
 | 
			
		||||
// including the file, line, and column location.
 | 
			
		||||
// A Position is valid if the line number is > 0.
 | 
			
		||||
//
 | 
			
		||||
type Position struct {
 | 
			
		||||
	Filename string // filename, if any
 | 
			
		||||
	Offset   int    // offset, starting at 0
 | 
			
		||||
@ -34,6 +35,7 @@ func (pos *Position) IsValid() bool { return pos.Line > 0 }
 | 
			
		||||
//	line:column         valid position without file name
 | 
			
		||||
//	file                invalid position with file name
 | 
			
		||||
//	-                   invalid position without file name
 | 
			
		||||
//
 | 
			
		||||
func (pos Position) String() string {
 | 
			
		||||
	s := pos.Filename
 | 
			
		||||
	if pos.IsValid() {
 | 
			
		||||
@ -67,12 +69,14 @@ func (pos Position) String() string {
 | 
			
		||||
// equivalent to comparing the respective source file offsets. If p and q
 | 
			
		||||
// are in different files, p < q is true if the file implied by p was added
 | 
			
		||||
// to the respective file set before the file implied by q.
 | 
			
		||||
//
 | 
			
		||||
type Pos int
 | 
			
		||||
 | 
			
		||||
// The zero value for Pos is NoPos; there is no file and line information
 | 
			
		||||
// associated with it, and NoPos().IsValid() is false. NoPos is always
 | 
			
		||||
// smaller than any other Pos value. The corresponding Position value
 | 
			
		||||
// for NoPos is the zero value for Position.
 | 
			
		||||
//
 | 
			
		||||
const NoPos Pos = 0
 | 
			
		||||
 | 
			
		||||
// IsValid returns true if the position is valid.
 | 
			
		||||
@ -85,6 +89,7 @@ func (p Pos) IsValid() bool {
 | 
			
		||||
 | 
			
		||||
// A File is a handle for a file belonging to a FileSet.
 | 
			
		||||
// A File has a name, size, and line offset table.
 | 
			
		||||
//
 | 
			
		||||
type File struct {
 | 
			
		||||
	set  *FileSet
 | 
			
		||||
	name string // file name as provided to AddFile
 | 
			
		||||
@ -122,6 +127,7 @@ func (f *File) LineCount() int {
 | 
			
		||||
// AddLine adds the line offset for a new line.
 | 
			
		||||
// The line offset must be larger than the offset for the previous line
 | 
			
		||||
// and smaller than the file size; otherwise the line offset is ignored.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) AddLine(offset int) {
 | 
			
		||||
	f.set.mutex.Lock()
 | 
			
		||||
	if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size {
 | 
			
		||||
@ -137,6 +143,7 @@ func (f *File) AddLine(offset int) {
 | 
			
		||||
// Each line offset must be larger than the offset for the previous line
 | 
			
		||||
// and smaller than the file size; otherwise SetLines fails and returns
 | 
			
		||||
// false.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) SetLines(lines []int) bool {
 | 
			
		||||
	// verify validity of lines table
 | 
			
		||||
	size := f.size
 | 
			
		||||
@ -190,6 +197,7 @@ type lineInfo struct {
 | 
			
		||||
//
 | 
			
		||||
// AddLineInfo is typically used to register alternative position
 | 
			
		||||
// information for //line filename:line comments in source files.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) AddLineInfo(offset int, filename string, line int) {
 | 
			
		||||
	f.set.mutex.Lock()
 | 
			
		||||
	if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size {
 | 
			
		||||
@ -201,6 +209,7 @@ func (f *File) AddLineInfo(offset int, filename string, line int) {
 | 
			
		||||
// Pos returns the Pos value for the given file offset;
 | 
			
		||||
// the offset must be <= f.Size().
 | 
			
		||||
// f.Pos(f.Offset(p)) == p.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) Pos(offset int) Pos {
 | 
			
		||||
	if offset > f.size {
 | 
			
		||||
		panic("illegal file offset")
 | 
			
		||||
@ -211,6 +220,7 @@ func (f *File) Pos(offset int) Pos {
 | 
			
		||||
// Offset returns the offset for the given file position p;
 | 
			
		||||
// p must be a valid Pos value in that file.
 | 
			
		||||
// f.Offset(f.Pos(offset)) == offset.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) Offset(p Pos) int {
 | 
			
		||||
	if int(p) < f.base || int(p) > f.base+f.size {
 | 
			
		||||
		panic("illegal Pos value")
 | 
			
		||||
@ -220,6 +230,7 @@ func (f *File) Offset(p Pos) int {
 | 
			
		||||
 | 
			
		||||
// Line returns the line number for the given file position p;
 | 
			
		||||
// p must be a Pos value in that file or NoPos.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) Line(p Pos) int {
 | 
			
		||||
	// TODO(gri) this can be implemented much more efficiently
 | 
			
		||||
	return f.Position(p).Line
 | 
			
		||||
@ -257,6 +268,7 @@ func (f *File) position(p Pos) (pos Position) {
 | 
			
		||||
 | 
			
		||||
// Position returns the Position value for the given file position p;
 | 
			
		||||
// p must be a Pos value in that file or NoPos.
 | 
			
		||||
//
 | 
			
		||||
func (f *File) Position(p Pos) (pos Position) {
 | 
			
		||||
	if p != NoPos {
 | 
			
		||||
		if int(p) < f.base || int(p) > f.base+f.size {
 | 
			
		||||
@ -273,6 +285,7 @@ func (f *File) Position(p Pos) (pos Position) {
 | 
			
		||||
// A FileSet represents a set of source files.
 | 
			
		||||
// Methods of file sets are synchronized; multiple goroutines
 | 
			
		||||
// may invoke them concurrently.
 | 
			
		||||
//
 | 
			
		||||
type FileSet struct {
 | 
			
		||||
	mutex sync.RWMutex // protects the file set
 | 
			
		||||
	base  int          // base offset for the next file
 | 
			
		||||
@ -289,6 +302,7 @@ func NewFileSet() *FileSet {
 | 
			
		||||
 | 
			
		||||
// Base returns the minimum base offset that must be provided to
 | 
			
		||||
// AddFile when adding the next file.
 | 
			
		||||
//
 | 
			
		||||
func (s *FileSet) Base() int {
 | 
			
		||||
	s.mutex.RLock()
 | 
			
		||||
	b := s.base
 | 
			
		||||
@ -311,6 +325,7 @@ func (s *FileSet) Base() int {
 | 
			
		||||
// with offs in the range [0, size] and thus p in the range [base, base+size].
 | 
			
		||||
// For convenience, File.Pos may be used to create file-specific position
 | 
			
		||||
// values from a file offset.
 | 
			
		||||
//
 | 
			
		||||
func (s *FileSet) AddFile(filename string, base, size int) *File {
 | 
			
		||||
	s.mutex.Lock()
 | 
			
		||||
	defer s.mutex.Unlock()
 | 
			
		||||
@ -332,6 +347,7 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
 | 
			
		||||
 | 
			
		||||
// Iterate calls f for the files in the file set in the order they were added
 | 
			
		||||
// until f returns false.
 | 
			
		||||
//
 | 
			
		||||
func (s *FileSet) Iterate(f func(*File) bool) {
 | 
			
		||||
	for i := 0; ; i++ {
 | 
			
		||||
		var file *File
 | 
			
		||||
@ -370,6 +386,7 @@ func (s *FileSet) file(p Pos) *File {
 | 
			
		||||
// File returns the file that contains the position p.
 | 
			
		||||
// If no such file is found (for instance for p == NoPos),
 | 
			
		||||
// the result is nil.
 | 
			
		||||
//
 | 
			
		||||
func (s *FileSet) File(p Pos) (f *File) {
 | 
			
		||||
	if p != NoPos {
 | 
			
		||||
		s.mutex.RLock()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/go-git/gcfg/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/go-git/gcfg/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -7,6 +7,7 @@
 | 
			
		||||
//
 | 
			
		||||
// Note that the API for the token package may change to accommodate new
 | 
			
		||||
// features or implementation changes in gcfg.
 | 
			
		||||
//
 | 
			
		||||
package token
 | 
			
		||||
 | 
			
		||||
import "strconv"
 | 
			
		||||
@ -57,6 +58,7 @@ var tokens = [...]string{
 | 
			
		||||
// sequence (e.g., for the token ASSIGN, the string is "="). For all other
 | 
			
		||||
// tokens the string corresponds to the token constant name (e.g. for the
 | 
			
		||||
// token IDENT, the string is "IDENT").
 | 
			
		||||
//
 | 
			
		||||
func (tok Token) String() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	if 0 <= tok && tok < Token(len(tokens)) {
 | 
			
		||||
@ -72,8 +74,10 @@ func (tok Token) String() string {
 | 
			
		||||
 | 
			
		||||
// IsLiteral returns true for tokens corresponding to identifiers
 | 
			
		||||
// and basic type literals; it returns false otherwise.
 | 
			
		||||
//
 | 
			
		||||
func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
 | 
			
		||||
 | 
			
		||||
// IsOperator returns true for tokens corresponding to operators and
 | 
			
		||||
// delimiters; it returns false otherwise.
 | 
			
		||||
//
 | 
			
		||||
func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/go-git/go-billy/v5/memfs/memory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-git/go-billy/v5/memfs/memory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -25,7 +25,7 @@ type Memory struct {
 | 
			
		||||
	tempCount int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new Memory filesystem.
 | 
			
		||||
//New returns a new Memory filesystem.
 | 
			
		||||
func New() billy.Filesystem {
 | 
			
		||||
	fs := &Memory{s: newStorage()}
 | 
			
		||||
	return chroot.New(fs, string(separator))
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/go-git/go-billy/v5/util/walk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/go-git/go-billy/v5/util/walk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -46,7 +46,7 @@ func walk(fs billy.Filesystem, path string, info os.FileInfo, walkFn filepath.Wa
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Walk walks the file tree rooted at root, calling fn for each file or
 | 
			
		||||
// Walk walks the file tree rooted at root, calling fn for each file or 
 | 
			
		||||
// directory in the tree, including root. All errors that arise visiting files
 | 
			
		||||
// and directories are filtered by fn: see the WalkFunc documentation for
 | 
			
		||||
// details.
 | 
			
		||||
@ -54,7 +54,7 @@ func walk(fs billy.Filesystem, path string, info os.FileInfo, walkFn filepath.Wa
 | 
			
		||||
// The files are walked in lexical order, which makes the output deterministic
 | 
			
		||||
// but requires Walk to read an entire directory into memory before proceeding
 | 
			
		||||
// to walk that directory. Walk does not follow symbolic links.
 | 
			
		||||
//
 | 
			
		||||
// 
 | 
			
		||||
// Function adapted from https://github.com/golang/go/blob/3b770f2ccb1fa6fecc22ea822a19447b10b70c5c/src/path/filepath/path.go#L500
 | 
			
		||||
func Walk(fs billy.Filesystem, root string, walkFn filepath.WalkFunc) error {
 | 
			
		||||
	info, err := fs.Lstat(root)
 | 
			
		||||
@ -63,10 +63,10 @@ func Walk(fs billy.Filesystem, root string, walkFn filepath.WalkFunc) error {
 | 
			
		||||
	} else {
 | 
			
		||||
		err = walk(fs, root, info, walkFn)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	if err == filepath.SkipDir {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user