github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/commands/golang/gorecursivepublish.go (about) 1 package golang 2 3 import ( 4 "github.com/jfrog/gocmd" 5 "github.com/jfrog/gocmd/cmd" 6 "github.com/jfrog/gocmd/executers" 7 gocmdutils "github.com/jfrog/gocmd/executers/utils" 8 "github.com/jfrog/gocmd/params" 9 "github.com/jfrog/jfrog-cli-go/artifactory/utils" 10 "github.com/jfrog/jfrog-cli-go/artifactory/utils/golang" 11 "github.com/jfrog/jfrog-client-go/utils/errorutils" 12 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 13 "github.com/jfrog/jfrog-client-go/utils/log" 14 "io/ioutil" 15 "os" 16 "strings" 17 ) 18 19 type GoRecursivePublishCommand struct { 20 utils.RepositoryConfig 21 } 22 23 func NewGoRecursivePublishCommand() *GoRecursivePublishCommand { 24 return &GoRecursivePublishCommand{} 25 } 26 27 func (grp *GoRecursivePublishCommand) Run() error { 28 rtDetails, err := grp.RtDetails() 29 if errorutils.CheckError(err) != nil { 30 return err 31 } 32 serviceManager, err := utils.CreateServiceManager(rtDetails, false) 33 if err != nil { 34 return err 35 } 36 goModEditMessage := os.Getenv("JFROG_CLI_GO_MOD_EDIT_MSG") 37 if goModEditMessage == "" { 38 goModEditMessage = "// Generated by JFrog" 39 } else { 40 if !strings.HasPrefix(goModEditMessage, "//") { 41 newContent := append([]byte("// "), goModEditMessage...) 42 goModEditMessage = string(newContent) 43 } 44 } 45 46 modFileExists, err := fileutils.IsFileExists("go.mod", false) 47 if err != nil { 48 return err 49 } 50 gmi := goModInfo{} 51 wd, err := os.Getwd() 52 if errorutils.CheckError(err) != nil { 53 return gmi.revert(wd, err) 54 } 55 err = golang.LogGoVersion() 56 if err != nil { 57 return err 58 } 59 if !modFileExists { 60 err = gmi.prepareModFile(wd, goModEditMessage) 61 if err != nil { 62 return err 63 } 64 } else { 65 log.Debug("Using existing root mod file.") 66 gmi.modFileContent, gmi.modFileStat, err = cmd.GetFileDetails("go.mod") 67 if err != nil { 68 return err 69 } 70 } 71 72 goInfo := ¶ms.ResolverDeployer{} 73 resolverDeployer := ¶ms.Params{} 74 resolverDeployer.SetServiceManager(serviceManager).SetRepo(grp.TargetRepo()) 75 goInfo.SetDeployer(resolverDeployer).SetResolver(resolverDeployer) 76 err = gocmd.RecursivePublish(goModEditMessage, goInfo) 77 if errorutils.CheckError(err) != nil { 78 if !modFileExists { 79 log.Debug("Graph failed, preparing to run go mod tidy on the root project since got the following error:", err.Error()) 80 err = gmi.prepareAndRunTidyOnFailedGraph(wd, goModEditMessage, goInfo) 81 if err != nil { 82 return gmi.revert(wd, err) 83 } 84 } else { 85 return gmi.revert(wd, err) 86 } 87 } 88 89 err = os.Chdir(wd) 90 if errorutils.CheckError(err) != nil { 91 return gmi.revert(wd, err) 92 } 93 return gmi.revert(wd, nil) 94 } 95 96 func (grp *GoRecursivePublishCommand) CommandName() string { 97 return "rt_go_recursive_publish" 98 } 99 100 type goModInfo struct { 101 modFileContent []byte 102 modFileStat os.FileInfo 103 shouldRevertModFile bool 104 } 105 106 func (gmi *goModInfo) revert(wd string, err error) error { 107 if gmi.shouldRevertModFile { 108 log.Debug("Reverting to original go.mod of the root project") 109 revertErr := ioutil.WriteFile("go.mod", gmi.modFileContent, gmi.modFileStat.Mode()) 110 if errorutils.CheckError(revertErr) != nil { 111 if err != nil { 112 log.Error(revertErr) 113 return errorutils.CheckError(err) 114 } else { 115 return revertErr 116 } 117 } 118 } 119 return nil 120 } 121 122 func (gmi *goModInfo) prepareModFile(wd, goModEditMessage string) error { 123 err := cmd.RunGoModInit("") 124 if err != nil { 125 return errorutils.CheckError(err) 126 } 127 regExp, err := gocmdutils.GetRegex() 128 if err != nil { 129 return errorutils.CheckError(err) 130 } 131 notEmptyModRegex := regExp.GetNotEmptyModRegex() 132 gmi.modFileContent, gmi.modFileStat, err = cmd.GetFileDetails("go.mod") 133 if err != nil { 134 return err 135 } 136 projectPackage := executers.Package{} 137 projectPackage.SetModContent(gmi.modFileContent) 138 packageWithDep := executers.PackageWithDeps{Dependency: &projectPackage} 139 if !packageWithDep.PatternMatched(notEmptyModRegex) { 140 log.Debug("Root mod is empty, preparing to run 'go mod tidy'") 141 err = cmd.RunGoModTidy() 142 if errorutils.CheckError(err) != nil { 143 return gmi.revert(wd, err) 144 } 145 gmi.shouldRevertModFile = true 146 } else { 147 log.Debug("Root project mod not empty.") 148 } 149 150 return nil 151 } 152 153 func (gmi *goModInfo) prepareAndRunTidyOnFailedGraph(wd, goModEditMessage string, goInfo *params.ResolverDeployer) error { 154 // First revert the mod to an empty mod that includes only module name 155 lines := strings.Split(string(gmi.modFileContent), "\n") 156 emptyMod := strings.Join(lines[:3], "\n") 157 gmi.modFileContent = []byte(emptyMod) 158 gmi.shouldRevertModFile = true 159 err := gmi.revert(wd, nil) 160 if err != nil { 161 log.Error(err) 162 } 163 // Run go mod tidy. 164 err = cmd.RunGoModTidy() 165 if err != nil { 166 return errorutils.CheckError(err) 167 } 168 // Perform collection again after tidy finished successfully. 169 err = gocmd.RecursivePublish(goModEditMessage, goInfo) 170 if errorutils.CheckError(err) != nil { 171 return gmi.revert(wd, err) 172 } 173 return nil 174 }