github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/custom/script.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 custom
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"os/exec"
    24  	"path/filepath"
    25  	"runtime"
    26  
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/misc"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    31  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    32  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    33  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    34  )
    35  
    36  var (
    37  	// For testing
    38  	buildContext = retrieveBuildContext
    39  )
    40  
    41  func (b *Builder) runBuildScript(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) error {
    42  	cmd, err := b.retrieveCmd(ctx, out, a, tag, platforms)
    43  	if err != nil {
    44  		return fmt.Errorf("retrieving cmd: %w", err)
    45  	}
    46  
    47  	log.Entry(ctx).Debugf("Running command: %s", cmd.Args)
    48  	if err := cmd.Start(); err != nil {
    49  		return fmt.Errorf("starting cmd: %w", err)
    50  	}
    51  
    52  	return misc.HandleGracefulTermination(ctx, cmd)
    53  }
    54  
    55  func (b *Builder) retrieveCmd(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) (*exec.Cmd, error) {
    56  	artifact := a.CustomArtifact
    57  
    58  	// Expand command
    59  	command, err := util.ExpandEnvTemplate(artifact.BuildCommand, nil)
    60  	if err != nil {
    61  		return nil, fmt.Errorf("unable to parse build command %q: %w", artifact.BuildCommand, err)
    62  	}
    63  
    64  	var cmd *exec.Cmd
    65  	// We evaluate the command with a shell so that it can contain
    66  	// env variables.
    67  	if runtime.GOOS == "windows" {
    68  		cmd = exec.CommandContext(ctx, "cmd.exe", "/C", command)
    69  	} else {
    70  		cmd = exec.CommandContext(ctx, "sh", "-c", command)
    71  	}
    72  	cmd.Stdout = out
    73  	cmd.Stderr = out
    74  
    75  	env, err := b.retrieveEnv(a, tag, platforms)
    76  	if err != nil {
    77  		return nil, fmt.Errorf("retrieving env variables for %q: %w", a.ImageName, err)
    78  	}
    79  	cmd.Env = env
    80  
    81  	dir, err := buildContext(a.Workspace)
    82  	if err != nil {
    83  		return nil, fmt.Errorf("getting context for artifact: %w", err)
    84  	}
    85  	cmd.Dir = dir
    86  
    87  	return cmd, nil
    88  }
    89  
    90  func (b *Builder) retrieveEnv(a *latest.Artifact, tag string, platforms platform.Matcher) ([]string, error) {
    91  	buildContext, err := buildContext(a.Workspace)
    92  	if err != nil {
    93  		return nil, fmt.Errorf("getting absolute path for artifact build context: %w", err)
    94  	}
    95  
    96  	envs := []string{
    97  		fmt.Sprintf("%s=%s", constants.Image, tag),
    98  		fmt.Sprintf("%s=%t", constants.PushImage, b.pushImages),
    99  		fmt.Sprintf("%s=%s", constants.BuildContext, buildContext),
   100  		fmt.Sprintf("%s=%s", constants.Platforms, platforms.String()),
   101  		fmt.Sprintf("%s=%t", constants.SkipTest, b.skipTest),
   102  	}
   103  
   104  	ref, err := docker.ParseReference(tag)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("parsing image %v: %w", tag, err)
   107  	}
   108  
   109  	// Standardize access to Image reference fields in templates
   110  	envs = append(envs, fmt.Sprintf("%s=%s", constants.ImageRef.Repo, ref.BaseName))
   111  	envs = append(envs, fmt.Sprintf("%s=%s", constants.ImageRef.Tag, ref.Tag))
   112  
   113  	envs = append(envs, b.additionalEnv...)
   114  	envs = append(envs, util.OSEnviron()...)
   115  	return envs, nil
   116  }
   117  
   118  func retrieveBuildContext(workspace string) (string, error) {
   119  	return filepath.Abs(workspace)
   120  }