github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/golang/go.go (about) 1 package golang 2 3 import ( 4 "errors" 5 "fmt" 6 "path" 7 "path/filepath" 8 "strings" 9 10 "github.com/jfrog/gocmd" 11 executersutils "github.com/jfrog/gocmd/executers/utils" 12 "github.com/jfrog/gocmd/params" 13 "github.com/jfrog/jfrog-cli-core/artifactory/utils" 14 "github.com/jfrog/jfrog-cli-core/artifactory/utils/golang" 15 "github.com/jfrog/jfrog-cli-core/artifactory/utils/golang/project" 16 "github.com/jfrog/jfrog-cli-core/utils/config" 17 "github.com/jfrog/jfrog-client-go/artifactory" 18 _go "github.com/jfrog/jfrog-client-go/artifactory/services/go" 19 "github.com/jfrog/jfrog-client-go/auth" 20 "github.com/jfrog/jfrog-client-go/utils/errorutils" 21 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 22 "github.com/jfrog/jfrog-client-go/utils/version" 23 ) 24 25 const GoCommandName = "rt_go" 26 27 type GoCommand struct { 28 noRegistry bool 29 publishDeps bool 30 goArg []string 31 buildConfiguration *utils.BuildConfiguration 32 deployerParams *utils.RepositoryConfig 33 resolverParams *utils.RepositoryConfig 34 } 35 36 func NewGoCommand() *GoCommand { 37 return &GoCommand{} 38 } 39 40 func (gc *GoCommand) SetResolverParams(resolverParams *utils.RepositoryConfig) *GoCommand { 41 gc.resolverParams = resolverParams 42 return gc 43 } 44 45 func (gc *GoCommand) SetDeployerParams(deployerParams *utils.RepositoryConfig) *GoCommand { 46 gc.deployerParams = deployerParams 47 return gc 48 } 49 50 func (gc *GoCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *GoCommand { 51 gc.buildConfiguration = buildConfiguration 52 return gc 53 } 54 55 func (gc *GoCommand) SetNoRegistry(noRegistry bool) *GoCommand { 56 gc.noRegistry = noRegistry 57 return gc 58 } 59 60 func (gc *GoCommand) SetPublishDeps(publishDeps bool) *GoCommand { 61 gc.publishDeps = publishDeps 62 return gc 63 } 64 65 func (gc *GoCommand) SetGoArg(goArg []string) *GoCommand { 66 gc.goArg = goArg 67 return gc 68 } 69 70 func (gc *GoCommand) RtDetails() (*config.ArtifactoryDetails, error) { 71 if gc.deployerParams != nil && !gc.deployerParams.IsRtDetailsEmpty() { 72 return gc.deployerParams.RtDetails() 73 } 74 return gc.resolverParams.RtDetails() 75 } 76 77 func (gc *GoCommand) CommandName() string { 78 return GoCommandName 79 } 80 81 func (gc *GoCommand) Run() error { 82 err := golang.LogGoVersion() 83 if err != nil { 84 return err 85 } 86 buildName := gc.buildConfiguration.BuildName 87 buildNumber := gc.buildConfiguration.BuildNumber 88 isCollectBuildInfo := len(buildName) > 0 && len(buildNumber) > 0 89 if isCollectBuildInfo { 90 err = utils.SaveBuildGeneralDetails(buildName, buildNumber) 91 if err != nil { 92 return err 93 } 94 } 95 96 resolverDetails, err := gc.resolverParams.RtDetails() 97 if err != nil { 98 return err 99 } 100 resolverServiceManager, err := utils.CreateServiceManager(resolverDetails, false) 101 if err != nil { 102 return err 103 } 104 resolverParams := ¶ms.Params{} 105 resolverParams.SetRepo(gc.resolverParams.TargetRepo()).SetServiceManager(resolverServiceManager) 106 goInfo := ¶ms.ResolverDeployer{} 107 goInfo.SetResolver(resolverParams) 108 var targetRepo string 109 var deployerServiceManager artifactory.ArtifactoryServicesManager 110 if gc.publishDeps { 111 deployerDetails, err := gc.deployerParams.RtDetails() 112 if err != nil { 113 return err 114 } 115 deployerServiceManager, err = utils.CreateServiceManager(deployerDetails, false) 116 if err != nil { 117 return err 118 } 119 targetRepo = gc.deployerParams.TargetRepo() 120 deployerParams := ¶ms.Params{} 121 deployerParams.SetRepo(targetRepo).SetServiceManager(deployerServiceManager) 122 goInfo.SetDeployer(deployerParams) 123 } 124 125 err = gocmd.RunWithFallbacksAndPublish(gc.goArg, gc.noRegistry, gc.publishDeps, goInfo) 126 if err != nil { 127 return err 128 } 129 if isCollectBuildInfo { 130 tempDirPath := "" 131 if isGoGetCommand := len(gc.goArg) > 0 && gc.goArg[0] == "get"; isGoGetCommand { 132 if len(gc.goArg) < 2 { 133 // Package name was not supplied. Invalid go get commend 134 return errorutils.CheckError(errors.New("Invalid get command. Package name is missing")) 135 } 136 tempDirPath, err = fileutils.CreateTempDir() 137 if err != nil { 138 return err 139 } 140 // Cleanup the temp working directory at the end. 141 defer fileutils.RemoveTempDir(tempDirPath) 142 // Get Artifactory config in order to extract the package version. 143 rtDetails, err := resolverDetails.CreateArtAuthConfig() 144 if err != nil { 145 return err 146 } 147 err = copyGoPackageFiles(tempDirPath, gc.goArg[1], gc.resolverParams.TargetRepo(), rtDetails) 148 if err != nil { 149 return err 150 } 151 } 152 goProject, err := project.Load("-", tempDirPath) 153 if err != nil { 154 return err 155 } 156 includeInfoFiles, err := shouldIncludeInfoFiles(deployerServiceManager, resolverServiceManager) 157 if err != nil { 158 return err 159 } 160 err = goProject.LoadDependencies() 161 if err != nil { 162 return err 163 } 164 err = goProject.CreateBuildInfoDependencies(includeInfoFiles) 165 if err != nil { 166 return err 167 } 168 err = utils.SaveBuildInfo(buildName, buildNumber, goProject.BuildInfo(false, gc.buildConfiguration.Module, targetRepo)) 169 } 170 171 return err 172 } 173 174 // copyGoPackageFiles copies the package files from the go mod cache directory to the given destPath. 175 // The path to those chache files is retrived using the supplied package name and Artifactory details. 176 func copyGoPackageFiles(destPath, packageName, rtTargetRepo string, rtDetails auth.ServiceDetails) error { 177 packageFilesPath, err := getPackageFilePathFromArtifactory(packageName, rtTargetRepo, rtDetails) 178 if err != nil { 179 return err 180 } 181 // Copy the entire content of the relevant Go pkg directory to the requested destination path. 182 err = fileutils.CopyDir(packageFilesPath, destPath, true, nil) 183 if err != nil { 184 return fmt.Errorf("Couldn't find suitable package files: %s", packageFilesPath) 185 } 186 return nil 187 } 188 189 // getPackageFilePathFromArtifactory returns a string that represents the package files chache path. 190 // In most cases the path to those chache files is retrived using the supplied package name and Artifactory details. 191 // However if the user asked for a specifc version (package@vX.Y.Z) the unnecessary call to Artifactpry is avoided. 192 func getPackageFilePathFromArtifactory(packageName, rtTargetRepo string, rtDetails auth.ServiceDetails) (packageFilesPath string, err error) { 193 var version string 194 packageCachePath, err := executersutils.GetGoModCachePath() 195 if err != nil { 196 return 197 } 198 packageNameSplitted := strings.Split(packageName, "@") 199 name := packageNameSplitted[0] 200 // The case the user asks for a specifc version 201 if len(packageNameSplitted) == 2 && strings.HasPrefix(packageNameSplitted[1], "v") { 202 version = packageNameSplitted[1] 203 } else { 204 branchName := "" 205 // The case the user asks for a specifc branch 206 if len(packageNameSplitted) == 2 { 207 branchName = packageNameSplitted[1] 208 } 209 packageVersionRequest := buildPackageVersionRequest(name, branchName) 210 // Retrive the package version using Artifactory 211 version, err = executersutils.GetPackageVersion(rtTargetRepo, packageVersionRequest, rtDetails) 212 if err != nil { 213 return 214 } 215 } 216 return filepath.Join(packageCachePath, name+"@"+version), nil 217 218 } 219 220 // buildPackageVersionRequest returns a string representing the version request to Artifactory. 221 // The resulted string is in the following format: "<Package Name>/@V/<Branch Name>.info". 222 // If a branch name is not given, the branch name will be replaced with the "latest" keyword. 223 // ("<Package Name>/@V/latest.info"). 224 func buildPackageVersionRequest(name, branchName string) string { 225 packageVersionRequest := path.Join(name, "@v") 226 if branchName != "" { 227 // A branch name was given by the user 228 return path.Join(packageVersionRequest, branchName+".info") 229 } 230 // No version was given to "go get" command, so the latest version should be requested 231 return path.Join(packageVersionRequest, "latest.info") 232 } 233 234 // Returns true/false if info files should be included in the build info. 235 func shouldIncludeInfoFiles(deployerServiceManager artifactory.ArtifactoryServicesManager, resolverServiceManager artifactory.ArtifactoryServicesManager) (bool, error) { 236 var artifactoryVersion string 237 var err error 238 if deployerServiceManager != nil { 239 artifactoryVersion, err = deployerServiceManager.GetConfig().GetServiceDetails().GetVersion() 240 } else { 241 artifactoryVersion, err = resolverServiceManager.GetConfig().GetServiceDetails().GetVersion() 242 } 243 if err != nil { 244 return false, err 245 } 246 version := version.NewVersion(artifactoryVersion) 247 includeInfoFiles := version.AtLeast(_go.ArtifactoryMinSupportedVersionForInfoFile) 248 return includeInfoFiles, nil 249 }