Merge pull request #9085 from miminar/refactor-help

Display help output on stdout #8980
This commit is contained in:
Tibor Vass 2015-01-06 12:05:49 -05:00
commit 60027853aa
44 changed files with 422 additions and 343 deletions

View file

@ -75,24 +75,31 @@ func (cli *DockerCli) Cmd(args ...string) error {
if len(args) > 0 {
method, exists := cli.getMethod(args[0])
if !exists {
fmt.Println("Error: Command not found:", args[0])
return cli.CmdHelp()
fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
os.Exit(1)
}
return method(args[1:]...)
}
return cli.CmdHelp()
}
func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet {
flags := flag.NewFlagSet(name, flag.ContinueOnError)
func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bool) *flag.FlagSet {
var errorHandling flag.ErrorHandling
if exitOnError {
errorHandling = flag.ExitOnError
} else {
errorHandling = flag.ContinueOnError
}
flags := flag.NewFlagSet(name, errorHandling)
flags.Usage = func() {
options := ""
if flags.FlagCountUndeprecated() > 0 {
options = "[OPTIONS] "
}
fmt.Fprintf(cli.err, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
fmt.Fprintf(cli.out, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
flags.SetOutput(cli.out)
flags.PrintDefaults()
os.Exit(2)
os.Exit(0)
}
return flags
}

View file

@ -63,7 +63,8 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
if len(args) > 0 {
method, exists := cli.getMethod(args[0])
if !exists {
fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0])
fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
os.Exit(1)
} else {
method("--help")
return nil
@ -76,20 +77,16 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
}
func (cli *DockerCli) CmdBuild(args ...string) error {
cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH")
cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, true)
var (
context archive.Archive
@ -247,17 +244,17 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
// 'docker login': login / register a user to registry service.
func (cli *DockerCli) CmdLogin(args ...string) error {
cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
cmd.Require(flag.Max, 1)
var username, password, email string
cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
err := cmd.Parse(args)
if err != nil {
return nil
}
utils.ParseFlags(cmd, args, true)
serverAddress := registry.IndexServerAddress()
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
@ -363,11 +360,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
// log out from a Docker registry
func (cli *DockerCli) CmdLogout(args ...string) error {
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
cmd.Require(flag.Max, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
utils.ParseFlags(cmd, args, false)
serverAddress := registry.IndexServerAddress()
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
@ -389,14 +385,11 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
// 'docker wait': block until a container stops
func (cli *DockerCli) CmdWait(args ...string) error {
cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
var encounteredError error
for _, name := range cmd.Args() {
status, err := waitForExit(cli, name)
@ -412,15 +405,11 @@ func (cli *DockerCli) CmdWait(args ...string) error {
// 'docker version': show version information
func (cli *DockerCli) CmdVersion(args ...string) error {
cmd := cli.Subcmd("version", "", "Show the Docker version information.")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
cmd.Require(flag.Exact, 0)
utils.ParseFlags(cmd, args, false)
if cmd.NArg() > 0 {
cmd.Usage()
return nil
}
if dockerversion.VERSION != "" {
fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
}
@ -458,14 +447,9 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
// 'docker info': display system-wide information.
func (cli *DockerCli) CmdInfo(args ...string) error {
cmd := cli.Subcmd("info", "", "Display system-wide information")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() > 0 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("info", "", "Display system-wide information", true)
cmd.Require(flag.Exact, 0)
utils.ParseFlags(cmd, args, false)
body, _, err := readBody(cli.call("GET", "/info", nil, false))
if err != nil {
@ -577,15 +561,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
}
func (cli *DockerCli) CmdStop(args ...string) error {
cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
v := url.Values{}
v.Set("t", strconv.Itoa(*nSeconds))
@ -604,15 +584,11 @@ func (cli *DockerCli) CmdStop(args ...string) error {
}
func (cli *DockerCli) CmdRestart(args ...string) error {
cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
v := url.Values{}
v.Set("t", strconv.Itoa(*nSeconds))
@ -661,18 +637,13 @@ func (cli *DockerCli) CmdStart(args ...string) error {
cErr chan error
tty bool
cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true)
attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
hijacked := make(chan io.Closer)
@ -774,15 +745,9 @@ func (cli *DockerCli) CmdStart(args ...string) error {
}
func (cli *DockerCli) CmdUnpause(args ...string) error {
cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true)
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, false)
var encounteredError error
for _, name := range cmd.Args() {
@ -797,15 +762,9 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
}
func (cli *DockerCli) CmdPause(args ...string) error {
cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true)
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, false)
var encounteredError error
for _, name := range cmd.Args() {
@ -820,15 +779,11 @@ func (cli *DockerCli) CmdPause(args ...string) error {
}
func (cli *DockerCli) CmdInspect(args ...string) error {
cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
var tmpl *template.Template
if *tmplStr != "" {
@ -900,14 +855,11 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
}
func (cli *DockerCli) CmdTop(args ...string) error {
cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() == 0 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
val := url.Values{}
if cmd.NArg() > 1 {
val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
@ -935,14 +887,9 @@ func (cli *DockerCli) CmdTop(args ...string) error {
}
func (cli *DockerCli) CmdPort(args ...string) error {
cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT", true)
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
if err != nil {
@ -991,17 +938,13 @@ func (cli *DockerCli) CmdPort(args ...string) error {
// 'docker rmi IMAGE' removes all images with the name IMAGE
func (cli *DockerCli) CmdRmi(args ...string) error {
var (
cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
force = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
v := url.Values{}
if *force {
@ -1037,17 +980,12 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
}
func (cli *DockerCli) CmdHistory(args ...string) error {
cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
cmd.Require(flag.Exact, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
if err != nil {
@ -1094,18 +1032,13 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
}
func (cli *DockerCli) CmdRm(args ...string) error {
cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers")
cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
cmd.Require(flag.Min, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
val := url.Values{}
if *v {
@ -1134,16 +1067,11 @@ func (cli *DockerCli) CmdRm(args ...string) error {
// 'docker kill NAME' kills a running container
func (cli *DockerCli) CmdKill(args ...string) error {
cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
cmd.Require(flag.Min, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
var encounteredError error
for _, name := range cmd.Args() {
@ -1158,15 +1086,10 @@ func (cli *DockerCli) CmdKill(args ...string) error {
}
func (cli *DockerCli) CmdImport(args ...string) error {
cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.")
cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.", true)
cmd.Require(flag.Min, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
var (
v = url.Values{}
@ -1200,16 +1123,12 @@ func (cli *DockerCli) CmdImport(args ...string) error {
}
func (cli *DockerCli) CmdPush(args ...string) error {
cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
if err := cmd.Parse(args); err != nil {
return nil
}
name := cmd.Arg(0)
cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
cmd.Require(flag.Exact, 1)
if name == "" {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
name := cmd.Arg(0)
cli.LoadConfigFile()
@ -1265,16 +1184,12 @@ func (cli *DockerCli) CmdPush(args ...string) error {
}
func (cli *DockerCli) CmdPull(args ...string) error {
cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true)
allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, true)
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
var (
v = url.Values{}
remote = cmd.Arg(0)
@ -1331,7 +1246,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
}
func (cli *DockerCli) CmdImages(args ...string) error {
cmd := cli.Subcmd("images", "[REPOSITORY]", "List images")
cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
@ -1341,14 +1256,9 @@ func (cli *DockerCli) CmdImages(args ...string) error {
flFilter := opts.NewListOpts(nil)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
cmd.Require(flag.Max, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() > 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
// Consolidate all filter flags, and sanity check them early.
// They'll get process in the daemon/server.
@ -1574,7 +1484,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
psFilterArgs = filters.Args{}
v = url.Values{}
cmd = cli.Subcmd("ps", "", "List containers")
cmd = cli.Subcmd("ps", "", "List containers", true)
quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
@ -1585,13 +1495,11 @@ func (cli *DockerCli) CmdPs(args ...string) error {
last = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
flFilter = opts.NewListOpts(nil)
)
cmd.Require(flag.Exact, 0)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
if err := cmd.Parse(args); err != nil {
return nil
}
utils.ParseFlags(cmd, args, true)
if *last == -1 && *nLatest {
*last = 1
}
@ -1726,26 +1634,21 @@ func (cli *DockerCli) CmdPs(args ...string) error {
}
func (cli *DockerCli) CmdCommit(args ...string) error {
cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd.Require(flag.Max, 2)
cmd.Require(flag.Min, 1)
utils.ParseFlags(cmd, args, true)
var (
name = cmd.Arg(0)
repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
)
if name == "" || len(cmd.Args()) > 2 {
cmd.Usage()
return nil
}
//Check if the given image name can be resolved
if repository != "" {
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
@ -1787,21 +1690,15 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
}
func (cli *DockerCli) CmdEvents(args ...string) error {
cmd := cli.Subcmd("events", "", "Get real time events from the server")
cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
flFilter := opts.NewListOpts(nil)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
cmd.Require(flag.Exact, 0)
if err := cmd.Parse(args); err != nil {
return nil
}
utils.ParseFlags(cmd, args, true)
if cmd.NArg() != 0 {
cmd.Usage()
return nil
}
var (
v = url.Values{}
loc = time.FixedZone(time.Now().Zone())
@ -1848,15 +1745,10 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
}
func (cli *DockerCli) CmdExport(args ...string) error {
cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
cmd.Require(flag.Exact, 1)
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
return err
@ -1865,14 +1757,10 @@ func (cli *DockerCli) CmdExport(args ...string) error {
}
func (cli *DockerCli) CmdDiff(args ...string) error {
cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, true)
body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
@ -1901,20 +1789,15 @@ func (cli *DockerCli) CmdDiff(args ...string) error {
func (cli *DockerCli) CmdLogs(args ...string) error {
var (
cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
)
cmd.Require(flag.Exact, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
utils.ParseFlags(cmd, args, true)
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
name := cmd.Arg(0)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@ -1945,19 +1828,13 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
func (cli *DockerCli) CmdAttach(args ...string) error {
var (
cmd = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
cmd = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
)
cmd.Require(flag.Exact, 1)
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
name := cmd.Arg(0)
stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@ -2022,18 +1899,14 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
}
func (cli *DockerCli) CmdSearch(args ...string) error {
cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images")
cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 1 {
cmd.Usage()
return nil
}
cmd.Require(flag.Exact, 1)
utils.ParseFlags(cmd, args, true)
v := url.Values{}
v.Set("term", cmd.Arg(0))
@ -2077,15 +1950,11 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
type ports []int
func (cli *DockerCli) CmdTag(args ...string) error {
cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 2 {
cmd.Usage()
return nil
}
cmd.Require(flag.Exact, 2)
utils.ParseFlags(cmd, args, true)
var (
repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
@ -2158,6 +2027,7 @@ func newCIDFile(path string) (*cidFile, error) {
if _, err := os.Stat(path); err == nil {
return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
}
f, err := os.Create(path)
if err != nil {
return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
@ -2245,7 +2115,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
}
func (cli *DockerCli) CmdCreate(args ...string) error {
cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container")
cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
// These are flags not stored in Config/HostConfig
var (
@ -2254,7 +2124,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
if err != nil {
return err
return &utils.StatusError{StatusCode: 1}
}
if config.Image == "" {
cmd.Usage()
@ -2273,7 +2143,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
func (cli *DockerCli) CmdRun(args ...string) error {
// FIXME: just use runconfig.Parse already
cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
// These are flags not stored in Config/HostConfig
var (
@ -2289,8 +2159,9 @@ func (cli *DockerCli) CmdRun(args ...string) error {
)
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
// just in case the Parse does not exit
if err != nil {
return err
return &utils.StatusError{StatusCode: 1}
}
if config.Image == "" {
cmd.Usage()
@ -2473,15 +2344,10 @@ func (cli *DockerCli) CmdRun(args ...string) error {
}
func (cli *DockerCli) CmdCp(args ...string) error {
cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true)
cmd.Require(flag.Exact, 2)
if cmd.NArg() != 2 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
var copyData engine.Env
info := strings.Split(cmd.Arg(0), ":")
@ -2513,17 +2379,11 @@ func (cli *DockerCli) CmdCp(args ...string) error {
}
func (cli *DockerCli) CmdSave(args ...string) error {
cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
cmd.Require(flag.Min, 1)
if err := cmd.Parse(args); err != nil {
return err
}
if cmd.NArg() < 1 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
var (
output io.Writer = cli.out
@ -2556,17 +2416,11 @@ func (cli *DockerCli) CmdSave(args ...string) error {
}
func (cli *DockerCli) CmdLoad(args ...string) error {
cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
cmd.Require(flag.Exact, 0)
if err := cmd.Parse(args); err != nil {
return err
}
if cmd.NArg() != 0 {
cmd.Usage()
return nil
}
utils.ParseFlags(cmd, args, true)
var (
input io.Reader = cli.in
@ -2585,16 +2439,12 @@ func (cli *DockerCli) CmdLoad(args ...string) error {
}
func (cli *DockerCli) CmdExec(args ...string) error {
cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container")
cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
execConfig, err := runconfig.ParseExec(cmd, args)
if err != nil {
cmd.Usage()
return err
}
if execConfig.Container == "" {
cmd.Usage()
return nil
// just in case the ParseExec does not exit
if execConfig.Container == "" || err != nil {
return &utils.StatusError{StatusCode: 1}
}
stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)

View file

@ -36,6 +36,7 @@ var (
flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify flag")
flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
flTlsVerify = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs
@ -57,8 +58,9 @@ func init() {
opts.HostListVar(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.")
flag.Usage = func() {
fmt.Fprint(os.Stderr, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
flag.CommandLine.SetOutput(os.Stdout)
flag.PrintDefaults()
help := "\nCommands:\n"
@ -105,6 +107,6 @@ func init() {
help += fmt.Sprintf(" %-10.10s%s\n", command[0], command[1])
}
help += "\nRun 'docker COMMAND --help' for more information on a command."
fmt.Fprintf(os.Stderr, "%s\n", help)
fmt.Fprintf(os.Stdout, "%s\n", help)
}
}

View file

@ -6,6 +6,7 @@ docker-attach - Attach to a running container
# SYNOPSIS
**docker attach**
[**--help**]/
[**--no-stdin**[=*false*]]
[**--sig-proxy**[=*true*]]
CONTAINER
@ -24,6 +25,9 @@ It is forbidden to redirect the standard input of a docker attach command while
attaching to a tty-enabled container (i.e.: launched with -t`).
# OPTIONS
**--help**
Print usage statement
**--no-stdin**=*true*|*false*
Do not attach STDIN. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-build - Build a new image from the source code at PATH
# SYNOPSIS
**docker build**
[**--help**]
[**--force-rm**[=*false*]]
[**--no-cache**[=*false*]]
[**-q**|**--quiet**[=*false*]]
@ -36,6 +37,9 @@ as context.
**--no-cache**=*true*|*false*
Do not use cache when building the image. The default is *false*.
**--help**
Print usage statement
**-q**, **--quiet**=*true*|*false*
Suppress the verbose output generated by the containers. The default is *false*.

View file

@ -7,6 +7,7 @@ docker-commit - Create a new image from a container's changes
# SYNOPSIS
**docker commit**
[**-a**|**--author**[=*AUTHOR*]]
[**--help**]
[**-m**|**--message**[=*MESSAGE*]]
[**-p**|**--pause**[=*true*]]
CONTAINER [REPOSITORY[:TAG]]
@ -18,6 +19,9 @@ Using an existing container's name or ID you can create a new image.
**-a**, **--author**=""
Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
**--help**
Print usage statement
**-m**, **--message**=""
Commit message

View file

@ -6,6 +6,7 @@ docker-cp - Copy files/folders from the PATH to the HOSTPATH
# SYNOPSIS
**docker cp**
[**--help**]
CONTAINER:PATH HOSTPATH
# DESCRIPTION
@ -14,7 +15,8 @@ path. Paths are relative to the root of the filesystem. Files
can be copied from a running or stopped container.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES
An important shell script file, created in a bash shell, is copied from

View file

@ -21,6 +21,7 @@ docker-create - Create a new container
[**--env-file**[=*[]*]]
[**--expose**[=*[]*]]
[**-h**|**--hostname**[=*HOSTNAME*]]
[**--help**]
[**-i**|**--interactive**[=*false*]]
[**--ipc**[=*IPC*]]
[**--link**[=*[]*]]
@ -87,6 +88,9 @@ IMAGE [COMMAND] [ARG...]
**-h**, **--hostname**=""
Container host name
**--help**
Print usage statement
**-i**, **--interactive**=*true*|*false*
Keep STDIN open even if not attached. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-diff - Inspect changes on a container's filesystem
# SYNOPSIS
**docker diff**
[**--help**]
CONTAINER
# DESCRIPTION
@ -14,7 +15,8 @@ shortened container ID or the container name set using
**docker run --name** option.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES
Inspect the changes to on a nginx container:

View file

@ -6,6 +6,7 @@ docker-events - Get real time events from the server
# SYNOPSIS
**docker events**
[**--help**]
[**--since**[=*SINCE*]]
[**--until**[=*UNTIL*]]
@ -23,6 +24,9 @@ and Docker images will report:
untag, delete
# OPTIONS
**--help**
Print usage statement
**--since**=""
Show all events created since timestamp

View file

@ -7,6 +7,7 @@ docker-exec - Run a command in a running container
# SYNOPSIS
**docker exec**
[**-d**|**--detach**[=*false*]]
[**--help**]
[**-i**|**--interactive**[=*false*]]
[**-t**|**--tty**[=*false*]]
CONTAINER COMMAND [ARG...]
@ -25,6 +26,9 @@ container is unpaused, and then run
**-d**, **--detach**=*true*|*false*
Detached mode: run command in the background. The default is *false*.
**--help**
Print usage statement
**-i**, **--interactive**=*true*|*false*
Keep STDIN open even if not attached. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-export - Export the contents of a filesystem as a tar archive to STDOUT
# SYNOPSIS
**docker export**
[**--help**]
CONTAINER
# DESCRIPTION
@ -14,7 +15,8 @@ container ID or container name. The output is exported to STDOUT and can be
redirected to a tar file.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES
Export the contents of the container called angry_bell to a tar file

View file

@ -6,6 +6,7 @@ docker-history - Show the history of an image
# SYNOPSIS
**docker history**
[**--help**]
[**--no-trunc**[=*false*]]
[**-q**|**--quiet**[=*false*]]
IMAGE
@ -15,6 +16,9 @@ IMAGE
Show the history of when and how an image was created.
# OPTIONS
**--help**
Print usage statement
**--no-trunc**=*true*|*false*
Don't truncate output. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-images - List images
# SYNOPSIS
**docker images**
[**--help**]
[**-a**|**--all**[=*false*]]
[**-f**|**--filter**[=*[]*]]
[**--no-trunc**[=*false*]]
@ -35,6 +36,9 @@ versions.
**-f**, **--filter**=[]
Provide filter values (i.e. 'dangling=true')
**--help**
Print usage statement
**--no-trunc**=*true*|*false*
Don't truncate output. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-import - Create an empty filesystem image and import the contents of the
# SYNOPSIS
**docker import**
[**--help**]
URL|- [REPOSITORY[:TAG]]
# DESCRIPTION
@ -13,7 +14,8 @@ Create a new filesystem image from the contents of a tarball (`.tar`,
`.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES

View file

@ -6,6 +6,7 @@ docker-info - Display system-wide information
# SYNOPSIS
**docker info**
[**--help**]
# DESCRIPTION
@ -20,7 +21,8 @@ allocates a certain amount of data space and meta data space from the space
available on the volume where `/var/lib/docker` is mounted.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES

View file

@ -6,6 +6,7 @@ docker-inspect - Return low-level information on a container or image
# SYNOPSIS
**docker inspect**
[**--help**]
[**-f**|**--format**[=*FORMAT*]]
CONTAINER|IMAGE [CONTAINER|IMAGE...]
@ -17,6 +18,9 @@ array. If a format is specified, the given template will be executed for
each result.
# OPTIONS
**--help**
Print usage statement
**-f**, **--format**=""
Format the output using the given go template.

View file

@ -6,6 +6,7 @@ docker-kill - Kill a running container using SIGKILL or a specified signal
# SYNOPSIS
**docker kill**
[**--help**]
[**-s**|**--signal**[=*"KILL"*]]
CONTAINER [CONTAINER...]
@ -15,6 +16,9 @@ The main process inside each container specified will be sent SIGKILL,
or any signal specified with option --signal.
# OPTIONS
**--help**
Print usage statement
**-s**, **--signal**="KILL"
Signal to send to the container

View file

@ -6,6 +6,7 @@ docker-load - Load an image from a tar archive on STDIN
# SYNOPSIS
**docker load**
[**--help**]
[**-i**|**--input**[=*INPUT*]]
@ -15,6 +16,9 @@ Loads a tarred repository from a file or the standard input stream.
Restores both images and tags.
# OPTIONS
**--help**
Print usage statement
**-i**, **--input**=""
Read from a tar archive file, instead of STDIN

View file

@ -7,6 +7,7 @@ docker-login - Register or log in to a Docker registry server, if no server is s
# SYNOPSIS
**docker login**
[**-e**|**--email**[=*EMAIL*]]
[**--help**]
[**-p**|**--password**[=*PASSWORD*]]
[**-u**|**--username**[=*USERNAME*]]
[SERVER]
@ -20,6 +21,9 @@ login to a private registry you can specify this by adding the server name.
**-e**, **--email**=""
Email
**--help**
Print usage statement
**-p**, **--password**=""
Password

View file

@ -7,6 +7,7 @@ docker-logs - Fetch the logs of a container
# SYNOPSIS
**docker logs**
[**-f**|**--follow**[=*false*]]
[**--help**]
[**-t**|**--timestamps**[=*false*]]
[**--tail**[=*"all"*]]
CONTAINER
@ -22,6 +23,9 @@ The **docker logs --follow** command combines commands **docker logs** and
then continue streaming new output from the containers stdout and stderr.
# OPTIONS
**--help**
Print usage statement
**-f**, **--follow**=*true*|*false*
Follow log output. The default is *false*.

View file

@ -6,13 +6,15 @@ docker-port - List port mappings for the CONTAINER, or lookup the public-facing
# SYNOPSIS
**docker port**
[**--help**]
CONTAINER [PRIVATE_PORT[/PROTO]]
# DESCRIPTION
List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES
You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or

View file

@ -8,6 +8,7 @@ docker-ps - List containers
**docker ps**
[**-a**|**--all**[=*false*]]
[**--before**[=*BEFORE*]]
[**--help**]
[**-f**|**--filter**[=*[]*]]
[**-l**|**--latest**[=*false*]]
[**-n**[=*-1*]]
@ -29,6 +30,9 @@ the running containers.
**--before**=""
Show only container created before Id or Name, include non-running ones.
**--help**
Print usage statement
**-f**, **--filter**=[]
Provide filter values. Valid filters:
exited=<int> - containers with exit code of <int>

View file

@ -7,6 +7,7 @@ docker-pull - Pull an image or a repository from the registry
# SYNOPSIS
**docker pull**
[**-a**|**--all-tags**[=*false*]]
[**--help**]
NAME[:TAG]
# DESCRIPTION
@ -19,8 +20,10 @@ It is also possible to specify a non-default registry to pull from.
# OPTIONS
**-a**, **--all-tags**=*true*|*false*
Download all tagged images in the repository. The default is *false*.
**--help**
Print usage statement
# EXAMPLES
# EXAMPLE
# Pull a repository with multiple images
# Note that if the image is previously downloaded then the status would be

View file

@ -6,6 +6,7 @@ docker-push - Push an image or a repository to the registry
# SYNOPSIS
**docker push**
[**--help**]
NAME[:TAG]
# DESCRIPTION
@ -15,7 +16,8 @@ image can be pushed to another, perhaps private, registry as demonstrated in
the example below.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES

View file

@ -6,6 +6,7 @@ docker-restart - Restart a running container
# SYNOPSIS
**docker restart**
[**--help**]
[**-t**|**--time**[=*10*]]
CONTAINER [CONTAINER...]
@ -13,6 +14,9 @@ CONTAINER [CONTAINER...]
Restart each container listed.
# OPTIONS
**--help**
Print usage statement
**-t**, **--time**=10
Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.

View file

@ -19,6 +19,9 @@ remove a running container unless you use the \fB-f\fR option. To see all
containers on a host use the **docker ps -a** command.
# OPTIONS
**--help**
Print usage statement
**-f**, **--force**=*true*|*false*
Force the removal of a running container (uses SIGKILL). The default is *false*.

View file

@ -7,6 +7,7 @@ docker-rmi - Remove one or more images
# SYNOPSIS
**docker rmi**
[**-f**|**--force**[=*false*]]
[**--help**]
[**--no-prune**[=*false*]]
IMAGE [IMAGE...]
@ -21,6 +22,9 @@ use the **docker images** command.
**-f**, **--force**=*true*|*false*
Force removal of the image. The default is *false*.
**--help**
Print usage statement
**--no-prune**=*true*|*false*
Do not delete untagged parents. The default is *false*.

View file

@ -22,6 +22,7 @@ docker-run - Run a command in a new container
[**--env-file**[=*[]*]]
[**--expose**[=*[]*]]
[**-h**|**--hostname**[=*HOSTNAME*]]
[**--help**]
[**-i**|**--interactive**[=*false*]]
[**--ipc**[=*IPC*]]
[**--link**[=*[]*]]
@ -153,6 +154,9 @@ ENTRYPOINT.
Sets the container host name that is available inside the container.
**--help**
Print usage statement
**-i**, **--interactive**=*true*|*false*
Keep STDIN open even if not attached. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-save - Save an image(s) to a tar archive (streamed to STDOUT by default)
# SYNOPSIS
**docker save**
[**--help**]
[**-o**|**--output**[=*OUTPUT*]]
IMAGE [IMAGE...]
@ -16,6 +17,9 @@ parent layers, and all tags + versions, or specified repo:tag.
Stream to a file instead of STDOUT by using **-o**.
# OPTIONS
**--help**
Print usage statement
**-o**, **--output**=""
Write to a file, instead of STDOUT

View file

@ -7,6 +7,7 @@ docker-search - Search the Docker Hub for images
# SYNOPSIS
**docker search**
[**--automated**[=*false*]]
[**--help**]
[**--no-trunc**[=*false*]]
[**-s**|**--stars**[=*0*]]
TERM
@ -22,6 +23,9 @@ is automated.
**--automated**=*true*|*false*
Only show automated builds. The default is *false*.
**--help**
Print usage statement
**--no-trunc**=*true*|*false*
Don't truncate output. The default is *false*.

View file

@ -7,6 +7,7 @@ docker-start - Restart a stopped container
# SYNOPSIS
**docker start**
[**-a**|**--attach**[=*false*]]
[**--help**]
[**-i**|**--interactive**[=*false*]]
CONTAINER [CONTAINER...]
@ -18,6 +19,9 @@ Start a stopped container.
**-a**, **--attach**=*true*|*false*
Attach container's STDOUT and STDERR and forward all signals to the process. The default is *false*.
**--help**
Print usage statement
**-i**, **--interactive**=*true*|*false*
Attach container's STDIN. The default is *false*.

View file

@ -6,6 +6,7 @@ docker-stop - Stop a running container by sending SIGTERM and then SIGKILL after
# SYNOPSIS
**docker stop**
[**--help**]
[**-t**|**--time**[=*10*]]
CONTAINER [CONTAINER...]
@ -14,6 +15,9 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
grace period)
# OPTIONS
**--help**
Print usage statement
**-t**, **--time**=10
Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.

View file

@ -7,6 +7,7 @@ docker-tag - Tag an image into a repository
# SYNOPSIS
**docker tag**
[**-f**|**--force**[=*false*]]
[**--help**]
IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
# DESCRIPTION

View file

@ -6,6 +6,7 @@ docker-top - Display the running processes of a container
# SYNOPSIS
**docker top**
[**--help**]
CONTAINER [ps OPTIONS]
# DESCRIPTION
@ -14,7 +15,8 @@ Look up the running process of the container. ps-OPTION can be any of the
options you would pass to a Linux ps command.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES

View file

@ -6,6 +6,7 @@ docker-wait - Block until a container stops, then print its exit code.
# SYNOPSIS
**docker wait**
[**--help**]
CONTAINER [CONTAINER...]
# DESCRIPTION
@ -13,7 +14,8 @@ CONTAINER [CONTAINER...]
Block until a container stops, then print its exit code.
# OPTIONS
There are no available options.
**--help**
Print usage statement
# EXAMPLES

View file

@ -26,6 +26,9 @@ To see the man page for a command run **man docker <command>**.
**-D**=*true*|*false*
Enable debug mode. Default is false.
**--help**
Print usage statement
**-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host:port] to bind or
unix://[/path/to/socket] to use.
The socket(s) to bind to in daemon mode specified using one or more

View file

@ -15,6 +15,19 @@ or execute `docker help`:
...
## Help
To list the help on any command just execute the command, followed by the `--help` option.
$ sudo docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
-a, --attach=[] Attach to STDIN, STDOUT or STDERR.
-c, --cpu-shares=0 CPU shares (relative weight)
...
## Option types
Single character commandline options can be combined, so rather than

View file

@ -362,10 +362,10 @@ func TestExecParseError(t *testing.T) {
// Test normal (non-detached) case first
cmd := exec.Command(dockerBinary, "exec", "top")
if out, _, err := runCommandWithOutput(cmd); err == nil || !strings.Contains(out, "Usage:") {
t.Fatalf("Should have thrown error & given usage: %s", out)
if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 {
t.Fatalf("Should have thrown error & point to help: %s", stderr)
}
logDone("exec - error on parseExec should return usage")
logDone("exec - error on parseExec should point to help")
}
func TestExecStopNotHanging(t *testing.T) {

View file

@ -284,13 +284,14 @@ type FlagSet struct {
// a custom error handler.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use out() accessor
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use Out() accessor
nArgRequirements []nArgRequirement
}
// A Flag represents the state of a flag.
@ -348,7 +349,13 @@ func sortFlags(flags map[string]*Flag) []*Flag {
return result
}
func (f *FlagSet) out() io.Writer {
// Name returns the name of the FlagSet.
func (f *FlagSet) Name() string {
return f.name
}
// Out returns the destination for usage and error messages.
func (f *FlagSet) Out() io.Writer {
if f.output == nil {
return os.Stderr
}
@ -410,6 +417,62 @@ func IsSet(name string) bool {
return CommandLine.IsSet(name)
}
type nArgRequirementType int
// Indicator used to pass to BadArgs function
const (
Exact nArgRequirementType = iota
Max
Min
)
type nArgRequirement struct {
Type nArgRequirementType
N int
}
// Require adds a requirement about the number of arguments for the FlagSet.
// The first parameter can be Exact, Max, or Min to respectively specify the exact,
// the maximum, or the minimal number of arguments required.
// The actual check is done in FlagSet.CheckArgs().
func (f *FlagSet) Require(nArgRequirementType nArgRequirementType, nArg int) {
f.nArgRequirements = append(f.nArgRequirements, nArgRequirement{nArgRequirementType, nArg})
}
// CheckArgs uses the requirements set by FlagSet.Require() to validate
// the number of arguments. If the requirements are not met,
// an error message string is returned.
func (f *FlagSet) CheckArgs() (message string) {
for _, req := range f.nArgRequirements {
var arguments string
if req.N == 1 {
arguments = "1 argument"
} else {
arguments = fmt.Sprintf("%d arguments", req.N)
}
str := func(kind string) string {
return fmt.Sprintf("%q requires %s%s", f.name, kind, arguments)
}
switch req.Type {
case Exact:
if f.NArg() != req.N {
return str("")
}
case Max:
if f.NArg() > req.N {
return str("a maximum of ")
}
case Min:
if f.NArg() < req.N {
return str("a minimum of ")
}
}
}
return ""
}
// Set sets the value of the named flag.
func (f *FlagSet) Set(name, value string) error {
flag, ok := f.formal[name]
@ -435,7 +498,7 @@ func Set(name, value string) error {
// PrintDefaults prints, to standard error unless configured
// otherwise, the default values of all defined flags in the set.
func (f *FlagSet) PrintDefaults() {
writer := tabwriter.NewWriter(f.out(), 20, 1, 3, ' ', 0)
writer := tabwriter.NewWriter(f.Out(), 20, 1, 3, ' ', 0)
f.VisitAll(func(flag *Flag) {
format := " -%s=%s"
if _, ok := flag.Value.(*stringValue); ok {
@ -469,9 +532,9 @@ func PrintDefaults() {
// defaultUsage is the default function to print a usage message.
func defaultUsage(f *FlagSet) {
if f.name == "" {
fmt.Fprintf(f.out(), "Usage:\n")
fmt.Fprintf(f.Out(), "Usage:\n")
} else {
fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
fmt.Fprintf(f.Out(), "Usage of %s:\n", f.name)
}
f.PrintDefaults()
}
@ -483,7 +546,7 @@ func defaultUsage(f *FlagSet) {
// Usage prints to standard error a usage message documenting all defined command-line flags.
// The function is a variable that may be changed to point to a custom function.
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0])
PrintDefaults()
}
@ -764,7 +827,7 @@ func (f *FlagSet) Var(value Value, names []string, usage string) {
} else {
msg = fmt.Sprintf("%s flag redefined: %s", f.name, name)
}
fmt.Fprintln(f.out(), msg)
fmt.Fprintln(f.Out(), msg)
panic(msg) // Happens only if flags are declared with identical names
}
if f.formal == nil {
@ -788,8 +851,12 @@ func Var(value Value, names []string, usage string) {
// returns the error.
func (f *FlagSet) failf(format string, a ...interface{}) error {
err := fmt.Errorf(format, a...)
fmt.Fprintln(f.out(), err)
f.usage()
fmt.Fprintln(f.Out(), err)
if os.Args[0] == f.name {
fmt.Fprintf(f.Out(), "See '%s --help'.\n", os.Args[0])
} else {
fmt.Fprintf(f.Out(), "See '%s %s --help'.\n", os.Args[0], f.name)
}
return err
}
@ -915,9 +982,9 @@ func (f *FlagSet) parseOne() (bool, string, error) {
}
}
if replacement != "" {
fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement)
fmt.Fprintf(f.Out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement)
} else {
fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
fmt.Fprintf(f.Out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
}
}
}

View file

@ -151,17 +151,6 @@ func TestGet(t *testing.T) {
VisitAll(visitor)
}
func TestUsage(t *testing.T) {
called := false
ResetForTesting(func() { called = true })
if CommandLine.Parse([]string{"-x"}) == nil {
t.Error("parse did not fail for unknown flag")
}
if !called {
t.Error("did not call Usage for unknown flag")
}
}
func testParse(f *FlagSet, t *testing.T) {
if f.Parsed() {
t.Error("f.Parse() = true before Parse")

View file

@ -5,6 +5,7 @@ import (
"github.com/docker/docker/engine"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/utils"
)
type ExecConfig struct {
@ -48,14 +49,12 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
execCmd []string
container string
)
if err := cmd.Parse(args); err != nil {
cmd.Require(flag.Min, 2)
if err := utils.ParseFlags(cmd, args, true); err != nil {
return nil, err
}
parsedArgs := cmd.Args()
if len(parsedArgs) < 2 {
return nil, fmt.Errorf("not enough arguments to create exec command")
}
container = cmd.Arg(0)
parsedArgs := cmd.Args()
execCmd = parsedArgs[1:]
execConfig := &ExecConfig{

View file

@ -83,7 +83,9 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
if err := cmd.Parse(args); err != nil {
cmd.Require(flag.Min, 1)
if err := utils.ParseFlags(cmd, args, true); err != nil {
return nil, nil, cmd, err
}
@ -156,11 +158,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
parsedArgs = cmd.Args()
runCmd []string
entrypoint []string
image string
image = cmd.Arg(0)
)
if len(parsedArgs) >= 1 {
image = cmd.Arg(0)
}
if len(parsedArgs) > 1 {
runCmd = parsedArgs[1:]
}

41
utils/flags.go Normal file
View file

@ -0,0 +1,41 @@
package utils
import (
"fmt"
"os"
flag "github.com/docker/docker/pkg/mflag"
)
// ParseFlags is a utility function that adds a help flag if withHelp is true,
// calls cmd.Parse(args) and prints a relevant error message if there are
// incorrect number of arguments. It returns error only if error handling is
// set to ContinueOnError and parsing fails. If error handling is set to
// ExitOnError, it's safe to ignore the return value.
// TODO: move this to a better package than utils
func ParseFlags(cmd *flag.FlagSet, args []string, withHelp bool) error {
var help *bool
if withHelp {
help = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
}
if err := cmd.Parse(args); err != nil {
return err
}
if help != nil && *help {
cmd.Usage()
// just in case Usage does not exit
os.Exit(0)
}
if str := cmd.CheckArgs(); str != "" {
if withHelp {
if os.Args[0] == cmd.Name() {
str += ". See '" + os.Args[0] + " --help'"
} else {
str += ". See '" + os.Args[0] + " " + cmd.Name() + " --help'"
}
}
fmt.Fprintf(cmd.Out(), "docker: %s.\n", str)
os.Exit(1)
}
return nil
}