github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/jib/maven.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 jib
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"os/exec"
    24  
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    31  )
    32  
    33  // For testing
    34  var (
    35  	mavenArgsFunc      = mavenArgs
    36  	mavenBuildArgsFunc = mavenBuildArgs
    37  )
    38  
    39  // Skaffold-Jib depends on functionality introduced with Jib-Maven 1.4.0
    40  const MinimumJibMavenVersion = "1.4.0"
    41  const MinimumJibMavenVersionForSync = "2.0.0"
    42  const MinimumJibMavenVersionForCrossPlatform = "3.2.0"
    43  
    44  // MavenCommand stores Maven executable and wrapper name
    45  var MavenCommand = util.CommandWrapper{Executable: "mvn", Wrapper: "mvnw"}
    46  
    47  func (b *Builder) buildJibMavenToDocker(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibArtifact, deps []*latest.ArtifactDependency, tag string, platforms platform.Matcher) (string, error) {
    48  	args := GenerateMavenBuildArgs("dockerBuild", tag, artifact, platforms, b.skipTests, b.pushImages, deps, b.artifacts, b.cfg.GetInsecureRegistries(), output.IsColorable(out))
    49  	if err := b.runMavenCommand(ctx, out, workspace, args); err != nil {
    50  		return "", jibToolErr(err)
    51  	}
    52  
    53  	return b.localDocker.ImageID(ctx, tag)
    54  }
    55  
    56  func (b *Builder) buildJibMavenToRegistry(ctx context.Context, out io.Writer, workspace string, artifact *latest.JibArtifact, deps []*latest.ArtifactDependency, tag string, platforms platform.Matcher) (string, error) {
    57  	args := GenerateMavenBuildArgs("build", tag, artifact, platforms, b.skipTests, b.pushImages, deps, b.artifacts, b.cfg.GetInsecureRegistries(), output.IsColorable(out))
    58  	if err := b.runMavenCommand(ctx, out, workspace, args); err != nil {
    59  		return "", jibToolErr(err)
    60  	}
    61  
    62  	return docker.RemoteDigest(tag, b.cfg, nil)
    63  }
    64  
    65  func (b *Builder) runMavenCommand(ctx context.Context, out io.Writer, workspace string, args []string) error {
    66  	cmd := MavenCommand.CreateCommand(ctx, workspace, args)
    67  	cmd.Env = append(util.OSEnviron(), b.localDocker.ExtraEnv()...)
    68  	cmd.Stdout = out
    69  	cmd.Stderr = out
    70  
    71  	log.Entry(ctx).Infof("Building %s: %s, %v", workspace, cmd.Path, cmd.Args)
    72  	if err := util.RunCmd(ctx, &cmd); err != nil {
    73  		return fmt.Errorf("maven build failed: %w", err)
    74  	}
    75  
    76  	return nil
    77  }
    78  
    79  // getDependenciesMaven finds the source dependencies for the given jib-maven artifact.
    80  // All paths are absolute.
    81  func getDependenciesMaven(ctx context.Context, workspace string, a *latest.JibArtifact) ([]string, error) {
    82  	deps, err := getDependencies(ctx, workspace, getCommandMaven(ctx, workspace, a), a)
    83  	if err != nil {
    84  		return nil, dependencyErr(JibMaven, workspace, err)
    85  	}
    86  	log.Entry(ctx).Debugf("Found dependencies for jib maven artifact: %v", deps)
    87  	return deps, nil
    88  }
    89  
    90  func getCommandMaven(ctx context.Context, workspace string, a *latest.JibArtifact) exec.Cmd {
    91  	args := mavenArgsFunc(a, MinimumJibMavenVersion)
    92  	args = append(args, "jib:_skaffold-files-v2", "--quiet", "--batch-mode")
    93  
    94  	return MavenCommand.CreateCommand(ctx, workspace, args)
    95  }
    96  
    97  func getSyncMapCommandMaven(ctx context.Context, workspace string, a *latest.JibArtifact) *exec.Cmd {
    98  	cmd := MavenCommand.CreateCommand(ctx, workspace, mavenBuildArgsFunc("_skaffold-sync-map", a, true, false, MinimumJibMavenVersionForSync))
    99  	return &cmd
   100  }
   101  
   102  // GenerateMavenBuildArgs generates the arguments to Maven for building the project as an image.
   103  func GenerateMavenBuildArgs(goal, imageName string, a *latest.JibArtifact, platforms platform.Matcher, skipTests, pushImages bool, deps []*latest.ArtifactDependency, r ArtifactResolver, insecureRegistries map[string]bool, showColors bool) []string {
   104  	minVersion := MinimumJibMavenVersion
   105  	if platforms.IsCrossPlatform() {
   106  		minVersion = MinimumJibMavenVersionForCrossPlatform
   107  	}
   108  	args := mavenBuildArgsFunc(goal, a, skipTests, showColors, minVersion)
   109  	if insecure, err := isOnInsecureRegistry(imageName, insecureRegistries); err == nil && insecure {
   110  		// jib doesn't support marking specific registries as insecure
   111  		args = append(args, "-Djib.allowInsecureRegistries=true")
   112  	}
   113  	if baseImg, found := baseImageArg(a, r, deps, pushImages); found {
   114  		args = append(args, baseImg)
   115  	}
   116  	if platforms.IsNotEmpty() {
   117  		args = append(args, fmt.Sprintf("-Djib.from.platforms=%s", platforms.String()))
   118  	}
   119  	args = append(args, "-Dimage="+imageName)
   120  	return args
   121  }
   122  
   123  // Do not use directly, use mavenBuildArgsFunc
   124  func mavenBuildArgs(goal string, a *latest.JibArtifact, skipTests, showColors bool, minimumVersion string) []string {
   125  	// Disable jib's rich progress footer on builds. Show colors on normal builds for clearer information,
   126  	// but use --batch-mode for internal goals to avoid formatting issues
   127  	var args []string
   128  	if showColors {
   129  		args = []string{"-Dstyle.color=always", "-Djansi.passthrough=true", "-Djib.console=plain"}
   130  	} else {
   131  		args = []string{"--batch-mode"}
   132  	}
   133  	args = append(args, mavenArgsFunc(a, minimumVersion)...)
   134  
   135  	if skipTests {
   136  		args = append(args, "-DskipTests=true")
   137  	}
   138  
   139  	if a.Project == "" {
   140  		// single-module project
   141  		args = append(args, "prepare-package", "jib:"+goal)
   142  	} else {
   143  		// multi-module project: instruct jib to containerize only the given module
   144  		args = append(args, "package", "jib:"+goal, "-Djib.containerize="+a.Project)
   145  	}
   146  	return args
   147  }
   148  
   149  // Do not use directly, use mavenArgsFunc
   150  func mavenArgs(a *latest.JibArtifact, minimumVersion string) []string {
   151  	args := []string{"jib:_skaffold-fail-if-jib-out-of-date", "-Djib.requiredVersion=" + minimumVersion}
   152  	args = append(args, a.Flags...)
   153  
   154  	if a.Project == "" {
   155  		// single-module project
   156  		args = append(args, "--non-recursive")
   157  	} else {
   158  		// multi-module project
   159  		args = append(args, "--projects", a.Project, "--also-make")
   160  	}
   161  
   162  	return args
   163  }