Browse code

docker tar: stream the contents of a container as a tar archive

Solomon Hykes authored on 2013/01/27 17:59:49
Showing 3 changed files
... ...
@@ -39,6 +39,7 @@ func (srv *Server) Help() string {
39 39
 		{"commit", "Save the state of a container"},
40 40
 		{"attach", "Attach to the standard inputs and outputs of a running container"},
41 41
 		{"info", "Display system-wide information"},
42
+		{"tar", "Stream the contents of a container as a tar archive"},
42 43
 		{"web", "Generate a web UI"},
43 44
 	} {
44 45
 		help += fmt.Sprintf("    %-10.10s%s\n", cmd...)
... ...
@@ -233,9 +234,16 @@ func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string)
233 233
 		return nil
234 234
 	}
235 235
 	name := flags.Arg(0)
236
-	if _, exists := srv.findContainer(name); exists {
236
+	if container, exists := srv.findContainer(name); exists {
237
+		data, err := container.Filesystem.Tar()
238
+		if err != nil {
239
+			return err
240
+		}
237 241
 		// Stream the entire contents of the container (basically a volatile snapshot)
238
-		return fake.WriteFakeTar(stdout)
242
+		if _, err := io.Copy(stdout, data); err != nil {
243
+			return err
244
+		}
245
+		return nil
239 246
 	}
240 247
 	return errors.New("No such container: " + name)
241 248
 }
... ...
@@ -67,6 +67,24 @@ func (fs *Filesystem) IsMounted() bool {
67 67
 	return false
68 68
 }
69 69
 
70
+// Tar returns the contents of the filesystem as an uncompressed tar stream
71
+func (fs *Filesystem) Tar() (io.Reader, error) {
72
+	if err := fs.EnsureMounted(); err != nil {
73
+		return nil, err
74
+	}
75
+	return Tar(fs.RootFS)
76
+}
77
+
78
+
79
+func (fs *Filesystem) EnsureMounted() error {
80
+	if !fs.IsMounted() {
81
+		if err := fs.Mount(); err != nil {
82
+			return err
83
+		}
84
+	}
85
+	return nil
86
+}
87
+
70 88
 type ChangeType int
71 89
 
72 90
 const (
... ...
@@ -5,8 +5,28 @@ import (
5 5
 	"container/list"
6 6
 	"io"
7 7
 	"sync"
8
+	"os/exec"
8 9
 )
9 10
 
11
+// Tar generates a tar archive from a filesystem path, and returns it as a stream.
12
+// Path must point to a directory.
13
+
14
+func Tar(path string) (io.Reader, error) {
15
+	cmd := exec.Command("tar", "-C", path, "-c", ".")
16
+	output, err := cmd.StdoutPipe()
17
+	if err != nil {
18
+		return nil, err
19
+	}
20
+	if err := cmd.Start(); err != nil {
21
+		return nil, err
22
+	}
23
+	// FIXME: errors will not be passed because we don't wait for the command.
24
+	// Instead, consumers will hit EOF right away.
25
+	// This can be fixed by waiting for the process to exit, or for the first write
26
+	// on stdout, whichever comes first.
27
+	return output, nil
28
+}
29
+
10 30
 type nopWriteCloser struct {
11 31
 	io.Writer
12 32
 }