-
Notifications
You must be signed in to change notification settings - Fork 9
/
makeindex.go
118 lines (98 loc) · 3.31 KB
/
makeindex.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package oci
import (
"context"
"fmt"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/types"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"namespacelabs.dev/foundation/internal/compute"
"namespacelabs.dev/foundation/internal/fnerrors"
"namespacelabs.dev/foundation/internal/parsing/platform"
"namespacelabs.dev/foundation/internal/uniquestrings"
"namespacelabs.dev/foundation/std/tasks"
)
type ImageWithPlatform struct {
Image NamedImage
Platform specs.Platform
}
func MakeImageIndex(images ...ImageWithPlatform) compute.Computable[ResolvableImage] {
return &makeImageIndex{images: images}
}
type makeImageIndex struct {
images []ImageWithPlatform
compute.LocalScoped[ResolvableImage]
}
func (al *makeImageIndex) Inputs() *compute.In {
var platforms []string
in := compute.Inputs()
for k, d := range al.images {
in = in.Computable(fmt.Sprintf("image%d", k), d.Image.Image())
platforms = append(platforms, platform.FormatPlatform(d.Platform))
}
return in.Strs("platforms", platforms)
}
func (al *makeImageIndex) Action() *tasks.ActionEvent {
var u uniquestrings.List
var platforms []string
for _, d := range al.images {
u.Add(d.Image.Description())
platforms = append(platforms, platform.FormatPlatform(d.Platform))
}
return tasks.Action("oci.make-image-index").Arg("refs", u.Strings()).Arg("platforms", platforms)
}
func (al *makeImageIndex) Compute(ctx context.Context, deps compute.Resolved) (ResolvableImage, error) {
images := make([]RawImageWithPlatform, len(al.images))
for k, d := range al.images {
image := compute.MustGetDepValue(deps, d.Image.Image(), fmt.Sprintf("image%d", k))
images[k] = RawImageWithPlatform{
Image: image,
Platform: d.Platform,
}
}
return RawMakeIndex(images...)
}
type RawImageWithPlatform struct {
Image Image
Platform specs.Platform
}
func RawMakeIndex(images ...RawImageWithPlatform) (ResolvableImage, error) {
var adds []mutate.IndexAddendum
for _, d := range images {
image := d.Image
digest, err := image.Digest()
if err != nil {
return nil, err
}
mediaType, err := image.MediaType()
if err != nil {
return nil, err
}
if !isImageMediaType(mediaType) {
return nil, fnerrors.InternalError("%s: unexpected media type: %s", digest.String(), mediaType)
}
adds = append(adds, mutate.IndexAddendum{
Add: image,
Descriptor: v1.Descriptor{
MediaType: mediaType,
Platform: &v1.Platform{
OS: d.Platform.OS,
Architecture: d.Platform.Architecture,
Variant: d.Platform.Variant,
},
},
})
}
idx := mutate.AppendManifests(mutate.IndexMediaType(empty.Index, types.OCIImageIndex), adds...)
// The Digest() is requested here to guarantee that the index can indeed be created.
// This will also mark the digest "computed", which is the closest we can get to a
// sealed result.
if _, err := idx.Digest(); err != nil {
return nil, fnerrors.InternalError("failed to compute image index digest: %w", err)
}
return rawImageIndex{idx}, nil
}