Skip to content

Commit 8d3cfdf

Browse files
authored
Fix Dockerfile ARG parsing (#103)
1 parent bac13b6 commit 8d3cfdf

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

devcontainer/devcontainer.go

+23-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/go-git/go-billy/v5"
1616
"github.com/google/go-containerregistry/pkg/name"
1717
"github.com/google/go-containerregistry/pkg/v1/remote"
18+
"github.com/moby/buildkit/frontend/dockerfile/shell"
1819
"github.com/tailscale/hujson"
1920
)
2021

@@ -317,30 +318,43 @@ func UserFromDockerfile(dockerfileContent string) string {
317318
// ImageFromDockerfile inspects the contents of a provided Dockerfile
318319
// and returns the image that will be used to run the container.
319320
func ImageFromDockerfile(dockerfileContent string) (name.Reference, error) {
320-
args := map[string]string{}
321+
lexer := shell.NewLex('\\')
322+
var args []string
321323
var imageRef string
322324
lines := strings.Split(dockerfileContent, "\n")
323325
// Iterate over lines in reverse
324326
for i := len(lines) - 1; i >= 0; i-- {
325327
line := lines[i]
326-
if strings.HasPrefix(line, "ARG ") {
327-
arg := strings.TrimSpace(strings.TrimPrefix(line, "ARG "))
328+
if arg, ok := strings.CutPrefix(line, "ARG "); ok {
329+
arg = strings.TrimSpace(arg)
328330
if strings.Contains(arg, "=") {
329331
parts := strings.SplitN(arg, "=", 2)
330-
args[parts[0]] = parts[1]
332+
key, err := lexer.ProcessWord(parts[0], args)
333+
if err != nil {
334+
return nil, fmt.Errorf("processing %q: %w", line, err)
335+
}
336+
val, err := lexer.ProcessWord(parts[1], args)
337+
if err != nil {
338+
return nil, fmt.Errorf("processing %q: %w", line, err)
339+
}
340+
args = append(args, key+"="+val)
331341
}
332342
continue
333343
}
334-
if imageRef == "" && strings.HasPrefix(line, "FROM ") {
335-
imageRef = strings.TrimPrefix(line, "FROM ")
344+
if imageRef == "" {
345+
if fromArgs, ok := strings.CutPrefix(line, "FROM "); ok {
346+
imageRef = fromArgs
347+
}
336348
}
337349
}
338350
if imageRef == "" {
339351
return nil, fmt.Errorf("no FROM directive found")
340352
}
341-
image, err := name.ParseReference(os.Expand(imageRef, func(s string) string {
342-
return args[s]
343-
}))
353+
imageRef, err := lexer.ProcessWord(imageRef, args)
354+
if err != nil {
355+
return nil, fmt.Errorf("processing %q: %w", imageRef, err)
356+
}
357+
image, err := name.ParseReference(strings.TrimSpace(imageRef))
344358
if err != nil {
345359
return nil, fmt.Errorf("parse image ref %q: %w", imageRef, err)
346360
}

devcontainer/devcontainer_test.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,14 @@ func TestImageFromDockerfile(t *testing.T) {
167167
content: "FROM ubuntu",
168168
image: "index.docker.io/library/ubuntu:latest",
169169
}, {
170-
content: "ARG VARIANT=ionic\nFROM ubuntu:$VARIANT",
171-
image: "index.docker.io/library/ubuntu:ionic",
170+
content: "ARG VARIANT=bionic\nFROM ubuntu:$VARIANT",
171+
image: "index.docker.io/library/ubuntu:bionic",
172+
}, {
173+
content: "ARG VARIANT=\"3.10\"\nFROM mcr.microsoft.com/devcontainers/python:0-${VARIANT}",
174+
image: "mcr.microsoft.com/devcontainers/python:0-3.10",
175+
}, {
176+
content: "ARG VARIANT=\"3.10\"\nFROM mcr.microsoft.com/devcontainers/python:0-$VARIANT ",
177+
image: "mcr.microsoft.com/devcontainers/python:0-3.10",
172178
}} {
173179
tc := tc
174180
t.Run(tc.image, func(t *testing.T) {

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ require (
3030
github.com/google/go-containerregistry v0.15.2
3131
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
3232
github.com/mattn/go-isatty v0.0.20
33+
github.com/moby/buildkit v0.11.6
3334
github.com/otiai10/copy v1.14.0
3435
github.com/sirupsen/logrus v1.9.3
3536
github.com/spf13/cobra v1.7.0
@@ -184,7 +185,6 @@ require (
184185
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
185186
github.com/mitchellh/mapstructure v1.5.0 // indirect
186187
github.com/mitchellh/reflectwalk v1.0.2 // indirect
187-
github.com/moby/buildkit v0.11.6 // indirect
188188
github.com/moby/locker v1.0.1 // indirect
189189
github.com/moby/patternmatcher v0.5.0 // indirect
190190
github.com/moby/swarmkit/v2 v2.0.0-20230315203717-e28e8ba9bc83 // indirect

0 commit comments

Comments
 (0)