diff --git a/api/client/commands.go b/api/client/commands.go index 4b7157b80d..38df26650f 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1872,14 +1872,40 @@ func (cli *DockerCli) CmdEvents(args ...string) error { } func (cli *DockerCli) CmdExport(args ...string) error { - cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true) + cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true) + outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT") cmd.Require(flag.Exact, 1) utils.ParseFlags(cmd, args, true) - if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil { - return err + var ( + output io.Writer = cli.out + err error + ) + if *outfile != "" { + output, err = os.Create(*outfile) + if err != nil { + return err + } + } else if cli.isTerminalOut { + return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.") } + + if len(cmd.Args()) == 1 { + image := cmd.Arg(0) + if err := cli.stream("GET", "/containers/"+image+"/export", nil, output, nil); err != nil { + return err + } + } else { + v := url.Values{} + for _, arg := range cmd.Args() { + v.Add("names", arg) + } + if err := cli.stream("GET", "/containers/get?"+v.Encode(), nil, output, nil); err != nil { + return err + } + } + return nil } diff --git a/docs/man/docker-export.1.md b/docs/man/docker-export.1.md index 226ae5c1d5..df69bc37d8 100644 --- a/docs/man/docker-export.1.md +++ b/docs/man/docker-export.1.md @@ -14,17 +14,24 @@ Export the contents of a container's filesystem using the full or shortened container ID or container name. The output is exported to STDOUT and can be redirected to a tar file. +Stream to a file instead of STDOUT by using **-o**. + # OPTIONS **--help** Print usage statement +**-o**, **--output**="" + Write to a file, instead of STDOUT # EXAMPLES Export the contents of the container called angry_bell to a tar file -called test.tar: +called angry_bell.tar: - # docker export angry_bell > test.tar - # ls *.tar - test.tar + # docker export angry_bell > angry_bell.tar + # docker export --output=angry_bell-latest.tar angry_bell + # ls -sh angry_bell.tar + 321M angry_bell.tar + # ls -sh angry_bell-latest.tar + 321M angry_bell-latest.tar # See also **docker-import(1)** to create an empty filesystem image @@ -34,3 +41,4 @@ and import the contents of the tarball into it, then optionally tag it. April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.com source material and internal work. June 2014, updated by Sven Dowideit +Janurary 2015, updated by Joseph Kern (josephakern at gmail dot com) diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 6b2d7c1bdd..cbba196168 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -1066,14 +1066,22 @@ This will create a new Bash session in the container `ubuntu_bash`. ## export - Usage: docker export CONTAINER + Usage: docker export [OPTIONS] CONTAINER - Export the contents of a filesystem as a tar archive to STDOUT + Export the contents of a filesystem to a tar archive (streamed to STDOUT by default) -For example: + -o, --output="" Write to a file, instead of STDOUT + + Produces a tarred repository to the standard output stream. + + For example: $ sudo docker export red_panda > latest.tar + Or + + $ sudo docker export --output="latest.tar" red_panda + > **Note:** > `docker export` does not export the contents of volumes associated with the > container. If a volume is mounted on top of an existing directory in the diff --git a/integration-cli/docker_cli_export_import_test.go b/integration-cli/docker_cli_export_import_test.go index 224bb95bbf..2793797bbd 100644 --- a/integration-cli/docker_cli_export_import_test.go +++ b/integration-cli/docker_cli_export_import_test.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "os" "os/exec" "strings" "testing" @@ -47,3 +49,49 @@ func TestExportContainerAndImportImage(t *testing.T) { logDone("export - export a container") logDone("import - import an image") } + +// Used to test output flag in the export command +func TestExportContainerWithOutputAndImportImage(t *testing.T) { + runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") + out, _, err := runCommandWithOutput(runCmd) + if err != nil { + t.Fatal("failed to create a container", out, err) + } + + cleanedContainerID := stripTrailingCharacters(out) + + inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID) + out, _, err = runCommandWithOutput(inspectCmd) + if err != nil { + t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err) + } + + exportCmdTemplate := `%v export --output=/tmp/testexp.tar %v` + exportCmdFinal := fmt.Sprintf(exportCmdTemplate, dockerBinary, cleanedContainerID) + exportCmd := exec.Command(exportCmdFinal) + if out, _, err = runCommandWithOutput(exportCmd); err != nil { + t.Fatalf("failed to export container: %s, %v", out, err) + } + + importCmdFinal := `cat /tmp/testexp.tar | docker import - repo/testexp:v1` + importCmd := exec.Command(importCmdFinal) + out, _, err = runCommandWithOutput(importCmd) + if err != nil { + t.Fatalf("failed to import image: %s, %v", out, err) + } + + cleanedImageID := stripTrailingCharacters(out) + + inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID) + if out, _, err = runCommandWithOutput(inspectCmd); err != nil { + t.Fatalf("output should've been an image id: %s, %v", out, err) + } + + deleteContainer(cleanedContainerID) + deleteImages("repo/testexp:v1") + + os.Remove("/tmp/testexp.tar") + + logDone("export - export a container with output flag") + logDone("import - import an image with output flag") +}