github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/mvn/mvn.go (about)

     1  package mvn
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	gofrogcmd "github.com/jfrog/gofrog/io"
     7  	"github.com/jfrog/jfrog-cli-core/artifactory/utils"
     8  	"github.com/jfrog/jfrog-cli-core/utils/config"
     9  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    10  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    11  	"github.com/jfrog/jfrog-client-go/utils/log"
    12  	"github.com/spf13/viper"
    13  	"io"
    14  	"io/ioutil"
    15  	"os"
    16  	"os/exec"
    17  	"path"
    18  	"path/filepath"
    19  	"strings"
    20  )
    21  
    22  const mavenExtractorDependencyVersion = "2.20.0"
    23  const classworldsConfFileName = "classworlds.conf"
    24  const MavenHome = "M2_HOME"
    25  
    26  type MvnCommand struct {
    27  	goals         []string
    28  	configPath    string
    29  	insecureTls   bool
    30  	configuration *utils.BuildConfiguration
    31  	rtDetails     *config.ArtifactoryDetails
    32  	threads       int
    33  }
    34  
    35  func NewMvnCommand() *MvnCommand {
    36  	return &MvnCommand{}
    37  }
    38  
    39  func (mc *MvnCommand) SetRtDetails(rtDetails *config.ArtifactoryDetails) *MvnCommand {
    40  	mc.rtDetails = rtDetails
    41  	return mc
    42  }
    43  
    44  func (mc *MvnCommand) SetConfiguration(configuration *utils.BuildConfiguration) *MvnCommand {
    45  	mc.configuration = configuration
    46  	return mc
    47  }
    48  
    49  func (mc *MvnCommand) SetConfigPath(configPath string) *MvnCommand {
    50  	mc.configPath = configPath
    51  	return mc
    52  }
    53  
    54  func (mc *MvnCommand) SetGoals(goals []string) *MvnCommand {
    55  	mc.goals = goals
    56  	return mc
    57  }
    58  
    59  func (mc *MvnCommand) SetThreads(threads int) *MvnCommand {
    60  	mc.threads = threads
    61  	return mc
    62  }
    63  
    64  func (mc *MvnCommand) SetInsecureTls(insecureTls bool) *MvnCommand {
    65  	mc.insecureTls = insecureTls
    66  	return mc
    67  }
    68  
    69  func (mc *MvnCommand) Run() error {
    70  	log.Info("Running Mvn...")
    71  	err := validateMavenInstallation()
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	var dependenciesPath string
    77  	dependenciesPath, err = downloadDependencies()
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	mvnRunConfig, err := mc.createMvnRunConfig(dependenciesPath)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	defer os.Remove(mvnRunConfig.buildInfoProperties)
    88  	return gofrogcmd.RunCmd(mvnRunConfig)
    89  }
    90  
    91  // Returns the ArtfiactoryDetails. The information returns from the config file provided.
    92  func (mc *MvnCommand) RtDetails() (*config.ArtifactoryDetails, error) {
    93  	// Get the rtDetails from the config file.
    94  	var err error
    95  	if mc.rtDetails == nil {
    96  		vConfig, err := utils.ReadConfigFile(mc.configPath, utils.YAML)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		mc.rtDetails, err = utils.GetRtDetails(vConfig)
   101  	}
   102  	return mc.rtDetails, err
   103  }
   104  
   105  func (mc *MvnCommand) CommandName() string {
   106  	return "rt_maven"
   107  }
   108  
   109  func validateMavenInstallation() error {
   110  	log.Debug("Checking prerequisites.")
   111  	mavenHome := os.Getenv(MavenHome)
   112  	if mavenHome == "" {
   113  		return errorutils.CheckError(errors.New(MavenHome + " environment variable is not set"))
   114  	}
   115  	return nil
   116  }
   117  
   118  func downloadDependencies() (string, error) {
   119  	dependenciesPath, err := config.GetJfrogDependenciesPath()
   120  	if err != nil {
   121  		return "", err
   122  	}
   123  	dependenciesPath = filepath.Join(dependenciesPath, "maven", mavenExtractorDependencyVersion)
   124  
   125  	filename := fmt.Sprintf("build-info-extractor-maven3-%s-uber.jar", mavenExtractorDependencyVersion)
   126  	filePath := fmt.Sprintf("org/jfrog/buildinfo/build-info-extractor-maven3/%s", mavenExtractorDependencyVersion)
   127  	downloadPath := path.Join(filePath, filename)
   128  
   129  	err = utils.DownloadExtractorIfNeeded(downloadPath, filepath.Join(dependenciesPath, filename))
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	err = createClassworldsConfig(dependenciesPath)
   135  	return dependenciesPath, err
   136  }
   137  
   138  func createClassworldsConfig(dependenciesPath string) error {
   139  	classworldsPath := filepath.Join(dependenciesPath, classworldsConfFileName)
   140  
   141  	if fileutils.IsPathExists(classworldsPath, false) {
   142  		return nil
   143  	}
   144  	return errorutils.CheckError(ioutil.WriteFile(classworldsPath, []byte(utils.ClassworldsConf), 0644))
   145  }
   146  
   147  func (mc *MvnCommand) createMvnRunConfig(dependenciesPath string) (*mvnRunConfig, error) {
   148  	var err error
   149  	var javaExecPath string
   150  
   151  	javaHome := os.Getenv("JAVA_HOME")
   152  	if javaHome != "" {
   153  		javaExecPath = filepath.Join(javaHome, "bin", "java")
   154  	} else {
   155  		javaExecPath, err = exec.LookPath("java")
   156  		if err != nil {
   157  			return nil, errorutils.CheckError(err)
   158  		}
   159  	}
   160  
   161  	mavenHome := os.Getenv("M2_HOME")
   162  	plexusClassworlds, err := filepath.Glob(filepath.Join(mavenHome, "boot", "plexus-classworlds*.jar"))
   163  	if err != nil {
   164  		return nil, errorutils.CheckError(err)
   165  	}
   166  
   167  	mavenOpts := os.Getenv("MAVEN_OPTS")
   168  
   169  	if len(plexusClassworlds) != 1 {
   170  		return nil, errorutils.CheckError(errors.New("couldn't find plexus-classworlds-x.x.x.jar in Maven installation path, please check M2_HOME environment variable"))
   171  	}
   172  
   173  	var currentWorkdir string
   174  	currentWorkdir, err = os.Getwd()
   175  	if err != nil {
   176  		return nil, errorutils.CheckError(err)
   177  	}
   178  
   179  	var vConfig *viper.Viper
   180  	vConfig, err = utils.ReadConfigFile(mc.configPath, utils.YAML)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	if len(mc.configuration.BuildName) > 0 && len(mc.configuration.BuildNumber) > 0 {
   186  		vConfig.Set(utils.BUILD_NAME, mc.configuration.BuildName)
   187  		vConfig.Set(utils.BUILD_NUMBER, mc.configuration.BuildNumber)
   188  		err = utils.SaveBuildGeneralDetails(mc.configuration.BuildName, mc.configuration.BuildNumber)
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  	}
   193  	vConfig.Set(utils.INSECURE_TLS, mc.insecureTls)
   194  
   195  	if mc.threads > 0 {
   196  		vConfig.Set(utils.FORK_COUNT, mc.threads)
   197  	}
   198  
   199  	if !vConfig.IsSet("deployer") {
   200  		setEmptyDeployer(vConfig)
   201  	}
   202  
   203  	buildInfoProperties, err := utils.CreateBuildInfoPropertiesFile(mc.configuration.BuildName, mc.configuration.BuildNumber, vConfig, utils.Maven)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	return &mvnRunConfig{
   209  		java:                         javaExecPath,
   210  		pluginDependencies:           dependenciesPath,
   211  		plexusClassworlds:            plexusClassworlds[0],
   212  		cleassworldsConfig:           filepath.Join(dependenciesPath, classworldsConfFileName),
   213  		mavenHome:                    mavenHome,
   214  		workspace:                    currentWorkdir,
   215  		goals:                        mc.goals,
   216  		buildInfoProperties:          buildInfoProperties,
   217  		artifactoryResolutionEnabled: vConfig.IsSet("resolver"),
   218  		generatedBuildInfoPath:       vConfig.GetString(utils.GENERATED_BUILD_INFO),
   219  		mavenOpts:                    mavenOpts,
   220  	}, nil
   221  }
   222  
   223  func setEmptyDeployer(vConfig *viper.Viper) {
   224  	vConfig.Set(utils.DEPLOYER_PREFIX+utils.DEPLOY_ARTIFACTS, "false")
   225  	vConfig.Set(utils.DEPLOYER_PREFIX+utils.URL, "http://empty_url")
   226  	vConfig.Set(utils.DEPLOYER_PREFIX+utils.RELEASE_REPO, "empty_repo")
   227  	vConfig.Set(utils.DEPLOYER_PREFIX+utils.SNAPSHOT_REPO, "empty_repo")
   228  }
   229  
   230  func (config *mvnRunConfig) GetCmd() *exec.Cmd {
   231  	var cmd []string
   232  	cmd = append(cmd, config.java)
   233  	cmd = append(cmd, "-classpath", config.plexusClassworlds)
   234  	cmd = append(cmd, "-Dmaven.home="+config.mavenHome)
   235  	cmd = append(cmd, "-DbuildInfoConfig.propertiesFile="+config.buildInfoProperties)
   236  	if config.artifactoryResolutionEnabled {
   237  		cmd = append(cmd, "-DbuildInfoConfig.artifactoryResolutionEnabled=true")
   238  	}
   239  	cmd = append(cmd, "-Dm3plugin.lib="+config.pluginDependencies)
   240  	cmd = append(cmd, "-Dclassworlds.conf="+config.cleassworldsConfig)
   241  	cmd = append(cmd, "-Dmaven.multiModuleProjectDirectory="+config.workspace)
   242  	if config.mavenOpts != "" {
   243  		cmd = append(cmd, strings.Split(config.mavenOpts, " ")...)
   244  	}
   245  	cmd = append(cmd, "org.codehaus.plexus.classworlds.launcher.Launcher")
   246  	cmd = append(cmd, config.goals...)
   247  	return exec.Command(cmd[0], cmd[1:]...)
   248  }
   249  
   250  func (config *mvnRunConfig) GetEnv() map[string]string {
   251  	return map[string]string{}
   252  }
   253  
   254  func (config *mvnRunConfig) GetStdWriter() io.WriteCloser {
   255  	return nil
   256  }
   257  
   258  func (config *mvnRunConfig) GetErrWriter() io.WriteCloser {
   259  	return nil
   260  }
   261  
   262  type mvnRunConfig struct {
   263  	java                         string
   264  	plexusClassworlds            string
   265  	cleassworldsConfig           string
   266  	mavenHome                    string
   267  	pluginDependencies           string
   268  	workspace                    string
   269  	pom                          string
   270  	goals                        []string
   271  	buildInfoProperties          string
   272  	artifactoryResolutionEnabled bool
   273  	generatedBuildInfoPath       string
   274  	mavenOpts                    string
   275  }