github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/local/types.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package local
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/bazel"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/buildpacks"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/custom"
    28  	dockerbuilder "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/docker"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/jib"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko"
    31  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/misc"
    32  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
    33  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
    34  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
    35  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    36  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    37  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    38  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    39  )
    40  
    41  // Builder uses the host docker daemon to build and tag the image.
    42  type Builder struct {
    43  	local latest.LocalBuild
    44  
    45  	cfg                docker.Config
    46  	localDocker        docker.LocalDaemon
    47  	localCluster       bool
    48  	pushImages         bool
    49  	tryImportMissing   bool
    50  	prune              bool
    51  	pruneChildren      bool
    52  	skipTests          bool
    53  	mode               config.RunMode
    54  	kubeContext        string
    55  	builtImages        []string
    56  	insecureRegistries map[string]bool
    57  	muted              build.Muted
    58  	localPruner        *pruner
    59  	artifactStore      build.ArtifactStore
    60  	sourceDependencies graph.SourceDependenciesCache
    61  }
    62  
    63  type Config interface {
    64  	docker.Config
    65  
    66  	GlobalConfig() string
    67  	GetKubeContext() string
    68  	GetCluster() config.Cluster
    69  	SkipTests() bool
    70  	Mode() config.RunMode
    71  	NoPruneChildren() bool
    72  	Muted() config.Muted
    73  	PushImages() config.BoolOrUndefined
    74  }
    75  
    76  type BuilderContext interface {
    77  	Config
    78  	ArtifactStore() build.ArtifactStore
    79  	SourceDependenciesResolver() graph.SourceDependenciesCache
    80  }
    81  
    82  // NewBuilder returns an new instance of a local Builder.
    83  func NewBuilder(ctx context.Context, bCtx BuilderContext, buildCfg *latest.LocalBuild) (*Builder, error) {
    84  	localDocker, err := docker.NewAPIClient(ctx, bCtx)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("getting docker client: %w", err)
    87  	}
    88  
    89  	cluster := bCtx.GetCluster()
    90  	pushFlag := bCtx.PushImages()
    91  
    92  	var pushImages bool
    93  	switch {
    94  	case pushFlag.Value() != nil:
    95  		pushImages = *pushFlag.Value()
    96  		log.Entry(context.TODO()).Debugf("push value set via skaffold build --push flag, --push=%t", *pushFlag.Value())
    97  	case buildCfg.Push == nil:
    98  		pushImages = cluster.PushImages
    99  		log.Entry(context.TODO()).Debugf("push value not present in NewBuilder, defaulting to %t because cluster.PushImages is %t", pushImages, cluster.PushImages)
   100  	default:
   101  		pushImages = *buildCfg.Push
   102  	}
   103  
   104  	tryImportMissing := buildCfg.TryImportMissing
   105  
   106  	return &Builder{
   107  		local:              *buildCfg,
   108  		cfg:                bCtx,
   109  		kubeContext:        bCtx.GetKubeContext(),
   110  		localDocker:        localDocker,
   111  		localCluster:       cluster.Local,
   112  		pushImages:         pushImages,
   113  		tryImportMissing:   tryImportMissing,
   114  		skipTests:          bCtx.SkipTests(),
   115  		mode:               bCtx.Mode(),
   116  		prune:              bCtx.Prune(),
   117  		pruneChildren:      !bCtx.NoPruneChildren(),
   118  		localPruner:        newPruner(localDocker, !bCtx.NoPruneChildren()),
   119  		insecureRegistries: bCtx.GetInsecureRegistries(),
   120  		muted:              bCtx.Muted(),
   121  		artifactStore:      bCtx.ArtifactStore(),
   122  		sourceDependencies: bCtx.SourceDependenciesResolver(),
   123  	}, nil
   124  }
   125  
   126  // Prune uses the docker API client to remove all images built with Skaffold
   127  func (b *Builder) Prune(ctx context.Context, _ io.Writer) error {
   128  	var toPrune []string
   129  	seen := make(map[string]bool)
   130  
   131  	for _, img := range b.builtImages {
   132  		if !seen[img] && !b.localPruner.isPruned(img) {
   133  			toPrune = append(toPrune, img)
   134  			seen[img] = true
   135  		}
   136  	}
   137  	_, err := b.localDocker.Prune(ctx, toPrune, b.pruneChildren)
   138  	return err
   139  }
   140  
   141  // artifactBuilder represents a per artifact builder interface
   142  type artifactBuilder interface {
   143  	Build(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) (string, error)
   144  	SupportedPlatforms() platform.Matcher
   145  }
   146  
   147  // newPerArtifactBuilder returns an instance of `artifactBuilder`
   148  func newPerArtifactBuilder(b *Builder, a *latest.Artifact) (artifactBuilder, error) {
   149  	switch {
   150  	case a.DockerArtifact != nil:
   151  		return dockerbuilder.NewArtifactBuilder(b.localDocker, b.cfg, b.local.UseDockerCLI, b.local.UseBuildkit, b.pushImages, b.artifactStore, b.sourceDependencies), nil
   152  
   153  	case a.BazelArtifact != nil:
   154  		return bazel.NewArtifactBuilder(b.localDocker, b.cfg, b.pushImages), nil
   155  
   156  	case a.JibArtifact != nil:
   157  		return jib.NewArtifactBuilder(b.localDocker, b.cfg, b.pushImages, b.skipTests, b.artifactStore), nil
   158  
   159  	case a.CustomArtifact != nil:
   160  		// required artifacts as environment variables
   161  		dependencies := util.EnvPtrMapToSlice(docker.ResolveDependencyImages(a.Dependencies, b.artifactStore, true), "=")
   162  		return custom.NewArtifactBuilder(b.localDocker, b.cfg, b.pushImages, b.skipTests, append(b.retrieveExtraEnv(), dependencies...)), nil
   163  
   164  	case a.BuildpackArtifact != nil:
   165  		return buildpacks.NewArtifactBuilder(b.localDocker, b.pushImages, b.mode, b.artifactStore), nil
   166  
   167  	case a.KoArtifact != nil:
   168  		return ko.NewArtifactBuilder(b.localDocker, b.pushImages, b.mode, b.insecureRegistries), nil
   169  
   170  	default:
   171  		return nil, fmt.Errorf("unexpected type %q for local artifact:\n%s", misc.ArtifactType(a), misc.FormatArtifact(a))
   172  	}
   173  }