| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | /* | 
					
						
							|  |  |  | Copyright 2018 Google LLC 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. | 
					
						
							|  |  |  | You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | See the License for the specific language governing permissions and | 
					
						
							|  |  |  | limitations under the License. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-26 15:56:15 -07:00
										 |  |  | package commands | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-11-10 01:23:09 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"log" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:23:09 +08:00
										 |  |  | 	"os/signal" | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2020-04-20 09:13:33 -07:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2019-11-10 01:23:09 +08:00
										 |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/google/go-containerregistry/pkg/authn" | 
					
						
							|  |  |  | 	"github.com/google/go-containerregistry/pkg/name" | 
					
						
							|  |  |  | 	v1 "github.com/google/go-containerregistry/pkg/v1" | 
					
						
							| 
									
										
										
										
											2021-06-09 09:20:45 -07:00
										 |  |  | 	"github.com/google/go-containerregistry/pkg/v1/daemon" | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	"github.com/google/go-containerregistry/pkg/v1/remote" | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 	"github.com/google/go-containerregistry/pkg/v1/types" | 
					
						
							|  |  |  | 	"github.com/google/ko/pkg/build" | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | 	"github.com/google/ko/pkg/commands/options" | 
					
						
							| 
									
										
										
										
											2021-06-09 09:20:45 -07:00
										 |  |  | 	"github.com/google/ko/pkg/publish" | 
					
						
							| 
									
										
										
										
											2019-04-30 13:08:54 -05:00
										 |  |  | 	"github.com/spf13/viper" | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 	defaultBaseImage   string | 
					
						
							|  |  |  | 	baseImageOverrides map[string]string | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | // getBaseImage returns a function that determines the base image for a given import path. | 
					
						
							|  |  |  | // If the `bo.BaseImage` parameter is non-empty, it overrides base image configuration from `.ko.yaml`. | 
					
						
							|  |  |  | func getBaseImage(platform string, bo *options.BuildOptions) build.GetBase { | 
					
						
							| 
									
										
										
										
											2020-12-21 11:47:05 -08:00
										 |  |  | 	return func(ctx context.Context, s string) (build.Result, error) { | 
					
						
							| 
									
										
										
										
											2020-09-25 11:50:20 -07:00
										 |  |  | 		s = strings.TrimPrefix(s, build.StrictScheme) | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		// Viper configuration file keys are case insensitive, and are | 
					
						
							|  |  |  | 		// returned as all lowercase.  This means that import paths with | 
					
						
							|  |  |  | 		// uppercase must be normalized for matching here, e.g. | 
					
						
							|  |  |  | 		//    github.com/GoogleCloudPlatform/foo/cmd/bar | 
					
						
							|  |  |  | 		// comes through as: | 
					
						
							|  |  |  | 		//    github.com/googlecloudplatform/foo/cmd/bar | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 		baseImage, ok := baseImageOverrides[strings.ToLower(s)] | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 			baseImage = defaultBaseImage | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | 		if bo.BaseImage != "" { | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 			baseImage = bo.BaseImage | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nameOpts := []name.Option{} | 
					
						
							|  |  |  | 		if bo.InsecureRegistry { | 
					
						
							|  |  |  | 			nameOpts = append(nameOpts, name.Insecure) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ref, err := name.ParseReference(baseImage, nameOpts...) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("parsing base image (%q): %v", baseImage, err) | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-06-09 09:20:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// For ko.local, look in the daemon. | 
					
						
							|  |  |  | 		if ref.Context().RegistryStr() == publish.LocalDomain { | 
					
						
							|  |  |  | 			return daemon.Image(ref) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | 		userAgent := ua() | 
					
						
							|  |  |  | 		if bo.UserAgent != "" { | 
					
						
							|  |  |  | 			userAgent = bo.UserAgent | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		ropt := []remote.Option{ | 
					
						
							|  |  |  | 			remote.WithAuthFromKeychain(authn.DefaultKeychain), | 
					
						
							| 
									
										
										
										
											2021-05-26 04:44:52 +10:00
										 |  |  | 			remote.WithUserAgent(userAgent), | 
					
						
							| 
									
										
										
										
											2020-12-21 11:47:05 -08:00
										 |  |  | 			remote.WithContext(ctx), | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Using --platform=all will use an image index for the base, | 
					
						
							|  |  |  | 		// otherwise we'll resolve it to the appropriate platform. | 
					
						
							| 
									
										
										
										
											2020-12-21 16:53:00 -08:00
										 |  |  | 		// | 
					
						
							|  |  |  | 		// Platforms can be comma-separated if we only want a subset of the base | 
					
						
							|  |  |  | 		// image. | 
					
						
							|  |  |  | 		multiplatform := platform == "all" || strings.Contains(platform, ",") | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 		var p v1.Platform | 
					
						
							| 
									
										
										
										
											2020-12-21 16:53:00 -08:00
										 |  |  | 		if platform != "" && !multiplatform { | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 			parts := strings.Split(platform, "/") | 
					
						
							|  |  |  | 			if len(parts) > 0 { | 
					
						
							|  |  |  | 				p.OS = parts[0] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if len(parts) > 1 { | 
					
						
							|  |  |  | 				p.Architecture = parts[1] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if len(parts) > 2 { | 
					
						
							|  |  |  | 				p.Variant = parts[2] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if len(parts) > 3 { | 
					
						
							|  |  |  | 				return nil, fmt.Errorf("too many slashes in platform spec: %s", platform) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ropt = append(ropt, remote.WithPlatform(p)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		log.Printf("Using base %s for %s", ref, s) | 
					
						
							|  |  |  | 		desc, err := remote.Get(ref, ropt...) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		switch desc.MediaType { | 
					
						
							|  |  |  | 		case types.OCIImageIndex, types.DockerManifestList: | 
					
						
							| 
									
										
										
										
											2020-12-21 16:53:00 -08:00
										 |  |  | 			if multiplatform { | 
					
						
							| 
									
										
										
										
											2020-09-24 15:58:08 -07:00
										 |  |  | 				return desc.ImageIndex() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return desc.Image() | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return desc.Image() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 21:50:35 +02:00
										 |  |  | func getTimeFromEnv(env string) (*v1.Time, error) { | 
					
						
							|  |  |  | 	epoch := os.Getenv(env) | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	if epoch == "" { | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	seconds, err := strconv.ParseInt(epoch, 10, 64) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-15 21:50:35 +02:00
										 |  |  | 		return nil, fmt.Errorf("the environment variable %s should be the number of seconds since January 1st 1970, 00:00 UTC, got: %v", env, err) | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-10 17:21:31 +02:00
										 |  |  | 	return &v1.Time{Time: time.Unix(seconds, 0)}, nil | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 21:50:35 +02:00
										 |  |  | func getCreationTime() (*v1.Time, error) { | 
					
						
							|  |  |  | 	return getTimeFromEnv("SOURCE_DATE_EPOCH") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getKoDataCreationTime() (*v1.Time, error) { | 
					
						
							|  |  |  | 	return getTimeFromEnv("KO_DATA_DATE_EPOCH") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:23:09 +08:00
										 |  |  | func createCancellableContext() context.Context { | 
					
						
							|  |  |  | 	signals := make(chan os.Signal) | 
					
						
							|  |  |  | 	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) | 
					
						
							|  |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		<-signals | 
					
						
							|  |  |  | 		cancel() | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ctx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | func init() { | 
					
						
							|  |  |  | 	// If omitted, use this base image. | 
					
						
							| 
									
										
										
										
											2020-09-24 16:14:58 -07:00
										 |  |  | 	viper.SetDefault("defaultBaseImage", "gcr.io/distroless/static:nonroot") | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	viper.SetConfigName(".ko") // .yaml is implicit | 
					
						
							| 
									
										
										
										
											2020-02-06 13:51:22 -08:00
										 |  |  | 	viper.SetEnvPrefix("KO") | 
					
						
							|  |  |  | 	viper.AutomaticEnv() | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if override := os.Getenv("KO_CONFIG_PATH"); override != "" { | 
					
						
							|  |  |  | 		viper.AddConfigPath(override) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	viper.AddConfigPath("./") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := viper.ReadInConfig(); err != nil { | 
					
						
							|  |  |  | 		if _, ok := err.(viper.ConfigFileNotFoundError); !ok { | 
					
						
							|  |  |  | 			log.Fatalf("error reading config file: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ref := viper.GetString("defaultBaseImage") | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 	if _, err := name.ParseReference(ref); err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 		log.Fatalf("'defaultBaseImage': error parsing %q as image reference: %v", ref, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 	defaultBaseImage = ref | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 	baseImageOverrides = make(map[string]string) | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	overrides := viper.GetStringMapString("baseImageOverrides") | 
					
						
							|  |  |  | 	for k, v := range overrides { | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 		if _, err := name.ParseReference(v); err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 			log.Fatalf("'baseImageOverrides': error parsing %q as image reference: %v", v, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-06-01 09:47:30 -07:00
										 |  |  | 		baseImageOverrides[k] = v | 
					
						
							| 
									
										
										
										
											2019-03-14 14:23:47 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |