mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
update commands.go
update docker.go move to pkg update docs update name and copyright change --sinceId to --since-id, update completion and docs Docker-DCO-1.1-Signed-off-by: Victor Vieux <victor@docker.com> (github: vieux)
This commit is contained in:
parent
ebaa92b208
commit
e71dbf4ee5
14 changed files with 1558 additions and 206 deletions
136
commands.go
136
commands.go
|
@ -7,11 +7,11 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/dotcloud/docker/registry"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
|
@ -164,10 +164,10 @@ func MkBuildContext(dockerfile string, files [][2]string) (archive.Archive, erro
|
|||
|
||||
func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||
cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
|
||||
tag := cmd.String("t", "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
|
||||
suppressOutput := cmd.Bool("q", false, "Suppress verbose build output")
|
||||
noCache := cmd.Bool("no-cache", false, "Do not use cache when building the image")
|
||||
rm := cmd.Bool("rm", false, "Remove intermediate containers after a successful build")
|
||||
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 verbose build output")
|
||||
noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
|
||||
rm := cmd.Bool([]string{"#rm", "-rm"}, false, "Remove intermediate containers after a successful build")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -253,9 +253,9 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
|||
|
||||
var username, password, email string
|
||||
|
||||
cmd.StringVar(&username, "u", "", "username")
|
||||
cmd.StringVar(&password, "p", "", "password")
|
||||
cmd.StringVar(&email, "e", "", "email")
|
||||
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
|
||||
|
@ -504,7 +504,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdStop(args ...string) error {
|
||||
cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container (Send SIGTERM, and then SIGKILL after grace period)")
|
||||
nSeconds := cmd.Int("t", 10, "Number of seconds to wait for the container to stop before killing it.")
|
||||
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -531,7 +531,7 @@ func (cli *DockerCli) CmdStop(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdRestart(args ...string) error {
|
||||
cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
|
||||
nSeconds := cmd.Int("t", 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
|
||||
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=10")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -574,8 +574,8 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
|
|||
|
||||
func (cli *DockerCli) CmdStart(args ...string) error {
|
||||
cmd := cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
|
||||
attach := cmd.Bool("a", false, "Attach container's stdout/stderr and forward all signals to the process")
|
||||
openStdin := cmd.Bool("i", false, "Attach container's stdin")
|
||||
attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach container's stdout/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
|
||||
}
|
||||
|
@ -660,7 +660,7 @@ func (cli *DockerCli) CmdStart(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/image")
|
||||
tmplStr := cmd.String("format", "", "Format the output using the given go template.")
|
||||
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -846,8 +846,8 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdHistory(args ...string) error {
|
||||
cmd := cli.Subcmd("history", "[OPTIONS] IMAGE", "Show the history of an image")
|
||||
quiet := cmd.Bool("q", false, "only show numeric IDs")
|
||||
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "only show numeric IDs")
|
||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -906,8 +906,8 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdRm(args ...string) error {
|
||||
cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
||||
v := cmd.Bool("v", false, "Remove the volumes associated to the container")
|
||||
link := cmd.Bool("link", false, "Remove the specified link and not the underlying container")
|
||||
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
|
||||
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -1058,7 +1058,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdPull(args ...string) error {
|
||||
cmd := cli.Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
|
||||
tag := cmd.String("t", "", "Download tagged image in repository")
|
||||
tag := cmd.String([]string{"t", "-tag"}, "", "Download tagged image in repository")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1118,11 +1118,11 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdImages(args ...string) error {
|
||||
cmd := cli.Subcmd("images", "[OPTIONS] [NAME]", "List images")
|
||||
quiet := cmd.Bool("q", false, "only show numeric IDs")
|
||||
all := cmd.Bool("a", false, "show all images (by default filter out the intermediate images used to build)")
|
||||
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
flViz := cmd.Bool("viz", false, "output graph in graphviz format")
|
||||
flTree := cmd.Bool("tree", false, "output graph in tree format")
|
||||
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 images used to build)")
|
||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||
flViz := cmd.Bool([]string{"v", "#viz", "-viz"}, false, "output graph in graphviz format")
|
||||
flTree := cmd.Bool([]string{"t", "#tree", "-tree"}, false, "output graph in tree format")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -1329,14 +1329,14 @@ func displayablePorts(ports []APIPort) string {
|
|||
|
||||
func (cli *DockerCli) CmdPs(args ...string) error {
|
||||
cmd := cli.Subcmd("ps", "[OPTIONS]", "List containers")
|
||||
quiet := cmd.Bool("q", false, "Only display numeric IDs")
|
||||
size := cmd.Bool("s", false, "Display sizes")
|
||||
all := cmd.Bool("a", false, "Show all containers. Only running containers are shown by default.")
|
||||
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.")
|
||||
since := cmd.String("sinceId", "", "Show only containers created since Id, include non-running ones.")
|
||||
before := cmd.String("beforeId", "", "Show only container created before Id, include non-running ones.")
|
||||
last := cmd.Int("n", -1, "Show n last created containers, include non-running ones.")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
||||
size := cmd.Bool([]string{"s", "-size"}, false, "Display sizes")
|
||||
all := cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
|
||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||
nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
|
||||
since := cmd.String([]string{"#sinceId", "-since-id"}, "", "Show only containers created since Id, include non-running ones.")
|
||||
before := cmd.String([]string{"#beforeId", "-before-id"}, "", "Show only container created before Id, include non-running ones.")
|
||||
last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -1418,9 +1418,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdCommit(args ...string) error {
|
||||
cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
|
||||
flComment := cmd.String("m", "", "Commit message")
|
||||
flAuthor := cmd.String("author", "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
|
||||
flConfig := cmd.String("run", "", "Config automatically applied when the image is run. "+`(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
|
||||
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
||||
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
|
||||
flConfig := cmd.String([]string{"#run", "-run"}, "", "Config automatically applied when the image is run. "+`(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')`)
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1470,7 +1470,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdEvents(args ...string) error {
|
||||
cmd := cli.Subcmd("events", "[OPTIONS]", "Get real time events from the server")
|
||||
since := cmd.String("since", "", "Show previously created events and then stream.")
|
||||
since := cmd.String([]string{"#since", "-since"}, "", "Show previously created events and then stream.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1557,7 +1557,7 @@ func (cli *DockerCli) CmdDiff(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdLogs(args ...string) error {
|
||||
cmd := cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
|
||||
follow := cmd.Bool("f", false, "Follow log output")
|
||||
follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1593,8 +1593,8 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdAttach(args ...string) error {
|
||||
cmd := cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container")
|
||||
noStdin := cmd.Bool("nostdin", false, "Do not attach stdin")
|
||||
proxy := cmd.Bool("sig-proxy", true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
noStdin := cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach stdin")
|
||||
proxy := cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1657,9 +1657,9 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
|||
|
||||
func (cli *DockerCli) CmdSearch(args ...string) error {
|
||||
cmd := cli.Subcmd("search", "TERM", "Search the docker index for images")
|
||||
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
trusted := cmd.Bool("trusted", false, "Only show trusted builds")
|
||||
stars := cmd.Int("stars", 0, "Only displays with at least xxx stars")
|
||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||
trusted := cmd.Bool([]string{"t", "#trusted", "-trusted"}, false, "Only show trusted builds")
|
||||
stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least xxx stars")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1712,7 +1712,7 @@ type ports []int
|
|||
|
||||
func (cli *DockerCli) CmdTag(args ...string) error {
|
||||
cmd := cli.Subcmd("tag", "[OPTIONS] IMAGE REPOSITORY[:TAG]", "Tag an image into a repository")
|
||||
force := cmd.Bool("f", false, "Force")
|
||||
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -1766,36 +1766,36 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
|
|||
flVolumesFrom ListOpts
|
||||
flLxcOpts ListOpts
|
||||
|
||||
flAutoRemove = cmd.Bool("rm", false, "Automatically remove the container when it exits (incompatible with -d)")
|
||||
flDetach = cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
|
||||
flNetwork = cmd.Bool("n", true, "Enable networking for this container")
|
||||
flPrivileged = cmd.Bool("privileged", false, "Give extended privileges to this container")
|
||||
flPublishAll = cmd.Bool("P", false, "Publish all exposed ports to the host interfaces")
|
||||
flStdin = cmd.Bool("i", false, "Keep stdin open even if not attached")
|
||||
flTty = cmd.Bool("t", false, "Allocate a pseudo-tty")
|
||||
flContainerIDFile = cmd.String("cidfile", "", "Write the container ID to the file")
|
||||
flEntrypoint = cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
|
||||
flHostname = cmd.String("h", "", "Container host name")
|
||||
flMemoryString = cmd.String("m", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
|
||||
flUser = cmd.String("u", "", "Username or UID")
|
||||
flWorkingDir = cmd.String("w", "", "Working directory inside the container")
|
||||
flCpuShares = cmd.Int64("c", 0, "CPU shares (relative weight)")
|
||||
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
||||
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
|
||||
flNetwork = cmd.Bool([]string{"n", "-networking"}, true, "Enable networking for this container")
|
||||
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
||||
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep stdin open even if not attached")
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-tty")
|
||||
flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file")
|
||||
flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default entrypoint of the image")
|
||||
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
||||
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
|
||||
flUser = cmd.String([]string{"u", "-username"}, "", "Username or UID")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||
|
||||
// For documentation purpose
|
||||
_ = cmd.Bool("sig-proxy", true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
_ = cmd.String("name", "", "Assign a name to the container")
|
||||
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
||||
_ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
||||
)
|
||||
|
||||
cmd.Var(&flAttach, "a", "Attach to stdin, stdout or stderr.")
|
||||
cmd.Var(&flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
||||
cmd.Var(&flLinks, "link", "Add link to another container (name:alias)")
|
||||
cmd.Var(&flEnv, "e", "Set environment variables")
|
||||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to stdin, stdout or stderr.")
|
||||
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
||||
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
|
||||
cmd.Var(&flPublish, "p", fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", PortSpecTemplateFormat))
|
||||
cmd.Var(&flExpose, "expose", "Expose a port from the container without publishing it to your host")
|
||||
cmd.Var(&flDns, "dns", "Set custom dns servers")
|
||||
cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
|
||||
cmd.Var(&flLxcOpts, "lxc-conf", "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", PortSpecTemplateFormat))
|
||||
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
|
||||
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options -lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil, nil, cmd, err
|
||||
|
@ -1892,7 +1892,7 @@ func parseRun(cmd *flag.FlagSet, args []string, capabilities *Capabilities) (*Co
|
|||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid port format for -expose: %s", e)
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
p := NewPort(splitProtoPort(e))
|
||||
if _, exists := ports[p]; !exists {
|
||||
|
|
|
@ -25,7 +25,7 @@ __docker_containers_all()
|
|||
{
|
||||
local containers
|
||||
containers="$( docker ps -a -q )"
|
||||
names="$( docker inspect -format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
names="$( docker inspect --format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
COMPREPLY=( $( compgen -W "$names $containers" -- "$cur" ) )
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ __docker_containers_running()
|
|||
{
|
||||
local containers
|
||||
containers="$( docker ps -q )"
|
||||
names="$( docker inspect -format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
names="$( docker inspect --format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
COMPREPLY=( $( compgen -W "$names $containers" -- "$cur" ) )
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ __docker_containers_stopped()
|
|||
{
|
||||
local containers
|
||||
containers="$( comm -13 <(docker ps -q | sort -u) <(docker ps -a -q | sort -u) )"
|
||||
names="$( docker inspect -format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
names="$( docker inspect --format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
COMPREPLY=( $( compgen -W "$names $containers" -- "$cur" ) )
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ __docker_containers_and_images()
|
|||
{
|
||||
local containers images
|
||||
containers="$( docker ps -a -q )"
|
||||
names="$( docker inspect -format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
names="$( docker inspect --format '{{.Name}}' $containers | sed 's,^/,,' )"
|
||||
images="$( docker images | awk 'NR>1{print $1":"$2}' )"
|
||||
COMPREPLY=( $( compgen -W "$images $names $containers" -- "$cur" ) )
|
||||
__ltrim_colon_completions "$cur"
|
||||
|
@ -118,7 +118,7 @@ _docker_build()
|
|||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-no-cache -t -q -rm" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--no-cache -t -q --rm" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
@ -138,7 +138,7 @@ _docker_commit()
|
|||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-author -m -run" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--author -m --run" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
local counter=$cpos
|
||||
|
@ -191,7 +191,7 @@ _docker_events()
|
|||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-since" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--since" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
|
@ -223,7 +223,7 @@ _docker_images()
|
|||
{
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-a -notrunc -q -viz" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "-a --no-trunc -q --viz" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
local counter=$cpos
|
||||
|
@ -308,7 +308,7 @@ _docker_port()
|
|||
_docker_ps()
|
||||
{
|
||||
case "$prev" in
|
||||
-beforeId|-n|-sinceId)
|
||||
-before-id|-n|-since-id)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
|
@ -317,7 +317,7 @@ _docker_ps()
|
|||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-a -beforeId -l -n -notrunc -q -s -sinceId" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "-a --before-id -l -n --no-trunc -q -s --since-id" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
|
@ -388,13 +388,13 @@ _docker_rmi()
|
|||
_docker_run()
|
||||
{
|
||||
case "$prev" in
|
||||
-cidfile)
|
||||
--cidfile)
|
||||
_filedir
|
||||
;;
|
||||
-volumes-from)
|
||||
--volumes-from)
|
||||
__docker_containers_all
|
||||
;;
|
||||
-a|-c|-dns|-e|-entrypoint|-h|-lxc-conf|-m|-p|-u|-v|-w)
|
||||
-a|-c|--dns|-e|--entrypoint|-h|--lxc-conf|-m|-p|-u|-v|-w)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
|
@ -403,13 +403,13 @@ _docker_run()
|
|||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-a -c -cidfile -d -dns -e -entrypoint -h -i -lxc-conf -m -n -p -privileged -t -u -v -volumes-from -w" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "-a -c --cidfile -d --dns -e --entrypoint -h -i --lxc-conf -m -n -p --privileged -t -u -v --volumes-from -w" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
local counter=$cpos
|
||||
while [ $counter -le $cword ]; do
|
||||
case "${words[$counter]}" in
|
||||
-a|-c|-cidfile|-dns|-e|-entrypoint|-h|-lxc-conf|-m|-p|-u|-v|-volumes-from|-w)
|
||||
-a|-c|--cidfile|--dns|-e|--entrypoint|-h|--lxc-conf|-m|-p|-u|-v|--volumes-from|-w)
|
||||
(( counter++ ))
|
||||
;;
|
||||
-*)
|
||||
|
@ -430,7 +430,7 @@ _docker_run()
|
|||
|
||||
_docker_search()
|
||||
{
|
||||
COMPREPLY=( $( compgen -W "-notrunc" "-stars" "-trusted" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--no-trunc" "--stars" "--trusted" -- "$cur" ) )
|
||||
}
|
||||
|
||||
_docker_start()
|
||||
|
|
|
@ -174,7 +174,7 @@ __docker_subcommand () {
|
|||
(ps)
|
||||
_arguments '-a[Show all containers. Only running containers are shown by default]' \
|
||||
'-h[Show help]' \
|
||||
'-beforeId=-[Show only container created before Id, include non-running one]:containers:__docker_containers' \
|
||||
'-before-id=-[Show only container created before Id, include non-running one]:containers:__docker_containers' \
|
||||
'-n=-[Show n last created containers, include non-running one]:n:(1 5 10 25 50)'
|
||||
;;
|
||||
(tag)
|
||||
|
@ -189,9 +189,9 @@ __docker_subcommand () {
|
|||
'-a=-[Attach to stdin, stdout or stderr]:toggle:(true false)' \
|
||||
'-c=-[CPU shares (relative weight)]:CPU shares: ' \
|
||||
'-d[Detached mode: leave the container running in the background]' \
|
||||
'*-dns=[Set custom dns servers]:dns server: ' \
|
||||
'*--dns=[Set custom dns servers]:dns server: ' \
|
||||
'*-e=[Set environment variables]:environment variable: ' \
|
||||
'-entrypoint=-[Overwrite the default entrypoint of the image]:entry point: ' \
|
||||
'--entrypoint=-[Overwrite the default entrypoint of the image]:entry point: ' \
|
||||
'-h=-[Container host name]:hostname:_hosts' \
|
||||
'-i[Keep stdin open even if not attached]' \
|
||||
'-m=-[Memory limit (in bytes)]:limit: ' \
|
||||
|
@ -199,7 +199,7 @@ __docker_subcommand () {
|
|||
'-t=-[Allocate a pseudo-tty]:toggle:(true false)' \
|
||||
'-u=-[Username or UID]:user:_users' \
|
||||
'*-v=-[Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)]:volume: '\
|
||||
'-volumes-from=-[Mount volumes from the specified container]:volume: ' \
|
||||
'--volumes-from=-[Mount volumes from the specified container]:volume: ' \
|
||||
'(-):images:__docker_images' \
|
||||
'(-):command: _command_names -e' \
|
||||
'*::arguments: _normal'
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/sysinit"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"log"
|
||||
|
@ -25,25 +25,25 @@ func main() {
|
|||
}
|
||||
|
||||
var (
|
||||
flVersion = flag.Bool("v", false, "Print version information and quit")
|
||||
flDaemon = flag.Bool("d", false, "Enable daemon mode")
|
||||
flDebug = flag.Bool("D", false, "Enable debug mode")
|
||||
flAutoRestart = flag.Bool("r", true, "Restart previously running containers")
|
||||
bridgeName = flag.String("b", "", "Attach containers to a pre-existing network bridge; use 'none' to disable container networking")
|
||||
bridgeIp = flag.String("bip", "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
|
||||
pidfile = flag.String("p", "/var/run/docker.pid", "Path to use for daemon PID file")
|
||||
flRoot = flag.String("g", "/var/lib/docker", "Path to use as the root of the docker runtime")
|
||||
flEnableCors = flag.Bool("api-enable-cors", false, "Enable CORS headers in the remote API")
|
||||
flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
|
||||
flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
|
||||
flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
|
||||
flAutoRestart = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers")
|
||||
bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge; use 'none' to disable container networking")
|
||||
bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
|
||||
pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file")
|
||||
flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the docker runtime")
|
||||
flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
|
||||
flDns = docker.NewListOpts(docker.ValidateIp4Address)
|
||||
flEnableIptables = flag.Bool("iptables", true, "Disable docker's addition of iptables rules")
|
||||
flDefaultIp = flag.String("ip", "0.0.0.0", "Default IP address to use when binding container ports")
|
||||
flInterContainerComm = flag.Bool("icc", true, "Enable inter-container communication")
|
||||
flGraphDriver = flag.String("s", "", "Force the docker runtime to use a specific storage driver")
|
||||
flEnableIptables = flag.Bool([]string{"#iptables", "-iptables"}, true, "Disable docker's addition of iptables rules")
|
||||
flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
|
||||
flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
||||
flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the docker runtime to use a specific storage driver")
|
||||
flHosts = docker.NewListOpts(docker.ValidateHost)
|
||||
flMtu = flag.Int("mtu", docker.DefaultNetworkMtu, "Set the containers network mtu")
|
||||
flMtu = flag.Int([]string{"#mtu", "-mtu"}, docker.DefaultNetworkMtu, "Set the containers network mtu")
|
||||
)
|
||||
flag.Var(&flDns, "dns", "Force docker to use specific DNS servers")
|
||||
flag.Var(&flHosts, "H", "Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise")
|
||||
flag.Var(&flDns, []string{"#dns", "-dns"}, "Force docker to use specific DNS servers")
|
||||
flag.Var(&flHosts, []string{"H", "-host"}, "Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
|
@ -62,7 +62,7 @@ func main() {
|
|||
}
|
||||
|
||||
if *bridgeName != "" && *bridgeIp != "" {
|
||||
log.Fatal("You specified -b & -bip, mutually exclusive options. Please specify only one.")
|
||||
log.Fatal("You specified -b & --bip, mutually exclusive options. Please specify only one.")
|
||||
}
|
||||
|
||||
if *flDebug {
|
||||
|
|
|
@ -41,7 +41,7 @@ This time, we're requesting shared access to ``$COUCH1``'s volumes.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH2=$(sudo docker run -d -p 5984 -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
|
||||
COUCH2=$(sudo docker run -d -p 5984 --volumes-from $COUCH1 shykes/couchdb:2013-05-03)
|
||||
|
||||
Browse data on the second database
|
||||
----------------------------------
|
||||
|
|
|
@ -43,7 +43,7 @@ container. The ``BUILD_JOB`` environment variable will be set with the new conta
|
|||
[...]
|
||||
|
||||
While this container is running, we can attach to the new container to
|
||||
see what is going on. The flag ``-sig-proxy`` set as ``false`` allows you to connect and
|
||||
see what is going on. The flag ``--sig-proxy`` set as ``false`` allows you to connect and
|
||||
disconnect (Ctrl-C) to it without stopping the container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
|
@ -44,7 +44,7 @@ use a container link to provide access to our Redis database.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -name redis -d <your username>/redis
|
||||
sudo docker run --name redis -d <your username>/redis
|
||||
|
||||
Create your web application container
|
||||
-------------------------------------
|
||||
|
@ -56,7 +56,7 @@ Redis instance running inside that container to only this container.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo docker run -link redis:db -i -t ubuntu:12.10 /bin/bash
|
||||
sudo docker run --link redis:db -i -t ubuntu:12.10 /bin/bash
|
||||
|
||||
Once inside our freshly created container we need to install Redis to get the
|
||||
``redis-cli`` binary to test our connection.
|
||||
|
|
|
@ -26,22 +26,21 @@ To list available commands, either run ``docker`` with no parameters or execute
|
|||
::
|
||||
|
||||
Usage of docker:
|
||||
-D=false: Enable debug mode
|
||||
-H=[unix:///var/run/docker.sock]: tcp://[host[:port]] to bind or unix://[/path/to/socket] to use. When host=[0.0.0.0], port=[4243] or path=[/var/run/docker.sock] is omitted, default values are used.
|
||||
-api-enable-cors=false: Enable CORS headers in the remote API
|
||||
-b="": Attach containers to a pre-existing network bridge; use 'none' to disable container networking
|
||||
-bip="": Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of -b
|
||||
-d=false: Enable daemon mode
|
||||
-dns="": Force docker to use specific DNS servers
|
||||
-g="/var/lib/docker": Path to use as the root of the docker runtime
|
||||
-icc=true: Enable inter-container communication
|
||||
-ip="0.0.0.0": Default IP address to use when binding container ports
|
||||
-iptables=true: Disable docker's addition of iptables rules
|
||||
-mtu=1500: Set the containers network mtu
|
||||
-p="/var/run/docker.pid": Path to use for daemon PID file
|
||||
-r=true: Restart previously running containers
|
||||
-s="": Force the docker runtime to use a specific storage driver
|
||||
-v=false: Print version information and quit
|
||||
-D, --debug=false: Enable debug mode
|
||||
-H, --host=[]: Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise
|
||||
--api-enable-cors=false: Enable CORS headers in the remote API
|
||||
-b, --bridge="": Attach containers to a pre-existing network bridge; use 'none' to disable container networking
|
||||
--bip="": Use this CIDR notation address for the network bridge's IP, not compatible with -b
|
||||
-d, --daemon=false: Enable daemon mode
|
||||
--dns=[]: Force docker to use specific DNS servers
|
||||
-g, --graph="/var/lib/docker": Path to use as the root of the docker runtime
|
||||
--icc=true: Enable inter-container communication
|
||||
--ip="0.0.0.0": Default IP address to use when binding container ports
|
||||
--iptables=true: Disable docker's addition of iptables rules
|
||||
-p, --pidfile="/var/run/docker.pid": Path to use for daemon PID file
|
||||
-r, --restart=true: Restart previously running containers
|
||||
-s, --storage-driver="": Force the docker runtime to use a specific storage driver
|
||||
-v, --version=false: Print version information and quit
|
||||
|
||||
The Docker daemon is the persistent process that manages containers. Docker uses the same binary for both the
|
||||
daemon and client. To run the daemon you provide the ``-d`` flag.
|
||||
|
@ -75,8 +74,8 @@ the ``-H`` flag for the client.
|
|||
|
||||
Attach to a running container.
|
||||
|
||||
-nostdin=false: Do not attach stdin
|
||||
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
--no-stdin=false: Do not attach stdin
|
||||
--sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
|
||||
You can detach from the container again (and leave it running) with
|
||||
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
|
||||
|
@ -135,11 +134,11 @@ Examples:
|
|||
|
||||
Usage: docker build [OPTIONS] PATH | URL | -
|
||||
Build a new container image from the source code at PATH
|
||||
-t="": Repository name (and optionally a tag) to be applied
|
||||
-t, --time="": Repository name (and optionally a tag) to be applied
|
||||
to the resulting image in case of success.
|
||||
-q=false: Suppress verbose build output.
|
||||
-no-cache: Do not use the cache when building the image.
|
||||
-rm: Remove intermediate containers after a successful build
|
||||
-q, --quiet=false: Suppress verbose build output.
|
||||
--no-cache: Do not use the cache when building the image.
|
||||
--rm: Remove intermediate containers after a successful build
|
||||
|
||||
The files at ``PATH`` or ``URL`` are called the "context" of the build. The
|
||||
build process may refer to any of the files in the context, for example when
|
||||
|
@ -233,9 +232,9 @@ by using the ``git://`` schema.
|
|||
|
||||
Create a new image from a container's changes
|
||||
|
||||
-m="": Commit message
|
||||
-author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
|
||||
-run="": Configuration to be applied when the image is launched with `docker run`.
|
||||
-m, --message="": Commit message
|
||||
-a, --author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
|
||||
--run="": Configuration to be applied when the image is launched with `docker run`.
|
||||
(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
|
||||
|
||||
.. _cli_commit_examples:
|
||||
|
@ -279,7 +278,7 @@ run ``ls /etc``.
|
|||
Full -run example
|
||||
.................
|
||||
|
||||
The ``-run`` JSON hash changes the ``Config`` section when running ``docker inspect CONTAINERID``
|
||||
The ``--run`` JSON hash changes the ``Config`` section when running ``docker inspect CONTAINERID``
|
||||
or ``config`` when running ``docker inspect IMAGEID``.
|
||||
|
||||
(Multiline is okay within a single quote ``'``)
|
||||
|
@ -379,7 +378,7 @@ For example:
|
|||
|
||||
Get real time events from the server
|
||||
|
||||
-since="": Show previously created events and then stream.
|
||||
--since="": Show previously created events and then stream.
|
||||
(either seconds since epoch, or date string as below)
|
||||
|
||||
.. _cli_events_example:
|
||||
|
@ -459,8 +458,8 @@ For example:
|
|||
|
||||
Show the history of an image
|
||||
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: only show numeric IDs
|
||||
--no-trunc=false: Don't truncate output
|
||||
-q, --quiet=false: only show numeric IDs
|
||||
|
||||
To see how the ``docker:latest`` image was built:
|
||||
|
||||
|
@ -507,11 +506,11 @@ To see how the ``docker:latest`` image was built:
|
|||
|
||||
List images
|
||||
|
||||
-a=false: show all images (by default filter out the intermediate images used to build)
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: only show numeric IDs
|
||||
-tree=false: output graph in tree format
|
||||
-viz=false: output graph in graphviz format
|
||||
-a, --all=false: show all images (by default filter out the intermediate images used to build)
|
||||
--no-trunc=false: Don't truncate output
|
||||
-q, --quiet=false: only show numeric IDs
|
||||
--tree=false: output graph in tree format
|
||||
--viz=false: output graph in graphviz format
|
||||
|
||||
Listing the most recently created images
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -535,7 +534,7 @@ Listing the full length image IDs
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images -notrunc | head
|
||||
$ sudo docker images --no-trunc | head
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
<none> <none> 77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 1.089 GB
|
||||
committest latest b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 1.089 GB
|
||||
|
@ -552,7 +551,7 @@ Displaying images visually
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images -viz | dot -Tpng -o docker.png
|
||||
$ sudo docker images --viz | dot -Tpng -o docker.png
|
||||
|
||||
.. image:: docker_images.gif
|
||||
:alt: Example inheritance graph of Docker images.
|
||||
|
@ -563,7 +562,7 @@ Displaying image hierarchy
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker images -tree
|
||||
$ sudo docker images --tree
|
||||
|
||||
├─8dbd9e392a96 Size: 131.5 MB (virtual 131.5 MB) Tags: ubuntu:12.04,ubuntu:latest,ubuntu:precise
|
||||
└─27cf78414709 Size: 180.1 MB (virtual 180.1 MB)
|
||||
|
@ -702,7 +701,7 @@ Insert file from GitHub
|
|||
|
||||
Return low-level information on a container/image
|
||||
|
||||
-format="": Format the output using the given go template.
|
||||
-f, --format="": Format the output using the given go template.
|
||||
|
||||
By default, this will render all results in a JSON array. If a format
|
||||
is specified, the given template will be executed for each result.
|
||||
|
@ -721,7 +720,7 @@ fairly straightforward manner.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker inspect -format='{{.NetworkSettings.IPAddress}}' $INSTANCE_ID
|
||||
$ sudo docker inspect --format='{{.NetworkSettings.IPAddress}}' $INSTANCE_ID
|
||||
|
||||
List All Port Bindings
|
||||
......................
|
||||
|
@ -790,9 +789,9 @@ Known Issues (kill)
|
|||
|
||||
Register or Login to the docker registry server
|
||||
|
||||
-e="": email
|
||||
-p="": password
|
||||
-u="": username
|
||||
-e, --email="": email
|
||||
-p, --password="": password
|
||||
-u, --username="": username
|
||||
|
||||
If you want to login to a private registry you can
|
||||
specify this by adding the server name.
|
||||
|
@ -812,12 +811,14 @@ Known Issues (kill)
|
|||
|
||||
Fetch the logs of a container
|
||||
|
||||
-f, --follow=false: Follow log output
|
||||
|
||||
The ``docker logs`` command is a convenience which batch-retrieves whatever
|
||||
logs are present at the time of execution. This does not guarantee execution
|
||||
order when combined with a ``docker run`` (i.e. your run may not have generated
|
||||
any logs at the time you execute ``docker logs``).
|
||||
|
||||
The ``docker logs -f`` command combines ``docker logs`` and ``docker attach``:
|
||||
The ``docker logs --follow`` command combines ``docker logs`` and ``docker attach``:
|
||||
it will first return all logs from the beginning and then continue streaming
|
||||
new output from the container's stdout and stderr.
|
||||
|
||||
|
@ -845,9 +846,9 @@ new output from the container's stdout and stderr.
|
|||
|
||||
List containers
|
||||
|
||||
-a=false: Show all containers. Only running containers are shown by default.
|
||||
-notrunc=false: Don't truncate output
|
||||
-q=false: Only display numeric IDs
|
||||
-a, --all=false: Show all containers. Only running containers are shown by default.
|
||||
--no-trunc=false: Don't truncate output
|
||||
-q, --quiet=false: Only display numeric IDs
|
||||
|
||||
Running ``docker ps`` showing 2 linked containers.
|
||||
|
||||
|
@ -903,7 +904,7 @@ Running ``docker ps`` showing 2 linked containers.
|
|||
Usage: docker rm [OPTIONS] CONTAINER
|
||||
|
||||
Remove one or more containers
|
||||
-link="": Remove the link instead of the actual container
|
||||
--link="": Remove the link instead of the actual container
|
||||
|
||||
Known Issues (rm)
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
@ -926,7 +927,7 @@ This will remove the container referenced under the link ``/redis``.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker rm -link /webapp/redis
|
||||
$ sudo docker rm --link /webapp/redis
|
||||
/webapp/redis
|
||||
|
||||
|
||||
|
@ -996,31 +997,31 @@ image is removed.
|
|||
|
||||
Run a command in a new container
|
||||
|
||||
-a=map[]: Attach to stdin, stdout or stderr
|
||||
-c=0: CPU shares (relative weight)
|
||||
-cidfile="": Write the container ID to the file
|
||||
-d=false: Detached mode: Run container in the background, print new container id
|
||||
-e=[]: Set environment variables
|
||||
-h="": Container host name
|
||||
-i=false: Keep stdin open even if not attached
|
||||
-privileged=false: Give extended privileges to this container
|
||||
-m="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
|
||||
-n=true: Enable networking for this container
|
||||
-p=[]: Map a network port to the container
|
||||
-rm=false: Automatically remove the container when it exits (incompatible with -d)
|
||||
-t=false: Allocate a pseudo-tty
|
||||
-u="": Username or UID
|
||||
-dns=[]: Set custom dns servers for the container
|
||||
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
|
||||
-volumes-from="": Mount all volumes from the given container(s)
|
||||
-entrypoint="": Overwrite the default entrypoint set by the image
|
||||
-w="": Working directory inside the container
|
||||
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||
-sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
-expose=[]: Expose a port from the container without publishing it to your host
|
||||
-link="": Add link to another container (name:alias)
|
||||
-name="": Assign the specified name to the container. If no name is specific docker will generate a random name
|
||||
-P=false: Publish all exposed ports to the host interfaces
|
||||
-a, --attach=map[]: Attach to stdin, stdout or stderr
|
||||
-c, --cpu-shares=0: CPU shares (relative weight)
|
||||
--cidfile="": Write the container ID to the file
|
||||
-d, --detach=false: Detached mode: Run container in the background, print new container id
|
||||
-e, --env=[]: Set environment variables
|
||||
-h, --host="": Container host name
|
||||
-i, --interactive=false: Keep stdin open even if not attached
|
||||
--privileged=false: Give extended privileges to this container
|
||||
-m, --memory="": Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
|
||||
-n, --networking=true: Enable networking for this container
|
||||
-p, --publish=[]: Map a network port to the container
|
||||
--rm=false: Automatically remove the container when it exits (incompatible with -d)
|
||||
-t, --tty=false: Allocate a pseudo-tty
|
||||
-u, --username="": Username or UID
|
||||
--dns=[]: Set custom dns servers for the container
|
||||
-v, --volume=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume.
|
||||
--volumes-from="": Mount all volumes from the given container(s)
|
||||
--entrypoint="": Overwrite the default entrypoint set by the image
|
||||
-w, --workdir="": Working directory inside the container
|
||||
--lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||
--sig-proxy=true: Proxify all received signal to the process (even in non-tty mode)
|
||||
--expose=[]: Expose a port from the container without publishing it to your host
|
||||
--link="": Add link to another container (name:alias)
|
||||
--name="": Assign the specified name to the container. If no name is specific docker will generate a random name
|
||||
-P, --publish-all=false: Publish all exposed ports to the host interfaces
|
||||
|
||||
The ``docker run`` command first ``creates`` a writeable container layer over
|
||||
the specified image, and then ``starts`` it using the specified command. That
|
||||
|
@ -1042,7 +1043,7 @@ Examples:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
|
||||
$ sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
|
||||
|
||||
This will create a container and print ``test`` to the console. The
|
||||
``cidfile`` flag makes Docker attempt to create a new file and write the
|
||||
|
@ -1051,7 +1052,7 @@ error. Docker will close this file when ``docker run`` exits.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -t -i -rm ubuntu bash
|
||||
$ sudo docker run -t -i --rm ubuntu bash
|
||||
root@bc338942ef20:/# mount -t tmpfs none /mnt
|
||||
mount: permission denied
|
||||
|
||||
|
@ -1063,7 +1064,7 @@ allow it to run:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -privileged ubuntu bash
|
||||
$ sudo docker run --privileged ubuntu bash
|
||||
root@50e3f57e16e6:/# mount -t tmpfs none /mnt
|
||||
root@50e3f57e16e6:/# df -h
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
|
@ -1104,7 +1105,7 @@ in Docker.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -expose 80 ubuntu bash
|
||||
$ sudo docker run --expose 80 ubuntu bash
|
||||
|
||||
This exposes port ``80`` of the container for use within a link without
|
||||
publishing the port to the host system's interfaces. :ref:`port_redirection`
|
||||
|
@ -1112,28 +1113,28 @@ explains in detail how to manipulate ports in Docker.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -name console -t -i ubuntu bash
|
||||
$ sudo docker run --name console -t -i ubuntu bash
|
||||
|
||||
This will create and run a new container with the container name
|
||||
being ``console``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -link /redis:redis -name console ubuntu bash
|
||||
$ sudo docker run --link /redis:redis --name console ubuntu bash
|
||||
|
||||
The ``-link`` flag will link the container named ``/redis`` into the
|
||||
The ``--link`` flag will link the container named ``/redis`` into the
|
||||
newly created container with the alias ``redis``. The new container
|
||||
can access the network and environment of the redis container via
|
||||
environment variables. The ``-name`` flag will assign the name ``console``
|
||||
environment variables. The ``--name`` flag will assign the name ``console``
|
||||
to the newly created container.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd
|
||||
$ sudo docker run --volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd
|
||||
|
||||
The ``-volumes-from`` flag mounts all the defined volumes from the
|
||||
The ``--volumes-from`` flag mounts all the defined volumes from the
|
||||
referenced containers. Containers can be specified by a comma seperated
|
||||
list or by repetitions of the ``-volumes-from`` argument. The container
|
||||
list or by repetitions of the ``--volumes-from`` argument. The container
|
||||
ID may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
|
||||
read-only or read-write mode, respectively. By default, the volumes are mounted
|
||||
in the same mode (read write or read only) as the reference container.
|
||||
|
@ -1143,11 +1144,11 @@ A complete example
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo docker run -d -name static static-web-files sh
|
||||
$ sudo docker run -d -expose=8098 -name riak riakserver
|
||||
$ sudo docker run -d -m 100m -e DEVELOPMENT=1 -e BRANCH=example-code -v $(pwd):/app/bin:ro -name app appserver
|
||||
$ sudo docker run -d -p 1443:443 -dns=dns.dev.org -v /var/log/httpd -volumes-from static -link riak -link app -h www.sven.dev.org -name web webserver
|
||||
$ sudo docker run -t -i -rm -volumes-from web -w /var/log/httpd busybox tail -f access.log
|
||||
$ sudo docker run -d --name static static-web-files sh
|
||||
$ sudo docker run -d --expose=8098 --name riak riakserver
|
||||
$ sudo docker run -d -m 100m -e DEVELOPMENT=1 -e BRANCH=example-code -v $(pwd):/app/bin:ro --name app appserver
|
||||
$ sudo docker run -d -p 1443:443 --dns=dns.dev.org -v /var/log/httpd --volumes-from static --link riak --link app -h www.sven.dev.org --name web webserver
|
||||
$ sudo docker run -t -i --rm --volumes-from web -w /var/log/httpd busybox tail -f access.log
|
||||
|
||||
This example shows 5 containers that might be set up to test a web application change:
|
||||
|
||||
|
@ -1181,9 +1182,9 @@ This example shows 5 containers that might be set up to test a web application c
|
|||
|
||||
Search the docker index for images
|
||||
|
||||
-notrunc=false: Don't truncate output
|
||||
-stars=0: Only displays with at least xxx stars
|
||||
-trusted=false: Only show trusted builds
|
||||
--no-trunc=false: Don't truncate output
|
||||
-s, --stars=0: Only displays with at least xxx stars
|
||||
-t, --trusted=false: Only show trusted builds
|
||||
|
||||
.. _cli_start:
|
||||
|
||||
|
@ -1196,8 +1197,8 @@ This example shows 5 containers that might be set up to test a web application c
|
|||
|
||||
Start a stopped container
|
||||
|
||||
-a=false: Attach container's stdout/stderr and forward all signals to the process
|
||||
-i=false: Attach container's stdin
|
||||
-a, --attach=false: Attach container's stdout/stderr and forward all signals to the process
|
||||
-i, --interactive=false: Attach container's stdin
|
||||
|
||||
.. _cli_stop:
|
||||
|
||||
|
@ -1210,7 +1211,7 @@ This example shows 5 containers that might be set up to test a web application c
|
|||
|
||||
Stop a running container (Send SIGTERM, and then SIGKILL after grace period)
|
||||
|
||||
-t=10: Number of seconds to wait for the container to stop before killing it.
|
||||
-t, --time=10: Number of seconds to wait for the container to stop before killing it.
|
||||
|
||||
The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL
|
||||
|
||||
|
@ -1225,7 +1226,7 @@ The main process inside the container will receive SIGTERM, and after a grace pe
|
|||
|
||||
Tag an image into a repository
|
||||
|
||||
-f=false: Force
|
||||
-f, --force=false: Force
|
||||
|
||||
.. _cli_top:
|
||||
|
||||
|
|
27
pkg/mflag/LICENSE
Normal file
27
pkg/mflag/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2014 The Docker & Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
40
pkg/mflag/README.md
Normal file
40
pkg/mflag/README.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
Package mflag (aka multiple-flag) implements command-line flag parsing.
|
||||
It's an **hacky** fork of the [official golang package](http://golang.org/pkg/flag/)
|
||||
|
||||
It adds:
|
||||
|
||||
* both short and long flag version
|
||||
`./example -s red` `./example --string blue`
|
||||
|
||||
* multiple names for the same option
|
||||
```
|
||||
$>./example -h
|
||||
Usage of example:
|
||||
-s, --string="": a simple string
|
||||
```
|
||||
|
||||
___
|
||||
It is very flexible on purpose, so you can do things like:
|
||||
```
|
||||
$>./example -h
|
||||
Usage of example:
|
||||
-s, -string, --string="": a simple string
|
||||
```
|
||||
|
||||
Or:
|
||||
```
|
||||
$>./example -h
|
||||
Usage of example:
|
||||
-oldflag, --newflag="": a simple string
|
||||
```
|
||||
|
||||
You can also hide some flags from the usage, so if we want only `--newflag`:
|
||||
```
|
||||
$>./example -h
|
||||
Usage of example:
|
||||
--newflag="": a simple string
|
||||
$>./example -oldflag str
|
||||
str
|
||||
```
|
||||
|
||||
See [example.go](example/example.go) for more details.
|
27
pkg/mflag/example/example.go
Normal file
27
pkg/mflag/example/example.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/pkg/flag"
|
||||
)
|
||||
|
||||
var (
|
||||
i int
|
||||
str string
|
||||
b, h bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&b, []string{"b"}, false, "a simple bool")
|
||||
flag.IntVar(&i, []string{"#integer", "-integer"}, -1, "a simple integer")
|
||||
flag.StringVar(&str, []string{"s", "#hidden", "-string"}, "", "a simple string") //-s -hidden and --string will work, but -hidden won't be in the usage
|
||||
flag.BoolVar(&h, []string{"h", "#help", "-help"}, false, "display the help")
|
||||
flag.Parse()
|
||||
}
|
||||
func main() {
|
||||
if h {
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
fmt.Printf("%s\n", str)
|
||||
fmt.Printf("%s\n", flag.Lookup("s").Value.String())
|
||||
}
|
17
pkg/mflag/export_test.go
Normal file
17
pkg/mflag/export_test.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2014 The Docker & Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mflag
|
||||
|
||||
import "os"
|
||||
|
||||
// Additional routines compiled into the package only during testing.
|
||||
|
||||
// ResetForTesting clears all flag state and sets the usage function as directed.
|
||||
// After calling ResetForTesting, parse errors in flag handling will not
|
||||
// exit the program.
|
||||
func ResetForTesting(usage func()) {
|
||||
CommandLine = NewFlagSet(os.Args[0], ContinueOnError)
|
||||
Usage = usage
|
||||
}
|
863
pkg/mflag/flag.go
Normal file
863
pkg/mflag/flag.go
Normal file
|
@ -0,0 +1,863 @@
|
|||
// Copyright 2014 The Docker & Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package flag implements command-line flag parsing.
|
||||
|
||||
Usage:
|
||||
|
||||
Define flags using flag.String(), Bool(), Int(), etc.
|
||||
|
||||
This declares an integer flag, -f or --flagname, stored in the pointer ip, with type *int.
|
||||
import "flag"
|
||||
var ip = flag.Int([]string{"f", "-flagname"}, 1234, "help message for flagname")
|
||||
If you like, you can bind the flag to a variable using the Var() functions.
|
||||
var flagvar int
|
||||
func init() {
|
||||
// -flaghidden will work, but will be hidden from the usage
|
||||
flag.IntVar(&flagvar, []string{"f", "#flaghidden", "-flagname"}, 1234, "help message for flagname")
|
||||
}
|
||||
Or you can create custom flags that satisfy the Value interface (with
|
||||
pointer receivers) and couple them to flag parsing by
|
||||
flag.Var(&flagVal, []string{"name"}, "help message for flagname")
|
||||
For such flags, the default value is just the initial value of the variable.
|
||||
|
||||
After all flags are defined, call
|
||||
flag.Parse()
|
||||
to parse the command line into the defined flags.
|
||||
|
||||
Flags may then be used directly. If you're using the flags themselves,
|
||||
they are all pointers; if you bind to variables, they're values.
|
||||
fmt.Println("ip has value ", *ip)
|
||||
fmt.Println("flagvar has value ", flagvar)
|
||||
|
||||
After parsing, the arguments after the flag are available as the
|
||||
slice flag.Args() or individually as flag.Arg(i).
|
||||
The arguments are indexed from 0 through flag.NArg()-1.
|
||||
|
||||
Command line flag syntax:
|
||||
-flag
|
||||
-flag=x
|
||||
-flag x // non-boolean flags only
|
||||
One or two minus signs may be used; they are equivalent.
|
||||
The last form is not permitted for boolean flags because the
|
||||
meaning of the command
|
||||
cmd -x *
|
||||
will change if there is a file called 0, false, etc. You must
|
||||
use the -flag=false form to turn off a boolean flag.
|
||||
|
||||
Flag parsing stops just before the first non-flag argument
|
||||
("-" is a non-flag argument) or after the terminator "--".
|
||||
|
||||
Integer flags accept 1234, 0664, 0x1234 and may be negative.
|
||||
Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
|
||||
Duration flags accept any input valid for time.ParseDuration.
|
||||
|
||||
The default set of command-line flags is controlled by
|
||||
top-level functions. The FlagSet type allows one to define
|
||||
independent sets of flags, such as to implement subcommands
|
||||
in a command-line interface. The methods of FlagSet are
|
||||
analogous to the top-level functions for the command-line
|
||||
flag set.
|
||||
*/
|
||||
package mflag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
|
||||
var ErrHelp = errors.New("flag: help requested")
|
||||
|
||||
// -- bool Value
|
||||
type boolValue bool
|
||||
|
||||
func newBoolValue(val bool, p *bool) *boolValue {
|
||||
*p = val
|
||||
return (*boolValue)(p)
|
||||
}
|
||||
|
||||
func (b *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = boolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *boolValue) Get() interface{} { return bool(*b) }
|
||||
|
||||
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
|
||||
|
||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
// optional interface to indicate boolean flags that can be
|
||||
// supplied without "=value" text
|
||||
type boolFlag interface {
|
||||
Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// -- int Value
|
||||
type intValue int
|
||||
|
||||
func newIntValue(val int, p *int) *intValue {
|
||||
*p = val
|
||||
return (*intValue)(p)
|
||||
}
|
||||
|
||||
func (i *intValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = intValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *intValue) Get() interface{} { return int(*i) }
|
||||
|
||||
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- int64 Value
|
||||
type int64Value int64
|
||||
|
||||
func newInt64Value(val int64, p *int64) *int64Value {
|
||||
*p = val
|
||||
return (*int64Value)(p)
|
||||
}
|
||||
|
||||
func (i *int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int64Value) Get() interface{} { return int64(*i) }
|
||||
|
||||
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- uint Value
|
||||
type uintValue uint
|
||||
|
||||
func newUintValue(val uint, p *uint) *uintValue {
|
||||
*p = val
|
||||
return (*uintValue)(p)
|
||||
}
|
||||
|
||||
func (i *uintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uintValue) Get() interface{} { return uint(*i) }
|
||||
|
||||
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- uint64 Value
|
||||
type uint64Value uint64
|
||||
|
||||
func newUint64Value(val uint64, p *uint64) *uint64Value {
|
||||
*p = val
|
||||
return (*uint64Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint64Value) Get() interface{} { return uint64(*i) }
|
||||
|
||||
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- string Value
|
||||
type stringValue string
|
||||
|
||||
func newStringValue(val string, p *string) *stringValue {
|
||||
*p = val
|
||||
return (*stringValue)(p)
|
||||
}
|
||||
|
||||
func (s *stringValue) Set(val string) error {
|
||||
*s = stringValue(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringValue) Get() interface{} { return string(*s) }
|
||||
|
||||
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
|
||||
|
||||
// -- float64 Value
|
||||
type float64Value float64
|
||||
|
||||
func newFloat64Value(val float64, p *float64) *float64Value {
|
||||
*p = val
|
||||
return (*float64Value)(p)
|
||||
}
|
||||
|
||||
func (f *float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float64Value) Get() interface{} { return float64(*f) }
|
||||
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
|
||||
// -- time.Duration Value
|
||||
type durationValue time.Duration
|
||||
|
||||
func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
|
||||
*p = val
|
||||
return (*durationValue)(p)
|
||||
}
|
||||
|
||||
func (d *durationValue) Set(s string) error {
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = durationValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *durationValue) Get() interface{} { return time.Duration(*d) }
|
||||
|
||||
func (d *durationValue) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
// Value is the interface to the dynamic value stored in a flag.
|
||||
// (The default value is represented as a string.)
|
||||
//
|
||||
// If a Value has an IsBoolFlag() bool method returning true,
|
||||
// the command-line parser makes -name equivalent to -name=true
|
||||
// rather than using the next command-line argument.
|
||||
type Value interface {
|
||||
String() string
|
||||
Set(string) error
|
||||
}
|
||||
|
||||
// Getter is an interface that allows the contents of a Value to be retrieved.
|
||||
// It wraps the Value interface, rather than being part of it, because it
|
||||
// appeared after Go 1 and its compatibility rules. All Value types provided
|
||||
// by this package satisfy the Getter interface.
|
||||
type Getter interface {
|
||||
Value
|
||||
Get() interface{}
|
||||
}
|
||||
|
||||
// ErrorHandling defines how to handle flag parsing errors.
|
||||
type ErrorHandling int
|
||||
|
||||
const (
|
||||
ContinueOnError ErrorHandling = iota
|
||||
ExitOnError
|
||||
PanicOnError
|
||||
)
|
||||
|
||||
// A FlagSet represents a set of defined flags. The zero value of a FlagSet
|
||||
// has no name and has ContinueOnError error handling.
|
||||
type FlagSet struct {
|
||||
// Usage is the function called when an error occurs while parsing flags.
|
||||
// The field is a function (not a method) that may be changed to point to
|
||||
// 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
|
||||
}
|
||||
|
||||
// A Flag represents the state of a flag.
|
||||
type Flag struct {
|
||||
Names []string // name as it appears on command line
|
||||
Usage string // help message
|
||||
Value Value // value as set
|
||||
DefValue string // default value (as text); for usage message
|
||||
}
|
||||
|
||||
// sortFlags returns the flags as a slice in lexicographical sorted order.
|
||||
func sortFlags(flags map[string]*Flag) []*Flag {
|
||||
var list sort.StringSlice
|
||||
for _, f := range flags {
|
||||
found := false
|
||||
fName := strings.TrimPrefix(strings.TrimPrefix(f.Names[0], "#"), "-")
|
||||
for _, name := range list {
|
||||
if name == fName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
list = append(list, fName)
|
||||
}
|
||||
}
|
||||
list.Sort()
|
||||
result := make([]*Flag, len(list))
|
||||
for i, name := range list {
|
||||
result[i] = flags[name]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *FlagSet) out() io.Writer {
|
||||
if f.output == nil {
|
||||
return os.Stderr
|
||||
}
|
||||
return f.output
|
||||
}
|
||||
|
||||
// SetOutput sets the destination for usage and error messages.
|
||||
// If output is nil, os.Stderr is used.
|
||||
func (f *FlagSet) SetOutput(output io.Writer) {
|
||||
f.output = output
|
||||
}
|
||||
|
||||
// VisitAll visits the flags in lexicographical order, calling fn for each.
|
||||
// It visits all flags, even those not set.
|
||||
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.formal) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitAll visits the command-line flags in lexicographical order, calling
|
||||
// fn for each. It visits all flags, even those not set.
|
||||
func VisitAll(fn func(*Flag)) {
|
||||
CommandLine.VisitAll(fn)
|
||||
}
|
||||
|
||||
// Visit visits the flags in lexicographical order, calling fn for each.
|
||||
// It visits only those flags that have been set.
|
||||
func (f *FlagSet) Visit(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.actual) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Visit visits the command-line flags in lexicographical order, calling fn
|
||||
// for each. It visits only those flags that have been set.
|
||||
func Visit(fn func(*Flag)) {
|
||||
CommandLine.Visit(fn)
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named flag, returning nil if none exists.
|
||||
func (f *FlagSet) Lookup(name string) *Flag {
|
||||
return f.formal[name]
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named command-line flag,
|
||||
// returning nil if none exists.
|
||||
func Lookup(name string) *Flag {
|
||||
return CommandLine.formal[name]
|
||||
}
|
||||
|
||||
// Set sets the value of the named flag.
|
||||
func (f *FlagSet) Set(name, value string) error {
|
||||
flag, ok := f.formal[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("no such flag -%v", name)
|
||||
}
|
||||
err := flag.Value.Set(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.actual == nil {
|
||||
f.actual = make(map[string]*Flag)
|
||||
}
|
||||
f.actual[name] = flag
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets the value of the named command-line flag.
|
||||
func Set(name, value string) error {
|
||||
return CommandLine.Set(name, value)
|
||||
}
|
||||
|
||||
// PrintDefaults prints, to standard error unless configured
|
||||
// otherwise, the default values of all defined flags in the set.
|
||||
func (f *FlagSet) PrintDefaults() {
|
||||
f.VisitAll(func(flag *Flag) {
|
||||
format := " -%s=%s: %s\n"
|
||||
if _, ok := flag.Value.(*stringValue); ok {
|
||||
// put quotes on the value
|
||||
format = " -%s=%q: %s\n"
|
||||
}
|
||||
names := []string{}
|
||||
for _, name := range flag.Names {
|
||||
if name[0] != '#' {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(f.out(), format, strings.Join(names, ", -"), flag.DefValue, flag.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
// PrintDefaults prints to standard error the default values of all defined command-line flags.
|
||||
func PrintDefaults() {
|
||||
CommandLine.PrintDefaults()
|
||||
}
|
||||
|
||||
// defaultUsage is the default function to print a usage message.
|
||||
func defaultUsage(f *FlagSet) {
|
||||
if f.name == "" {
|
||||
fmt.Fprintf(f.out(), "Usage:\n")
|
||||
} else {
|
||||
fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
|
||||
}
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
// NOTE: Usage is not just defaultUsage(CommandLine)
|
||||
// because it serves (via godoc flag Usage) as the example
|
||||
// for how to write your own usage function.
|
||||
|
||||
// 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])
|
||||
PrintDefaults()
|
||||
}
|
||||
|
||||
// NFlag returns the number of flags that have been set.
|
||||
func (f *FlagSet) NFlag() int { return len(f.actual) }
|
||||
|
||||
// NFlag returns the number of command-line flags that have been set.
|
||||
func NFlag() int { return len(CommandLine.actual) }
|
||||
|
||||
// Arg returns the i'th argument. Arg(0) is the first remaining argument
|
||||
// after flags have been processed.
|
||||
func (f *FlagSet) Arg(i int) string {
|
||||
if i < 0 || i >= len(f.args) {
|
||||
return ""
|
||||
}
|
||||
return f.args[i]
|
||||
}
|
||||
|
||||
// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
|
||||
// after flags have been processed.
|
||||
func Arg(i int) string {
|
||||
return CommandLine.Arg(i)
|
||||
}
|
||||
|
||||
// NArg is the number of arguments remaining after flags have been processed.
|
||||
func (f *FlagSet) NArg() int { return len(f.args) }
|
||||
|
||||
// NArg is the number of arguments remaining after flags have been processed.
|
||||
func NArg() int { return len(CommandLine.args) }
|
||||
|
||||
// Args returns the non-flag arguments.
|
||||
func (f *FlagSet) Args() []string { return f.args }
|
||||
|
||||
// Args returns the non-flag command-line arguments.
|
||||
func Args() []string { return CommandLine.args }
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func (f *FlagSet) BoolVar(p *bool, names []string, value bool, usage string) {
|
||||
f.Var(newBoolValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func BoolVar(p *bool, names []string, value bool, usage string) {
|
||||
CommandLine.Var(newBoolValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func (f *FlagSet) Bool(names []string, value bool, usage string) *bool {
|
||||
p := new(bool)
|
||||
f.BoolVar(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func Bool(names []string, value bool, usage string) *bool {
|
||||
return CommandLine.Bool(names, value, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IntVar(p *int, names []string, value int, usage string) {
|
||||
f.Var(newIntValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func IntVar(p *int, names []string, value int, usage string) {
|
||||
CommandLine.Var(newIntValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int(names []string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
f.IntVar(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func Int(names []string, value int, usage string) *int {
|
||||
return CommandLine.Int(names, value, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int64Var(p *int64, names []string, value int64, usage string) {
|
||||
f.Var(newInt64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func Int64Var(p *int64, names []string, value int64, usage string) {
|
||||
CommandLine.Var(newInt64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int64(names []string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
f.Int64Var(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func Int64(names []string, value int64, usage string) *int64 {
|
||||
return CommandLine.Int64(names, value, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) UintVar(p *uint, names []string, value uint, usage string) {
|
||||
f.Var(newUintValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func UintVar(p *uint, names []string, value uint, usage string) {
|
||||
CommandLine.Var(newUintValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint(names []string, value uint, usage string) *uint {
|
||||
p := new(uint)
|
||||
f.UintVar(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint(names []string, value uint, usage string) *uint {
|
||||
return CommandLine.Uint(names, value, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint64Var(p *uint64, names []string, value uint64, usage string) {
|
||||
f.Var(newUint64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func Uint64Var(p *uint64, names []string, value uint64, usage string) {
|
||||
CommandLine.Var(newUint64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint64(names []string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
f.Uint64Var(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func Uint64(names []string, value uint64, usage string) *uint64 {
|
||||
return CommandLine.Uint64(names, value, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func (f *FlagSet) StringVar(p *string, names []string, value string, usage string) {
|
||||
f.Var(newStringValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func StringVar(p *string, names []string, value string, usage string) {
|
||||
CommandLine.Var(newStringValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func (f *FlagSet) String(names []string, value string, usage string) *string {
|
||||
p := new(string)
|
||||
f.StringVar(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func String(names []string, value string, usage string) *string {
|
||||
return CommandLine.String(names, value, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float64Var(p *float64, names []string, value float64, usage string) {
|
||||
f.Var(newFloat64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func Float64Var(p *float64, names []string, value float64, usage string) {
|
||||
CommandLine.Var(newFloat64Value(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float64(names []string, value float64, usage string) *float64 {
|
||||
p := new(float64)
|
||||
f.Float64Var(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func Float64(names []string, value float64, usage string) *float64 {
|
||||
return CommandLine.Float64(names, value, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func (f *FlagSet) DurationVar(p *time.Duration, names []string, value time.Duration, usage string) {
|
||||
f.Var(newDurationValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func DurationVar(p *time.Duration, names []string, value time.Duration, usage string) {
|
||||
CommandLine.Var(newDurationValue(value, p), names, usage)
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func (f *FlagSet) Duration(names []string, value time.Duration, usage string) *time.Duration {
|
||||
p := new(time.Duration)
|
||||
f.DurationVar(p, names, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func Duration(names []string, value time.Duration, usage string) *time.Duration {
|
||||
return CommandLine.Duration(names, value, usage)
|
||||
}
|
||||
|
||||
// Var defines a flag with the specified name and usage string. The type and
|
||||
// value of the flag are represented by the first argument, of type Value, which
|
||||
// typically holds a user-defined implementation of Value. For instance, the
|
||||
// caller could create a flag that turns a comma-separated string into a slice
|
||||
// of strings by giving the slice the methods of Value; in particular, Set would
|
||||
// decompose the comma-separated string into the slice.
|
||||
func (f *FlagSet) Var(value Value, names []string, usage string) {
|
||||
// Remember the default value as a string; it won't change.
|
||||
flag := &Flag{names, usage, value, value.String()}
|
||||
for _, name := range names {
|
||||
name = strings.TrimPrefix(name, "#")
|
||||
_, alreadythere := f.formal[name]
|
||||
if alreadythere {
|
||||
var msg string
|
||||
if f.name == "" {
|
||||
msg = fmt.Sprintf("flag redefined: %s", name)
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s flag redefined: %s", f.name, name)
|
||||
}
|
||||
fmt.Fprintln(f.out(), msg)
|
||||
panic(msg) // Happens only if flags are declared with identical names
|
||||
}
|
||||
if f.formal == nil {
|
||||
f.formal = make(map[string]*Flag)
|
||||
}
|
||||
f.formal[name] = flag
|
||||
}
|
||||
}
|
||||
|
||||
// Var defines a flag with the specified name and usage string. The type and
|
||||
// value of the flag are represented by the first argument, of type Value, which
|
||||
// typically holds a user-defined implementation of Value. For instance, the
|
||||
// caller could create a flag that turns a comma-separated string into a slice
|
||||
// of strings by giving the slice the methods of Value; in particular, Set would
|
||||
// decompose the comma-separated string into the slice.
|
||||
func Var(value Value, names []string, usage string) {
|
||||
CommandLine.Var(value, names, usage)
|
||||
}
|
||||
|
||||
// failf prints to standard error a formatted error and usage message and
|
||||
// returns the error.
|
||||
func (f *FlagSet) failf(format string, a ...interface{}) error {
|
||||
err := fmt.Errorf(format, a...)
|
||||
fmt.Fprintln(f.out(), err)
|
||||
f.usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// usage calls the Usage method for the flag set, or the usage function if
|
||||
// the flag set is CommandLine.
|
||||
func (f *FlagSet) usage() {
|
||||
if f == CommandLine {
|
||||
Usage()
|
||||
} else if f.Usage == nil {
|
||||
defaultUsage(f)
|
||||
} else {
|
||||
f.Usage()
|
||||
}
|
||||
}
|
||||
|
||||
// parseOne parses one flag. It reports whether a flag was seen.
|
||||
func (f *FlagSet) parseOne() (bool, error) {
|
||||
if len(f.args) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
s := f.args[0]
|
||||
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
|
||||
return false, nil
|
||||
}
|
||||
if s[1] == '-' && len(s) == 2 { // "--" terminates the flags
|
||||
f.args = f.args[1:]
|
||||
return false, nil
|
||||
}
|
||||
name := s[1:]
|
||||
if len(name) == 0 || name[0] == '=' {
|
||||
return false, f.failf("bad flag syntax: %s", s)
|
||||
}
|
||||
|
||||
// it's a flag. does it have an argument?
|
||||
f.args = f.args[1:]
|
||||
has_value := false
|
||||
value := ""
|
||||
for i := 1; i < len(name); i++ { // equals cannot be first
|
||||
if name[i] == '=' {
|
||||
value = name[i+1:]
|
||||
has_value = true
|
||||
name = name[0:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
m := f.formal
|
||||
flag, alreadythere := m[name] // BUG
|
||||
if !alreadythere {
|
||||
if name == "-help" || name == "help" || name == "h" { // special case for nice help message.
|
||||
f.usage()
|
||||
return false, ErrHelp
|
||||
}
|
||||
return false, f.failf("flag provided but not defined: -%s", name)
|
||||
}
|
||||
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
|
||||
if has_value {
|
||||
if err := fv.Set(value); err != nil {
|
||||
return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
|
||||
}
|
||||
} else {
|
||||
fv.Set("true")
|
||||
}
|
||||
} else {
|
||||
// It must have a value, which might be the next argument.
|
||||
if !has_value && len(f.args) > 0 {
|
||||
// value is the next arg
|
||||
has_value = true
|
||||
value, f.args = f.args[0], f.args[1:]
|
||||
}
|
||||
if !has_value {
|
||||
return false, f.failf("flag needs an argument: -%s", name)
|
||||
}
|
||||
if err := flag.Value.Set(value); err != nil {
|
||||
return false, f.failf("invalid value %q for flag -%s: %v", value, name, err)
|
||||
}
|
||||
}
|
||||
if f.actual == nil {
|
||||
f.actual = make(map[string]*Flag)
|
||||
}
|
||||
f.actual[name] = flag
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Parse parses flag definitions from the argument list, which should not
|
||||
// include the command name. Must be called after all flags in the FlagSet
|
||||
// are defined and before flags are accessed by the program.
|
||||
// The return value will be ErrHelp if -help was set but not defined.
|
||||
func (f *FlagSet) Parse(arguments []string) error {
|
||||
f.parsed = true
|
||||
f.args = arguments
|
||||
for {
|
||||
seen, err := f.parseOne()
|
||||
if seen {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
switch f.errorHandling {
|
||||
case ContinueOnError:
|
||||
return err
|
||||
case ExitOnError:
|
||||
os.Exit(2)
|
||||
case PanicOnError:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parsed reports whether f.Parse has been called.
|
||||
func (f *FlagSet) Parsed() bool {
|
||||
return f.parsed
|
||||
}
|
||||
|
||||
// Parse parses the command-line flags from os.Args[1:]. Must be called
|
||||
// after all flags are defined and before flags are accessed by the program.
|
||||
func Parse() {
|
||||
// Ignore errors; CommandLine is set for ExitOnError.
|
||||
CommandLine.Parse(os.Args[1:])
|
||||
}
|
||||
|
||||
// Parsed returns true if the command-line flags have been parsed.
|
||||
func Parsed() bool {
|
||||
return CommandLine.Parsed()
|
||||
}
|
||||
|
||||
// CommandLine is the default set of command-line flags, parsed from os.Args.
|
||||
// The top-level functions such as BoolVar, Arg, and on are wrappers for the
|
||||
// methods of CommandLine.
|
||||
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
|
||||
|
||||
// NewFlagSet returns a new, empty flag set with the specified name and
|
||||
// error handling property.
|
||||
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
|
||||
f := &FlagSet{
|
||||
name: name,
|
||||
errorHandling: errorHandling,
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Init sets the name and error handling property for a flag set.
|
||||
// By default, the zero FlagSet uses an empty name and the
|
||||
// ContinueOnError error handling policy.
|
||||
func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
|
||||
f.name = name
|
||||
f.errorHandling = errorHandling
|
||||
}
|
377
pkg/mflag/flag_test.go
Normal file
377
pkg/mflag/flag_test.go
Normal file
|
@ -0,0 +1,377 @@
|
|||
// Copyright 2014 The Docker & Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mflag_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
. "github.com/dotcloud/docker/pkg/mflag"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func boolString(s string) string {
|
||||
if s == "0" {
|
||||
return "false"
|
||||
}
|
||||
return "true"
|
||||
}
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
ResetForTesting(nil)
|
||||
Bool([]string{"test_bool"}, false, "bool value")
|
||||
Int([]string{"test_int"}, 0, "int value")
|
||||
Int64([]string{"test_int64"}, 0, "int64 value")
|
||||
Uint([]string{"test_uint"}, 0, "uint value")
|
||||
Uint64([]string{"test_uint64"}, 0, "uint64 value")
|
||||
String([]string{"test_string"}, "0", "string value")
|
||||
Float64([]string{"test_float64"}, 0, "float64 value")
|
||||
Duration([]string{"test_duration"}, 0, "time.Duration value")
|
||||
|
||||
m := make(map[string]*Flag)
|
||||
desired := "0"
|
||||
visitor := func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
if len(name) > 5 && name[0:5] == "test_" {
|
||||
m[name] = f
|
||||
ok := false
|
||||
switch {
|
||||
case f.Value.String() == desired:
|
||||
ok = true
|
||||
case name == "test_bool" && f.Value.String() == boolString(desired):
|
||||
ok = true
|
||||
case name == "test_duration" && f.Value.String() == desired+"s":
|
||||
ok = true
|
||||
}
|
||||
if !ok {
|
||||
t.Error("Visit: bad value", f.Value.String(), "for", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VisitAll(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("VisitAll misses some flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
m = make(map[string]*Flag)
|
||||
Visit(visitor)
|
||||
if len(m) != 0 {
|
||||
t.Errorf("Visit sees unset flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now set all flags
|
||||
Set("test_bool", "true")
|
||||
Set("test_int", "1")
|
||||
Set("test_int64", "1")
|
||||
Set("test_uint", "1")
|
||||
Set("test_uint64", "1")
|
||||
Set("test_string", "1")
|
||||
Set("test_float64", "1")
|
||||
Set("test_duration", "1s")
|
||||
desired = "1"
|
||||
Visit(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("Visit fails after set")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now test they're visited in sort order.
|
||||
var flagNames []string
|
||||
Visit(func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
flagNames = append(flagNames, name)
|
||||
}
|
||||
})
|
||||
if !sort.StringsAreSorted(flagNames) {
|
||||
t.Errorf("flag names not sorted: %v", flagNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
ResetForTesting(nil)
|
||||
Bool([]string{"test_bool"}, true, "bool value")
|
||||
Int([]string{"test_int"}, 1, "int value")
|
||||
Int64([]string{"test_int64"}, 2, "int64 value")
|
||||
Uint([]string{"test_uint"}, 3, "uint value")
|
||||
Uint64([]string{"test_uint64"}, 4, "uint64 value")
|
||||
String([]string{"test_string"}, "5", "string value")
|
||||
Float64([]string{"test_float64"}, 6, "float64 value")
|
||||
Duration([]string{"test_duration"}, 7, "time.Duration value")
|
||||
|
||||
visitor := func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
if len(name) > 5 && name[0:5] == "test_" {
|
||||
g, ok := f.Value.(Getter)
|
||||
if !ok {
|
||||
t.Errorf("Visit: value does not satisfy Getter: %T", f.Value)
|
||||
return
|
||||
}
|
||||
switch name {
|
||||
case "test_bool":
|
||||
ok = g.Get() == true
|
||||
case "test_int":
|
||||
ok = g.Get() == int(1)
|
||||
case "test_int64":
|
||||
ok = g.Get() == int64(2)
|
||||
case "test_uint":
|
||||
ok = g.Get() == uint(3)
|
||||
case "test_uint64":
|
||||
ok = g.Get() == uint64(4)
|
||||
case "test_string":
|
||||
ok = g.Get() == "5"
|
||||
case "test_float64":
|
||||
ok = g.Get() == float64(6)
|
||||
case "test_duration":
|
||||
ok = g.Get() == time.Duration(7)
|
||||
}
|
||||
if !ok {
|
||||
t.Errorf("Visit: bad value %T(%v) for %s", g.Get(), g.Get(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
boolFlag := f.Bool([]string{"bool"}, false, "bool value")
|
||||
bool2Flag := f.Bool([]string{"bool2"}, false, "bool2 value")
|
||||
intFlag := f.Int([]string{"-int"}, 0, "int value")
|
||||
int64Flag := f.Int64([]string{"-int64"}, 0, "int64 value")
|
||||
uintFlag := f.Uint([]string{"uint"}, 0, "uint value")
|
||||
uint64Flag := f.Uint64([]string{"-uint64"}, 0, "uint64 value")
|
||||
stringFlag := f.String([]string{"string"}, "0", "string value")
|
||||
float64Flag := f.Float64([]string{"float64"}, 0, "float64 value")
|
||||
durationFlag := f.Duration([]string{"duration"}, 5*time.Second, "time.Duration value")
|
||||
extra := "one-extra-argument"
|
||||
args := []string{
|
||||
"-bool",
|
||||
"-bool2=true",
|
||||
"--int", "22",
|
||||
"--int64", "0x23",
|
||||
"-uint", "24",
|
||||
"--uint64", "25",
|
||||
"-string", "hello",
|
||||
"-float64", "2718e28",
|
||||
"-duration", "2m",
|
||||
extra,
|
||||
}
|
||||
if err := f.Parse(args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f.Parsed() {
|
||||
t.Error("f.Parse() = false after Parse")
|
||||
}
|
||||
if *boolFlag != true {
|
||||
t.Error("bool flag should be true, is ", *boolFlag)
|
||||
}
|
||||
if *bool2Flag != true {
|
||||
t.Error("bool2 flag should be true, is ", *bool2Flag)
|
||||
}
|
||||
if *intFlag != 22 {
|
||||
t.Error("int flag should be 22, is ", *intFlag)
|
||||
}
|
||||
if *int64Flag != 0x23 {
|
||||
t.Error("int64 flag should be 0x23, is ", *int64Flag)
|
||||
}
|
||||
if *uintFlag != 24 {
|
||||
t.Error("uint flag should be 24, is ", *uintFlag)
|
||||
}
|
||||
if *uint64Flag != 25 {
|
||||
t.Error("uint64 flag should be 25, is ", *uint64Flag)
|
||||
}
|
||||
if *stringFlag != "hello" {
|
||||
t.Error("string flag should be `hello`, is ", *stringFlag)
|
||||
}
|
||||
if *float64Flag != 2718e28 {
|
||||
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
||||
}
|
||||
if *durationFlag != 2*time.Minute {
|
||||
t.Error("duration flag should be 2m, is ", *durationFlag)
|
||||
}
|
||||
if len(f.Args()) != 1 {
|
||||
t.Error("expected one argument, got", len(f.Args()))
|
||||
} else if f.Args()[0] != extra {
|
||||
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ResetForTesting(func() { t.Error("bad parse") })
|
||||
testParse(CommandLine, t)
|
||||
}
|
||||
|
||||
func TestFlagSetParse(t *testing.T) {
|
||||
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||
}
|
||||
|
||||
// Declare a user-defined flag type.
|
||||
type flagVar []string
|
||||
|
||||
func (f *flagVar) String() string {
|
||||
return fmt.Sprint([]string(*f))
|
||||
}
|
||||
|
||||
func (f *flagVar) Set(value string) error {
|
||||
*f = append(*f, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestUserDefined(t *testing.T) {
|
||||
var flags FlagSet
|
||||
flags.Init("test", ContinueOnError)
|
||||
var v flagVar
|
||||
flags.Var(&v, []string{"v"}, "usage")
|
||||
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(v) != 3 {
|
||||
t.Fatal("expected 3 args; got ", len(v))
|
||||
}
|
||||
expect := "[1 2 3]"
|
||||
if v.String() != expect {
|
||||
t.Errorf("expected value %q got %q", expect, v.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Declare a user-defined boolean flag type.
|
||||
type boolFlagVar struct {
|
||||
count int
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) String() string {
|
||||
return fmt.Sprintf("%d", b.count)
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) Set(value string) error {
|
||||
if value == "true" {
|
||||
b.count++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) IsBoolFlag() bool {
|
||||
return b.count < 4
|
||||
}
|
||||
|
||||
func TestUserDefinedBool(t *testing.T) {
|
||||
var flags FlagSet
|
||||
flags.Init("test", ContinueOnError)
|
||||
var b boolFlagVar
|
||||
var err error
|
||||
flags.Var(&b, []string{"b"}, "usage")
|
||||
if err = flags.Parse([]string{"-b", "-b", "-b", "-b=true", "-b=false", "-b", "barg", "-b"}); err != nil {
|
||||
if b.count < 4 {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if b.count != 4 {
|
||||
t.Errorf("want: %d; got: %d", 4, b.count)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Error("expected error; got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetOutput(t *testing.T) {
|
||||
var flags FlagSet
|
||||
var buf bytes.Buffer
|
||||
flags.SetOutput(&buf)
|
||||
flags.Init("test", ContinueOnError)
|
||||
flags.Parse([]string{"-unknown"})
|
||||
if out := buf.String(); !strings.Contains(out, "-unknown") {
|
||||
t.Logf("expected output mentioning unknown; got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
// This tests that one can reset the flags. This still works but not well, and is
|
||||
// superseded by FlagSet.
|
||||
func TestChangingArgs(t *testing.T) {
|
||||
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
oldArgs := os.Args
|
||||
defer func() { os.Args = oldArgs }()
|
||||
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
|
||||
before := Bool([]string{"before"}, false, "")
|
||||
if err := CommandLine.Parse(os.Args[1:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := Arg(0)
|
||||
os.Args = Args()
|
||||
after := Bool([]string{"after"}, false, "")
|
||||
Parse()
|
||||
args := Args()
|
||||
|
||||
if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
|
||||
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that -help invokes the usage message and returns ErrHelp.
|
||||
func TestHelp(t *testing.T) {
|
||||
var helpCalled = false
|
||||
fs := NewFlagSet("help test", ContinueOnError)
|
||||
fs.Usage = func() { helpCalled = true }
|
||||
var flag bool
|
||||
fs.BoolVar(&flag, []string{"flag"}, false, "regular flag")
|
||||
// Regular flag invocation should work
|
||||
err := fs.Parse([]string{"-flag=true"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got ", err)
|
||||
}
|
||||
if !flag {
|
||||
t.Error("flag was not set by -flag")
|
||||
}
|
||||
if helpCalled {
|
||||
t.Error("help called for regular flag")
|
||||
helpCalled = false // reset for next test
|
||||
}
|
||||
// Help flag should work as expected.
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err == nil {
|
||||
t.Fatal("error expected")
|
||||
}
|
||||
if err != ErrHelp {
|
||||
t.Fatal("expected ErrHelp; got ", err)
|
||||
}
|
||||
if !helpCalled {
|
||||
t.Fatal("help was not called")
|
||||
}
|
||||
// If we define a help flag, that should override.
|
||||
var help bool
|
||||
fs.BoolVar(&help, []string{"help"}, false, "help flag")
|
||||
helpCalled = false
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error for defined -help; got ", err)
|
||||
}
|
||||
if helpCalled {
|
||||
t.Fatal("help was called; should not have been for defined help flag")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue