@@ -33,17 +33,20 @@ import (
3333 "strings"
3434
3535 v1 "github.com/google/go-containerregistry/pkg/v1"
36+ "github.com/google/go-containerregistry/pkg/v1/empty"
3637 "github.com/google/go-containerregistry/pkg/v1/mutate"
3738 "github.com/google/go-containerregistry/pkg/v1/tarball"
39+ "github.com/google/go-containerregistry/pkg/v1/types"
3840)
3941
4042const (
4143 appDir = "/ko-app"
4244 defaultAppFilename = "ko-app"
4345)
4446
45- // GetBase takes an importpath and returns a base v1.Image.
46- type GetBase func (string ) (v1.Image , error )
47+ // GetBase takes an importpath and returns a base image.
48+ type GetBase func (string ) (Result , error )
49+
4750type builder func (context.Context , string , v1.Platform , bool ) (string , error )
4851
4952type buildContext interface {
@@ -442,15 +445,9 @@ func (g *gobuild) tarKoData(ref reference) (*bytes.Buffer, error) {
442445 return buf , walkRecursive (tw , root , kodataRoot )
443446}
444447
445- // Build implements build.Interface
446- func (gb * gobuild ) Build (ctx context.Context , s string ) (v1.Image , error ) {
448+ func (gb * gobuild ) buildOne (ctx context.Context , s string , base v1.Image ) (v1.Image , error ) {
447449 ref := newRef (s )
448450
449- // Determine the appropriate base image for this import path.
450- base , err := gb .getBase (ref .Path ())
451- if err != nil {
452- return nil , err
453- }
454451 cf , err := base .ConfigFile ()
455452 if err != nil {
456453 return nil , err
@@ -563,3 +560,72 @@ func updatePath(cf *v1.ConfigFile) {
563560 // If we get here, we never saw PATH.
564561 cf .Config .Env = append (cf .Config .Env , "PATH=" + appDir )
565562}
563+
564+ // Build implements build.Interface
565+ func (gb * gobuild ) Build (ctx context.Context , s string ) (Result , error ) {
566+ // Determine the appropriate base image for this import path.
567+ base , err := gb .getBase (s )
568+ if err != nil {
569+ return nil , err
570+ }
571+
572+ // Determine what kind of base we have and if we should publish an image or an index.
573+ mt , err := base .MediaType ()
574+ if err != nil {
575+ return nil , err
576+ }
577+
578+ switch mt {
579+ case types .OCIImageIndex , types .DockerManifestList :
580+ base , ok := base .(v1.ImageIndex )
581+ if ! ok {
582+ return nil , fmt .Errorf ("failed to interpret base as index: %v" , base )
583+ }
584+ return gb .buildAll (ctx , s , base )
585+ case types .OCIManifestSchema1 , types .DockerManifestSchema2 :
586+ base , ok := base .(v1.Image )
587+ if ! ok {
588+ return nil , fmt .Errorf ("failed to interpret base as image: %v" , base )
589+ }
590+ return gb .buildOne (ctx , s , base )
591+ default :
592+ return nil , fmt .Errorf ("base image media type: %s" , mt )
593+ }
594+ }
595+
596+ func (gb * gobuild ) buildAll (ctx context.Context , s string , base v1.ImageIndex ) (v1.ImageIndex , error ) {
597+ im , err := base .IndexManifest ()
598+ if err != nil {
599+ return nil , err
600+ }
601+
602+ // Build an image for each child from the base and append it to a new index to produce the result.
603+ adds := []mutate.IndexAddendum {}
604+ for _ , desc := range im .Manifests {
605+ // TODO(jonjohnsonjr): This would fail for a nested index, which is exceedingly rare.
606+ base , err := base .Image (desc .Digest )
607+ if err != nil {
608+ return nil , err
609+ }
610+ img , err := gb .buildOne (ctx , s , base )
611+ if err != nil {
612+ return nil , err
613+ }
614+ adds = append (adds , mutate.IndexAddendum {
615+ Add : img ,
616+ Descriptor : v1.Descriptor {
617+ URLs : desc .URLs ,
618+ MediaType : desc .MediaType ,
619+ Annotations : desc .Annotations ,
620+ Platform : desc .Platform ,
621+ },
622+ })
623+ }
624+
625+ baseType , err := base .MediaType ()
626+ if err != nil {
627+ return nil , err
628+ }
629+
630+ return mutate .IndexMediaType (mutate .AppendManifests (empty .Index , adds ... ), baseType ), nil
631+ }
0 commit comments