github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/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-go/artifactory/utils"
     8  	"github.com/jfrog/jfrog-cli-go/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.17.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  	buildInfoProperties, err := utils.CreateBuildInfoPropertiesFile(mc.configuration.BuildName, mc.configuration.BuildNumber, vConfig, utils.Maven)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	return &mvnRunConfig{
   205  		java:                   javaExecPath,
   206  		pluginDependencies:     dependenciesPath,
   207  		plexusClassworlds:      plexusClassworlds[0],
   208  		cleassworldsConfig:     filepath.Join(dependenciesPath, classworldsConfFileName),
   209  		mavenHome:              mavenHome,
   210  		workspace:              currentWorkdir,
   211  		goals:                  mc.goals,
   212  		buildInfoProperties:    buildInfoProperties,
   213  		generatedBuildInfoPath: vConfig.GetString(utils.GENERATED_BUILD_INFO),
   214  		mavenOpts:              mavenOpts,
   215  	}, nil
   216  }
   217  
   218  func (config *mvnRunConfig) GetCmd() *exec.Cmd {
   219  	var cmd []string
   220  	cmd = append(cmd, config.java)
   221  	cmd = append(cmd, "-classpath", config.plexusClassworlds)
   222  	cmd = append(cmd, "-Dmaven.home="+config.mavenHome)
   223  	cmd = append(cmd, "-DbuildInfoConfig.propertiesFile="+config.buildInfoProperties)
   224  	cmd = append(cmd, "-Dm3plugin.lib="+config.pluginDependencies)
   225  	cmd = append(cmd, "-Dclassworlds.conf="+config.cleassworldsConfig)
   226  	cmd = append(cmd, "-Dmaven.multiModuleProjectDirectory="+config.workspace)
   227  	if config.mavenOpts != "" {
   228  		cmd = append(cmd, strings.Split(config.mavenOpts, " ")...)
   229  	}
   230  	cmd = append(cmd, "org.codehaus.plexus.classworlds.launcher.Launcher")
   231  	cmd = append(cmd, strings.Split(config.goals, " ")...)
   232  	return exec.Command(cmd[0], cmd[1:]...)
   233  }
   234  
   235  func (config *mvnRunConfig) GetEnv() map[string]string {
   236  	return map[string]string{}
   237  }
   238  
   239  func (config *mvnRunConfig) GetStdWriter() io.WriteCloser {
   240  	return nil
   241  }
   242  
   243  func (config *mvnRunConfig) GetErrWriter() io.WriteCloser {
   244  	return nil
   245  }
   246  
   247  type mvnRunConfig struct {
   248  	java                   string
   249  	plexusClassworlds      string
   250  	cleassworldsConfig     string
   251  	mavenHome              string
   252  	pluginDependencies     string
   253  	workspace              string
   254  	pom                    string
   255  	goals                  string
   256  	buildInfoProperties    string
   257  	generatedBuildInfoPath string
   258  	mavenOpts              string
   259  }