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)
This commit is contained in:
Erik Hollensbe 2014-09-11 06:27:51 -07:00
Родитель 32b5d145fa
Коммит a5ca549a18
7 изменённых файлов: 47 добавлений и 13 удалений

Просмотреть файл

@ -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 // Expose the volume /foo for use. Will also accept the JSON array form.
// way requires exactly one argument.
// //
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

Просмотреть файл

@ -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)
}

Просмотреть файл

@ -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,
} }
} }

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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 string with multiple arguments, such as `VOLUME /var/log` or `VOLUME /var/log
instructions via the Docker client, refer to [*Share Directories via Volumes*]( /var/db`. For more information/examples and mounting instructions via the
/userguide/dockervolumes/#volume-def) documentation. Docker client, refer to [*Share Directories via Volumes*](/userguide/dockervolumes/#volume-def)
documentation.
## USER ## USER

Просмотреть файл

@ -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)