Skip to content

Commit

Permalink
fix: dockerfile2llb: handle escaping of backslashes correctly
Browse files Browse the repository at this point in the history
`shlex` in was treating single backslash "\\" in string as
escape sequence, hence stripping them off. Modify `processCmdEnv`
to double escape `\\`.

This was in turn affecting the vertex `Name`, and mostly pronounced
on Windows where backslashes are prevalent in path names. For example
`C:\hello\world\path` was being rendered as `C:helloworldpath`, hence
confusing users.

Fixes #5250

Build progress before fix:
```
	#5 [2/4] RUN echo C:helloworldpath
	#5 1.359 C:\hello\world\path
	#5 DONE 1.7s

	#6 [3/4] RUN echo C:\hello\escaped\path
	#6 1.734 C:\\hello\\escaped\\path
	#6 DONE 2.1s

	#7 [4/4] RUN echo "C:\hello\quoted\path"
	#7 1.765 "C:\hello\quoted\path"
	#7 DONE 2.1s
```

Build progress after fix:
```
	#5 [2/4] RUN echo C:\hello\world\path
	#5 1.458 C:\hello\world\path
	#5 DONE 1.8s

	#6 [3/4] RUN echo C:\\hello\\escaped\\path
	#6 1.730 C:\\hello\\escaped\\path
	#6 DONE 2.1s

	#7 [4/4] RUN echo "C:\hello\quoted\path"
	#7 1.702 "C:\hello\quoted\path"
	#7 DONE 2.1s
```

You can also see that now paths in the step/vertex names now
match those in the log lines right after the name.

Signed-off-by: Anthony Nandaa <[email protected]>
  • Loading branch information
profnandaa committed Sep 9, 2024
1 parent 436609d commit 538bdcf
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
2 changes: 2 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,8 @@ func uppercaseCmd(str string) string {
}

func processCmdEnv(shlex *shell.Lex, cmd string, env shell.EnvGetter) string {
// since shlex is tripping off backslashes
cmd = strings.ReplaceAll(cmd, "\\", "\\\\")
w, _, err := shlex.ProcessWord(cmd, env)
if err != nil {
return cmd
Expand Down
51 changes: 51 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,54 @@ RUN echo bar
assert.Equal(t, []digest.Digest{"sha256:2e112031b4b923a873c8b3d685d48037e4d5ccd967b658743d93a6e56c3064b9"}, baseImg.RootFS.DiffIDs)
assert.Equal(t, "2024-01-17 21:49:12 +0000 UTC", baseImg.Created.String())
}

// MockEnvGetter is a mock implementation of shell.EnvGetter for testing purposes.
type MockEnvGetter struct{}

func (m *MockEnvGetter) Get(key string) (string, bool) {
return "", false
}

func (m *MockEnvGetter) Keys() []string {
return []string{}
}

func TestProcessCmdEnv(t *testing.T) {
tests := []struct {
name string
cmd string
expected string
}{
{
name: "basic command without backslashes",
cmd: "echo hello world",
expected: "echo hello world",
},
{
name: "command with single backslashes",
cmd: `echo C:\hello\world`,
expected: `echo C:\hello\world`,
},
{
name: "command with multiple backslashes",
cmd: `echo C:\\hello\\world`,
expected: `echo C:\\hello\\world`,
},
{
name: "command with mixed content",
cmd: `echo "C:\hello\world" && dir C:\test\path`,
expected: `echo "C:\hello\world" && dir C:\test\path`,
},
}

shlex := shell.NewLex('\\')
shlex.RawQuotes = true
env := &MockEnvGetter{}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := processCmdEnv(shlex, tt.cmd, env)
assert.Equal(t, tt.expected, result)
})
}
}

0 comments on commit 538bdcf

Please sign in to comment.