github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/commands/buildinfo/adddependencies.go (about)

     1  package buildinfo
     2  
     3  import (
     4  	"errors"
     5  	commandsutils "github.com/jfrog/jfrog-cli-go/artifactory/commands/utils"
     6  	"github.com/jfrog/jfrog-cli-go/artifactory/spec"
     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/artifactory/buildinfo"
    10  	"github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns"
    11  	specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
    12  	clientutils "github.com/jfrog/jfrog-client-go/utils"
    13  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    14  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    15  	"github.com/jfrog/jfrog-client-go/utils/log"
    16  	regxp "regexp"
    17  	"strconv"
    18  )
    19  
    20  type BuildAddDependenciesCommand struct {
    21  	buildConfiguration *utils.BuildConfiguration
    22  	dependenciesSpec   *spec.SpecFiles
    23  	dryRun             bool
    24  	result             *commandsutils.Result
    25  }
    26  
    27  func NewBuildAddDependenciesCommand() *BuildAddDependenciesCommand {
    28  	return &BuildAddDependenciesCommand{result: new(commandsutils.Result)}
    29  }
    30  
    31  func (badc *BuildAddDependenciesCommand) Result() *commandsutils.Result {
    32  	return badc.result
    33  }
    34  
    35  func (badc *BuildAddDependenciesCommand) CommandName() string {
    36  	return "rt_build_add_dependencies"
    37  }
    38  
    39  func (badc *BuildAddDependenciesCommand) RtDetails() (*config.ArtifactoryDetails, error) {
    40  	return config.GetDefaultArtifactoryConf()
    41  }
    42  
    43  func (badc *BuildAddDependenciesCommand) Run() error {
    44  	log.Info("Running Build Add Dependencies command...")
    45  	if !badc.dryRun {
    46  		if err := utils.SaveBuildGeneralDetails(badc.buildConfiguration.BuildName, badc.buildConfiguration.BuildNumber); err != nil {
    47  			return err
    48  		}
    49  	}
    50  
    51  	dependenciesPaths, errorOccurred := badc.collectDependenciesBySpec()
    52  	dependenciesDetails, errorOccurred, failures := collectDependenciesChecksums(dependenciesPaths, errorOccurred)
    53  	if !badc.dryRun {
    54  		err := badc.saveDependenciesToFileSystem(dependenciesDetails)
    55  		if err != nil {
    56  			errorOccurred = true
    57  			log.Error(err)
    58  			// mark all as failures and clean the succeeded
    59  			failures += len(dependenciesDetails)
    60  			dependenciesDetails = make(map[string]*fileutils.FileDetails)
    61  		}
    62  	}
    63  	badc.result.SetSuccessCount(len(dependenciesDetails))
    64  	badc.result.SetFailCount(failures)
    65  	if errorOccurred {
    66  		return errors.New("Build Add Dependencies command finished with errors. Please review the logs.")
    67  	}
    68  	return nil
    69  }
    70  
    71  func (badc *BuildAddDependenciesCommand) SetDryRun(dryRun bool) *BuildAddDependenciesCommand {
    72  	badc.dryRun = dryRun
    73  	return badc
    74  }
    75  
    76  func (badc *BuildAddDependenciesCommand) SetDependenciesSpec(dependenciesSpec *spec.SpecFiles) *BuildAddDependenciesCommand {
    77  	badc.dependenciesSpec = dependenciesSpec
    78  	return badc
    79  }
    80  
    81  func (badc *BuildAddDependenciesCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *BuildAddDependenciesCommand {
    82  	badc.buildConfiguration = buildConfiguration
    83  	return badc
    84  }
    85  
    86  func collectDependenciesChecksums(dependenciesPaths map[string]string, errorOccurred bool) (map[string]*fileutils.FileDetails, bool, int) {
    87  	failures := 0
    88  	dependenciesDetails := make(map[string]*fileutils.FileDetails)
    89  	for _, dependencyPath := range dependenciesPaths {
    90  		var details *fileutils.FileDetails
    91  		var err error
    92  		if fileutils.IsPathSymlink(dependencyPath) {
    93  			log.Info("Adding symlink dependency:", dependencyPath)
    94  			details, err = fspatterns.CreateSymlinkFileDetails()
    95  		} else {
    96  			log.Info("Adding dependency:", dependencyPath)
    97  			details, err = fileutils.GetFileDetails(dependencyPath)
    98  		}
    99  		if err != nil {
   100  			errorOccurred = true
   101  			log.Error(err)
   102  			failures++
   103  			continue
   104  		}
   105  		dependenciesDetails[dependencyPath] = details
   106  	}
   107  	return dependenciesDetails, errorOccurred, failures
   108  }
   109  
   110  func (badc *BuildAddDependenciesCommand) collectDependenciesBySpec() (map[string]string, bool) {
   111  	errorOccurred := false
   112  	dependenciesPaths := make(map[string]string)
   113  	for _, specFile := range badc.dependenciesSpec.Files {
   114  		params, err := prepareArtifactoryParams(specFile)
   115  		if err != nil {
   116  			errorOccurred = true
   117  			log.Error(err)
   118  			continue
   119  		}
   120  		paths, err := getDependenciesBySpecFileParams(params)
   121  		if err != nil {
   122  			errorOccurred = true
   123  			log.Error(err)
   124  			continue
   125  		}
   126  		for _, path := range paths {
   127  			log.Debug("Found matching path:", path)
   128  			dependenciesPaths[path] = path
   129  		}
   130  	}
   131  	return dependenciesPaths, errorOccurred
   132  }
   133  
   134  func prepareArtifactoryParams(specFile spec.File) (*specutils.ArtifactoryCommonParams, error) {
   135  	params := specFile.ToArtifactoryCommonParams()
   136  	recursive, err := clientutils.StringToBool(specFile.Recursive, true)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	params.Recursive = recursive
   142  	regexp, err := clientutils.StringToBool(specFile.Regexp, false)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	params.Regexp = regexp
   148  	return params, nil
   149  }
   150  
   151  func getDependenciesBySpecFileParams(addDepsParams *specutils.ArtifactoryCommonParams) ([]string, error) {
   152  	addDepsParams.SetPattern(clientutils.ReplaceTildeWithUserHome(addDepsParams.GetPattern()))
   153  	// Save parentheses index in pattern, witch have corresponding placeholder.
   154  	rootPath, err := fspatterns.GetRootPath(addDepsParams.GetPattern(), addDepsParams.GetTarget(), addDepsParams.IsRegexp(), false)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	isDir, err := fileutils.IsDirExists(rootPath, false)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	if !isDir || fileutils.IsPathSymlink(addDepsParams.GetPattern()) {
   165  		artifact, err := fspatterns.GetSingleFileToUpload(rootPath, "", false, false)
   166  		if err != nil {
   167  			return nil, err
   168  		}
   169  		return []string{artifact.LocalPath}, nil
   170  	}
   171  	return collectPatternMatchingFiles(addDepsParams, rootPath)
   172  }
   173  
   174  func collectPatternMatchingFiles(addDepsParams *specutils.ArtifactoryCommonParams, rootPath string) ([]string, error) {
   175  	addDepsParams.SetPattern(clientutils.PrepareLocalPathForUpload(addDepsParams.Pattern, addDepsParams.IsRegexp()))
   176  	excludePathPattern := fspatterns.PrepareExcludePathPattern(addDepsParams)
   177  	patternRegex, err := regxp.Compile(addDepsParams.Pattern)
   178  	if errorutils.CheckError(err) != nil {
   179  		return nil, err
   180  	}
   181  
   182  	paths, err := fspatterns.GetPaths(rootPath, addDepsParams.IsRecursive(), addDepsParams.IsIncludeDirs(), true)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	result := []string{}
   187  
   188  	for _, path := range paths {
   189  		matches, _, _, err := fspatterns.PrepareAndFilterPaths(path, excludePathPattern, true, false, patternRegex)
   190  		if err != nil {
   191  			log.Error(err)
   192  			continue
   193  		}
   194  		if len(matches) > 0 {
   195  			result = append(result, path)
   196  		}
   197  	}
   198  	return result, nil
   199  }
   200  
   201  func (badc *BuildAddDependenciesCommand) saveDependenciesToFileSystem(files map[string]*fileutils.FileDetails) error {
   202  	log.Debug("Saving", strconv.Itoa(len(files)), "dependencies.")
   203  	populateFunc := func(partial *buildinfo.Partial) {
   204  		partial.Dependencies = convertFileInfoToDependencies(files)
   205  	}
   206  	return utils.SavePartialBuildInfo(badc.buildConfiguration.BuildName, badc.buildConfiguration.BuildNumber, populateFunc)
   207  }
   208  
   209  func convertFileInfoToDependencies(files map[string]*fileutils.FileDetails) []buildinfo.Dependency {
   210  	var buildDependencies []buildinfo.Dependency
   211  	for filePath, fileInfo := range files {
   212  		dependency := buildinfo.Dependency{Checksum: &buildinfo.Checksum{}}
   213  		dependency.Md5 = fileInfo.Checksum.Md5
   214  		dependency.Sha1 = fileInfo.Checksum.Sha1
   215  		filename, _ := fileutils.GetFileAndDirFromPath(filePath)
   216  		dependency.Id = filename
   217  		buildDependencies = append(buildDependencies, dependency)
   218  	}
   219  	return buildDependencies
   220  }