github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/build/inject.go (about) 1 package build 2 3 import ( 4 "fmt" 5 6 "github.com/pkg/errors" 7 "k8s.io/apimachinery/pkg/types" 8 9 "github.com/tilt-dev/tilt/internal/container" 10 "github.com/tilt-dev/tilt/internal/dockerfile" 11 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 12 ) 13 14 // Derived from 15 // https://github.com/moby/buildkit/blob/175e8415e38228dbb75e6b54efd2c8e9fc5b1cbf/util/archutil/detect.go#L15 16 var validBuildkitArchSet = map[string]bool{ 17 "amd64": true, 18 "arm64": true, 19 "riscv64": true, 20 "ppc64le": true, 21 "s390x": true, 22 "386": true, 23 "mips64le": true, 24 "mips64": true, 25 "arm": true, 26 } 27 28 // Create a new ImageTarget with the platform OS/Arch from the target cluster. 29 func InjectClusterPlatform(spec v1alpha1.DockerImageSpec, cluster *v1alpha1.Cluster) v1alpha1.DockerImageSpec { 30 if spec.Platform != "" || cluster == nil { 31 return spec 32 } 33 34 // Eventually, it might make sense to read the supported platforms 35 // off the buildkit server and negotiate the right one, but for 36 // now we hard-code a whitelist. 37 targetArch := cluster.Status.Arch 38 if !validBuildkitArchSet[targetArch] { 39 return spec 40 } 41 42 if targetArch == "arm" { 43 // This is typically communicated with GOARM. 44 // For now, just assume arm/v7 45 targetArch = "arm/v7" 46 } 47 48 // Currently Tilt only supports linux containers. 49 // We don't even build windows-compatible docker contexts. 50 spec.Platform = fmt.Sprintf("linux/%s", targetArch) 51 return spec 52 } 53 54 // Create a new ImageTarget with the Dockerfiles rewritten with the injected images. 55 func InjectImageDependencies(spec v1alpha1.DockerImageSpec, imageMaps map[types.NamespacedName]*v1alpha1.ImageMap) (v1alpha1.DockerImageSpec, error) { 56 if len(spec.ImageMaps) == 0 { 57 return spec, nil 58 } 59 60 df := dockerfile.Dockerfile(spec.DockerfileContents) 61 buildArgs := spec.Args 62 63 ast, err := dockerfile.ParseAST(df) 64 if err != nil { 65 return spec, errors.Wrap(err, "injectImageDependencies") 66 } 67 68 for _, dep := range spec.ImageMaps { 69 im, ok := imageMaps[types.NamespacedName{Name: dep}] 70 if !ok || im.Status.ImageFromLocal == "" { 71 return spec, fmt.Errorf("missing image dependency: %s", dep) 72 } 73 74 image := im.Status.ImageFromLocal 75 imageRef, err := container.ParseNamedTagged(image) 76 if err != nil { 77 return spec, errors.Wrap(err, "injectImageDependencies parse") 78 } 79 80 selector, err := container.SelectorFromImageMap(im.Spec) 81 if err != nil { 82 return spec, errors.Wrap(err, "injectImageDependencies selector") 83 } 84 85 modified, err := ast.InjectImageDigest(selector, imageRef, buildArgs) 86 if err != nil { 87 return spec, errors.Wrap(err, "injectImageDependencies inject") 88 } else if !modified { 89 return spec, fmt.Errorf("Could not inject image %q into Dockerfile of image %q", image, selector) 90 } 91 } 92 93 newDf, err := ast.Print() 94 if err != nil { 95 return spec, errors.Wrap(err, "injectImageDependencies") 96 } 97 98 spec.DockerfileContents = newDf.String() 99 100 return spec, nil 101 }