Skip to content

Commit a9d758c

Browse files
committed
Configure "podman build" to produce images with Docker manifests.
Podman's default is to produce OCI manifests and metadata, while Docker (unsurprisingly) produces the Docker filetypes. This can lead to behavior differences down the line, especially once container registries are added to the mix.
1 parent 18b8ef3 commit a9d758c

File tree

10 files changed

+323
-28
lines changed

10 files changed

+323
-28
lines changed

pkg/appregistry/dbloader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func NewDbLoader(dbName string, logger *logrus.Entry) (*dbLoader, error) {
3535

3636
type dbLoader struct {
3737
db *sql.DB
38-
loader *sqlite.SQLLoader
38+
loader registry.Load
3939
logger *logrus.Entry
4040
}
4141

pkg/containertools/containertool.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ func (t ContainerTool) String() (s string) {
2020
return
2121
}
2222

23+
func (t ContainerTool) CommandFactory() CommandFactory {
24+
switch t {
25+
case PodmanTool:
26+
return &PodmanCommandFactory{}
27+
case DockerTool:
28+
return &DockerCommandFactory{}
29+
}
30+
return &StubCommandFactory{}
31+
}
32+
2333
func NewContainerTool(s string, defaultTool ContainerTool) (t ContainerTool) {
2434
switch s {
2535
case "podman":

pkg/containertools/factory.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package containertools
2+
3+
import (
4+
"os/exec"
5+
)
6+
7+
type CommandFactory interface {
8+
BuildCommand(o BuildOptions) (*exec.Cmd, error)
9+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package containertools
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
)
7+
8+
type DockerCommandFactory struct{}
9+
10+
func (d *DockerCommandFactory) BuildCommand(o BuildOptions) (*exec.Cmd, error) {
11+
args := []string{"build"}
12+
13+
if o.format != "" && o.format != "docker" {
14+
return nil, fmt.Errorf(`format %q invalid for "docker build"`, o.format)
15+
}
16+
17+
if o.dockerfile != "" {
18+
args = append(args, "-f", o.dockerfile)
19+
}
20+
21+
for _, tag := range o.tags {
22+
args = append(args, "-t", tag)
23+
}
24+
25+
if o.context == "" {
26+
return nil, fmt.Errorf("context not provided")
27+
}
28+
args = append(args, o.context)
29+
30+
return exec.Command("docker", args...), nil
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package containertools
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
)
7+
8+
type PodmanCommandFactory struct{}
9+
10+
func (p *PodmanCommandFactory) BuildCommand(o BuildOptions) (*exec.Cmd, error) {
11+
args := []string{"build"}
12+
13+
if o.format != "" {
14+
args = append(args, "--format", o.format)
15+
} else {
16+
args = append(args, "--format", "docker")
17+
}
18+
19+
if o.dockerfile != "" {
20+
args = append(args, "-f", o.dockerfile)
21+
}
22+
23+
for _, tag := range o.tags {
24+
args = append(args, "-t", tag)
25+
}
26+
27+
if o.context == "" {
28+
return nil, fmt.Errorf("context not provided")
29+
}
30+
args = append(args, o.context)
31+
32+
return exec.Command("podman", args...), nil
33+
}

pkg/containertools/factory_stub.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package containertools
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
)
7+
8+
type StubCommandFactory struct {
9+
name string
10+
}
11+
12+
func (s *StubCommandFactory) BuildCommand(o BuildOptions) (*exec.Cmd, error) {
13+
return nil, fmt.Errorf(`"build" is not supported by tool %q`, s.name)
14+
}

pkg/containertools/factory_test.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package containertools
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestBuildCommand(t *testing.T) {
10+
for _, tt := range []struct {
11+
Name string
12+
Factory CommandFactory
13+
Options BuildOptions
14+
Args []string
15+
}{
16+
{
17+
Name: "docker defaults",
18+
Factory: &DockerCommandFactory{},
19+
Options: DefaultBuildOptions(),
20+
Args: []string{
21+
"docker", "build", ".",
22+
},
23+
},
24+
{
25+
Name: "docker unsupported format",
26+
Factory: &DockerCommandFactory{},
27+
Options: BuildOptions{
28+
context: ".",
29+
format: "oci",
30+
},
31+
},
32+
{
33+
Name: "docker context",
34+
Factory: &DockerCommandFactory{},
35+
Options: BuildOptions{
36+
context: "foo",
37+
},
38+
Args: []string{
39+
"docker", "build", "foo",
40+
},
41+
},
42+
{
43+
Name: "docker dockerfile",
44+
Factory: &DockerCommandFactory{},
45+
Options: BuildOptions{
46+
context: ".",
47+
dockerfile: "foo",
48+
},
49+
Args: []string{
50+
"docker", "build", "-f", "foo", ".",
51+
},
52+
},
53+
{
54+
Name: "docker single tag",
55+
Factory: &DockerCommandFactory{},
56+
Options: BuildOptions{
57+
context: ".",
58+
tags: []string{"foo"},
59+
},
60+
Args: []string{
61+
"docker", "build", "-t", "foo", ".",
62+
},
63+
},
64+
{
65+
Name: "docker multiple tags",
66+
Factory: &DockerCommandFactory{},
67+
Options: BuildOptions{
68+
context: ".",
69+
tags: []string{"foo", "bar"},
70+
},
71+
Args: []string{
72+
"docker", "build", "-t", "foo", "-t", "bar", ".",
73+
},
74+
},
75+
{
76+
Name: "podman defaults",
77+
Factory: &PodmanCommandFactory{},
78+
Options: DefaultBuildOptions(),
79+
Args: []string{
80+
"podman", "build", "--format", "docker", ".",
81+
},
82+
},
83+
{
84+
Name: "podman oci format",
85+
Factory: &PodmanCommandFactory{},
86+
Options: BuildOptions{
87+
context: ".",
88+
format: "oci",
89+
},
90+
Args: []string{
91+
"podman", "build", "--format", "oci", ".",
92+
},
93+
},
94+
{
95+
Name: "podman context",
96+
Factory: &PodmanCommandFactory{},
97+
Options: BuildOptions{
98+
context: "foo",
99+
},
100+
Args: []string{
101+
"podman", "build", "--format", "docker", "foo",
102+
},
103+
},
104+
{
105+
Name: "podman dockerfile",
106+
Factory: &PodmanCommandFactory{},
107+
Options: BuildOptions{
108+
context: ".",
109+
dockerfile: "foo",
110+
},
111+
Args: []string{
112+
"podman", "build", "--format", "docker", "-f", "foo", ".",
113+
},
114+
},
115+
{
116+
Name: "podman single tag",
117+
Factory: &PodmanCommandFactory{},
118+
Options: BuildOptions{
119+
context: ".",
120+
tags: []string{"foo"},
121+
},
122+
Args: []string{
123+
"podman", "build", "--format", "docker", "-t", "foo", ".",
124+
},
125+
},
126+
{
127+
Name: "podman multiple tags",
128+
Factory: &PodmanCommandFactory{},
129+
Options: BuildOptions{
130+
context: ".",
131+
tags: []string{"foo", "bar"},
132+
},
133+
Args: []string{
134+
"podman", "build", "--format", "docker", "-t", "foo", "-t", "bar", ".",
135+
},
136+
},
137+
{
138+
Name: "stub defaults",
139+
Factory: &StubCommandFactory{},
140+
Options: DefaultBuildOptions(),
141+
},
142+
} {
143+
t.Run(tt.Name, func(t *testing.T) {
144+
require := require.New(t)
145+
146+
cmd, err := tt.Factory.BuildCommand(tt.Options)
147+
if tt.Args == nil {
148+
require.Nil(cmd)
149+
require.Error(err)
150+
} else {
151+
require.NotNil(cmd)
152+
require.NoError(err)
153+
require.Equal(tt.Args, cmd.Args)
154+
}
155+
})
156+
}
157+
}

pkg/containertools/option_build.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package containertools
2+
3+
type BuildOptions struct {
4+
format string
5+
tags []string
6+
dockerfile string
7+
context string
8+
}
9+
10+
func (o *BuildOptions) SetFormatDocker() {
11+
o.format = "docker"
12+
}
13+
14+
func (o *BuildOptions) SetFormatOCI() {
15+
o.format = "oci"
16+
}
17+
18+
func (o *BuildOptions) AddTag(tag string) {
19+
o.tags = append(o.tags, tag)
20+
}
21+
22+
func (o *BuildOptions) SetDockerfile(dockerfile string) {
23+
o.dockerfile = dockerfile
24+
}
25+
26+
func (o *BuildOptions) SetContext(context string) {
27+
o.context = context
28+
}
29+
30+
func DefaultBuildOptions() BuildOptions {
31+
var o BuildOptions
32+
o.SetFormatDocker()
33+
o.SetContext(".")
34+
return o
35+
}

pkg/containertools/command.go renamed to pkg/containertools/runner.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type ContainerCommandRunner struct {
2828
// CommandRunner to run commands with that cli tool
2929
func NewCommandRunner(containerTool ContainerTool, logger *logrus.Entry) CommandRunner {
3030
r := ContainerCommandRunner{
31-
logger: logger,
31+
logger: logger,
3232
containerTool: containerTool,
3333
}
3434
return &r
@@ -59,15 +59,16 @@ func (r *ContainerCommandRunner) Pull(image string) error {
5959

6060
// Build takes a dockerfile and a tag and builds a container image
6161
func (r *ContainerCommandRunner) Build(dockerfile, tag string) error {
62-
args := []string{"build", "-f", dockerfile}
63-
62+
o := DefaultBuildOptions()
6463
if tag != "" {
65-
args = append(args, "-t", tag)
64+
o.AddTag(tag)
65+
}
66+
o.SetDockerfile(dockerfile)
67+
o.SetContext(".")
68+
command, err := r.containerTool.CommandFactory().BuildCommand(o)
69+
if err != nil {
70+
return fmt.Errorf("unable to perform build: %v", err)
6671
}
67-
68-
args = append(args, ".")
69-
70-
command := exec.Command(r.containerTool.String(), args...)
7172

7273
r.logger.Infof("running %s build", r.containerTool)
7374
r.logger.Infof("%s", command.Args)

0 commit comments

Comments
 (0)