From 0865185c841c778056f08a27e98fd110a8a5e5d1 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 11 Jul 2016 09:35:39 -0700 Subject: [PATCH 1/2] version: Add a version command And adjust 'runc --version' to print exactly the same content. The: $ COMMAND --version interface is a popular one for this information and makes a lot of sense for single-action commands. For example, printf(1) [1] is only ever going to do one meaningful thing, so --version, --help, and other command-like actions work well as options. Umbrella commands with multiple sub-commands, on the other hand, have a more consistent interface if '... and exit' actions get their own sub-commands. That allows you to declare an interface like: $ COMMAND [global-options] SUB-COMMAND [sub-command-specific-options] [sub-command-specific-arguments] without having to say "except if you use a sub-command-like global option, in which case SUB-COMMAND is not allowed". With this commit, we add support for 'version' while keeping --version, because while 'version' makes more sense for umbrella commands, a user may not know if runc is an umbrella command when they ask for the version. Existing umbrella commands are not particularly consistent: * git(1) supports both --version and 'version', --help and 'help'. * btrfs(8) supports both --version and 'version', --help and 'help'. * ip(1) supports -V / -Version and 'help'. * npm supports 'version' and 'help'. * pip supports '--version', --help and 'help'. Setting .Version to the empty string takes advantage of the {{if .Version}} conditional [2] to avoid --help showing: VERSION: 0.0.0 because we are no longer setting .Version. I floated a few options [4], and Mike Brown (the only one with a preference) was in favor of dropping the VERSION section [5] (which turned out to not need a AppHelpTemplate adjustment ;). The help tests ensure that attempting to remove "VERSION" from the help output does not change the output (i.e. that the output didn't contain "VERSION" to begin with). That protects us from subsequent urfave/cli changes breaking the empty-string .Version approach. I prefer "runC" to "runc", to match http://runc.io/ and some naming issues [6], but Michael prefers "runc" [7]. [1]: http://www.man7.org/linux/man-pages/man1/printf.1.html [2]: https://github.com/urfave/cli/blob/v1.18.1/README.md#customization-1 [3]: https://github.com/opencontainers/runc/pull/940#issuecomment-241837881 [4]: https://github.com/opencontainers/runc/pull/940#issuecomment-241847872 [5]: https://github.com/opencontainers/runc/pull/940#issuecomment-241889757 [6]: https://github.com/opencontainers/runc/issues/24 [7]: https://github.com/opencontainers/runc/pull/940#discussion_r85807103 Signed-off-by: W. Trevor King --- main.go | 22 ++++-------------- tests/integration/help.bats | 2 ++ tests/integration/version.bats | 12 ++++++++-- version.go | 42 ++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 version.go diff --git a/main.go b/main.go index 1cb8f4dbfa0..69f0116b381 100644 --- a/main.go +++ b/main.go @@ -4,21 +4,11 @@ import ( "fmt" "io" "os" - "strings" "github.com/Sirupsen/logrus" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/urfave/cli" ) -// version will be populated by the Makefile, read from -// VERSION file of the source code. -var version = "" - -// gitCommit will be the hash that the binary was built from -// and will be populated by the Makefile -var gitCommit = "" - const ( specConfig = "config.json" usage = `Open Container Initiative runtime @@ -50,16 +40,11 @@ func main() { app := cli.NewApp() app.Name = "runc" app.Usage = usage + app.Version = "" - var v []string - if version != "" { - v = append(v, version) - } - if gitCommit != "" { - v = append(v, fmt.Sprintf("commit: %s", gitCommit)) + cli.VersionPrinter = func(context *cli.Context) { + printVersion(context) } - v = append(v, fmt.Sprintf("spec: %s", specs.Version)) - app.Version = strings.Join(v, "\n") app.Flags = []cli.Flag{ cli.BoolFlag{ Name: "debug", @@ -108,6 +93,7 @@ func main() { startCommand, stateCommand, updateCommand, + versionCommand, } app.Before = func(context *cli.Context) error { if context.GlobalBool("debug") { diff --git a/tests/integration/help.bats b/tests/integration/help.bats index ca404f342af..397ace2cac0 100644 --- a/tests/integration/help.bats +++ b/tests/integration/help.bats @@ -7,11 +7,13 @@ load helpers [ "$status" -eq 0 ] [[ ${lines[0]} =~ NAME:+ ]] [[ ${lines[1]} =~ runc\ '-'\ Open\ Container\ Initiative\ runtime+ ]] + [ "${output}" = "${output/VERSION/}" ] runc --help [ "$status" -eq 0 ] [[ ${lines[0]} =~ NAME:+ ]] [[ ${lines[1]} =~ runc\ '-'\ Open\ Container\ Initiative\ runtime+ ]] + [ "${output}" = "${output/VERSION/}" ] } @test "runc command -h" { diff --git a/tests/integration/version.bats b/tests/integration/version.bats index ab77769f8e1..ac4ae7fad79 100644 --- a/tests/integration/version.bats +++ b/tests/integration/version.bats @@ -2,10 +2,18 @@ load helpers -@test "runc version" { +@test "runc --version" { runc -v [ "$status" -eq 0 ] - [[ ${lines[0]} =~ runc\ version\ [0-9]+\.[0-9]+\.[0-9]+ ]] + [[ ${lines[0]} =~ runc\ [0-9]+\.[0-9]+\.[0-9]+ ]] + [[ ${lines[1]} =~ commit:+ ]] + [[ ${lines[2]} =~ spec:\ [0-9]+\.[0-9]+\.[0-9]+ ]] +} + +@test "runc version" { + runc version + [ "$status" -eq 0 ] + [[ ${lines[0]} =~ runc\ [0-9]+\.[0-9]+\.[0-9]+ ]] [[ ${lines[1]} =~ commit:+ ]] [[ ${lines[2]} =~ spec:\ [0-9]+\.[0-9]+\.[0-9]+ ]] } diff --git a/version.go b/version.go new file mode 100644 index 00000000000..4933d11147a --- /dev/null +++ b/version.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/urfave/cli" +) + +// version will be populated by the Makefile, read from +// VERSION file of the source code. +var version = "" + +// gitCommit will be the hash that the binary was built from +// and will be populated by the Makefile +var gitCommit = "" + +var versionCommand = cli.Command{ + Name: "version", + Usage: "output the runtime version", + Description: `The version command outputs the runtime version.`, + Action: printVersion, +} + +func printVersion(context *cli.Context) (err error) { + if version == "" { + _, err = fmt.Print("runc unknown\n") + } else { + _, err = fmt.Printf("runc %s\n", version) + } + if err != nil { + return err + } + if gitCommit != "" { + _, err = fmt.Printf("commit: %s\n", gitCommit) + if err != nil { + return err + } + } + _, err = fmt.Printf("spec: %s\n", specs.Version) + return err +} From 76981272622839ca7811903d652a61355c07ad52 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 21 Mar 2017 16:46:11 -0700 Subject: [PATCH 2/2] *: Add man page and Bash completion for 'runc version' Signed-off-by: W. Trevor King --- contrib/completions/bash/runc | 1 + man/runc-version.8.md | 14 ++++++++++++++ man/runc.8.md | 1 + 3 files changed, 16 insertions(+) create mode 100644 man/runc-version.8.md diff --git a/contrib/completions/bash/runc b/contrib/completions/bash/runc index 0d6039df776..bd1d98e8090 100644 --- a/contrib/completions/bash/runc +++ b/contrib/completions/bash/runc @@ -760,6 +760,7 @@ _runc() { start state update + version help h ) diff --git a/man/runc-version.8.md b/man/runc-version.8.md new file mode 100644 index 00000000000..b7f1bdc183e --- /dev/null +++ b/man/runc-version.8.md @@ -0,0 +1,14 @@ +# NAME + runc version - output the runtime version + +# SYNOPSIS + runc version + +Write version information to stdout and exit. + +# DESCRIPTION + The version command writes version information for runc and the +supported spec release. This information is also exposed through +`runc --version`, and callers can use whichever is more convenient for +them. + diff --git a/man/runc.8.md b/man/runc.8.md index b5a8c54f671..67557ab45f3 100644 --- a/man/runc.8.md +++ b/man/runc.8.md @@ -44,6 +44,7 @@ value for "bundle" is the current directory. start executes the user defined process in a created container state output the state of a container update update container resource constraints + version output the runtime version help, h Shows a list of commands or help for one command # GLOBAL OPTIONS