-
Notifications
You must be signed in to change notification settings - Fork 690
Kong CLI parity via shared command logic #3047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: kong
Are you sure you want to change the base?
Changes from 9 commits
9075ab5
a1b710a
9b9f310
8428257
b5c8563
127e8b1
957c924
95b223e
1477b1f
1f1b4c4
89a4b4f
acff164
92f0237
63c65df
2ab4cc4
d6c2b70
4c0596d
bf8a249
f83efb3
89369f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/replicate/cog/pkg/cli" | ||
| "github.com/replicate/cog/pkg/docker/command" | ||
| ) | ||
|
|
||
| // BaseImageCmd implements the experimental "cog base-image" command group. | ||
| type BaseImageCmd struct { | ||
| Dockerfile BaseImageDockerfileCmd `cmd:"" help:"Display Cog base image Dockerfile."` | ||
| Build BaseImageBuildCmd `cmd:"" help:"Build Cog base image."` | ||
| } | ||
|
|
||
| // baseImageVersionFlags groups the version-selecting flags shared by the | ||
| // base-image subcommands. | ||
| type baseImageVersionFlags struct { | ||
| CUDA string `name:"cuda" help:"CUDA version."` | ||
| Python string `name:"python" help:"Python version."` | ||
| Torch string `name:"torch" help:"Torch version."` | ||
|
|
||
| // Hidden flags for parity with the Cobra base-image command. | ||
| BreakSystemPackages bool `name:"break-system-packages" hidden:"" help:"Allow pip to modify uv-managed Python installs."` | ||
| BuildContextDir string `name:"build-context-dir" hidden:"" help:"Directory for generated Docker build context artifacts."` | ||
| Timestamp int64 `name:"timestamp" hidden:"" default:"-1" help:"Number of seconds since Epoch to use for the build timestamp."` | ||
| } | ||
|
|
||
| func (f baseImageVersionFlags) options() cli.BaseImageOptions { | ||
| return cli.BaseImageOptions{ | ||
| CUDAVersion: f.CUDA, | ||
| PythonVersion: f.Python, | ||
| TorchVersion: f.Torch, | ||
| BreakSystemPackages: f.BreakSystemPackages, | ||
| BuildContextDir: f.BuildContextDir, | ||
| Timestamp: f.Timestamp, | ||
| } | ||
| } | ||
|
|
||
| // BaseImageDockerfileCmd implements "cog base-image dockerfile". | ||
| type BaseImageDockerfileCmd struct { | ||
| baseImageVersionFlags `embed:""` | ||
|
|
||
| NoCache bool `name:"no-cache" help:"Do not use cache when building the image."` | ||
| Progress string `name:"progress" default:"${progress_default}" enum:"auto,plain,tty,quiet" help:"Set type of build progress output: ${enum}."` | ||
| } | ||
|
|
||
| func (cmd *BaseImageDockerfileCmd) Run(ctx context.Context) error { | ||
| opts := cmd.options() | ||
| opts.NoCache = cmd.NoCache | ||
| opts.ProgressOutput = cmd.Progress | ||
| return cli.RunBaseImageDockerfile(ctx, opts) | ||
| } | ||
|
|
||
| // BaseImageBuildCmd implements "cog base-image build". | ||
| type BaseImageBuildCmd struct { | ||
| baseImageVersionFlags `embed:""` | ||
| } | ||
|
|
||
| func (cmd *BaseImageBuildCmd) Run(ctx context.Context, dockerClient command.Command) error { | ||
| return cli.RunBaseImageBuild(ctx, dockerClient, cmd.options()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,44 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "os" | ||
|
|
||
| "github.com/alecthomas/kong" | ||
|
|
||
| "github.com/replicate/cog/pkg/global" | ||
| "github.com/replicate/cog/pkg/update" | ||
| "github.com/replicate/cog/pkg/util/console" | ||
| ) | ||
|
|
||
| // Globals holds flags available to every command. | ||
| // The AfterApply hook replaces Cobra's PersistentPreRun. | ||
| type Globals struct { | ||
| Debug bool `name:"debug" short:"d" env:"COG_DEBUG" help:"Show debugging output."` | ||
| NoColor bool `name:"no-color" help:"Disable colored output."` | ||
| Help bool `name:"help" short:"h" help:"Show context-sensitive help."` | ||
| Registry string `name:"registry" default:"${registry_default}" env:"COG_REGISTRY_HOST" hidden:"" help:"Registry host."` | ||
| Profile bool `name:"profile" hidden:"" help:"Enable profiling."` | ||
| Version kong.VersionFlag `name:"version" short:"v" help:"Show version of Cog."` | ||
| Version kong.VersionFlag `name:"version" help:"Show version of Cog."` | ||
| } | ||
|
|
||
| // AfterApply runs after flag parsing, before the command's Run. | ||
| // This is the Kong equivalent of Cobra's PersistentPreRun. | ||
| func (g *Globals) AfterApply(ctx context.Context) error { | ||
| func (g *Globals) AfterApply() error { | ||
| if g.Debug { | ||
| global.Debug = true | ||
| console.SetLevel(console.DebugLevel) | ||
| } | ||
| if g.NoColor { | ||
| global.NoColor = true | ||
| } | ||
| if global.NoColor || !console.ShouldUseColor() { | ||
| console.SetColor(false) | ||
| } | ||
| if global.NoColor { | ||
| _ = os.Setenv("NO_COLOR", "1") | ||
| } | ||
| if g.Profile { | ||
| global.ProfilingEnabled = true | ||
| } | ||
| global.ReplicateRegistryHost = g.Registry | ||
|
|
||
| if err := update.DisplayAndCheckForRelease(ctx); err != nil { | ||
| console.Debugf("%s", err) | ||
| } | ||
| return nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ import ( | |
| "github.com/alecthomas/kong" | ||
|
|
||
| "github.com/replicate/cog/pkg/global" | ||
| "github.com/replicate/cog/pkg/update" | ||
| "github.com/replicate/cog/pkg/util/console" | ||
| ) | ||
|
|
||
|
|
@@ -26,35 +27,27 @@ var ( | |
| type CLI struct { | ||
| Globals | ||
|
|
||
| Build BuildCmd `cmd:"" help:"Build an image from cog.yaml."` | ||
| Push PushCmd `cmd:"" help:"Build and push model in current directory to a Docker registry."` | ||
| BaseImage BaseImageCmd `cmd:"" name:"base-image" help:"Tools for working with Cog base images."` | ||
| Build BuildCmd `cmd:"" help:"Build an image from cog.yaml."` | ||
| Debug DebugCmd `cmd:"" help:"Debug Cog internals."` | ||
| Doctor DoctorCmd `cmd:"" help:"Check your project for common issues and fix them (experimental)."` | ||
|
markphelps marked this conversation as resolved.
|
||
| Exec ExecCmd `cmd:"" help:"Execute a command inside a Docker environment."` | ||
| Init InitCmd `cmd:"" help:"Configure your project for use with Cog."` | ||
|
markphelps marked this conversation as resolved.
|
||
| Login LoginCmd `cmd:"" help:"Log in to a container registry."` | ||
| Predict PredictCmd `cmd:"" help:"Run a prediction."` | ||
| Push PushCmd `cmd:"" help:"Build and push model in current directory to a Docker registry."` | ||
| RunCommand RunCmd `cmd:"" name:"run" help:"Run a prediction."` | ||
| Serve ServeCmd `cmd:"" help:"Run an HTTP server."` | ||
| Train TrainCmd `cmd:"" help:"Run a training job."` | ||
|
markphelps marked this conversation as resolved.
Outdated
|
||
| Weights WeightsCmd `cmd:"" help:"Commands for managing model weight files."` | ||
|
markphelps marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| func main() { | ||
| ctx, cancel := newCancellationContext() | ||
|
|
||
| var cli CLI | ||
|
|
||
| initOpts := []kong.Option{ | ||
| // CLI metadata and variable interpolation for struct tags | ||
| kong.Name("cog"), | ||
| kong.Description("Containers for machine learning."), | ||
| kong.Vars{ | ||
| "version": fmt.Sprintf("cog version %s (built %s)", version, buildTime), | ||
| "commit": commit, | ||
| "progress_default": progressDefault(), | ||
| "registry_default": global.DefaultReplicateRegistryHost, | ||
| }, | ||
| kong.UsageOnError(), | ||
|
|
||
| // bindings for lazily injecting dependencies into Run() methods | ||
| kong.BindTo(ctx, (*context.Context)(nil)), | ||
| kong.BindSingletonProvider(provideDockerClient), | ||
| kong.BindToProvider(provideRegistryClient), | ||
| kong.BindSingletonProvider(provideProviderRegistry), | ||
| } | ||
|
|
||
| parser, err := kong.New(&cli, initOpts...) | ||
| parser, err := newParser(ctx, &cli) | ||
| if err != nil { | ||
| // Fatal error creating the parser — this is a bug, so panic to get a stack trace. | ||
| panic(err) | ||
|
|
@@ -74,14 +67,47 @@ func main() { | |
|
|
||
| // otherwise it's a real parse error (e.g. unexpected command or flag), so print the error and exit non-zero. | ||
| parser.FatalIfErrorf(err) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two systematic divergences from Cobra flow through
Worth a decision on whether parity requires matching Cobra's exit
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remaining The rescue at line 63 only matches |
||
| os.Exit(1) | ||
|
markphelps marked this conversation as resolved.
Outdated
|
||
| } | ||
| if cli.Help { | ||
| _ = kctx.PrintUsage(false) | ||
| return | ||
| } | ||
|
|
||
| displayUpdateCheck(ctx) | ||
| err = kctx.Run() | ||
| cancel() | ||
| // command returned an error. Print and exit non-zero. | ||
| if err != nil { | ||
| parser.FatalIfErrorf(err) | ||
| os.Exit(1) | ||
|
markphelps marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
|
|
||
| func displayUpdateCheck(ctx context.Context) { | ||
| if err := update.DisplayAndCheckForRelease(ctx); err != nil { | ||
| console.Debugf("%s", err) | ||
| } | ||
| } | ||
|
|
||
| func newParser(ctx context.Context, cli *CLI, options ...kong.Option) (*kong.Kong, error) { | ||
| defaultOptions := []kong.Option{ | ||
| kong.Name("cog"), | ||
| kong.Description("Containers for machine learning."), | ||
| kong.Vars{ | ||
| "version": fmt.Sprintf("cog version %s (built %s)", version, buildTime), | ||
| "commit": commit, | ||
| "progress_default": progressDefault(), | ||
| "registry_default": global.DefaultReplicateRegistryHost, | ||
| }, | ||
| kong.UsageOnError(), | ||
| kong.NoDefaultHelp(), | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Expected (Cobra): all print help and exit 0. Make
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 89369f1. Switched to Kong's built-in |
||
| kong.BindTo(ctx, (*context.Context)(nil)), | ||
| kong.BindSingletonProvider(provideDockerClient), | ||
| kong.BindToProvider(provideRegistryClient), | ||
| kong.BindSingletonProvider(provideProviderRegistry), | ||
| } | ||
| return kong.New(cli, append(defaultOptions, options...)...) | ||
| } | ||
|
|
||
| func newCancellationContext() (context.Context, context.CancelFunc) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.