Browse code

Merge pull request #11430 from jfrazelle/export_outputflag

Modified `docker export` to allow an --output flag

Tibor Vass authored on 2015/03/19 08:04:43
Showing 4 changed files
... ...
@@ -1899,14 +1899,40 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
1899 1899
 }
1900 1900
 
1901 1901
 func (cli *DockerCli) CmdExport(args ...string) error {
1902
-	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
1902
+	cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
1903
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
1903 1904
 	cmd.Require(flag.Exact, 1)
1904 1905
 
1905 1906
 	utils.ParseFlags(cmd, args, true)
1906 1907
 
1907
-	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
1908
-		return err
1908
+	var (
1909
+		output io.Writer = cli.out
1910
+		err    error
1911
+	)
1912
+	if *outfile != "" {
1913
+		output, err = os.Create(*outfile)
1914
+		if err != nil {
1915
+			return err
1916
+		}
1917
+	} else if cli.isTerminalOut {
1918
+		return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
1919
+	}
1920
+
1921
+	if len(cmd.Args()) == 1 {
1922
+		image := cmd.Arg(0)
1923
+		if err := cli.stream("GET", "/containers/"+image+"/export", nil, output, nil); err != nil {
1924
+			return err
1925
+		}
1926
+	} else {
1927
+		v := url.Values{}
1928
+		for _, arg := range cmd.Args() {
1929
+			v.Add("names", arg)
1930
+		}
1931
+		if err := cli.stream("GET", "/containers/get?"+v.Encode(), nil, output, nil); err != nil {
1932
+			return err
1933
+		}
1909 1934
 	}
1935
+
1910 1936
 	return nil
1911 1937
 }
1912 1938
 
... ...
@@ -14,17 +14,24 @@ Export the contents of a container's filesystem using the full or shortened
14 14
 container ID or container name. The output is exported to STDOUT and can be
15 15
 redirected to a tar file.
16 16
 
17
+Stream to a file instead of STDOUT by using **-o**.
18
+
17 19
 # OPTIONS
18 20
 **--help**
19 21
   Print usage statement
22
+**-o**, **--output**=""
23
+   Write to a file, instead of STDOUT
20 24
 
21 25
 # EXAMPLES
22 26
 Export the contents of the container called angry_bell to a tar file
23
-called test.tar:
27
+called angry_bell.tar:
24 28
 
25
-    # docker export angry_bell > test.tar
26
-    # ls *.tar
27
-    test.tar
29
+    # docker export angry_bell > angry_bell.tar
30
+    # docker export --output=angry_bell-latest.tar angry_bell
31
+    # ls -sh angry_bell.tar
32
+    321M angry_bell.tar
33
+    # ls -sh angry_bell-latest.tar
34
+    321M angry_bell-latest.tar
28 35
 
29 36
 # See also
30 37
 **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.
34 34
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
35 35
 based on docker.com source material and internal work.
36 36
 June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
37
+Janurary 2015, updated by Joseph Kern (josephakern at gmail dot com)
... ...
@@ -1068,14 +1068,22 @@ This will create a new Bash session in the container `ubuntu_bash`.
1068 1068
 
1069 1069
 ## export
1070 1070
 
1071
-    Usage: docker export CONTAINER
1071
+    Usage: docker export [OPTIONS] CONTAINER
1072 1072
 
1073
-    Export the contents of a filesystem as a tar archive to STDOUT
1073
+    Export the contents of a filesystem to a tar archive (streamed to STDOUT by default)
1074 1074
 
1075
-For example:
1075
+      -o, --output=""    Write to a file, instead of STDOUT
1076
+
1077
+      Produces a tarred repository to the standard output stream.
1078
+
1079
+   For example:
1076 1080
 
1077 1081
     $ sudo docker export red_panda > latest.tar
1078 1082
 
1083
+   Or
1084
+
1085
+    $ sudo docker export --output="latest.tar" red_panda
1086
+
1079 1087
 > **Note:**
1080 1088
 > `docker export` does not export the contents of volumes associated with the
1081 1089
 > container. If a volume is mounted on top of an existing directory in the
... ...
@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"os"
4 5
 	"os/exec"
5 6
 	"strings"
6 7
 	"testing"
... ...
@@ -47,3 +48,52 @@ func TestExportContainerAndImportImage(t *testing.T) {
47 47
 	logDone("export - export a container")
48 48
 	logDone("import - import an image")
49 49
 }
50
+
51
+// Used to test output flag in the export command
52
+func TestExportContainerWithOutputAndImportImage(t *testing.T) {
53
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
54
+	out, _, err := runCommandWithOutput(runCmd)
55
+	if err != nil {
56
+		t.Fatal("failed to create a container", out, err)
57
+	}
58
+
59
+	cleanedContainerID := stripTrailingCharacters(out)
60
+
61
+	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
62
+	out, _, err = runCommandWithOutput(inspectCmd)
63
+	if err != nil {
64
+		t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err)
65
+	}
66
+
67
+	exportCmd := exec.Command(dockerBinary, "export", "--output=testexp.tar", cleanedContainerID)
68
+	if out, _, err = runCommandWithOutput(exportCmd); err != nil {
69
+		t.Fatalf("failed to export container: %s, %v", out, err)
70
+	}
71
+
72
+	out, _, err = runCommandWithOutput(exec.Command("cat", "testexp.tar"))
73
+	if err != nil {
74
+		t.Fatal(out, err)
75
+	}
76
+
77
+	importCmd := exec.Command(dockerBinary, "import", "-", "repo/testexp:v1")
78
+	importCmd.Stdin = strings.NewReader(out)
79
+	out, _, err = runCommandWithOutput(importCmd)
80
+	if err != nil {
81
+		t.Fatalf("failed to import image: %s, %v", out, err)
82
+	}
83
+
84
+	cleanedImageID := stripTrailingCharacters(out)
85
+
86
+	inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID)
87
+	if out, _, err = runCommandWithOutput(inspectCmd); err != nil {
88
+		t.Fatalf("output should've been an image id: %s, %v", out, err)
89
+	}
90
+
91
+	deleteContainer(cleanedContainerID)
92
+	deleteImages("repo/testexp:v1")
93
+
94
+	os.Remove("/tmp/testexp.tar")
95
+
96
+	logDone("export - export a container with output flag")
97
+	logDone("import - import an image with output flag")
98
+}