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 }