diff --git a/client/llb/state.go b/client/llb/state.go index b40b450fd7e77..c26755114f3b3 100644 --- a/client/llb/state.go +++ b/client/llb/state.go @@ -262,6 +262,8 @@ func (s State) WithImageConfig(c []byte) (State, error) { OS: img.OS, Architecture: img.Architecture, Variant: img.Variant, + OSVersion: img.OSVersion, + OSFeatures: img.OSFeatures, }) } return s, nil diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index b43761aeda852..a215b1affe5ff 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -598,6 +598,8 @@ func defaultImageConfig() ([]byte, error) { img := ocispecs.Image{} img.Architecture = pl.Architecture img.OS = pl.OS + img.OSVersion = pl.OSVersion + img.OSFeatures = pl.OSFeatures img.Variant = pl.Variant img.RootFS.Type = "layers" img.Config.WorkingDir = "/" diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index 7cd57a343f630..64c24e140fec3 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -274,6 +274,8 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS OS: img.OS, Architecture: img.Architecture, Variant: img.Variant, + OSVersion: img.OSVersion, + OSFeatures: img.OSFeatures, } } } @@ -595,6 +597,8 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS target.image.OS = platformOpt.targetPlatform.OS target.image.Architecture = platformOpt.targetPlatform.Architecture target.image.Variant = platformOpt.targetPlatform.Variant + target.image.OSVersion = platformOpt.targetPlatform.OSVersion + target.image.OSFeatures = platformOpt.targetPlatform.OSFeatures } return target, nil diff --git a/frontend/dockerfile/dockerfile2llb/image.go b/frontend/dockerfile/dockerfile2llb/image.go index 70d81262bcf2b..6f38d8f5a902b 100644 --- a/frontend/dockerfile/dockerfile2llb/image.go +++ b/frontend/dockerfile/dockerfile2llb/image.go @@ -19,6 +19,8 @@ func emptyImage(platform ocispecs.Platform) image.Image { img := image.Image{} img.Architecture = platform.Architecture img.OS = platform.OS + img.OSVersion = platform.OSVersion + img.OSFeatures = platform.OSFeatures img.Variant = platform.Variant img.RootFS.Type = "layers" img.Config.WorkingDir = "/" diff --git a/solver/llbsolver/ops/exec.go b/solver/llbsolver/ops/exec.go index 4966269262b76..c5b8c35b97537 100644 --- a/solver/llbsolver/ops/exec.go +++ b/solver/llbsolver/ops/exec.go @@ -113,6 +113,8 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol OS: e.platform.OS, Architecture: e.platform.Architecture, Variant: e.platform.Variant, + OSVersion: e.platform.OSVersion, + OSFeatures: e.platform.OSFeatures, } } @@ -133,17 +135,21 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol } dt, err := json.Marshal(struct { - Type string - Exec *pb.ExecOp - OS string - Arch string - Variant string `json:",omitempty"` + Type string + Exec *pb.ExecOp + OS string + Arch string + Variant string `json:",omitempty"` + OSVersion string `json:",omitempty"` + OSFeatures []string `json:",omitempty"` }{ - Type: execCacheType, - Exec: &op, - OS: p.OS, - Arch: p.Architecture, - Variant: p.Variant, + Type: execCacheType, + Exec: &op, + OS: p.OS, + Arch: p.Architecture, + Variant: p.Variant, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, }) if err != nil { return nil, false, err diff --git a/solver/llbsolver/ops/exec_binfmt.go b/solver/llbsolver/ops/exec_binfmt.go index c2c5504cc36bc..41a8047dce93d 100644 --- a/solver/llbsolver/ops/exec_binfmt.go +++ b/solver/llbsolver/ops/exec_binfmt.go @@ -90,6 +90,8 @@ func getEmulator(ctx context.Context, p *pb.Platform, idmap *idtools.IdentityMap pp := platforms.Normalize(ocispecs.Platform{ Architecture: p.Architecture, OS: p.OS, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, Variant: p.Variant, }) diff --git a/solver/llbsolver/provenance/capture.go b/solver/llbsolver/provenance/capture.go index eb77ef6bc3a09..941401d02893c 100644 --- a/solver/llbsolver/provenance/capture.go +++ b/solver/llbsolver/provenance/capture.go @@ -152,7 +152,9 @@ func (c *Capture) AddImage(i ImageSource) { return } if v.Platform != nil && i.Platform != nil { - if v.Platform.Architecture == i.Platform.Architecture && v.Platform.OS == i.Platform.OS && v.Platform.Variant == i.Platform.Variant { + // NOTE: Deliberately excluding OSFeatures, as there's no extant (or rational) case where a source image is an index and contains images distinguished only by OSFeature + // See https://github.com/moby/buildkit/pull/4387#discussion_r1376234241 + if v.Platform.Architecture == i.Platform.Architecture && v.Platform.OS == i.Platform.OS && v.Platform.OSVersion == i.Platform.OSVersion && v.Platform.Variant == i.Platform.Variant { return } } diff --git a/solver/llbsolver/vertex.go b/solver/llbsolver/vertex.go index 154cc75dce52a..61af8a263f9d5 100644 --- a/solver/llbsolver/vertex.go +++ b/solver/llbsolver/vertex.go @@ -79,17 +79,27 @@ func NormalizeRuntimePlatforms() LoadOpt { OS: p.OS, Architecture: p.Architecture, Variant: p.Variant, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, } } op.Platform = defaultPlatform } - platform := ocispecs.Platform{OS: op.Platform.OS, Architecture: op.Platform.Architecture, Variant: op.Platform.Variant} + platform := ocispecs.Platform{ + OS: op.Platform.OS, + Architecture: op.Platform.Architecture, + Variant: op.Platform.Variant, + OSVersion: op.Platform.OSVersion, + OSFeatures: op.Platform.OSFeatures, + } normalizedPlatform := platforms.Normalize(platform) op.Platform = &pb.Platform{ OS: normalizedPlatform.OS, Architecture: normalizedPlatform.Architecture, Variant: normalizedPlatform.Variant, + OSVersion: normalizedPlatform.OSVersion, + OSFeatures: normalizedPlatform.OSFeatures, } return nil diff --git a/source/containerimage/pull.go b/source/containerimage/pull.go index cdc6dae84cfa9..8c0d7a252ef1a 100644 --- a/source/containerimage/pull.go +++ b/source/containerimage/pull.go @@ -60,17 +60,21 @@ type puller struct { func mainManifestKey(ctx context.Context, desc ocispecs.Descriptor, platform ocispecs.Platform, layerLimit *int) (digest.Digest, error) { dt, err := json.Marshal(struct { - Digest digest.Digest - OS string - Arch string - Variant string `json:",omitempty"` - Limit *int `json:",omitempty"` + Digest digest.Digest + OS string + Arch string + Variant string `json:",omitempty"` + OSVersion string `json:",omitempty"` + OSFeatures []string `json:",omitempty"` + Limit *int `json:",omitempty"` }{ - Digest: desc.Digest, - OS: platform.OS, - Arch: platform.Architecture, - Variant: platform.Variant, - Limit: layerLimit, + Digest: desc.Digest, + OS: platform.OS, + Arch: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Limit: layerLimit, }) if err != nil { return "", err