Skip to content

Commit 5651e76

Browse files
committed
feat: add support for DockerfileInline
As nerdctl currently uses "nerdctl build" to build the service images, write the inline file to a temporary file and use "-f" to specify the temporary dockerfile. Signed-off-by: Tushar Gupta <[email protected]>
1 parent 7eab2ce commit 5651e76

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

cmd/nerdctl/compose/compose_build_linux_test.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func TestComposeBuild(t *testing.T) {
3939
// Make sure we shard the image name to something unique to the test to avoid conflicts with other tests
4040
imageSvc0 := data.Identifier("svc0")
4141
imageSvc1 := data.Identifier("svc1")
42+
imageSvc2 := data.Identifier("svc2")
4243

4344
// We are not going to run them, so, ports conflicts should not matter here
4445
dockerComposeYAML := fmt.Sprintf(`
@@ -51,14 +52,21 @@ services:
5152
svc1:
5253
build: .
5354
image: %s
54-
`, imageSvc0, imageSvc1)
55+
svc2:
56+
image: %s
57+
build:
58+
context: .
59+
dockerfile_inline: |
60+
FROM %s
61+
`, imageSvc0, imageSvc1, imageSvc2, testutil.CommonImage)
5562

5663
data.Temp().Save(dockerComposeYAML, "compose.yaml")
5764
data.Temp().Save(dockerfile, "Dockerfile")
5865

5966
data.Labels().Set("composeYaml", data.Temp().Path("compose.yaml"))
6067
data.Labels().Set("imageSvc0", imageSvc0)
6168
data.Labels().Set("imageSvc1", imageSvc1)
69+
data.Labels().Set("imageSvc2", imageSvc2)
6270
}
6371

6472
testCase.SubTests = []*test.Case{
@@ -76,22 +84,41 @@ services:
7684
Output: expect.All(
7785
expect.Contains(data.Labels().Get("imageSvc0")),
7886
expect.DoesNotContain(data.Labels().Get("imageSvc1")),
87+
expect.DoesNotContain(data.Labels().Get("imageSvc2")),
88+
),
89+
}
90+
},
91+
},
92+
{
93+
Description: "build svc2",
94+
NoParallel: true,
95+
Setup: func(data test.Data, helpers test.Helpers) {
96+
helpers.Ensure("compose", "-f", data.Labels().Get("composeYaml"), "build", "svc2")
97+
},
98+
99+
Command: test.Command("images"),
100+
101+
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
102+
return &test.Expected{
103+
Output: expect.All(
104+
expect.Contains(data.Labels().Get("imageSvc2")),
105+
expect.DoesNotContain(data.Labels().Get("imageSvc1")),
79106
),
80107
}
81108
},
82109
},
83110
{
84-
Description: "build svc0 and svc1",
111+
Description: "build svc0, svc1, svc2",
85112
NoParallel: true,
86113
Setup: func(data test.Data, helpers test.Helpers) {
87-
helpers.Ensure("compose", "-f", data.Labels().Get("composeYaml"), "build", "svc0", "svc1")
114+
helpers.Ensure("compose", "-f", data.Labels().Get("composeYaml"), "build", "svc0", "svc1", "svc2")
88115
},
89116

90117
Command: test.Command("images"),
91118

92119
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
93120
return &test.Expected{
94-
Output: expect.Contains(data.Labels().Get("imageSvc0"), data.Labels().Get("imageSvc1")),
121+
Output: expect.Contains(data.Labels().Get("imageSvc0"), data.Labels().Get("imageSvc1"), data.Labels().Get("imageSvc2")),
95122
}
96123
},
97124
},
@@ -122,7 +149,7 @@ services:
122149

123150
testCase.Cleanup = func(data test.Data, helpers test.Helpers) {
124151
if data.Labels().Get("imageSvc0") != "" {
125-
helpers.Anyhow("rmi", data.Labels().Get("imageSvc0"), data.Labels().Get("imageSvc1"))
152+
helpers.Anyhow("rmi", data.Labels().Get("imageSvc0"), data.Labels().Get("imageSvc1"), data.Labels().Get("imageSvc2"))
126153
}
127154
}
128155

pkg/composer/serviceparser/build.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package serviceparser
1919
import (
2020
"errors"
2121
"fmt"
22+
"os"
2223
"path/filepath"
2324
"strings"
2425

@@ -34,7 +35,7 @@ import (
3435

3536
func parseBuildConfig(c *types.BuildConfig, project *types.Project, imageName string) (*Build, error) {
3637
if unknown := reflectutil.UnknownNonEmptyFields(c,
37-
"Context", "Dockerfile", "Args", "CacheFrom", "Target", "Labels", "Secrets", "AdditionalContexts",
38+
"Context", "Dockerfile", "Args", "CacheFrom", "Target", "Labels", "Secrets", "DockerfileInline", "AdditionalContexts",
3839
); len(unknown) > 0 {
3940
log.L.Warnf("Ignoring: build: %+v", unknown)
4041
}
@@ -86,6 +87,20 @@ func parseBuildConfig(c *types.BuildConfig, project *types.Project, imageName st
8687
}
8788
}
8889

90+
if c.DockerfileInline != "" {
91+
// if DockerfileInline is specified, write it to a temporary file
92+
// and use -f flag to use that docker file with project's ctxdir
93+
tmpFile, err := os.CreateTemp("", fmt.Sprintf("%s.Dockerfile", imageName))
94+
if err != nil {
95+
return nil, fmt.Errorf("failed to create temp file for DockerfileInline: %w", err)
96+
}
97+
defer tmpFile.Close()
98+
if _, err := tmpFile.Write([]byte(c.DockerfileInline)); err != nil {
99+
return nil, fmt.Errorf("failed to write DockerfileInline: %w", err)
100+
}
101+
b.BuildArgs = append(b.BuildArgs, "-f="+tmpFile.Name())
102+
}
103+
89104
for _, s := range c.Secrets {
90105
fileRef := types.FileReferenceConfig(s)
91106

pkg/composer/serviceparser/build_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package serviceparser
1818

1919
import (
20+
"fmt"
2021
"runtime"
22+
"strings"
2123
"testing"
2224

2325
"gotest.tools/v3/assert"
@@ -54,6 +56,12 @@ services:
5456
target: tgt_secret
5557
- simple_secret
5658
- absolute_secret
59+
baz:
60+
image: bazimg
61+
build:
62+
context: ./bazctx
63+
dockerfile_inline: |
64+
FROM random
5765
secrets:
5866
src_secret:
5967
file: test_secret1
@@ -95,4 +103,23 @@ secrets:
95103
assert.Assert(t, in(bar.Build.BuildArgs, "--secret=id=tgt_secret,src="+secretPath+"/test_secret1"))
96104
assert.Assert(t, in(bar.Build.BuildArgs, "--secret=id=simple_secret,src="+secretPath+"/test_secret2"))
97105
assert.Assert(t, in(bar.Build.BuildArgs, "--secret=id=absolute_secret,src=/tmp/absolute_secret"))
106+
107+
bazSvc, err := project.GetService("baz")
108+
assert.NilError(t, err)
109+
110+
baz, err := Parse(project, bazSvc)
111+
assert.NilError(t, err)
112+
113+
t.Logf("baz: %+v", baz)
114+
t.Logf("baz.Build.BuildArgs: %+v", baz.Build.BuildArgs)
115+
// incase of dockerfile_inline, assert -f flag is overridden to point to a temporary file that ends with
116+
// <service-image-name>.Dockerfile
117+
assert.Assert(t, func() bool {
118+
for _, arg := range baz.Build.BuildArgs {
119+
if strings.HasPrefix(arg, "-f=") && strings.Contains(arg, fmt.Sprintf("/%s.Dockerfile", baz.Image)) {
120+
return true
121+
}
122+
}
123+
return false
124+
}())
98125
}

0 commit comments

Comments
 (0)