From 5ff122f79713f177c07dbc43bb81f991243472d5 Mon Sep 17 00:00:00 2001 From: Joseph Kern Date: Fri, 19 Dec 2014 13:25:33 +0300 Subject: [PATCH 1/2] Modified `docker export` to allow an --output flag Copied code from CmdSave into CmdExport. This should work, not an expert in the API calls being made. But it does make more sense to have a consistent export/save flag. Signed-off-by: Joseph Kern checkpoint before edits on the export functions Signed-off-by: Joseph Kern Added an --output flag to docker export and created tests. Signed-off-by: Joseph Kern White space cleanup. Signed-off-by: Joseph Kern Docker-DCO-1.1-Signed-off-by: Joseph Kern (github: jfrazelle) checkpoint before edits on the export functions Signed-off-by: Joseph Kern White space cleanup. Signed-off-by: Joseph Kern Added text to reflect a new output option for the export command. Signed-off-by: Joseph Kern Whitespace clean up Signed-off-by: Joseph Kern Added man page documentation for the new --output flag in export Signed-off-by: Joseph Kern --- api/client/commands.go | 32 +++++++++++-- docs/man/docker-export.1.md | 16 +++++-- docs/sources/reference/commandline/cli.md | 14 ++++-- .../docker_cli_export_import_test.go | 48 +++++++++++++++++++ 4 files changed, 100 insertions(+), 10 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index 4b7157b80d8e7..38df26650fb0a 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 226ae5c1d57d6..df69bc37d8055 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 6b2d7c1bdd54f..cbba19616845b 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 224bb95bbfa2c..2793797bbde07 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") +} From 6a313e81ccfada1f8266a521ba480b3e7764754f Mon Sep 17 00:00:00 2001 From: Jessica Frazelle Date: Tue, 17 Mar 2015 00:36:56 -0700 Subject: [PATCH 2/2] fix TestExportContainerWithOutputAndImportImage on windows Docker-DCO-1.1-Signed-off-by: Jessica Frazelle (github: jfrazelle) --- integration-cli/docker_cli_export_import_test.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/integration-cli/docker_cli_export_import_test.go b/integration-cli/docker_cli_export_import_test.go index 2793797bbde07..5b2a016f14fbc 100644 --- a/integration-cli/docker_cli_export_import_test.go +++ b/integration-cli/docker_cli_export_import_test.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "os/exec" "strings" @@ -66,15 +65,18 @@ func TestExportContainerWithOutputAndImportImage(t *testing.T) { 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) + exportCmd := exec.Command(dockerBinary, "export", "--output=testexp.tar", cleanedContainerID) 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(exec.Command("cat", "testexp.tar")) + if err != nil { + t.Fatal(out, err) + } + + importCmd := exec.Command(dockerBinary, "import", "-", "repo/testexp:v1") + importCmd.Stdin = strings.NewReader(out) out, _, err = runCommandWithOutput(importCmd) if err != nil { t.Fatalf("failed to import image: %s, %v", out, err)