Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix multi-arch build. Merge code with docker
- Loading branch information
1 parent
53297f5
commit c009954
Showing
10 changed files
with
357 additions
and
366 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package containers | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/caarlos0/log" | ||
"github.com/goreleaser/goreleaser/internal/gio" | ||
"github.com/goreleaser/goreleaser/internal/pipe" | ||
"github.com/goreleaser/goreleaser/internal/tmpl" | ||
"github.com/goreleaser/goreleaser/pkg/config" | ||
"github.com/goreleaser/goreleaser/pkg/context" | ||
) | ||
|
||
type ImageBuildContext struct { | ||
ID string | ||
BuildPath string | ||
BuildFlags []string | ||
PushFlags []string | ||
Platforms []config.ContainerPlatform | ||
Images []string | ||
} | ||
|
||
func (p ImageBuildContext) Log() *log.Entry { | ||
if len(p.Images) > 0 { | ||
return log.WithField("image", p.Images[0]) | ||
} else { | ||
return log.WithField("id", p.ID) | ||
} | ||
} | ||
|
||
func LogEntry(ctx *context.Context, config config.Container) *log.Entry { | ||
images, _ := processImageTemplates(ctx, config.ImageTemplates) | ||
if len(images) > 0 { | ||
return log.WithField("image", images[0]) | ||
} else { | ||
return log.WithField("id", config.ID) | ||
} | ||
} | ||
|
||
func BuildContext(ctx *context.Context, id string, imageDef config.ImageDefinition, platforms []config.ContainerPlatform) (ImageBuildContext, func(), error) { | ||
context := ImageBuildContext{ | ||
ID: id, | ||
Platforms: platforms, | ||
} | ||
|
||
images, err := processImageTemplates(ctx, imageDef.ImageTemplates) | ||
if err != nil { | ||
return context, nil, err | ||
} | ||
|
||
if len(images) == 0 { | ||
return context, nil, pipe.Skip("no image templates found") | ||
} | ||
context.Images = images | ||
|
||
tmp, err := os.MkdirTemp("", "goreleaserdocker") | ||
if err != nil { | ||
return context, nil, fmt.Errorf("failed to create temporary dir: %w", err) | ||
} | ||
context.BuildPath = tmp | ||
|
||
keepContext := false | ||
defer func() { | ||
if !keepContext { | ||
os.RemoveAll(tmp) | ||
} | ||
}() | ||
|
||
log := log.WithField("image", images[0]) | ||
log.Debug("tempdir: " + tmp) | ||
|
||
// This will set all binaries for all architectures within the context | ||
// To ensure multi-arch builds can access the correct binaries, they are copied to $tmp/$TARGETPLATFORM/$name | ||
artifacts := getApplicableArtifacts(ctx, imageDef, platforms) | ||
if len(artifacts.List()) == 0 { | ||
log.Warn("no binaries or packages found for the given platform - COPY/ADD may not work") | ||
} | ||
log.WithField("artifacts", artifacts.Paths()).Debug("found artifacts") | ||
|
||
if err := tmpl.New(ctx).ApplyAll( | ||
&imageDef.Dockerfile, | ||
); err != nil { | ||
return context, nil, err | ||
} | ||
if err := gio.Copy( | ||
imageDef.Dockerfile, | ||
filepath.Join(tmp, "Dockerfile"), | ||
); err != nil { | ||
return context, nil, fmt.Errorf("failed to copy dockerfile: %w", err) | ||
} | ||
|
||
for _, file := range imageDef.Files { | ||
if err := os.MkdirAll(filepath.Join(tmp, filepath.Dir(file)), 0o755); err != nil { | ||
return context, nil, fmt.Errorf("failed to copy extra file '%s': %w", file, err) | ||
} | ||
if err := gio.Copy(file, filepath.Join(tmp, file)); err != nil { | ||
return context, nil, fmt.Errorf("failed to copy extra file '%s': %w", file, err) | ||
} | ||
} | ||
|
||
for _, art := range artifacts.List() { | ||
target := filepath.Join(tmp, art.Goos, art.Goarch, art.Name) | ||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { | ||
return context, nil, fmt.Errorf("failed to make dir for artifact: %w", err) | ||
} | ||
|
||
if err := gio.Copy(art.Path, target); err != nil { | ||
return context, nil, fmt.Errorf("failed to copy artifact: %w", err) | ||
} | ||
|
||
if len(context.Platforms) == 1 { | ||
if err := gio.Link(target, filepath.Join(tmp, art.Name)); err != nil { | ||
return context, nil, fmt.Errorf("failed to link artifact: %w", err) | ||
} | ||
} | ||
} | ||
|
||
buildFlags, err := processBuildFlagTemplates(ctx, imageDef.BuildFlagTemplates) | ||
if err != nil { | ||
return context, nil, err | ||
} | ||
context.BuildFlags = buildFlags | ||
context.PushFlags = imageDef.PushFlags | ||
|
||
keepContext = true | ||
return context, func() { | ||
os.RemoveAll(tmp) | ||
}, nil | ||
} | ||
|
||
func processImageTemplates(ctx *context.Context, templates []string) ([]string, error) { | ||
// nolint:prealloc | ||
var images []string | ||
for _, imageTemplate := range templates { | ||
image, err := tmpl.New(ctx).Apply(imageTemplate) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to execute image template '%s': %w", imageTemplate, err) | ||
} | ||
if image == "" { | ||
continue | ||
} | ||
|
||
images = append(images, image) | ||
} | ||
|
||
return images, nil | ||
} | ||
|
||
func processBuildFlagTemplates(ctx *context.Context, flagTemplates []string) ([]string, error) { | ||
// nolint:prealloc | ||
var buildFlags []string | ||
for _, buildFlagTemplate := range flagTemplates { | ||
buildFlag, err := tmpl.New(ctx).Apply(buildFlagTemplate) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to process build flag template '%s': %w", buildFlagTemplate, err) | ||
} | ||
buildFlags = append(buildFlags, buildFlag) | ||
} | ||
return buildFlags, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package containers | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/goreleaser/goreleaser/internal/testctx" | ||
"github.com/goreleaser/goreleaser/pkg/config" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_processImageTemplates(t *testing.T) { | ||
ctx := testctx.NewWithCfg( | ||
config.Project{ | ||
Builds: []config.Build{ | ||
{ | ||
ID: "default", | ||
}, | ||
}, | ||
Dockers: []config.Docker{ | ||
{ | ||
ImageDefinition: config.ImageDefinition{ | ||
Dockerfile: "Dockerfile.foo", | ||
ImageTemplates: []string{ | ||
"user/image:{{.Tag}}", | ||
"gcr.io/image:{{.Tag}}-{{.Env.FOO}}", | ||
"gcr.io/image:v{{.Major}}.{{.Minor}}", | ||
}, | ||
}, | ||
SkipPush: "true", | ||
}, | ||
}, | ||
Env: []string{"FOO=123"}, | ||
}, | ||
testctx.WithVersion("1.0.0"), | ||
testctx.WithCurrentTag("v1.0.0"), | ||
testctx.WithCommit("a1b2c3d4"), | ||
testctx.WithSemver(1, 0, 0, ""), | ||
) | ||
require.Len(t, ctx.Config.Dockers, 1) | ||
|
||
docker := ctx.Config.Dockers[0] | ||
require.Equal(t, "Dockerfile.foo", docker.Dockerfile) | ||
|
||
images, err := processImageTemplates(ctx, docker.ImageTemplates) | ||
require.NoError(t, err) | ||
require.Equal(t, []string{ | ||
"user/image:v1.0.0", | ||
"gcr.io/image:v1.0.0-123", | ||
"gcr.io/image:v1.0", | ||
}, images) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package containers | ||
|
||
import ( | ||
"github.com/goreleaser/goreleaser/internal/artifact" | ||
"github.com/goreleaser/goreleaser/pkg/config" | ||
"github.com/goreleaser/goreleaser/pkg/context" | ||
) | ||
|
||
func DefaultPlatforms(platforms []config.ContainerPlatform) []config.ContainerPlatform { | ||
if len(platforms) == 0 { | ||
platforms = make([]config.ContainerPlatform, 1) | ||
} | ||
for i := range platforms { | ||
DefaultPlatform(&platforms[i]) | ||
} | ||
return platforms | ||
} | ||
|
||
func DefaultPlatform(platform *config.ContainerPlatform) { | ||
if platform.Goos == "" { | ||
platform.Goos = "linux" | ||
} | ||
if platform.Goarch == "" { | ||
platform.Goarch = "amd64" | ||
} | ||
if platform.Goarm == "" { | ||
platform.Goarm = "6" | ||
} | ||
if platform.Goamd64 == "" { | ||
platform.Goamd64 = "v1" | ||
} | ||
} | ||
|
||
func getApplicableArtifacts(ctx *context.Context, imageDefinition config.ImageDefinition, platforms []config.ContainerPlatform) *artifact.Artifacts { | ||
var platformFilters []artifact.Filter | ||
for _, platform := range platforms { | ||
filters := []artifact.Filter{ | ||
artifact.ByGoos(platform.Goos), | ||
artifact.ByGoarch(platform.Goarch), | ||
} | ||
switch platform.Goarch { | ||
case "amd64": | ||
filters = append(filters, artifact.ByGoamd64(platform.Goamd64)) | ||
case "arm": | ||
filters = append(filters, artifact.ByGoarm(platform.Goarm)) | ||
} | ||
platformFilters = append(platformFilters, artifact.And( | ||
filters..., | ||
)) | ||
} | ||
filters := []artifact.Filter{ | ||
artifact.Or(platformFilters...), | ||
artifact.Or( | ||
artifact.ByType(artifact.Binary), | ||
artifact.ByType(artifact.LinuxPackage), | ||
), | ||
} | ||
if len(imageDefinition.IDs) > 0 { | ||
filters = append(filters, artifact.ByIDs(imageDefinition.IDs...)) | ||
} | ||
return ctx.Artifacts.Filter(artifact.And(filters...)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package gio | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/caarlos0/log" | ||
) | ||
|
||
// Link creates a hard link and the parent directory if it does not exist yet. | ||
func Link(src, dst string) error { | ||
log.WithField("src", src).WithField("dst", dst).Debug("creating link") | ||
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil { | ||
return fmt.Errorf("failed to make dir for destination: %w", err) | ||
} | ||
return os.Link(src, dst) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.