From fe1ea7334e588b6bcbe0a7677172483934f214e6 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Fri, 27 Dec 2024 13:33:15 -0800 Subject: [PATCH] WIP: Support OS version in platform string This allows platforms following the new `platforms.FormatAll` function, which allows for setting the `OSVersion` field of the platform with `()/`. Signed-off-by: Brian Goff --- client/llb/imagemetaresolver/resolver.go | 2 +- exporter/containerimage/annotations.go | 2 +- .../containerimage/exptypes/annotations.go | 2 +- exporter/containerimage/exptypes/parse.go | 2 +- exporter/verifier/platforms.go | 13 +- frontend/dockerfile/builder/build.go | 2 +- frontend/dockerfile/dockerfile2llb/convert.go | 10 +- .../dockerfile/dockerfile2llb/platform.go | 2 + frontend/dockerfile/dockerfile_test.go | 145 +++++++++++++++++- frontend/dockerui/build.go | 2 +- frontend/dockerui/config.go | 2 +- solver/llbsolver/bridge.go | 4 +- source/containerimage/source.go | 2 +- .../containerd/platforms/defaults_windows.go | 17 +- .../containerd/platforms/platforms.go | 10 +- 15 files changed, 186 insertions(+), 31 deletions(-) diff --git a/client/llb/imagemetaresolver/resolver.go b/client/llb/imagemetaresolver/resolver.go index e489ecf471d8..6a0c6dc31bec 100644 --- a/client/llb/imagemetaresolver/resolver.go +++ b/client/llb/imagemetaresolver/resolver.go @@ -107,7 +107,7 @@ func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string func (imr *imageMetaResolver) key(ref string, platform *ocispecs.Platform) string { if platform != nil { - ref += platforms.Format(*platform) + ref += platforms.FormatAll(*platform) } return ref } diff --git a/exporter/containerimage/annotations.go b/exporter/containerimage/annotations.go index 5973f628ad16..1bf10f6c15db 100644 --- a/exporter/containerimage/annotations.go +++ b/exporter/containerimage/annotations.go @@ -71,7 +71,7 @@ func (ag AnnotationsGroup) Platform(p *ocispecs.Platform) *Annotations { ps := []string{""} if p != nil { - ps = append(ps, platforms.Format(*p)) + ps = append(ps, platforms.FormatAll(*p)) } for _, a := range ag { diff --git a/exporter/containerimage/exptypes/annotations.go b/exporter/containerimage/exptypes/annotations.go index 37f1b205d15e..a9b74d6b9681 100644 --- a/exporter/containerimage/exptypes/annotations.go +++ b/exporter/containerimage/exptypes/annotations.go @@ -49,7 +49,7 @@ func (k AnnotationKey) PlatformString() string { if k.Platform == nil { return "" } - return platforms.Format(*k.Platform) + return platforms.FormatAll(*k.Platform) } func AnnotationIndexKey(key string) string { diff --git a/exporter/containerimage/exptypes/parse.go b/exporter/containerimage/exptypes/parse.go index bd6222338ef4..cd2256b566e9 100644 --- a/exporter/containerimage/exptypes/parse.go +++ b/exporter/containerimage/exptypes/parse.go @@ -53,7 +53,7 @@ func ParsePlatforms(meta map[string][]byte) (Platforms, error) { } } p = platforms.Normalize(p) - pk := platforms.Format(p) + pk := platforms.FormatAll(p) ps := Platforms{ Platforms: []Platform{{ID: pk, Platform: p}}, } diff --git a/exporter/verifier/platforms.go b/exporter/verifier/platforms.go index 5144b78e8e54..6f60ca62d112 100644 --- a/exporter/verifier/platforms.go +++ b/exporter/verifier/platforms.go @@ -46,13 +46,14 @@ func CheckInvalidPlatforms[T comparable](ctx context.Context, res *result.Result }) } p = platforms.Normalize(p) - _, ok := reqMap[platforms.Format(p)] + formatted := platforms.FormatAll(p) + _, ok := reqMap[formatted] if ok { warnings = append(warnings, client.VertexWarning{ Short: []byte(fmt.Sprintf("Duplicate platform result requested %q", v)), }) } - reqMap[platforms.Format(p)] = struct{}{} + reqMap[formatted] = struct{}{} reqList = append(reqList, exptypes.Platform{Platform: p}) } @@ -62,9 +63,9 @@ func CheckInvalidPlatforms[T comparable](ctx context.Context, res *result.Result if len(reqMap) == 1 && len(ps.Platforms) == 1 { pp := platforms.Normalize(ps.Platforms[0].Platform) - if _, ok := reqMap[platforms.Format(pp)]; !ok { + if _, ok := reqMap[platforms.FormatAll(pp)]; !ok { return []client.VertexWarning{{ - Short: []byte(fmt.Sprintf("Requested platform %q does not match result platform %q", req.Platforms[0], platforms.Format(pp))), + Short: []byte(fmt.Sprintf("Requested platform %q does not match result platform %q", req.Platforms[0], platforms.FormatAll(pp))), }}, nil } return nil, nil @@ -81,7 +82,7 @@ func CheckInvalidPlatforms[T comparable](ctx context.Context, res *result.Result if !mismatch { for _, p := range ps.Platforms { pp := platforms.Normalize(p.Platform) - if _, ok := reqMap[platforms.Format(pp)]; !ok { + if _, ok := reqMap[platforms.FormatAll(pp)]; !ok { mismatch = true break } @@ -100,7 +101,7 @@ func CheckInvalidPlatforms[T comparable](ctx context.Context, res *result.Result func platformsString(ps []exptypes.Platform) string { var ss []string for _, p := range ps { - ss = append(ss, platforms.Format(platforms.Normalize(p.Platform))) + ss = append(ss, platforms.FormatAll(platforms.Normalize(p.Platform))) } sort.Strings(ss) return strings.Join(ss, ",") diff --git a/frontend/dockerfile/builder/build.go b/frontend/dockerfile/builder/build.go index 31ca7381c761..62b76bd5e22e 100644 --- a/frontend/dockerfile/builder/build.go +++ b/frontend/dockerfile/builder/build.go @@ -160,7 +160,7 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { if platform != nil { p = *platform } - scanTargets.Store(platforms.Format(platforms.Normalize(p)), scanTarget) + scanTargets.Store(platforms.FormatAll(platforms.Normalize(p)), scanTarget) return ref, img, baseImg, nil }) diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index 934c3a338e3d..c3b06e73fc66 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -519,7 +519,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS if reachable { prefix := "[" if opt.MultiPlatformRequested && platform != nil { - prefix += platforms.Format(*platform) + " " + prefix += platforms.FormatAll(*platform) + " " } prefix += "internal]" mutRef, dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, sourceresolver.Opt{ @@ -2102,7 +2102,7 @@ func prefixCommand(ds *dispatchState, str string, prefixPlatform bool, platform } out := "[" if prefixPlatform && platform != nil { - out += platforms.Format(*platform) + formatTargetPlatform(*platform, platformFromEnv(env)) + " " + out += platforms.FormatAll(*platform) + formatTargetPlatform(*platform, platformFromEnv(env)) + " " } if ds.stageName != "" { out += ds.stageName + " " @@ -2136,7 +2136,7 @@ func formatTargetPlatform(base ocispecs.Platform, target *ocispecs.Platform) str return "->" + archVariant } if p.OS != base.OS { - return "->" + platforms.Format(p) + return "->" + platforms.FormatAll(p) } return "" } @@ -2483,8 +2483,8 @@ func wrapSuggestAny(err error, keys map[string]struct{}, options []string) error func validateBaseImagePlatform(name string, expected, actual ocispecs.Platform, location []parser.Range, lint *linter.Linter) { if expected.OS != actual.OS || expected.Architecture != actual.Architecture { - expectedStr := platforms.Format(platforms.Normalize(expected)) - actualStr := platforms.Format(platforms.Normalize(actual)) + expectedStr := platforms.FormatAll(platforms.Normalize(expected)) + actualStr := platforms.FormatAll(platforms.Normalize(actual)) msg := linter.RuleInvalidBaseImagePlatform.Format(name, expectedStr, actualStr) lint.Run(&linter.RuleInvalidBaseImagePlatform, location, msg) } diff --git a/frontend/dockerfile/dockerfile2llb/platform.go b/frontend/dockerfile/dockerfile2llb/platform.go index 5eb99d919a10..8276a782950b 100644 --- a/frontend/dockerfile/dockerfile2llb/platform.go +++ b/frontend/dockerfile/dockerfile2llb/platform.go @@ -45,10 +45,12 @@ func defaultArgs(po *platformOpt, overrides map[string]string, target string) *l s := [...][2]string{ {"BUILDPLATFORM", platforms.Format(bp)}, {"BUILDOS", bp.OS}, + {"BUILDOSVERSION", bp.OSVersion}, {"BUILDARCH", bp.Architecture}, {"BUILDVARIANT", bp.Variant}, {"TARGETPLATFORM", platforms.Format(tp)}, {"TARGETOS", tp.OS}, + {"TARGETOSVERSION", tp.OSVersion}, {"TARGETARCH", tp.Architecture}, {"TARGETVARIANT", tp.Variant}, {"TARGETSTAGE", target}, diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index 2e7eba86715b..5ac35c2e76a6 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -214,6 +214,7 @@ var allTests = integration.TestFuncs( testTargetStageNameArg, testStepNames, testPowershellInDefaultPathOnWindows, + testPlatformWithOSVersion, ) // Tests that depend on the `security.*` entitlements @@ -5000,7 +5001,7 @@ ONBUILD RUN mkdir \out && echo 11>> \out\foo require.NoError(t, err) dockerfile = []byte(fmt.Sprintf(` - FROM %s + FROM %s `, target)) dir = integration.Tmpdir( @@ -5218,9 +5219,9 @@ func testOnBuildNamedContext(t *testing.T, sb integration.Sandbox) { dockerfile := []byte(` FROM alpine AS otherstage RUN echo -n "hello" > /testfile - + FROM base AS inputstage - + FROM scratch COPY --from=inputstage /out/foo /bar `) @@ -6811,7 +6812,7 @@ RUN cat /etc/hosts | grep foo RUN echo $HOSTNAME | grep foo RUN echo $(hostname) | grep foo `, - ` + ` FROM nanoserver RUN reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v Hostname | findstr "foo" `, @@ -7463,7 +7464,7 @@ func testNamedImageContextScratch(t *testing.T, sb integration.Sandbox) { defer c.Close() dockerfile := []byte(fmt.Sprintf( - ` + ` FROM %s AS build COPY <