Skip to content

Commit a9d758c

Browse files
committedMay 27, 2020
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

10 files changed

+323
-28
lines changed
 

‎pkg/appregistry/dbloader.go

+1-1
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

+10
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

+9
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+
}

‎pkg/containertools/factory_docker.go

+31
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+
}

‎pkg/containertools/factory_podman.go

+33
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

+14
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

+157
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

+35
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 ‎pkg/containertools/runner.go

+9-8
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)
Please sign in to comment.