Browse Source

builder: Fix handling of VOLUME command where multiple volumes are
specified in a space delimited list.

Docker-DCO-1.1-Signed-off-by: Erik Hollensbe <github@hollensbe.org> (github: erikh)

Erik Hollensbe 11 years ago
parent
commit
a5ca549a18

+ 4 - 7
builder/dispatchers.go

@@ -310,23 +310,20 @@ func user(b *Builder, args []string, attributes map[string]bool) error {
 
 
 // VOLUME /foo
 // VOLUME /foo
 //
 //
-// Expose the volume /foo for use. Will also accept the JSON form, but either
-// way requires exactly one argument.
+// Expose the volume /foo for use. Will also accept the JSON array form.
 //
 //
 func volume(b *Builder, args []string, attributes map[string]bool) error {
 func volume(b *Builder, args []string, attributes map[string]bool) error {
-	if len(args) != 1 {
+	if len(args) == 0 {
 		return fmt.Errorf("Volume cannot be empty")
 		return fmt.Errorf("Volume cannot be empty")
 	}
 	}
 
 
-	volume := args
-
 	if b.Config.Volumes == nil {
 	if b.Config.Volumes == nil {
 		b.Config.Volumes = map[string]struct{}{}
 		b.Config.Volumes = map[string]struct{}{}
 	}
 	}
-	for _, v := range volume {
+	for _, v := range args {
 		b.Config.Volumes[v] = struct{}{}
 		b.Config.Volumes[v] = struct{}{}
 	}
 	}
-	if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %s", args)); err != nil {
+	if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil

+ 18 - 0
builder/parser/line_parsers.go

@@ -135,3 +135,21 @@ func parseMaybeJSON(rest string) (*Node, map[string]bool, error) {
 	node.Value = rest
 	node.Value = rest
 	return node, nil, nil
 	return node, nil, nil
 }
 }
+
+// parseMaybeJSONToList determines if the argument appears to be a JSON array. If
+// so, passes to parseJSON; if not, attmpts to parse it as a whitespace
+// delimited string.
+func parseMaybeJSONToList(rest string) (*Node, map[string]bool, error) {
+	rest = strings.TrimSpace(rest)
+
+	node, attrs, err := parseJSON(rest)
+
+	if err == nil {
+		return node, attrs, nil
+	}
+	if err == errDockerfileJSONNesting {
+		return nil, nil, err
+	}
+
+	return parseStringsWhitespaceDelimited(rest)
+}

+ 1 - 1
builder/parser/parser.go

@@ -55,7 +55,7 @@ func init() {
 		"cmd":            parseMaybeJSON,
 		"cmd":            parseMaybeJSON,
 		"entrypoint":     parseMaybeJSON,
 		"entrypoint":     parseMaybeJSON,
 		"expose":         parseStringsWhitespaceDelimited,
 		"expose":         parseStringsWhitespaceDelimited,
-		"volume":         parseMaybeJSON,
+		"volume":         parseMaybeJSONToList,
 		"insert":         parseIgnore,
 		"insert":         parseIgnore,
 	}
 	}
 }
 }

+ 3 - 0
builder/parser/testfiles/multiple-volumes/Dockerfile

@@ -0,0 +1,3 @@
+FROM foo
+
+VOLUME /opt/nagios/var /opt/nagios/etc /opt/nagios/libexec /var/log/apache2 /usr/share/snmp/mibs

+ 2 - 0
builder/parser/testfiles/multiple-volumes/result

@@ -0,0 +1,2 @@
+(from "foo")
+(volume "/opt/nagios/var" "/opt/nagios/etc" "/opt/nagios/libexec" "/var/log/apache2" "/usr/share/snmp/mibs")

+ 4 - 3
docs/sources/reference/builder.md

@@ -445,9 +445,10 @@ optional but default, you could use a `CMD` instruction:
 The `VOLUME` instruction will create a mount point with the specified name
 The `VOLUME` instruction will create a mount point with the specified name
 and mark it as holding externally mounted volumes from native host or other
 and mark it as holding externally mounted volumes from native host or other
 containers. The value can be a JSON array, `VOLUME ["/var/log/"]`, or a plain
 containers. The value can be a JSON array, `VOLUME ["/var/log/"]`, or a plain
-string, `VOLUME /var/log`. For more information/examples and mounting
-instructions via the Docker client, refer to [*Share Directories via Volumes*](
-/userguide/dockervolumes/#volume-def) documentation.
+string with multiple arguments, such as `VOLUME /var/log` or `VOLUME /var/log
+/var/db`.  For more information/examples and mounting instructions via the
+Docker client, refer to [*Share Directories via Volumes*](/userguide/dockervolumes/#volume-def)
+documentation.
 
 
 ## USER
 ## USER
 
 

+ 15 - 2
integration-cli/docker_cli_build_test.go

@@ -582,13 +582,26 @@ func TestBuildWithVolumes(t *testing.T) {
 		result   map[string]map[string]struct{}
 		result   map[string]map[string]struct{}
 		name     = "testbuildvolumes"
 		name     = "testbuildvolumes"
 		emptyMap = make(map[string]struct{})
 		emptyMap = make(map[string]struct{})
-		expected = map[string]map[string]struct{}{"/test1": emptyMap, "/test2": emptyMap}
+		expected = map[string]map[string]struct{}{
+			"/test1":  emptyMap,
+			"/test2":  emptyMap,
+			"/test3":  emptyMap,
+			"/test4":  emptyMap,
+			"/test5":  emptyMap,
+			"/test6":  emptyMap,
+			"[/test7": emptyMap,
+			"/test8]": emptyMap,
+		}
 	)
 	)
 	defer deleteImages(name)
 	defer deleteImages(name)
 	_, err := buildImage(name,
 	_, err := buildImage(name,
 		`FROM scratch
 		`FROM scratch
 		VOLUME /test1
 		VOLUME /test1
-		VOLUME /test2`,
+		VOLUME /test2
+    VOLUME /test3 /test4
+    VOLUME ["/test5", "/test6"]
+    VOLUME [/test7 /test8]
+    `,
 		true)
 		true)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)