cmd/docker: split handling exit-code to a separate utility

This allows dockerMain() to return an error "as usual", and puts the
responsibility for turning that into an appropriate exit-code in
main() (which also sets the exit-code when terminating).

We could consider putting this utility in the cli package and exporting
it if would be useful for doing a similar handling in plugins.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2024-07-04 13:45:43 +02:00
parent b7695d6c79
commit eae75092a0
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
1 changed files with 23 additions and 24 deletions

View File

@ -29,43 +29,42 @@ import (
) )
func main() { func main() {
statusCode := dockerMain() err := dockerMain(context.Background())
if statusCode != 0 { if err != nil && !errdefs.IsCancelled(err) {
os.Exit(statusCode) _, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(getExitCode(err))
} }
} }
func dockerMain() int { func dockerMain(ctx context.Context) error {
ctx, cancelNotify := signal.NotifyContext(context.Background(), platformsignals.TerminationSignals...) ctx, cancelNotify := signal.NotifyContext(ctx, platformsignals.TerminationSignals...)
defer cancelNotify() defer cancelNotify()
dockerCli, err := command.NewDockerCli(command.WithBaseContext(ctx)) dockerCli, err := command.NewDockerCli(command.WithBaseContext(ctx))
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) return err
return 1
} }
logrus.SetOutput(dockerCli.Err()) logrus.SetOutput(dockerCli.Err())
otel.SetErrorHandler(debug.OTELErrorHandler) otel.SetErrorHandler(debug.OTELErrorHandler)
if err := runDocker(ctx, dockerCli); err != nil { return runDocker(ctx, dockerCli)
var stErr cli.StatusError
if errors.As(err, &stErr) {
// StatusError should only be used for errors, and all errors should
// have a non-zero exit status, so never exit with 0
if stErr.StatusCode == 0 { // FIXME(thaJeztah): StatusCode should never be used with a zero status-code. Check if we do this anywhere.
stErr.StatusCode = 1
} }
_, _ = fmt.Fprintln(dockerCli.Err(), stErr)
// getExitCode returns the exit-code to use for the given error.
// If err is a [cli.StatusError] and has a StatusCode set, it uses the
// status-code from it, otherwise it returns "1" for any error.
func getExitCode(err error) int {
if err == nil {
return 0
}
var stErr cli.StatusError
if errors.As(err, &stErr) && stErr.StatusCode != 0 { // FIXME(thaJeztah): StatusCode should never be used with a zero status-code. Check if we do this anywhere.
return stErr.StatusCode return stErr.StatusCode
} }
if errdefs.IsCancelled(err) {
return 0 // No status-code provided; all errors should have a non-zero exit code.
}
fmt.Fprintln(dockerCli.Err(), err)
return 1 return 1
} }
return 0
}
func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand { func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
var ( var (