github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/spec/specfiles.go (about)

     1  package spec
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/jfrog/jfrog-cli-core/utils/coreutils"
     8  	"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
     9  	clientutils "github.com/jfrog/jfrog-client-go/utils"
    10  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    11  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    12  	"github.com/jfrog/jfrog-client-go/utils/log"
    13  )
    14  
    15  type SpecFiles struct {
    16  	Files []File
    17  }
    18  
    19  func (spec *SpecFiles) Get(index int) *File {
    20  	if index < len(spec.Files) {
    21  		return &spec.Files[index]
    22  	}
    23  	return new(File)
    24  }
    25  
    26  func CreateSpecFromFile(specFilePath string, specVars map[string]string) (spec *SpecFiles, err error) {
    27  	spec = new(SpecFiles)
    28  	content, err := fileutils.ReadFile(specFilePath)
    29  	if errorutils.CheckError(err) != nil {
    30  		return
    31  	}
    32  
    33  	if len(specVars) > 0 {
    34  		content = coreutils.ReplaceVars(content, specVars)
    35  	}
    36  
    37  	err = json.Unmarshal(content, spec)
    38  	if errorutils.CheckError(err) != nil {
    39  		return
    40  	}
    41  	return
    42  }
    43  
    44  type File struct {
    45  	Aql     utils.Aql
    46  	Pattern string
    47  	// Deprecated, use Exclusions instead
    48  	ExcludePatterns  []string
    49  	Exclusions       []string
    50  	Target           string
    51  	Explode          string
    52  	Props            string
    53  	ExcludeProps     string
    54  	SortOrder        string
    55  	SortBy           []string
    56  	Offset           int
    57  	Limit            int
    58  	Build            string
    59  	ExcludeArtifacts string
    60  	IncludeDeps      string
    61  	Bundle           string
    62  	Recursive        string
    63  	Flat             string
    64  	Regexp           string
    65  	IncludeDirs      string
    66  	ArchiveEntries   string
    67  	ValidateSymlinks string
    68  }
    69  
    70  func (f File) IsFlat(defaultValue bool) (bool, error) {
    71  	return clientutils.StringToBool(f.Flat, defaultValue)
    72  }
    73  
    74  func (f File) IsExplode(defaultValue bool) (bool, error) {
    75  	return clientutils.StringToBool(f.Explode, defaultValue)
    76  }
    77  
    78  func (f File) IsRegexp(defaultValue bool) (bool, error) {
    79  	return clientutils.StringToBool(f.Regexp, defaultValue)
    80  }
    81  
    82  func (f File) IsRecursive(defaultValue bool) (bool, error) {
    83  	return clientutils.StringToBool(f.Recursive, defaultValue)
    84  }
    85  
    86  func (f File) IsIncludeDirs(defaultValue bool) (bool, error) {
    87  	return clientutils.StringToBool(f.IncludeDirs, defaultValue)
    88  }
    89  
    90  func (f File) IsVlidateSymlinks(defaultValue bool) (bool, error) {
    91  	return clientutils.StringToBool(f.ValidateSymlinks, defaultValue)
    92  }
    93  
    94  func (f File) IsExcludeArtifacts(defaultValue bool) (bool, error) {
    95  	return clientutils.StringToBool(f.ExcludeArtifacts, defaultValue)
    96  }
    97  
    98  func (f File) IsIncludeDeps(defaultValue bool) (bool, error) {
    99  	return clientutils.StringToBool(f.IncludeDeps, defaultValue)
   100  }
   101  
   102  func (f *File) ToArtifactoryCommonParams() *utils.ArtifactoryCommonParams {
   103  	params := new(utils.ArtifactoryCommonParams)
   104  	params.Aql = f.Aql
   105  	params.Pattern = f.Pattern
   106  	params.ExcludePatterns = f.ExcludePatterns
   107  	params.Exclusions = f.Exclusions
   108  	params.Target = f.Target
   109  	params.Props = f.Props
   110  	params.ExcludeProps = f.ExcludeProps
   111  	params.Build = f.Build
   112  	params.Bundle = f.Bundle
   113  	params.SortOrder = f.SortOrder
   114  	params.SortBy = f.SortBy
   115  	params.Offset = f.Offset
   116  	params.Limit = f.Limit
   117  	params.ArchiveEntries = f.ArchiveEntries
   118  	return params
   119  }
   120  
   121  func ValidateSpec(files []File, isTargetMandatory, isSearchBasedSpec bool) error {
   122  	if len(files) == 0 {
   123  		return errors.New("Spec must include at least one file group")
   124  	}
   125  	excludePatternsUsed := false
   126  	for _, file := range files {
   127  		isAql := len(file.Aql.ItemsFind) > 0
   128  		isPattern := len(file.Pattern) > 0
   129  		isExcludePatterns := len(file.ExcludePatterns) > 0 && len(file.ExcludePatterns[0]) > 0
   130  		excludePatternsUsed = excludePatternsUsed || isExcludePatterns
   131  		isExclusions := len(file.Exclusions) > 0 && len(file.Exclusions[0]) > 0
   132  		isTarget := len(file.Target) > 0
   133  		isSortOrder := len(file.SortOrder) > 0
   134  		isSortBy := len(file.SortBy) > 0
   135  		isBuild := len(file.Build) > 0
   136  		isExcludeArtifacts, _ := file.IsExcludeArtifacts(false)
   137  		isIncludeDeps, _ := file.IsIncludeDeps(false)
   138  		isBundle := len(file.Bundle) > 0
   139  		isOffset := file.Offset > 0
   140  		isLimit := file.Limit > 0
   141  		isValidSortOrder := file.SortOrder == "asc" || file.SortOrder == "desc"
   142  
   143  		if isTargetMandatory && !isTarget {
   144  			return errors.New("Spec must include target.")
   145  		}
   146  		if !isSearchBasedSpec && !isPattern {
   147  			return errors.New("Spec must include a pattern.")
   148  		}
   149  		if isBuild && isBundle {
   150  			return fileSpecValidationError("build", "bundle")
   151  		}
   152  		if isSearchBasedSpec {
   153  			if !isAql && !isPattern && !isBuild && !isBundle {
   154  				return errors.New("Spec must include either aql, pattern, build or bundle.")
   155  			}
   156  			if isOffset {
   157  				if isBuild {
   158  					return fileSpecValidationError("build", "offset")
   159  				}
   160  				if isBundle {
   161  					return fileSpecValidationError("bundle", "offset")
   162  				}
   163  			}
   164  			if isLimit {
   165  				if isBuild {
   166  					return fileSpecValidationError("build", "limit")
   167  				}
   168  				if isBundle {
   169  					return fileSpecValidationError("bundle", "limit")
   170  				}
   171  			}
   172  		}
   173  		if isAql && isPattern {
   174  			return fileSpecValidationError("aql", "pattern")
   175  		}
   176  		if isAql && isExcludePatterns {
   177  			return fileSpecValidationError("aql", "exclude-patterns")
   178  		}
   179  		if isAql && isExclusions {
   180  			return fileSpecValidationError("aql", "exclusions")
   181  		}
   182  		if isExclusions && isExcludePatterns {
   183  			return fileSpecValidationError("exclusions", "exclude-patterns")
   184  		}
   185  		if !isSortBy && isSortOrder {
   186  			return errors.New("Spec cannot include 'sort-order' if 'sort-by' is not included")
   187  		}
   188  		if isSortOrder && !isValidSortOrder {
   189  			return errors.New("The value of 'sort-order' can only be 'asc' or 'desc'.")
   190  		}
   191  		if !isBuild && (isExcludeArtifacts || isIncludeDeps) {
   192  			return errors.New("Spec cannot include 'exclude-artifacts' or 'include-deps' if 'build' is not included.")
   193  		}
   194  	}
   195  	if excludePatternsUsed {
   196  		showDeprecationOnExcludePatterns()
   197  	}
   198  	return nil
   199  }
   200  
   201  func fileSpecValidationError(fieldA, fieldB string) error {
   202  	return errors.New(fmt.Sprintf("Spec cannot include both '%s' and '%s.'", fieldA, fieldB))
   203  }
   204  
   205  func showDeprecationOnExcludePatterns() {
   206  	log.Warn(`The --exclude-patterns command option and the 'excludePatterns' File Spec property are deprecated. 
   207  	Please use the --exclusions command option or the 'exclusions' File Spec property instead.
   208  	Unlike exclude-patterns, exclusions take into account the repository as part of the pattern.
   209  	For example: 
   210  	"excludePatterns": ["a.zip"]
   211  	can be translated to
   212  	"exclusions": ["repo-name/a.zip"]
   213  	or
   214  	"exclusions": ["*/a.zip"]`)
   215  }