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 }