diff --git a/autocomplete/complete.go b/autocomplete/complete.go index 1b6b7966e0..334b301e67 100644 --- a/autocomplete/complete.go +++ b/autocomplete/complete.go @@ -19,9 +19,8 @@ import ( "github.com/EarthBuild/earthbuild/domain" "github.com/EarthBuild/earthbuild/earthfile2llb" "github.com/EarthBuild/earthbuild/util/fileutil" - gwclient "github.com/moby/buildkit/frontend/gateway/client" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) var errCompPointOutOfBounds = errors.New("COMP_POINT out of bounds") @@ -412,14 +411,14 @@ func GetPotentials( gwClient gwclient.Client, compLine string, compPoint int, - app *cli.App, + app *cli.Command, ) ([]string, error) { if compPoint > len(compLine) { return nil, errCompPointOutOfBounds } compLine = compLine[:compPoint] - subCommands := app.Commands + commands := app.Commands flagValues := map[string]string{} flagValuePotentialFuncs := map[string]FlagValuePotentialFn{} @@ -503,9 +502,9 @@ func GetPotentials( target = w } else { // must be under a command - foundCmd := getCmd(w, subCommands) + foundCmd := getCmd(w, commands) if foundCmd != nil { - subCommands = foundCmd.Subcommands + commands = foundCmd.Commands cmd = foundCmd } @@ -546,7 +545,7 @@ func GetPotentials( case rootState, commandState: if cmd != nil { - potentials = getVisibleCommands(cmd.Subcommands) + potentials = getVisibleCommands(cmd.Commands) potentials = padStrings(potentials, "", " ") } else { potentials = getVisibleCommands(app.Commands) diff --git a/autocomplete/complete_test.go b/autocomplete/complete_test.go index 4dd5331993..449401bd16 100644 --- a/autocomplete/complete_test.go +++ b/autocomplete/complete_test.go @@ -6,12 +6,11 @@ import ( "github.com/EarthBuild/earthbuild/buildcontext" "github.com/EarthBuild/earthbuild/conslogging" - - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) -func getApp() *cli.App { - app := cli.NewApp() +func getApp() *cli.Command { + app := new(cli.Command) app.Flags = []cli.Flag{ &cli.BoolFlag{ Name: "flag", @@ -41,7 +40,7 @@ func getApp() *cli.App { Name: "subflag", }, }, - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "abc", }, @@ -55,7 +54,7 @@ func getApp() *cli.App { Name: "surf-the-internet", }, }, - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "dancing-queen", }, diff --git a/cmd/earthly/app/before.go b/cmd/earthly/app/before.go index b3f26cfb50..fafaf146ad 100644 --- a/cmd/earthly/app/before.go +++ b/cmd/earthly/app/before.go @@ -1,6 +1,7 @@ package app import ( + "context" "fmt" "net/http" "os" @@ -9,7 +10,6 @@ import ( "time" "github.com/EarthBuild/earthbuild/cmd/earthly/subcmd" - "github.com/EarthBuild/earthbuild/config" "github.com/EarthBuild/earthbuild/conslogging" logbussetup "github.com/EarthBuild/earthbuild/logbus/setup" @@ -20,10 +20,10 @@ import ( "github.com/EarthBuild/earthbuild/util/fileutil" "github.com/google/uuid" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) -func (app *EarthlyApp) before(cliCtx *cli.Context) error { +func (app *EarthlyApp) before(ctx context.Context, cmd *cli.Command) (context.Context, error) { flags := app.BaseCLI.Flags() if flags.EnableProfiler { @@ -31,15 +31,15 @@ func (app *EarthlyApp) before(cliCtx *cli.Context) error { } if flags.InstallationName != "" { - if !cliCtx.IsSet("config") { + if !cmd.IsSet("config") { flags.ConfigPath = defaultConfigPath(flags.InstallationName) } - if !cliCtx.IsSet("buildkit-container-name") { + if !cmd.IsSet("buildkit-container-name") { flags.ContainerName = flags.InstallationName + "-buildkitd" } - if !cliCtx.IsSet("buildkit-volume-name") { + if !cmd.IsSet("buildkit-volume-name") { flags.BuildkitdSettings.VolumeName = flags.InstallationName + "-cache" } } @@ -58,7 +58,7 @@ func (app *EarthlyApp) before(cliCtx *cli.Context) error { } busSetup, err := logbussetup.New( - cliCtx.Context, + ctx, app.BaseCLI.Logbus(), flags.Debug, flags.Verbose, @@ -72,12 +72,12 @@ func (app *EarthlyApp) before(cliCtx *cli.Context) error { flags.GithubAnnotations, ) if err != nil { - return errors.Wrap(err, "logbus setup") + return ctx, errors.Wrap(err, "logbus setup") } app.BaseCLI.SetLogbusSetup(busSetup) - if cliCtx.IsSet("config") { + if cmd.IsSet("config") { app.BaseCLI.Console().Printf("loading config values from %q\n", flags.ConfigPath) } @@ -86,32 +86,28 @@ func (app *EarthlyApp) before(cliCtx *cli.Context) error { if flags.ConfigPath != "" { yamlData, err = config.ReadConfigFile(flags.ConfigPath) if err != nil { - if cliCtx.IsSet("config") || !errors.Is(err, os.ErrNotExist) { - return errors.Wrapf(err, "read config") + if cmd.IsSet("config") || !errors.Is(err, os.ErrNotExist) { + return ctx, errors.Wrapf(err, "read config") } } } cfg, err := config.ParseYAML(yamlData, flags.InstallationName) if err != nil { - return errors.Wrapf(err, "failed to parse %s", flags.ConfigPath) + return ctx, errors.Wrapf(err, "failed to parse %s", flags.ConfigPath) } app.BaseCLI.SetCfg(&cfg) + app.processDeprecatedCommandOptions(app.BaseCLI.Cfg()) - err = app.processDeprecatedCommandOptions(app.BaseCLI.Cfg()) - if err != nil { - return err - } - - err = app.parseFrontend(cliCtx) + err = app.parseFrontend(ctx) if err != nil { - return err + return ctx, err } // Make a small attempt to check if we are not bootstrapped. If not, then do that before we do anything else. isBootstrapCmd := false - for _, f := range cliCtx.Args().Slice() { + for _, f := range cmd.Args().Slice() { isBootstrapCmd = f == "bootstrap" if isBootstrapCmd { @@ -124,16 +120,16 @@ func (app *EarthlyApp) before(cliCtx *cli.Context) error { app.BaseCLI.Flags().BootstrapNoBuildkit = true newBootstrap := subcmd.NewBootstrap(app.BaseCLI) - err = newBootstrap.Action(cliCtx) + err = newBootstrap.Action(ctx, cmd) if err != nil { - return errors.Wrap(err, "bootstrap unbootstrclied installation") + return ctx, errors.Wrap(err, "bootstrap unbootstrclied installation") } } - return nil + return ctx, nil } -func (app *EarthlyApp) parseFrontend(cliCtx *cli.Context) error { +func (app *EarthlyApp) parseFrontend(ctx context.Context) error { console := app.BaseCLI.Console().WithPrefix("frontend") feCfg := &containerutil.FrontendConfig{ BuildkitHostCLIValue: app.BaseCLI.Flags().BuildkitHost, @@ -144,11 +140,11 @@ func (app *EarthlyApp) parseFrontend(cliCtx *cli.Context) error { Console: console, } - fe, err := containerutil.FrontendForSetting(cliCtx.Context, app.BaseCLI.Cfg().Global.ContainerFrontend, feCfg) + fe, err := containerutil.FrontendForSetting(ctx, app.BaseCLI.Cfg().Global.ContainerFrontend, feCfg) if err != nil { origErr := err - stub, err := containerutil.NewStubFrontend(cliCtx.Context, feCfg) + stub, err := containerutil.NewStubFrontend(ctx, feCfg) if err != nil { return errors.Wrap(err, "failed stub frontend initialization") } @@ -178,7 +174,7 @@ func (app *EarthlyApp) parseFrontend(cliCtx *cli.Context) error { return nil } -func (app *EarthlyApp) processDeprecatedCommandOptions(cfg *config.Config) error { +func (app *EarthlyApp) processDeprecatedCommandOptions(cfg *config.Config) { app.warnIfEarth() if cfg.Global.CachePath != "" { @@ -217,8 +213,6 @@ func (app *EarthlyApp) processDeprecatedCommandOptions(cfg *config.Config) error cfg.Git[k] = v } } - - return nil } func (app *EarthlyApp) warnIfEarth() { diff --git a/cmd/earthly/app/run.go b/cmd/earthly/app/run.go index e8cb4c0590..4c3498b6a1 100644 --- a/cmd/earthly/app/run.go +++ b/cmd/earthly/app/run.go @@ -9,19 +9,13 @@ import ( "strings" "time" - "github.com/EarthBuild/earthbuild/logstream" - "github.com/fatih/color" - "github.com/moby/buildkit/util/grpcerrors" - "github.com/pkg/errors" - "github.com/urfave/cli/v2" - "google.golang.org/grpc/codes" - "github.com/EarthBuild/earthbuild/buildkitd" "github.com/EarthBuild/earthbuild/cmd/earthly/common" "github.com/EarthBuild/earthbuild/cmd/earthly/helper" "github.com/EarthBuild/earthbuild/conslogging" "github.com/EarthBuild/earthbuild/earthfile2llb" "github.com/EarthBuild/earthbuild/inputgraph" + "github.com/EarthBuild/earthbuild/logstream" "github.com/EarthBuild/earthbuild/util/containerutil" "github.com/EarthBuild/earthbuild/util/errutil" "github.com/EarthBuild/earthbuild/util/hint" @@ -29,6 +23,11 @@ import ( "github.com/EarthBuild/earthbuild/util/reflectutil" "github.com/EarthBuild/earthbuild/util/stringutil" "github.com/EarthBuild/earthbuild/util/syncutil" + "github.com/fatih/color" + "github.com/moby/buildkit/util/grpcerrors" + "github.com/pkg/errors" + "github.com/urfave/cli/v3" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -102,7 +101,7 @@ func unhideFlagsCommands(cmds []*cli.Command) { reflectutil.SetBool(flg, "Hidden", false) } - unhideFlagsCommands(cmd.Subcommands) + unhideFlagsCommands(cmd.Commands) } } @@ -136,7 +135,7 @@ func (app *EarthlyApp) run(ctx context.Context, args []string, lastSignal *syncu ) }() - err := app.BaseCLI.App().RunContext(ctx, args) + err := app.BaseCLI.App().Run(ctx, args) if err != nil { return app.handleError(ctx, err, args, lastSignal) } diff --git a/cmd/earthly/base/buildkit.go b/cmd/earthly/base/buildkit.go index d06a21e927..bb7efe6c2c 100644 --- a/cmd/earthly/base/buildkit.go +++ b/cmd/earthly/base/buildkit.go @@ -1,21 +1,22 @@ package base import ( - "github.com/moby/buildkit/client" - "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "context" "github.com/EarthBuild/earthbuild/buildkitd" + "github.com/moby/buildkit/client" + "github.com/pkg/errors" + "github.com/urfave/cli/v3" ) -func (cli *CLI) GetBuildkitClient(cliCtx *cli.Context) (c *client.Client, err error) { - err = cli.InitFrontend(cliCtx) +func (cli *CLI) GetBuildkitClient(ctx context.Context, cmd *cli.Command) (c *client.Client, err error) { + err = cli.InitFrontend(ctx, cmd) if err != nil { return nil, err } c, err = buildkitd.NewClient( - cliCtx.Context, cli.Console(), cli.Flags().BuildkitdImage, cli.Flags().ContainerName, cli.Flags().InstallationName, + ctx, cli.Console(), cli.Flags().BuildkitdImage, cli.Flags().ContainerName, cli.Flags().InstallationName, cli.Flags().ContainerFrontend, cli.Version(), cli.Flags().BuildkitdSettings) if err != nil { return nil, errors.Wrap(err, "could not construct new buildkit client") diff --git a/cmd/earthly/base/cli.go b/cmd/earthly/base/cli.go index 4205cc804a..98c4f53a09 100644 --- a/cmd/earthly/base/cli.go +++ b/cmd/earthly/base/cli.go @@ -3,12 +3,11 @@ package base import ( "github.com/EarthBuild/earthbuild/buildkitd" "github.com/EarthBuild/earthbuild/cmd/earthly/flag" - "github.com/EarthBuild/earthbuild/logbus" - "github.com/urfave/cli/v2" - "github.com/EarthBuild/earthbuild/config" "github.com/EarthBuild/earthbuild/conslogging" + "github.com/EarthBuild/earthbuild/logbus" "github.com/EarthBuild/earthbuild/logbus/setup" + "github.com/urfave/cli/v3" ) type CLI struct { @@ -19,7 +18,7 @@ type CLI struct { defaultBuildkitdImage string defaultInstallationName string deferredFuncs []func() - app *cli.App + app *cli.Command cfg *config.Config logbusSetup *setup.BusSetup logbus *logbus.Bus @@ -66,7 +65,7 @@ func WithDefaultInstallationName(name string) CLIOpt { func NewCLI(console conslogging.ConsoleLogger, opts ...CLIOpt) *CLI { cli := CLI{ - app: cli.NewApp(), + app: new(cli.Command), console: console, logbus: logbus.New(), flags: flag.Global{ @@ -81,7 +80,7 @@ func NewCLI(console conslogging.ConsoleLogger, opts ...CLIOpt) *CLI { return &cli } -func (c *CLI) App() *cli.App { +func (c *CLI) App() *cli.Command { return c.app } diff --git a/cmd/earthly/base/init_frontend.go b/cmd/earthly/base/init_frontend.go index 220d028336..2f5602ce3d 100644 --- a/cmd/earthly/base/init_frontend.go +++ b/cmd/earthly/base/init_frontend.go @@ -1,24 +1,24 @@ package base import ( + "context" "net/url" "path/filepath" "time" - "github.com/pkg/errors" - "github.com/urfave/cli/v2" - "github.com/EarthBuild/earthbuild/util/cliutil" + "github.com/pkg/errors" + "github.com/urfave/cli/v3" ) -func (cli *CLI) InitFrontend(cliCtx *cli.Context) error { +func (cli *CLI) InitFrontend(ctx context.Context, cmd *cli.Command) error { // command line option overrides the config which overrides the default value - if !cliCtx.IsSet("buildkit-image") && cli.Cfg().Global.BuildkitImage != "" { + if !cmd.IsSet("buildkit-image") && cli.Cfg().Global.BuildkitImage != "" { cli.Flags().BuildkitdImage = cli.Cfg().Global.BuildkitImage } if cli.Flags().UseTickTockBuildkitImage { - if cliCtx.IsSet("buildkit-image") { + if cmd.IsSet("buildkit-image") { return errors.New("the --buildkit-image and --ticktock flags are mutually exclusive") } diff --git a/cmd/earthly/flag/global.go b/cmd/earthly/flag/global.go index 90063638c7..771bd6afe2 100644 --- a/cmd/earthly/flag/global.go +++ b/cmd/earthly/flag/global.go @@ -4,11 +4,10 @@ import ( "os" "time" - "github.com/urfave/cli/v2" - "github.com/EarthBuild/earthbuild/buildkitd" "github.com/EarthBuild/earthbuild/cmd/earthly/common" "github.com/EarthBuild/earthbuild/util/containerutil" + "github.com/urfave/cli/v3" ) const ( @@ -95,7 +94,7 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.StringFlag{ Name: "installation-name", Value: defaultInstallationName, - EnvVars: []string{"EARTHLY_INSTALLATION_NAME"}, + Sources: cli.EnvVars("EARTHLY_INSTALLATION_NAME"), Usage: "The earth installation name to use when naming the buildkit container, " + "the docker volume and the ~/.earthly directory", Destination: &global.InstallationName, @@ -104,32 +103,32 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.StringFlag{ Name: "config", Value: "", // the default value will be applied in the "Before" fn, after flag.installationName is set. - EnvVars: []string{"EARTHLY_CONFIG"}, + Sources: cli.EnvVars("EARTHLY_CONFIG"), Usage: "Path to config file", Destination: &global.ConfigPath, }, &cli.StringFlag{ Name: "ssh-auth-sock", Value: os.Getenv("SSH_AUTH_SOCK"), - EnvVars: []string{"EARTHLY_SSH_AUTH_SOCK"}, + Sources: cli.EnvVars("EARTHLY_SSH_AUTH_SOCK"), Usage: "The SSH auth socket to use for ssh-agent forwarding", Destination: &global.SSHAuthSock, }, &cli.StringFlag{ Name: "git-username", - EnvVars: []string{"GIT_USERNAME"}, + Sources: cli.EnvVars("GIT_USERNAME"), Usage: "The git username to use for git HTTPS authentication", Destination: &global.GitUsernameOverride, }, &cli.StringFlag{ Name: "git-password", - EnvVars: []string{"GIT_PASSWORD"}, + Sources: cli.EnvVars("GIT_PASSWORD"), Usage: "The git password to use for git HTTPS authentication", Destination: &global.GitPasswordOverride, }, &cli.StringFlag{ Name: "git-branch", - EnvVars: []string{"EARTHLY_GIT_BRANCH_OVERRIDE"}, + Sources: cli.EnvVars("EARTHLY_GIT_BRANCH_OVERRIDE"), Usage: "The git branch the build should be considered running in", Destination: &global.GitBranchOverride, Hidden: true, // primarily used by CI to pass branch context @@ -137,14 +136,14 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.BoolFlag{ Name: "verbose", Aliases: []string{"V"}, - EnvVars: []string{"EARTHLY_VERBOSE"}, + Sources: cli.EnvVars("EARTHLY_VERBOSE"), Usage: "Enable verbose logging", Destination: &global.Verbose, }, &cli.BoolFlag{ Name: "debug", Aliases: []string{"D"}, - EnvVars: []string{"EARTHLY_DEBUG"}, + Sources: cli.EnvVars("EARTHLY_DEBUG"), Usage: "Enable debug mode. This flag also turns on the debug mode of buildkitd, " + "which may cause it to restart", Destination: &global.Debug, @@ -152,21 +151,21 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { }, &cli.BoolFlag{ Name: "exec-stats", - EnvVars: []string{"EARTHLY_EXEC_STATS"}, + Sources: cli.EnvVars("EARTHLY_EXEC_STATS"), Usage: "Display container stats (e.g. cpu and memory usage)", Destination: &global.DisplayExecStats, Hidden: true, // Experimental }, &cli.StringFlag{ Name: "exec-stats-summary", - EnvVars: []string{"EARTHLY_EXEC_STATS_SUMMARY"}, + Sources: cli.EnvVars("EARTHLY_EXEC_STATS_SUMMARY"), Usage: "Output summarized container stats (e.g. cpu and memory usage) to the specified file", Destination: &global.ExecStatsSummary, Hidden: true, // Experimental }, &cli.BoolFlag{ Name: "profiler", - EnvVars: []string{"EARTHLY_PROFILER"}, + Sources: cli.EnvVars("EARTHLY_PROFILER"), Usage: "Enable the profiler", Destination: &global.EnableProfiler, Hidden: true, // Dev purposes only. @@ -174,21 +173,21 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.StringFlag{ Name: "buildkit-host", Value: "", - EnvVars: []string{"EARTHLY_BUILDKIT_HOST"}, + Sources: cli.EnvVars("EARTHLY_BUILDKIT_HOST"), Usage: `The URL to use for connecting to a buildkit host If empty, earthly will attempt to start a buildkitd instance via docker run`, Destination: &global.BuildkitHost, }, &cli.BoolFlag{ Name: "no-buildkit-update", - EnvVars: []string{"EARTHLY_NO_BUILDKIT_UPDATE"}, + Sources: cli.EnvVars("EARTHLY_NO_BUILDKIT_UPDATE"), Usage: "Disable the automatic update of buildkitd", Destination: &global.NoBuildkitUpdate, Hidden: true, // Internal. }, &cli.StringFlag{ Name: "version-flag-overrides", - EnvVars: []string{"EARTHLY_VERSION_FLAG_OVERRIDES"}, + Sources: cli.EnvVars("EARTHLY_VERSION_FLAG_OVERRIDES"), Usage: "Apply additional flags after each VERSION command across all Earthfiles, " + "multiple flags can be separated by commas", Destination: &global.FeatureFlagOverrides, @@ -196,7 +195,7 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { }, &cli.StringFlag{ Name: EnvFileFlag, - EnvVars: []string{"EARTHLY_ENV_FILE_PATH"}, + Sources: cli.EnvVars("EARTHLY_ENV_FILE_PATH"), Usage: "Use values from this file as earth environment variables; " + "values are no longer used as --build-arg's or --secret's", Value: DefaultEnvFile, @@ -204,28 +203,28 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { }, &cli.StringFlag{ Name: ArgFileFlag, - EnvVars: []string{"EARTHLY_ARG_FILE_PATH"}, + Sources: cli.EnvVars("EARTHLY_ARG_FILE_PATH"), Usage: "Use values from this file as earth buildargs", Value: DefaultArgFile, Destination: &global.ArgFile, }, &cli.StringFlag{ Name: SecretFileFlag, - EnvVars: []string{"EARTHLY_SECRET_FILE_PATH"}, + Sources: cli.EnvVars("EARTHLY_SECRET_FILE_PATH"), Usage: "Use values from this file as earth secrets", Value: DefaultSecretFile, Destination: &global.SecretFile, }, &cli.StringFlag{ Name: "logstream-debug-file", - EnvVars: []string{"EARTHLY_LOGSTREAM_DEBUG_FILE"}, + Sources: cli.EnvVars("EARTHLY_LOGSTREAM_DEBUG_FILE"), Usage: "Enable log streaming debugging output to a file", Destination: &global.LogstreamDebugFile, Hidden: true, // Internal. }, &cli.StringFlag{ Name: "logstream-debug-manifest-file", - EnvVars: []string{"EARTHLY_LOGSTREAM_DEBUG_MANIFEST_FILE"}, + Sources: cli.EnvVars("EARTHLY_LOGSTREAM_DEBUG_MANIFEST_FILE"), Usage: "Enable log streaming manifest debugging output to a file", Destination: &global.LogstreamDebugManifestFile, Hidden: true, // Internal. @@ -233,7 +232,7 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.DurationFlag{ Name: "server-conn-timeout", Usage: "EarthBuild API server connection timeout value", - EnvVars: []string{"EARTHLY_SERVER_CONN_TIMEOUT"}, + Sources: cli.EnvVars("EARTHLY_SERVER_CONN_TIMEOUT"), Hidden: true, // Internal. Value: 5 * time.Second, Destination: &global.ServerConnTimeout, @@ -251,76 +250,76 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { }, &cli.BoolFlag{ Name: "pull", - EnvVars: []string{"EARTHLY_PULL"}, + Sources: cli.EnvVars("EARTHLY_PULL"), Usage: "Force pull any referenced Docker images", Destination: &global.Pull, Hidden: true, // Experimental }, &cli.BoolFlag{ Name: "push", - EnvVars: []string{"EARTHLY_PUSH"}, + Sources: cli.EnvVars("EARTHLY_PUSH"), Usage: "Push docker images and execute RUN --push commands", Destination: &global.Push, }, &cli.BoolFlag{ Name: "ci", - EnvVars: []string{"EARTHLY_CI"}, + Sources: cli.EnvVars("EARTHLY_CI"), Usage: common.Wrap("Execute in CI mode. ", "Implies --no-output --strict"), Destination: &global.CI, }, &cli.BoolFlag{ Name: "ticktock", - EnvVars: []string{"EARTHLY_TICKTOCK"}, + Sources: cli.EnvVars("EARTHLY_TICKTOCK"), Usage: "Use earthbuild's experimental buildkit ticktock codebase", Destination: &global.UseTickTockBuildkitImage, Hidden: true, // Experimental }, &cli.BoolFlag{ Name: "output", - EnvVars: []string{"EARTHLY_OUTPUT"}, + Sources: cli.EnvVars("EARTHLY_OUTPUT"), Usage: "Allow artifacts or images to be output, even when running under --ci mode", Destination: &global.Output, }, &cli.BoolFlag{ Name: "no-output", - EnvVars: []string{"EARTHLY_NO_OUTPUT"}, + Sources: cli.EnvVars("EARTHLY_NO_OUTPUT"), Usage: common.Wrap("Do not output artifacts or images", "(using --push is still allowed)"), Destination: &global.NoOutput, }, &cli.BoolFlag{ Name: "no-cache", - EnvVars: []string{"EARTHLY_NO_CACHE"}, + Sources: cli.EnvVars("EARTHLY_NO_CACHE"), Usage: "Do not use cache while building", Destination: &global.NoCache, }, &cli.BoolFlag{ Name: "auto-skip", - EnvVars: []string{"EARTHLY_AUTO_SKIP"}, + Sources: cli.EnvVars("EARTHLY_AUTO_SKIP"), Usage: "Skip buildkit if target has already been built", Destination: &global.SkipBuildkit, }, &cli.BoolFlag{ Name: "allow-privileged", Aliases: []string{"P"}, - EnvVars: []string{"EARTHLY_ALLOW_PRIVILEGED"}, + Sources: cli.EnvVars("EARTHLY_ALLOW_PRIVILEGED"), Usage: "Allow build to use the --privileged flag in RUN commands", Destination: &global.AllowPrivileged, }, &cli.BoolFlag{ Name: "max-remote-cache", - EnvVars: []string{"EARTHLY_MAX_REMOTE_CACHE"}, + Sources: cli.EnvVars("EARTHLY_MAX_REMOTE_CACHE"), Usage: "Saves all intermediate images too in the remote cache", Destination: &global.MaxRemoteCache, }, &cli.BoolFlag{ Name: "save-inline-cache", - EnvVars: []string{"EARTHLY_SAVE_INLINE_CACHE"}, + Sources: cli.EnvVars("EARTHLY_SAVE_INLINE_CACHE"), Usage: "Enable cache inlining when pushing images", Destination: &global.SaveInlineCache, }, &cli.BoolFlag{ Name: "use-inline-cache", - EnvVars: []string{"EARTHLY_USE_INLINE_CACHE"}, + Sources: cli.EnvVars("EARTHLY_USE_INLINE_CACHE"), Usage: common.Wrap("Attempt to use any inline cache that may have been previously pushed ", "uses image tags referenced by SAVE IMAGE --push or SAVE IMAGE --cache-from"), Destination: &global.UseInlineCache, @@ -328,33 +327,33 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.BoolFlag{ Name: "interactive", Aliases: []string{"i"}, - EnvVars: []string{"EARTHLY_INTERACTIVE"}, + Sources: cli.EnvVars("EARTHLY_INTERACTIVE"), Usage: "Enable interactive debugging", Destination: &global.InteractiveDebugging, }, &cli.BoolFlag{ Name: "no-fake-dep", - EnvVars: []string{"EARTHLY_NO_FAKE_DEP"}, + Sources: cli.EnvVars("EARTHLY_NO_FAKE_DEP"), Usage: "Internal feature flag for fake-dep", Destination: &global.NoFakeDep, Hidden: true, // Internal. }, &cli.BoolFlag{ Name: "strict", - EnvVars: []string{"EARTHLY_STRICT"}, + Sources: cli.EnvVars("EARTHLY_STRICT"), Usage: "Disallow usage of features that may create unrepeatable builds", Destination: &global.Strict, }, &cli.BoolFlag{ Name: "global-wait-end", - EnvVars: []string{"EARTHLY_GLOBAL_WAIT_END"}, + Sources: cli.EnvVars("EARTHLY_GLOBAL_WAIT_END"), Usage: "enables global wait-end code in place of builder code", Destination: &global.GlobalWaitEnd, Hidden: true, // used to force code-coverage of future builder.go refactor (once we remove support for 0.6) }, &cli.StringFlag{ Name: "git-lfs-pull-include", - EnvVars: []string{"EARTHLY_GIT_LFS_PULL_INCLUDE"}, + Sources: cli.EnvVars("EARTHLY_GIT_LFS_PULL_INCLUDE"), Usage: "When referencing a remote target, perform a git lfs pull include prior to running the target. " + "Note that this flag is (hopefully) temporary, " + "see https://github.com/earthly/earthly/issues/2921 for details.", @@ -363,21 +362,21 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { }, &cli.StringFlag{ Name: "auto-skip-db-path", - EnvVars: []string{"EARTHLY_AUTO_SKIP_DB_PATH"}, + Sources: cli.EnvVars("EARTHLY_AUTO_SKIP_DB_PATH"), Usage: "use a local database for auto-skip", Destination: &global.LocalSkipDB, }, &cli.StringFlag{ Name: "buildkit-image", Value: bkImage, - EnvVars: []string{"EARTHLY_BUILDKIT_IMAGE"}, + Sources: cli.EnvVars("EARTHLY_BUILDKIT_IMAGE"), Usage: "The docker image to use for the buildkit daemon", Destination: &global.BuildkitdImage, }, &cli.StringFlag{ Name: "buildkit-container-name", Value: defaultInstallationName + DefaultBuildkitdContainerSuffix, - EnvVars: []string{"EARTHLY_CONTAINER_NAME"}, + Sources: cli.EnvVars("EARTHLY_CONTAINER_NAME"), Usage: "The docker container name to use for the buildkit daemon", Destination: &global.ContainerName, Hidden: true, @@ -385,35 +384,35 @@ func (global *Global) RootFlags(installName string, bkImage string) []cli.Flag { &cli.StringFlag{ Name: "buildkit-volume-name", Value: defaultInstallationName + DefaultBuildkitdVolumeSuffix, - EnvVars: []string{"EARTHLY_VOLUME_NAME"}, + Sources: cli.EnvVars("EARTHLY_VOLUME_NAME"), Usage: "The docker volume name to use for the buildkit daemon cache", Destination: &global.BuildkitdSettings.VolumeName, Hidden: true, }, &cli.StringFlag{ Name: "remote-cache", - EnvVars: []string{"EARTHLY_REMOTE_CACHE"}, + Sources: cli.EnvVars("EARTHLY_REMOTE_CACHE"), Usage: "A remote docker image tag use as explicit cache and optionally additional attributes " + "to set in the image (Format: \"[,=,=,...]\")", Destination: &global.RemoteCache, }, &cli.BoolFlag{ Name: "disable-remote-registry-proxy", - EnvVars: []string{"EARTHLY_DISABLE_REMOTE_REGISTRY_PROXY"}, + Sources: cli.EnvVars("EARTHLY_DISABLE_REMOTE_REGISTRY_PROXY"), Usage: "Don't use the Docker registry proxy when transferring images", Destination: &global.DisableRemoteRegistryProxy, Value: false, }, &cli.BoolFlag{ Name: "no-auto-skip", - EnvVars: []string{"EARTHLY_NO_AUTO_SKIP"}, + Sources: cli.EnvVars("EARTHLY_NO_AUTO_SKIP"), Usage: "Disable auto-skip functionality", Destination: &global.NoAutoSkip, Value: false, }, &cli.BoolFlag{ Name: "github-annotations", - EnvVars: []string{"GITHUB_ACTIONS"}, + Sources: cli.EnvVars("GITHUB_ACTIONS"), Usage: "Enable Git Hub Actions workflow specific output", Destination: &global.GithubAnnotations, Value: false, diff --git a/cmd/earthly/main.go b/cmd/earthly/main.go index 3400b12496..d1fd4b9b65 100644 --- a/cmd/earthly/main.go +++ b/cmd/earthly/main.go @@ -147,20 +147,24 @@ func run() (code int) { rootApp := subcmd.NewRoot(cli, buildApp) for _, f := range cli.Flags().RootFlags(DefaultInstallationName, DefaultBuildkitdImage) { - err = f.Apply(flagSet) - if err != nil { - envFileFromArgOK = false - break + for _, name := range f.Names() { + if bf, ok := f.(interface{ IsBoolFlag() bool }); ok && bf.IsBoolFlag() { + flagSet.Bool(name, false, "") + } else { + flagSet.String(name, "", "") + } } } if envFileFromArgOK { err = flagSet.Parse(os.Args[1:]) if err == nil { - if envFileFlag := flagSet.Lookup(eFlag.EnvFileFlag); envFileFlag != nil { - envFile = envFileFlag.Value.String() - envFileOverride = envFile != eFlag.DefaultEnvFile // flag lib doesn't expose if a value was set or not - } + flagSet.Visit(func(f *flag.Flag) { + if f.Name == eFlag.EnvFileFlag { + envFile = f.Value.String() + envFileOverride = true + } + }) } } diff --git a/cmd/earthly/subcmd/bootstrap_cmds.go b/cmd/earthly/subcmd/bootstrap_cmds.go index 05f21e86a7..e9b09bebc5 100644 --- a/cmd/earthly/subcmd/bootstrap_cmds.go +++ b/cmd/earthly/subcmd/bootstrap_cmds.go @@ -1,6 +1,7 @@ package subcmd import ( + "context" "fmt" "net/url" "os" @@ -10,15 +11,14 @@ import ( "runtime" "strings" - "github.com/adrg/xdg" - "github.com/pkg/errors" - "github.com/urfave/cli/v2" - "github.com/EarthBuild/earthbuild/buildkitd" "github.com/EarthBuild/earthbuild/cmd/earthly/common" "github.com/EarthBuild/earthbuild/util/cliutil" "github.com/EarthBuild/earthbuild/util/fileutil" "github.com/EarthBuild/earthbuild/util/termutil" + "github.com/adrg/xdg" + "github.com/pkg/errors" + "github.com/urfave/cli/v3" ) type BootstrapInterface interface { @@ -76,7 +76,7 @@ func (b *Bootstrap) Cmds() []*cli.Command { &cli.StringFlag{ Name: "certs-hostname", Usage: "Hostname to generate certificates for", - EnvVars: []string{"EARTHLY_CERTS_HOSTNAME"}, + Sources: cli.EnvVars("EARTHLY_CERTS_HOSTNAME"), Value: "localhost", Destination: &b.certsHostName, }, @@ -85,7 +85,7 @@ func (b *Bootstrap) Cmds() []*cli.Command { } } -func (a *Bootstrap) Action(cliCtx *cli.Context) error { +func (a *Bootstrap) Action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("actionbootstrap") switch a.homebrewSource { @@ -115,10 +115,10 @@ func (a *Bootstrap) Action(cliCtx *cli.Context) error { return errors.Errorf("unhandled source %q", a.homebrewSource) } - return a.bootstrap(cliCtx) + return a.bootstrap(ctx, cmd) } -func (a *Bootstrap) bootstrap(cliCtx *cli.Context) error { +func (a *Bootstrap) bootstrap(ctx context.Context, cmd *cli.Command) error { console := a.cli.Console().WithPrefix("bootstrap") defer func() { @@ -175,7 +175,7 @@ func (a *Bootstrap) bootstrap(cliCtx *cli.Context) error { if !a.noBuildkit { // connect to local buildkit instance (to trigger pulling and running the earthbuild/buildkitd image) - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { console.Warnf("Warning: Bootstrapping buildkit failed: %v", err) // Keep going. diff --git a/cmd/earthly/subcmd/build_cmd.go b/cmd/earthly/subcmd/build_cmd.go index 03d69bd5e7..0c38126e3e 100644 --- a/cmd/earthly/subcmd/build_cmd.go +++ b/cmd/earthly/subcmd/build_cmd.go @@ -52,7 +52,7 @@ import ( "github.com/moby/buildkit/util/entitlements" buildkitgitutil "github.com/moby/buildkit/util/gitutil" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) const autoSkipPrefix = "auto-skip" @@ -60,12 +60,12 @@ const autoSkipPrefix = "auto-skip" type Build struct { cli CLI dockerTarget string - buildArgs cli.StringSlice - platformsStr cli.StringSlice - secrets cli.StringSlice - secretFiles cli.StringSlice - cacheFrom cli.StringSlice - dockerTags cli.StringSlice + buildArgs []string + platformsStr []string + secrets []string + secretFiles []string + cacheFrom []string + dockerTags []string } func NewBuild(cli CLI) *Build { @@ -100,7 +100,7 @@ func (a *Build) Cmds() []*cli.Command { &cli.StringFlag{ Name: "dockerfile", Aliases: []string{"f"}, - EnvVars: []string{"EARTHLY_DOCKER_FILE"}, + Sources: cli.EnvVars("EARTHLY_DOCKER_FILE"), Usage: "Path to dockerfile input", Value: "Dockerfile", Destination: &a.cli.Flags().DockerfilePath, @@ -108,13 +108,13 @@ func (a *Build) Cmds() []*cli.Command { &cli.StringSliceFlag{ Name: "tag", Aliases: []string{"t"}, - EnvVars: []string{"EARTHLY_DOCKER_TAGS"}, + Sources: cli.EnvVars("EARTHLY_DOCKER_TAGS"), Usage: "Name and tag for the built image; formatted as 'name:tag'", Destination: &a.dockerTags, }, &cli.StringFlag{ Name: "target", - EnvVars: []string{"EARTHLY_DOCKER_TARGET"}, + Sources: cli.EnvVars("EARTHLY_DOCKER_TARGET"), Usage: "The docker target to build in the specified dockerfile", Destination: &a.dockerTarget, }, @@ -123,7 +123,7 @@ func (a *Build) Cmds() []*cli.Command { } } -func (a *Build) Action(cliCtx *cli.Context) error { +func (a *Build) Action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("build") if a.cli.Flags().CI { @@ -151,12 +151,12 @@ func (a *Build) Action(cliCtx *cli.Context) error { return params.Errorf("A tty-terminal must be present in order to use the --interactive flag") } - flagArgs, nonFlagArgs, err := variables.ParseFlagArgsWithNonFlags(cliCtx.Args().Slice()) + flagArgs, nonFlagArgs, err := variables.ParseFlagArgsWithNonFlags(cmd.Args().Slice()) if err != nil { - return errors.Wrapf(err, "parse args %s", strings.Join(cliCtx.Args().Slice(), " ")) + return errors.Wrapf(err, "parse args %s", strings.Join(cmd.Args().Slice(), " ")) } - return a.ActionBuildImp(cliCtx, flagArgs, nonFlagArgs) + return a.ActionBuildImp(ctx, cmd, flagArgs, nonFlagArgs) } // warnIfArgContainsBuildArg will issue a warning if a flag is incorrectly prefixed with build-arg. @@ -181,7 +181,7 @@ func (a *Build) gitLogLevel() buildkitgitutil.GitLogLevel { return buildkitgitutil.GitLogLevelDefault } -func (a *Build) parseTarget(cliCtx *cli.Context, nonFlagArgs []string) (domain.Target, domain.Artifact, string, error) { +func (a *Build) parseTarget(cmd *cli.Command, nonFlagArgs []string) (domain.Target, domain.Artifact, string, error) { var ( target domain.Target artifact domain.Artifact @@ -191,12 +191,12 @@ func (a *Build) parseTarget(cliCtx *cli.Context, nonFlagArgs []string) (domain.T switch { case a.cli.Flags().ImageMode: if len(nonFlagArgs) == 0 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf( - "no image reference provided. Try %s --image +", cliCtx.App.Name) + "no image reference provided. Try %s --image +", cmd.Root().Name) } else if len(nonFlagArgs) != 1 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf("invalid arguments %s", strings.Join(nonFlagArgs, " ")) } @@ -210,12 +210,12 @@ func (a *Build) parseTarget(cliCtx *cli.Context, nonFlagArgs []string) (domain.T } case a.cli.Flags().ArtifactMode: if len(nonFlagArgs) == 0 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf( - "no artifact reference provided. Try %s --artifact +/", cliCtx.App.Name) + "no artifact reference provided. Try %s --artifact +/", cmd.Root().Name) } else if len(nonFlagArgs) > 2 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf("invalid arguments %s", strings.Join(nonFlagArgs, " ")) } @@ -234,12 +234,12 @@ func (a *Build) parseTarget(cliCtx *cli.Context, nonFlagArgs []string) (domain.T target = artifact.Target default: if len(nonFlagArgs) == 0 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf( - "no target reference provided. Try %s +", cliCtx.App.Name) + "no target reference provided. Try %s +", cmd.Root().Name) } else if len(nonFlagArgs) != 1 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return target, artifact, "", params.Errorf("invalid arguments %s", strings.Join(nonFlagArgs, " ")) } @@ -256,8 +256,8 @@ func (a *Build) parseTarget(cliCtx *cli.Context, nonFlagArgs []string) (domain.T return target, artifact, destPath, nil } -func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []string) error { - target, artifact, destPath, err := a.parseTarget(cliCtx, nonFlagArgs) +func (a *Build) ActionBuildImp(ctx context.Context, cmd *cli.Command, flagArgs, nonFlagArgs []string) error { + target, artifact, destPath, err := a.parseTarget(cmd, nonFlagArgs) if err != nil { return err } @@ -273,7 +273,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri dotEnvMap, err := godotenv.Read(a.cli.Flags().EnvFile) if err != nil { // ignore ErrNotExist when using default .env file - if cliCtx.IsSet(flag.EnvFileFlag) || !errors.Is(err, os.ErrNotExist) { + if cmd.IsSet(flag.EnvFileFlag) || !errors.Is(err, os.ErrNotExist) { return errors.Wrapf(err, "read %s", a.cli.Flags().EnvFile) } } @@ -281,7 +281,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri argMap, err := godotenv.Read(a.cli.Flags().ArgFile) if err == nil { showUnexpectedEnvWarnings = false - } else if cliCtx.IsSet(flag.ArgFileFlag) || !errors.Is(err, os.ErrNotExist) { + } else if cmd.IsSet(flag.ArgFileFlag) || !errors.Is(err, os.ErrNotExist) { // ignore ErrNotExist when using default .env file return errors.Wrapf(err, "read %s", a.cli.Flags().ArgFile) } @@ -289,7 +289,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri secretsFileMap, err := godotenv.Read(a.cli.Flags().SecretFile) if err == nil { showUnexpectedEnvWarnings = false - } else if cliCtx.IsSet(flag.SecretFileFlag) || !errors.Is(err, os.ErrNotExist) { + } else if cmd.IsSet(flag.SecretFileFlag) || !errors.Is(err, os.ErrNotExist) { // ignore ErrNotExist when using default .env file return errors.Wrapf(err, "read %s", a.cli.Flags().SecretFile) } @@ -305,7 +305,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri } secretsMap, err := common. - ProcessSecrets(a.secrets.Value(), a.secretFiles.Value(), secretsFileMap, a.cli.Flags().SecretFile) + ProcessSecrets(a.secrets, a.secretFiles, secretsFileMap, a.cli.Flags().SecretFile) if err != nil { return err } @@ -321,7 +321,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri } } - overridingVars, err := common.CombineVariables(argMap, flagArgs, a.buildArgs.Value()) + overridingVars, err := common.CombineVariables(argMap, flagArgs, a.buildArgs) if err != nil { return err } @@ -331,7 +331,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri a.cli.Console().WithPrefix(autoSkipPrefix).Warnf("Failed to initialize auto-skip database: %v", err) } - addHashFn, doSkip, err := a.initAutoSkip(cliCtx.Context, skipDB, target, overridingVars) + addHashFn, doSkip, err := a.initAutoSkip(ctx, skipDB, target, overridingVars) if err != nil { a.cli.Console().PrintFailure("auto-skip") return err @@ -341,7 +341,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri return nil } - err = a.cli.InitFrontend(cliCtx) + err = a.cli.InitFrontend(ctx, cmd) if err != nil { return errors.Wrapf(err, "could not init frontend") } @@ -353,7 +353,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri } bkClient, err := buildkitd.NewClient( - cliCtx.Context, + ctx, a.cli.Console(), a.cli.Flags().BuildkitdImage, a.cli.Flags().ContainerName, @@ -367,12 +367,12 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri } defer bkClient.Close() - platr, err := a.platformResolver(cliCtx.Context, bkClient, target) + platr, err := a.platformResolver(ctx, bkClient, target) if err != nil { return err } - runnerName, isLocal, err := a.runnerName(cliCtx.Context) + runnerName, isLocal, err := a.runnerName(ctx) if err != nil { return err } @@ -419,7 +419,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri switch a.cli.Flags().ContainerFrontend.Config().Setting { case containerutil.FrontendPodman, containerutil.FrontendPodmanShell: - attachable = authprovider.NewPodman(os.Stderr) + attachable = authprovider.NewPodman(ctx, os.Stderr) default: // includes containerutil.FrontendDocker, containerutil.FrontendDockerShell: attachable = dockerauthprovider.NewDockerAuthProvider(cfg, nil) @@ -464,7 +464,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri debugTermConsole := a.cli.Console().WithPrefix("internal-term") - termErr := terminal.ConnectTerm(cliCtx.Context, conn, debugTermConsole) //nolint:contextcheck + termErr := terminal.ConnectTerm(ctx, conn, debugTermConsole) if termErr != nil { return errors.Wrap(termErr, "interactive terminal") } @@ -500,8 +500,8 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri cacheImports = append(cacheImports, cacheImportImageName) } - if len(a.cacheFrom.Value()) > 0 { - cacheImports = append(cacheImports, a.cacheFrom.Value()...) + if len(a.cacheFrom) > 0 { + cacheImports = append(cacheImports, a.cacheFrom...) } var ( @@ -578,7 +578,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri NoAutoSkip: a.cli.Flags().NoAutoSkip, } - b, err := builder.NewBuilder(cliCtx.Context, builderOpts) + b, err := builder.NewBuilder(ctx, builderOpts) if err != nil { return errors.Wrap(err, "new builder") } @@ -620,7 +620,7 @@ func (a *Build) ActionBuildImp(cliCtx *cli.Context, flagArgs, nonFlagArgs []stri buildOpts.OnlyArtifactDestPath = destPath } - _, err = b.BuildTarget(cliCtx.Context, target, buildOpts) + _, err = b.BuildTarget(ctx, target, buildOpts) if err != nil { return errors.Wrap(err, "build target") } @@ -826,8 +826,8 @@ func (a *Build) platformResolver( platr := platutil.NewResolver(nativePlatform) platr.AllowNativeAndUser = true - platformsSlice := make([]platutil.Platform, 0, len(a.platformsStr.Value())) - for _, p := range a.platformsStr.Value() { + platformsSlice := make([]platutil.Platform, 0, len(a.platformsStr)) + for _, p := range a.platformsStr { platform, err := platr.Parse(p) if err != nil { return nil, errors.Wrapf(err, "parse platform %s", p) @@ -931,23 +931,23 @@ func (a *Build) initAutoSkip( return addHashFn, false, nil } -func (a *Build) actionDockerBuild(cliCtx *cli.Context) error { +func (a *Build) actionDockerBuild(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("docker-build") - flagArgs, nonFlagArgs, err := variables.ParseFlagArgsWithNonFlags(cliCtx.Args().Slice()) + flagArgs, nonFlagArgs, err := variables.ParseFlagArgsWithNonFlags(cmd.Args().Slice()) if err != nil { - return errors.Wrapf(err, "parse args %s", strings.Join(cliCtx.Args().Slice(), " ")) + return errors.Wrapf(err, "parse args %s", strings.Join(cmd.Args().Slice(), " ")) } if len(nonFlagArgs) == 0 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return errors.Errorf( - "no build context path provided. Try %s docker-build ", cliCtx.App.Name) + "no build context path provided. Try %s docker-build ", cmd.Root().Name) } if len(nonFlagArgs) != 1 { - _ = cli.ShowAppHelp(cliCtx) + _ = cli.ShowAppHelp(cmd) return errors.Errorf("invalid arguments %s", strings.Join(nonFlagArgs, " ")) } @@ -963,11 +963,11 @@ func (a *Build) actionDockerBuild(cliCtx *cli.Context) error { defer os.RemoveAll(tempDir) argMap, err := godotenv.Read(a.cli.Flags().ArgFile) - if err != nil && (cliCtx.IsSet(flag.ArgFileFlag) || !errors.Is(err, os.ErrNotExist)) { + if err != nil && (cmd.IsSet(flag.ArgFileFlag) || !errors.Is(err, os.ErrNotExist)) { return errors.Wrapf(err, "read %q", a.cli.Flags().ArgFile) } - buildArgs, err := common.CombineVariables(argMap, flagArgs, a.buildArgs.Value()) + buildArgs, err := common.CombineVariables(argMap, flagArgs, a.buildArgs) if err != nil { return errors.Wrapf(err, "combining build args") } @@ -975,7 +975,7 @@ func (a *Build) actionDockerBuild(cliCtx *cli.Context) error { platforms := flagutil.SplitFlagString(a.platformsStr) content, err := docker2earthly.GenerateEarthfile( - buildContextPath, a.cli.Flags().DockerfilePath, a.dockerTags.Value(), + buildContextPath, a.cli.Flags().DockerfilePath, a.dockerTags, buildArgs.Sorted(), platforms, a.dockerTarget) if err != nil { return errors.Wrap(err, "docker-build: failed to wrap Dockerfile with an Earthfile") @@ -999,10 +999,10 @@ func (a *Build) actionDockerBuild(cliCtx *cli.Context) error { a.cli.Flags().ImageMode = false a.cli.Flags().ArtifactMode = false a.dockerTarget = "" - a.dockerTags = cli.StringSlice{} - a.platformsStr = cli.StringSlice{} + a.dockerTags = []string{} + a.platformsStr = []string{} nonFlagArgs = []string{tempDir + "+build"} - return a.ActionBuildImp(cliCtx, flagArgs, nonFlagArgs) + return a.ActionBuildImp(ctx, cmd, flagArgs, nonFlagArgs) } diff --git a/cmd/earthly/subcmd/build_flags.go b/cmd/earthly/subcmd/build_flags.go index 2dda690d18..6aa6bc136d 100644 --- a/cmd/earthly/subcmd/build_flags.go +++ b/cmd/earthly/subcmd/build_flags.go @@ -3,20 +3,20 @@ package subcmd import ( "os" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) func (a *Build) buildFlags() []cli.Flag { return []cli.Flag{ &cli.StringSliceFlag{ Name: "platform", - EnvVars: []string{"EARTHLY_PLATFORMS"}, + Sources: cli.EnvVars("EARTHLY_PLATFORMS"), Usage: "Specify the target platform to build for or this can be read from ENV VAR", Destination: &a.platformsStr, }, &cli.StringSliceFlag{ Name: "build-arg", - EnvVars: []string{"EARTHLY_BUILD_ARGS"}, + Sources: cli.EnvVars("EARTHLY_BUILD_ARGS"), Usage: "A build arg override, specified as =[]", Destination: &a.buildArgs, Hidden: true, // Deprecated @@ -24,19 +24,19 @@ func (a *Build) buildFlags() []cli.Flag { &cli.StringSliceFlag{ Name: "secret", Aliases: []string{"s"}, - EnvVars: []string{"EARTHLY_SECRETS"}, + Sources: cli.EnvVars("EARTHLY_SECRETS"), Usage: "A secret override, specified as =[]", Destination: &a.secrets, }, &cli.StringSliceFlag{ Name: "secret-file", - EnvVars: []string{"EARTHLY_SECRET_FILES"}, + Sources: cli.EnvVars("EARTHLY_SECRET_FILES"), Usage: "A secret override, specified as =", Destination: &a.secretFiles, }, &cli.StringSliceFlag{ Name: "cache-from", - EnvVars: []string{"EARTHLY_CACHE_FROM"}, + Sources: cli.EnvVars("EARTHLY_CACHE_FROM"), Usage: "Remote docker image tags to use as readonly explicit cache (experimental)", Destination: &a.cacheFrom, Hidden: true, // Experimental diff --git a/cmd/earthly/subcmd/cli.go b/cmd/earthly/subcmd/cli.go index e4781da54c..92c9cf327f 100644 --- a/cmd/earthly/subcmd/cli.go +++ b/cmd/earthly/subcmd/cli.go @@ -1,18 +1,19 @@ package subcmd import ( - "github.com/moby/buildkit/client" - "github.com/urfave/cli/v2" + "context" "github.com/EarthBuild/earthbuild/cmd/earthly/flag" "github.com/EarthBuild/earthbuild/config" "github.com/EarthBuild/earthbuild/conslogging" "github.com/EarthBuild/earthbuild/logbus" "github.com/EarthBuild/earthbuild/logbus/setup" + "github.com/moby/buildkit/client" + "github.com/urfave/cli/v3" ) type CLI interface { - App() *cli.App + App() *cli.Command Version() string GitSHA() string @@ -21,11 +22,11 @@ type CLI interface { Console() conslogging.ConsoleLogger SetConsole(conslogging.ConsoleLogger) - InitFrontend(*cli.Context) error + InitFrontend(context.Context, *cli.Command) error Cfg() *config.Config SetCommandName(name string) - GetBuildkitClient(*cli.Context) (client *client.Client, err error) + GetBuildkitClient(context.Context, *cli.Command) (client *client.Client, err error) LogbusSetup() *setup.BusSetup Logbus() *logbus.Bus diff --git a/cmd/earthly/subcmd/cmds_test.go b/cmd/earthly/subcmd/cmds_test.go index 87e8328eb3..9a59ea27f6 100644 --- a/cmd/earthly/subcmd/cmds_test.go +++ b/cmd/earthly/subcmd/cmds_test.go @@ -11,7 +11,7 @@ import ( "github.com/EarthBuild/earthbuild/cmd/earthly/subcmd" "github.com/EarthBuild/earthbuild/conslogging" "github.com/stretchr/testify/require" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) func TestRootCmdsHelp(t *testing.T) { @@ -49,8 +49,8 @@ func checkSubCommands(commands []*cli.Command) []*cli.Command { for _, command := range commands { allCommands = append(allCommands, command) - if len(command.Subcommands) != 0 { - allCommands = append(allCommands, checkSubCommands(command.Subcommands)...) + if len(command.Commands) != 0 { + allCommands = append(allCommands, checkSubCommands(command.Commands)...) } } diff --git a/cmd/earthly/subcmd/common.go b/cmd/earthly/subcmd/common.go index d95b00e852..6a61f92119 100644 --- a/cmd/earthly/subcmd/common.go +++ b/cmd/earthly/subcmd/common.go @@ -1,7 +1,7 @@ package subcmd import ( - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) func concatCmds(slices [][]*cli.Command) []*cli.Command { diff --git a/cmd/earthly/subcmd/config_cmds.go b/cmd/earthly/subcmd/config_cmds.go index 20b713b073..7d00bdcd85 100644 --- a/cmd/earthly/subcmd/config_cmds.go +++ b/cmd/earthly/subcmd/config_cmds.go @@ -1,13 +1,13 @@ package subcmd import ( + "context" "fmt" "os" "github.com/EarthBuild/earthbuild/config" "github.com/pkg/errors" - - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Config struct { @@ -74,18 +74,18 @@ func (a *Config) Cmds() []*cli.Command { } } -func (a *Config) action(cliCtx *cli.Context) error { +func (a *Config) action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("config") - if cliCtx.NArg() != 2 { + if cmd.NArg() != 2 { return errors.New("invalid number of arguments provided") } - args := cliCtx.Args().Slice() + args := cmd.Args().Slice() inConfig, err := config.ReadConfigFile(a.cli.Flags().ConfigPath) if err != nil { - if cliCtx.IsSet("config") || !errors.Is(err, os.ErrNotExist) { + if cmd.IsSet("config") || !errors.Is(err, os.ErrNotExist) { return errors.Wrapf(err, "read config") } } diff --git a/cmd/earthly/subcmd/debug_cmds.go b/cmd/earthly/subcmd/debug_cmds.go index 8b0ab1a4ab..7eef9ef67f 100644 --- a/cmd/earthly/subcmd/debug_cmds.go +++ b/cmd/earthly/subcmd/debug_cmds.go @@ -1,6 +1,7 @@ package subcmd import ( + "context" "encoding/json" "fmt" "os" @@ -13,7 +14,7 @@ import ( "github.com/dustin/go-humanize" "github.com/moby/buildkit/client" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Debug struct { @@ -36,7 +37,7 @@ func (a *Debug) Cmds() []*cli.Command { Description: "Print debug information about an Earthfile.", ArgsUsage: "[]", Hidden: true, // Dev purposes only. - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "ast", Usage: "Output the AST", @@ -91,16 +92,16 @@ func (a *Debug) Cmds() []*cli.Command { } } -func (a *Debug) actionAst(cliCtx *cli.Context) error { +func (a *Debug) actionAst(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugAst") - if cliCtx.NArg() > 1 { + if cmd.NArg() > 1 { return errors.New("invalid number of arguments provided") } path := "./Earthfile" - if cliCtx.NArg() == 1 { - path = cliCtx.Args().First() + if cmd.NArg() == 1 { + path = cmd.Args().First() } ef, err := ast.Parse(path, a.enableSourceMap) @@ -118,16 +119,16 @@ func (a *Debug) actionAst(cliCtx *cli.Context) error { return nil } -func (a *Debug) actionBuildkitSessionHistory(cliCtx *cli.Context) error { +func (a *Debug) actionBuildkitSessionHistory(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugBuildkitSessions") - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "build new buildkitd client") } defer bkClient.Close() - history, err := bkClient.SessionHistory(cliCtx.Context) + history, err := bkClient.SessionHistory(ctx) if err != nil { return errors.Wrap(err, "get buildkit session history") } @@ -138,16 +139,16 @@ func (a *Debug) actionBuildkitSessionHistory(cliCtx *cli.Context) error { return nil } -func (a *Debug) actionBuildkitInfo(cliCtx *cli.Context) error { +func (a *Debug) actionBuildkitInfo(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugBuildkitInfo") - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "build new buildkitd client") } defer bkClient.Close() - info, err := bkClient.Info(cliCtx.Context) + info, err := bkClient.Info(ctx) if err != nil { return errors.Wrap(err, "get buildkit info") } @@ -160,16 +161,16 @@ func (a *Debug) actionBuildkitInfo(cliCtx *cli.Context) error { return nil } -func (a *Debug) actionBuildkitDiskUsage(cliCtx *cli.Context) error { +func (a *Debug) actionBuildkitDiskUsage(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugBuildkitDiskUsage") - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "build new buildkitd client") } defer bkClient.Close() - infos, err := bkClient.DiskUsage(cliCtx.Context) + infos, err := bkClient.DiskUsage(ctx) if err != nil { return errors.Wrap(err, "get buildkit disk usage") } @@ -215,16 +216,16 @@ func (a *Debug) actionBuildkitDiskUsage(cliCtx *cli.Context) error { return nil } -func (a *Debug) actionBuildkitWorkers(cliCtx *cli.Context) error { +func (a *Debug) actionBuildkitWorkers(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugBuildkitWorkers") - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "build new buildkitd client") } defer bkClient.Close() - workers, err := bkClient.ListWorkers(cliCtx.Context) + workers, err := bkClient.ListWorkers(ctx) if err != nil { return errors.Wrap(err, "get buildkit workers") } @@ -289,16 +290,16 @@ func (a *Debug) actionBuildkitWorkers(cliCtx *cli.Context) error { return nil } -func (a *Debug) actionBuildkitShutdownIfIdle(cliCtx *cli.Context) error { +func (a *Debug) actionBuildkitShutdownIfIdle(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("debugBuildkitShutdownIfIdle") - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "build new buildkitd client") } defer bkClient.Close() - ok, numSessions, err := bkClient.ShutdownIfIdle(cliCtx.Context) + ok, numSessions, err := bkClient.ShutdownIfIdle(ctx) if err != nil { return errors.Wrap(err, "shutdown buildkit if idle") } diff --git a/cmd/earthly/subcmd/doc_cmds.go b/cmd/earthly/subcmd/doc_cmds.go index 40fa578500..ef1c5cd109 100644 --- a/cmd/earthly/subcmd/doc_cmds.go +++ b/cmd/earthly/subcmd/doc_cmds.go @@ -1,6 +1,7 @@ package subcmd import ( + "context" "fmt" "slices" "strings" @@ -14,7 +15,7 @@ import ( "github.com/EarthBuild/earthbuild/util/platutil" gwclient "github.com/moby/buildkit/frontend/gateway/client" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Doc struct { @@ -49,16 +50,16 @@ func (a *Doc) Cmds() []*cli.Command { } } -func (a *Doc) action(cliCtx *cli.Context) error { +func (a *Doc) action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("docTarget") - if cliCtx.NArg() > 1 { + if cmd.NArg() > 1 { return errors.New("invalid number of arguments provided") } var tgtPath string - if cliCtx.NArg() > 0 { - tgtPath = cliCtx.Args().Get(0) + if cmd.NArg() > 0 { + tgtPath = cmd.Args().Get(0) switch tgtPath[0] { case '.', '/', '+': default: @@ -85,7 +86,7 @@ func (a *Doc) action(cliCtx *cli.Context) error { var gwClient gwclient.Client - bc, err := resolver.Resolve(cliCtx.Context, gwClient, platr, target) + bc, err := resolver.Resolve(ctx, gwClient, platr, target) if err != nil { return errors.Wrap(err, "failed to resolve target") } @@ -98,7 +99,7 @@ func (a *Doc) action(cliCtx *cli.Context) error { return errors.Wrap(err, "failed to look up target") } - return a.documentSingleTarget(cliCtx, "", docsIndent, bc.Features, bc.Earthfile.BaseRecipe, tgt, true) + return a.documentSingleTarget(ctx, "", docsIndent, bc.Features, bc.Earthfile.BaseRecipe, tgt, true) } tgts := bc.Earthfile.Targets @@ -107,7 +108,7 @@ func (a *Doc) action(cliCtx *cli.Context) error { const tgtIndent = docsIndent for _, tgt := range tgts { - _ = a.documentSingleTarget(cliCtx, tgtIndent, docsIndent, bc.Features, bc.Earthfile.BaseRecipe, tgt, a.docShowLong) + _ = a.documentSingleTarget(ctx, tgtIndent, docsIndent, bc.Features, bc.Earthfile.BaseRecipe, tgt, a.docShowLong) } return nil @@ -196,7 +197,7 @@ func (io blockIO) help(indent, scopeIndent string) string { } func addArg( - cliCtx *cli.Context, io *blockIO, ft *features.Features, stmt spec.Statement, isBase, onlyGlobal bool, + ctx context.Context, io *blockIO, ft *features.Features, stmt spec.Statement, isBase, onlyGlobal bool, ) error { if stmt.Command == nil { return nil @@ -207,7 +208,7 @@ func addArg( return nil } - ident, dflt, isRequired, isGlobal, err := earthfile2llb.ArgName(cliCtx.Context, cmd, isBase, ft.ExplicitGlobal) + ident, dflt, isRequired, isGlobal, err := earthfile2llb.ArgName(ctx, cmd, isBase, ft.ExplicitGlobal) if err != nil { return errors.Wrap(err, "failed to parse ARG statement") } @@ -236,10 +237,10 @@ func addArg( return nil } -func parseDocSections(cliCtx *cli.Context, ft *features.Features, baseRcp, cmds spec.Block) (*blockIO, error) { +func parseDocSections(ctx context.Context, ft *features.Features, baseRcp, cmds spec.Block) (*blockIO, error) { var io blockIO for _, base := range baseRcp { - err := addArg(cliCtx, &io, ft, base, true, true) + err := addArg(ctx, &io, ft, base, true, true) if err != nil { return nil, errors.Wrap(err, "failed to parse global ARG in base recipe") } @@ -253,12 +254,12 @@ func parseDocSections(cliCtx *cli.Context, ft *features.Features, baseRcp, cmds cmd := *rb.Command switch cmd.Name { case "ARG": - err := addArg(cliCtx, &io, ft, rb, false, false) + err := addArg(ctx, &io, ft, rb, false, false) if err != nil { return nil, errors.Wrap(err, "failed to parse non-global ARG") } case "SAVE ARTIFACT": - name, localName, err := earthfile2llb.ArtifactName(cliCtx.Context, cmd) + name, localName, err := earthfile2llb.ArtifactName(ctx, cmd) if err != nil { return nil, errors.Wrap(err, "could not parse SAVE ARTIFACT name") } @@ -283,7 +284,7 @@ func parseDocSections(cliCtx *cli.Context, ft *features.Features, baseRcp, cmds io.artifacts = append(io.artifacts, artDoc) case "SAVE IMAGE": - identifiers, err := earthfile2llb.ImageNames(cliCtx.Context, cmd) + identifiers, err := earthfile2llb.ImageNames(ctx, cmd) if err != nil { return nil, errors.Wrap(err, "could not parse SAVE IMAGE name(s)") } @@ -304,7 +305,7 @@ func parseDocSections(cliCtx *cli.Context, ft *features.Features, baseRcp, cmds } func (a *Doc) documentSingleTarget( - cliCtx *cli.Context, + ctx context.Context, currIndent, scopeIndent string, ft *features.Features, baseRcp spec.Block, @@ -321,7 +322,7 @@ func (a *Doc) documentSingleTarget( return err } - blockIO, err := parseDocSections(cliCtx, ft, baseRcp, tgt.Recipe) + blockIO, err := parseDocSections(ctx, ft, baseRcp, tgt.Recipe) if err != nil { return errors.Wrapf(err, "failed to parse body of recipe '%v'", tgt.Name) } diff --git a/cmd/earthly/subcmd/docker_earthly_cmds.go b/cmd/earthly/subcmd/docker_earthly_cmds.go index 2ba195196e..629140c194 100644 --- a/cmd/earthly/subcmd/docker_earthly_cmds.go +++ b/cmd/earthly/subcmd/docker_earthly_cmds.go @@ -1,12 +1,12 @@ package subcmd import ( + "context" "fmt" "os" "github.com/EarthBuild/earthbuild/docker2earthly" - - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Doc2Earth struct { @@ -53,7 +53,7 @@ func (a *Doc2Earth) Cmds() []*cli.Command { } } -func (a *Doc2Earth) action(cliCtx *cli.Context) error { +func (a *Doc2Earth) action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("docker2earthly") err := docker2earthly.Docker2Earthly(a.cli.Flags().DockerfilePath, a.earthfilePath, a.earthfileFinalImage) diff --git a/cmd/earthly/subcmd/init_cmds.go b/cmd/earthly/subcmd/init_cmds.go index 036a099ba4..3814aaa515 100644 --- a/cmd/earthly/subcmd/init_cmds.go +++ b/cmd/earthly/subcmd/init_cmds.go @@ -1,6 +1,7 @@ package subcmd import ( + "context" "io" "io/fs" "os" @@ -9,7 +10,7 @@ import ( "github.com/EarthBuild/earthbuild/util/hint" "github.com/EarthBuild/earthbuild/util/proj" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) const efIndent = " " @@ -35,9 +36,7 @@ func (a *Init) Cmds() []*cli.Command { } } -func (a *Init) action(cliCtx *cli.Context) error { - ctx := cliCtx.Context - +func (a *Init) action(ctx context.Context, cmd *cli.Command) error { wd, err := os.Getwd() if err != nil { return errors.Wrap(err, "could not load current working directory") diff --git a/cmd/earthly/subcmd/ls_cmds.go b/cmd/earthly/subcmd/ls_cmds.go index 72bc8993cf..9496168dba 100644 --- a/cmd/earthly/subcmd/ls_cmds.go +++ b/cmd/earthly/subcmd/ls_cmds.go @@ -1,6 +1,7 @@ package subcmd import ( + "context" "fmt" "sort" "strings" @@ -11,8 +12,7 @@ import ( "github.com/EarthBuild/earthbuild/earthfile2llb" gwclient "github.com/moby/buildkit/frontend/gateway/client" "github.com/pkg/errors" - - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type List struct { @@ -54,16 +54,16 @@ func (a *List) Cmds() []*cli.Command { } } -func (a *List) action(cliCtx *cli.Context) error { +func (a *List) action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("listTargets") - if cliCtx.NArg() > 1 { + if cmd.NArg() > 1 { return errors.New("invalid number of arguments provided") } var targetToParse string - if cliCtx.NArg() > 0 { - targetToParse = cliCtx.Args().Get(0) + if cmd.NArg() > 0 { + targetToParse = cmd.Args().Get(0) if !strings.HasPrefix(targetToParse, "/") && !strings.HasPrefix(targetToParse, ".") { return errors.New("remote-paths are not currently supported; local paths must start with \"/\" or \".\"") } @@ -99,7 +99,7 @@ func (a *List) action(cliCtx *cli.Context) error { return err } - targets, err := earthfile2llb.GetTargets(cliCtx.Context, resolver, gwClient, target) + targets, err := earthfile2llb.GetTargets(ctx, resolver, gwClient, target) if err != nil { if errors.As(errors.Cause(err), ¬ExistErr) { return errors.Errorf("unable to locate Earthfile under %s", targetToDisplay) @@ -117,7 +117,7 @@ func (a *List) action(cliCtx *cli.Context) error { if t != ast.TargetBase { target.Target = t - args, err = earthfile2llb.GetTargetArgs(cliCtx.Context, resolver, gwClient, target) + args, err = earthfile2llb.GetTargetArgs(ctx, resolver, gwClient, target) if err != nil { return err } diff --git a/cmd/earthly/subcmd/prune_cmds.go b/cmd/earthly/subcmd/prune_cmds.go index a0e359171d..0d724bbcfa 100644 --- a/cmd/earthly/subcmd/prune_cmds.go +++ b/cmd/earthly/subcmd/prune_cmds.go @@ -1,16 +1,16 @@ package subcmd import ( + "context" "time" + "github.com/EarthBuild/earthbuild/buildkitd" + "github.com/EarthBuild/earthbuild/util/flagutil" "github.com/dustin/go-humanize" "github.com/moby/buildkit/client" "github.com/pkg/errors" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" - - "github.com/EarthBuild/earthbuild/buildkitd" - "github.com/EarthBuild/earthbuild/util/flagutil" ) type Prune struct { @@ -44,13 +44,13 @@ func (a *Prune) Cmds() []*cli.Command { &cli.BoolFlag{ Name: "all", Aliases: []string{"a"}, - EnvVars: []string{"EARTHLY_PRUNE_ALL"}, + Sources: cli.EnvVars("EARTHLY_PRUNE_ALL"), Usage: "Prune all cache via BuildKit daemon", Destination: &a.all, }, &cli.BoolFlag{ Name: "reset", - EnvVars: []string{"EARTHLY_PRUNE_RESET"}, + Sources: cli.EnvVars("EARTHLY_PRUNE_RESET"), Usage: `Reset cache entirely by restarting BuildKit daemon and wiping cache dir.`, Destination: &a.reset, }, @@ -70,21 +70,21 @@ func (a *Prune) Cmds() []*cli.Command { } } -func (a *Prune) action(cliCtx *cli.Context) error { +func (a *Prune) action(ctx context.Context, cmd *cli.Command) error { a.cli.SetCommandName("prune") - if cliCtx.NArg() != 0 { + if cmd.NArg() != 0 { return errors.New("invalid arguments") } if a.reset { - err := a.cli.InitFrontend(cliCtx) + err := a.cli.InitFrontend(ctx, cmd) if err != nil { return err } err = buildkitd.ResetCache( - cliCtx.Context, a.cli.Console(), a.cli.Flags().BuildkitdImage, a.cli.Flags().ContainerName, + ctx, a.cli.Console(), a.cli.Flags().BuildkitdImage, a.cli.Flags().ContainerName, a.cli.Flags().InstallationName, a.cli.Flags().ContainerFrontend, a.cli.Flags().BuildkitdSettings) if err != nil { return errors.Wrap(err, "reset cache") @@ -93,7 +93,7 @@ func (a *Prune) action(cliCtx *cli.Context) error { return nil } - bkClient, err := a.cli.GetBuildkitClient(cliCtx) + bkClient, err := a.cli.GetBuildkitClient(ctx, cmd) if err != nil { return errors.Wrap(err, "prune new buildkitd client") } @@ -110,7 +110,7 @@ func (a *Prune) action(cliCtx *cli.Context) error { } ch := make(chan client.UsageInfo, 1) - eg, ctx := errgroup.WithContext(cliCtx.Context) + eg, ctx := errgroup.WithContext(ctx) eg.Go(func() error { err = bkClient.Prune(ctx, ch, opts...) if err != nil { diff --git a/cmd/earthly/subcmd/root_cmds.go b/cmd/earthly/subcmd/root_cmds.go index 63879ddaae..2124681194 100644 --- a/cmd/earthly/subcmd/root_cmds.go +++ b/cmd/earthly/subcmd/root_cmds.go @@ -1,7 +1,7 @@ package subcmd import ( - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Root struct { diff --git a/go.mod b/go.mod index 6692c0e45a..1ec8d234ba 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 - github.com/urfave/cli/v2 v2.27.7 + github.com/urfave/cli/v3 v3.8.0 go.etcd.io/bbolt v1.4.3 go.opentelemetry.io/contrib/exporters/autoexport v0.55.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 @@ -90,7 +90,6 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/containerd/ttrpc v1.2.7 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker v24.0.0-rc.2.0.20230905130451-032797ea4bcb+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect @@ -122,13 +121,11 @@ require ( github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.19.2 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect github.com/vbatts/tar-split v0.11.3 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect diff --git a/go.sum b/go.sum index aa9119e560..2571e3978f 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,6 @@ al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -git.sr.ht/~nelsam/correct v0.1.2 h1:jh6ey96zjubCvrEky6Jcpa7k5NCUFc8+TwQu3+voyVE= -git.sr.ht/~nelsam/correct v0.1.2/go.mod h1:ftLUfw6zfxcpnS9LQQe/7FiOGey3m/iF46olkT53uwE= git.sr.ht/~nelsam/correct v0.1.3 h1:mqTrpC8dfRUpia/VfqNP2uXU7KxuQOLxNfo4nmy9AWg= git.sr.ht/~nelsam/correct v0.1.3/go.mod h1:ftLUfw6zfxcpnS9LQQe/7FiOGey3m/iF46olkT53uwE= git.sr.ht/~nelsam/hel v0.9.4 h1:i9caNNprvdedpQ8WWNGW4jrTUH9IiLQKVVfF0r7ilMk= @@ -113,8 +111,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 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.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= -github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -260,8 +256,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= -github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= @@ -334,7 +328,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 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/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs= @@ -378,14 +371,12 @@ github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVN github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= -github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= -github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= +github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI= +github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= 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-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/util/cliutil/flag_envs.go b/util/cliutil/flag_envs.go index 422b07c44a..ebe66195ef 100644 --- a/util/cliutil/flag_envs.go +++ b/util/cliutil/flag_envs.go @@ -3,10 +3,10 @@ package cliutil import ( "reflect" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) -func GetValidEnvNames(app *cli.App) map[string]struct{} { +func GetValidEnvNames(app *cli.Command) map[string]struct{} { envs := map[string]struct{}{} for _, envName := range getValidEnvNamesFromCommands(app.Commands) { envs[envName] = struct{}{} diff --git a/util/flagutil/byte_size_value.go b/util/flagutil/byte_size_value.go index 3dbc0d9125..83f91627a8 100644 --- a/util/flagutil/byte_size_value.go +++ b/util/flagutil/byte_size_value.go @@ -18,3 +18,7 @@ func (b *ByteSizeValue) Set(s string) error { } func (b *ByteSizeValue) String() string { return humanize.Bytes(uint64(*b)) } + +func (vf *ByteSizeValue) Get() any { + return *vf +} diff --git a/util/flagutil/duration.go b/util/flagutil/duration.go index 94ffb3bb03..f4551a5fb1 100644 --- a/util/flagutil/duration.go +++ b/util/flagutil/duration.go @@ -39,3 +39,7 @@ func (d *Duration) Set(value string) error { return nil } + +func (vf *Duration) Get() any { + return *vf +} diff --git a/util/flagutil/parse.go b/util/flagutil/parse.go index 4b640510d2..fe34349e7a 100644 --- a/util/flagutil/parse.go +++ b/util/flagutil/parse.go @@ -9,10 +9,8 @@ import ( "github.com/EarthBuild/earthbuild/ast/commandflag" "github.com/EarthBuild/earthbuild/ast/spec" "github.com/EarthBuild/earthbuild/util/stringutil" - "github.com/pkg/errors" - "github.com/jessevdk/go-flags" - "github.com/urfave/cli/v2" + "github.com/pkg/errors" ) // ArgumentModFunc accepts a flagName which corresponds to the long flag name, and a pointer @@ -273,12 +271,17 @@ func preprocessArgs(args []string, boolFlags map[string]bool, modFunc ArgumentMo // multiple occuranced of the flag or with the values passed with a command. For example: // // --platform linux/amd64 --platform linux/arm64 and --platform "linux/amd64,linux/arm64" -func SplitFlagString(value cli.StringSlice) []string { - valueStr := strings.TrimLeft(strings.TrimRight(value.String(), "]"), "[") +func SplitFlagString(values []string) []string { + var res []string + + for _, val := range values { + parts := strings.FieldsFunc(val, func(r rune) bool { + return r == ' ' || r == ',' + }) + res = append(res, parts...) + } - return strings.FieldsFunc(valueStr, func(r rune) bool { - return r == ' ' || r == ',' - }) + return res } var ( diff --git a/util/flagutil/parse_test.go b/util/flagutil/parse_test.go index 2820cadc1b..0ae15938f2 100644 --- a/util/flagutil/parse_test.go +++ b/util/flagutil/parse_test.go @@ -7,14 +7,13 @@ import ( "github.com/jessevdk/go-flags" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/urfave/cli/v2" ) func TestSplitFlagString(t *testing.T) { t.Parallel() type args struct { - value cli.StringSlice + value []string } tests := []struct { @@ -25,21 +24,21 @@ func TestSplitFlagString(t *testing.T) { { name: "passing flag multiple times", args: args{ - value: *(cli.NewStringSlice("a b")), + value: []string{"a b"}, }, want: []string{"a", "b"}, }, { name: "passing values with a comma", args: args{ - value: *(cli.NewStringSlice("a,b")), + value: []string{"a,b"}, }, want: []string{"a", "b"}, }, { name: "passing values with a comma and multiple flags", args: args{ - value: *(cli.NewStringSlice("a b,c d")), + value: []string{"a b,c d"}, }, want: []string{"a", "b", "c", "d"}, }, diff --git a/util/llbutil/authprovider/podman.go b/util/llbutil/authprovider/podman.go index 8a5bb349e0..735bbfb488 100644 --- a/util/llbutil/authprovider/podman.go +++ b/util/llbutil/authprovider/podman.go @@ -57,7 +57,7 @@ func WithOS(o OS) PodmanOpt { } } -func NewPodman(stderr io.Writer, opts ...PodmanOpt) session.Attachable { +func NewPodman(ctx context.Context, stderr io.Writer, opts ...PodmanOpt) session.Attachable { conf := podmanCfg{ os: defaultOS{}, } @@ -79,7 +79,7 @@ func NewPodman(stderr io.Writer, opts ...PodmanOpt) session.Attachable { xdgRuntime := conf.os.Getenv("XDG_RUNTIME_DIR") if xdgRuntime == "" { - idCmd := exec.CommandContext(context.Background(), "id", "-u") + idCmd := exec.CommandContext(ctx, "id", "-u") out, err := idCmd.CombinedOutput() if err != nil { diff --git a/util/llbutil/authprovider/podman_test.go b/util/llbutil/authprovider/podman_test.go index 71d7477f97..520a1eca1b 100644 --- a/util/llbutil/authprovider/podman_test.go +++ b/util/llbutil/authprovider/podman_test.go @@ -58,7 +58,7 @@ func TestPodmanProvider(t *testing.T) { go func() { defer close(tt.result) - tt.result <- authprovider.NewPodman(tt.stderr, authprovider.WithOS(tt.os)) + tt.result <- authprovider.NewPodman(t.Context(), tt.stderr, authprovider.WithOS(tt.os)) }() t.Cleanup(func() {