Browse code

Merge pull request #7994 from erikh/parser_fix_volume_parsing

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

Tibor Vass authored on 2014/09/26 01:45:48
Showing 7 changed files
... ...
@@ -314,23 +314,20 @@ func user(b *Builder, args []string, attributes map[string]bool) error {
314 314
 
315 315
 // VOLUME /foo
316 316
 //
317
-// Expose the volume /foo for use. Will also accept the JSON form, but either
318
-// way requires exactly one argument.
317
+// Expose the volume /foo for use. Will also accept the JSON array form.
319 318
 //
320 319
 func volume(b *Builder, args []string, attributes map[string]bool) error {
321
-	if len(args) != 1 {
320
+	if len(args) == 0 {
322 321
 		return fmt.Errorf("Volume cannot be empty")
323 322
 	}
324 323
 
325
-	volume := args
326
-
327 324
 	if b.Config.Volumes == nil {
328 325
 		b.Config.Volumes = map[string]struct{}{}
329 326
 	}
330
-	for _, v := range volume {
327
+	for _, v := range args {
331 328
 		b.Config.Volumes[v] = struct{}{}
332 329
 	}
333
-	if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %s", args)); err != nil {
330
+	if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
334 331
 		return err
335 332
 	}
336 333
 	return nil
... ...
@@ -135,3 +135,21 @@ func parseMaybeJSON(rest string) (*Node, map[string]bool, error) {
135 135
 	node.Value = rest
136 136
 	return node, nil, nil
137 137
 }
138
+
139
+// parseMaybeJSONToList determines if the argument appears to be a JSON array. If
140
+// so, passes to parseJSON; if not, attmpts to parse it as a whitespace
141
+// delimited string.
142
+func parseMaybeJSONToList(rest string) (*Node, map[string]bool, error) {
143
+	rest = strings.TrimSpace(rest)
144
+
145
+	node, attrs, err := parseJSON(rest)
146
+
147
+	if err == nil {
148
+		return node, attrs, nil
149
+	}
150
+	if err == errDockerfileJSONNesting {
151
+		return nil, nil, err
152
+	}
153
+
154
+	return parseStringsWhitespaceDelimited(rest)
155
+}
... ...
@@ -55,7 +55,7 @@ func init() {
55 55
 		"cmd":            parseMaybeJSON,
56 56
 		"entrypoint":     parseMaybeJSON,
57 57
 		"expose":         parseStringsWhitespaceDelimited,
58
-		"volume":         parseMaybeJSON,
58
+		"volume":         parseMaybeJSONToList,
59 59
 		"insert":         parseIgnore,
60 60
 	}
61 61
 }
62 62
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+FROM foo
1
+
2
+VOLUME /opt/nagios/var /opt/nagios/etc /opt/nagios/libexec /var/log/apache2 /usr/share/snmp/mibs
0 3
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+(from "foo")
1
+(volume "/opt/nagios/var" "/opt/nagios/etc" "/opt/nagios/libexec" "/var/log/apache2" "/usr/share/snmp/mibs")
... ...
@@ -472,9 +472,10 @@ optional but default, you could use a `CMD` instruction:
472 472
 The `VOLUME` instruction will create a mount point with the specified name
473 473
 and mark it as holding externally mounted volumes from native host or other
474 474
 containers. The value can be a JSON array, `VOLUME ["/var/log/"]`, or a plain
475
-string, `VOLUME /var/log`. For more information/examples and mounting
476
-instructions via the Docker client, refer to [*Share Directories via Volumes*](
477
-/userguide/dockervolumes/#volume-def) documentation.
475
+string with multiple arguments, such as `VOLUME /var/log` or `VOLUME /var/log
476
+/var/db`.  For more information/examples and mounting instructions via the
477
+Docker client, refer to [*Share Directories via Volumes*](/userguide/dockervolumes/#volume-def)
478
+documentation.
478 479
 
479 480
 > **Note**:
480 481
 > The list is parsed a JSON array, which means that
... ...
@@ -728,13 +728,26 @@ func TestBuildWithVolumes(t *testing.T) {
728 728
 		result   map[string]map[string]struct{}
729 729
 		name     = "testbuildvolumes"
730 730
 		emptyMap = make(map[string]struct{})
731
-		expected = map[string]map[string]struct{}{"/test1": emptyMap, "/test2": emptyMap}
731
+		expected = map[string]map[string]struct{}{
732
+			"/test1":  emptyMap,
733
+			"/test2":  emptyMap,
734
+			"/test3":  emptyMap,
735
+			"/test4":  emptyMap,
736
+			"/test5":  emptyMap,
737
+			"/test6":  emptyMap,
738
+			"[/test7": emptyMap,
739
+			"/test8]": emptyMap,
740
+		}
732 741
 	)
733 742
 	defer deleteImages(name)
734 743
 	_, err := buildImage(name,
735 744
 		`FROM scratch
736 745
 		VOLUME /test1
737
-		VOLUME /test2`,
746
+		VOLUME /test2
747
+    VOLUME /test3 /test4
748
+    VOLUME ["/test5", "/test6"]
749
+    VOLUME [/test7 /test8]
750
+    `,
738 751
 		true)
739 752
 	if err != nil {
740 753
 		t.Fatal(err)