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 := &params.ResolverDeployer{}
    73  	resolverDeployer := &params.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  }