github.com/jfrog/jfrog-cli-core@v1.12.1/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  	TargetProps      string
    54  	ExcludeProps     string
    55  	SortOrder        string
    56  	SortBy           []string
    57  	Offset           int
    58  	Limit            int
    59  	Build            string
    60  	Project          string
    61  	ExcludeArtifacts string
    62  	IncludeDeps      string
    63  	Bundle           string
    64  	Recursive        string
    65  	Flat             string
    66  	Regexp           string
    67  	Ant              string
    68  	IncludeDirs      string
    69  	ArchiveEntries   string
    70  	ValidateSymlinks string
    71  	Archive          string
    72  	Symlinks         string
    73  	Transitive       string
    74  }
    75  
    76  func (f File) IsFlat(defaultValue bool) (bool, error) {
    77  	return clientutils.StringToBool(f.Flat, defaultValue)
    78  }
    79  
    80  func (f File) IsExplode(defaultValue bool) (bool, error) {
    81  	return clientutils.StringToBool(f.Explode, defaultValue)
    82  }
    83  
    84  func (f File) IsRegexp(defaultValue bool) (bool, error) {
    85  	return clientutils.StringToBool(f.Regexp, defaultValue)
    86  }
    87  
    88  func (f File) IsAnt(defaultValue bool) (bool, error) {
    89  	return clientutils.StringToBool(f.Ant, defaultValue)
    90  }
    91  
    92  func (f File) IsRecursive(defaultValue bool) (bool, error) {
    93  	return clientutils.StringToBool(f.Recursive, defaultValue)
    94  }
    95  
    96  func (f File) IsIncludeDirs(defaultValue bool) (bool, error) {
    97  	return clientutils.StringToBool(f.IncludeDirs, defaultValue)
    98  }
    99  
   100  func (f File) IsVlidateSymlinks(defaultValue bool) (bool, error) {
   101  	return clientutils.StringToBool(f.ValidateSymlinks, defaultValue)
   102  }
   103  
   104  func (f File) IsExcludeArtifacts(defaultValue bool) (bool, error) {
   105  	return clientutils.StringToBool(f.ExcludeArtifacts, defaultValue)
   106  }
   107  
   108  func (f File) IsIncludeDeps(defaultValue bool) (bool, error) {
   109  	return clientutils.StringToBool(f.IncludeDeps, defaultValue)
   110  }
   111  
   112  func (f File) IsSymlinks(defaultValue bool) (bool, error) {
   113  	return clientutils.StringToBool(f.Symlinks, defaultValue)
   114  }
   115  
   116  func (f File) IsTransitive(defaultValue bool) (bool, error) {
   117  	return clientutils.StringToBool(f.Transitive, defaultValue)
   118  }
   119  
   120  func (f *File) ToArtifactoryCommonParams() (*utils.ArtifactoryCommonParams, error) {
   121  	var err error
   122  	params := new(utils.ArtifactoryCommonParams)
   123  	params.TargetProps, err = utils.ParseProperties(f.TargetProps)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	params.Aql = f.Aql
   129  	params.Pattern = f.Pattern
   130  	params.ExcludePatterns = f.ExcludePatterns
   131  	params.Exclusions = f.Exclusions
   132  	params.Target = f.Target
   133  	params.Props = f.Props
   134  	params.ExcludeProps = f.ExcludeProps
   135  	params.Build = f.Build
   136  	params.Project = f.Project
   137  	params.Bundle = f.Bundle
   138  	params.SortOrder = f.SortOrder
   139  	params.SortBy = f.SortBy
   140  	params.Offset = f.Offset
   141  	params.Limit = f.Limit
   142  	params.ArchiveEntries = f.ArchiveEntries
   143  	return params, nil
   144  }
   145  
   146  func ValidateSpec(files []File, isTargetMandatory, isSearchBasedSpec, isUpload bool) error {
   147  	if len(files) == 0 {
   148  		return errors.New("Spec must include at least one file group")
   149  	}
   150  	excludePatternsUsed := false
   151  	propsUsedInUpload := false
   152  	for _, file := range files {
   153  		isAql := len(file.Aql.ItemsFind) > 0
   154  		isPattern := len(file.Pattern) > 0
   155  		isExcludePatterns := len(file.ExcludePatterns) > 0 && len(file.ExcludePatterns[0]) > 0
   156  		excludePatternsUsed = excludePatternsUsed || isExcludePatterns
   157  		isExclusions := len(file.Exclusions) > 0 && len(file.Exclusions[0]) > 0
   158  		isTarget := len(file.Target) > 0
   159  		isSortOrder := len(file.SortOrder) > 0
   160  		isSortBy := len(file.SortBy) > 0
   161  		isBuild := len(file.Build) > 0
   162  		isExcludeArtifacts, _ := file.IsExcludeArtifacts(false)
   163  		isIncludeDeps, _ := file.IsIncludeDeps(false)
   164  		isBundle := len(file.Bundle) > 0
   165  		isOffset := file.Offset > 0
   166  		isLimit := file.Limit > 0
   167  		isValidSortOrder := file.SortOrder == "asc" || file.SortOrder == "desc"
   168  		propsUsedInUpload = propsUsedInUpload || (isUpload && len(file.Props) > 0)
   169  		isExcludeProps := len(file.ExcludeProps) > 0
   170  		isArchive := len(file.Archive) > 0
   171  		isValidArchive := file.Archive == "zip"
   172  		isSymlinks, _ := file.IsSymlinks(false)
   173  		isRegexp := file.Regexp == "true"
   174  		isAnt := file.Ant == "true"
   175  		isExplode, _ := file.IsExplode(false)
   176  
   177  		if isTargetMandatory && !isTarget {
   178  			return errors.New("Spec must include target.")
   179  		}
   180  		if !isSearchBasedSpec && !isPattern {
   181  			return errors.New("Spec must include a pattern.")
   182  		}
   183  		if isBuild && isBundle {
   184  			return fileSpecValidationError("build", "bundle")
   185  		}
   186  		if isSearchBasedSpec {
   187  			if !isAql && !isPattern && !isBuild && !isBundle {
   188  				return errors.New("Spec must include either aql, pattern, build or bundle.")
   189  			}
   190  			if isOffset {
   191  				if isBuild {
   192  					return fileSpecValidationError("build", "offset")
   193  				}
   194  				if isBundle {
   195  					return fileSpecValidationError("bundle", "offset")
   196  				}
   197  			}
   198  			if isLimit {
   199  				if isBuild {
   200  					return fileSpecValidationError("build", "limit")
   201  				}
   202  				if isBundle {
   203  					return fileSpecValidationError("bundle", "limit")
   204  				}
   205  			}
   206  		}
   207  		if isAql && isPattern {
   208  			return fileSpecValidationError("aql", "pattern")
   209  		}
   210  		if isAql && isExcludePatterns {
   211  			return fileSpecValidationError("aql", "exclude-patterns")
   212  		}
   213  		if isAql && isExclusions {
   214  			return fileSpecValidationError("aql", "exclusions")
   215  		}
   216  		if isAql && isExcludeProps {
   217  			return fileSpecValidationError("aql", "excludeProps")
   218  		}
   219  		if isExclusions && isExcludePatterns {
   220  			return fileSpecValidationError("exclusions", "exclude-patterns")
   221  		}
   222  		if !isSortBy && isSortOrder {
   223  			return errors.New("Spec cannot include 'sort-order' if 'sort-by' is not included")
   224  		}
   225  		if isSortOrder && !isValidSortOrder {
   226  			return errors.New("The value of 'sort-order' can only be 'asc' or 'desc'.")
   227  		}
   228  		if !isBuild && (isExcludeArtifacts || isIncludeDeps) {
   229  			return errors.New("Spec cannot include 'exclude-artifacts' or 'include-deps' if 'build' is not included.")
   230  		}
   231  		if isRegexp && isAnt {
   232  			return errors.New("Can not use the option of regexp and ant together.")
   233  		}
   234  		if isArchive && isSymlinks && isExplode {
   235  			return errors.New("Symlinks cannot be stored in an archive that will be exploded in artifactory.\nWhen uploading a symlink to Artifactory, the symlink is represented in Artifactory as 0 size file with properties describing the symlink.\nThis symlink representation is not yet supported by Artifactory when exploding symlinks from a zip.")
   236  		}
   237  		if isArchive && !isValidArchive {
   238  			return errors.New("The value of 'archive' (if provided) must be 'zip'.")
   239  		}
   240  	}
   241  	if excludePatternsUsed {
   242  		showDeprecationOnExcludePatterns()
   243  	}
   244  	if propsUsedInUpload {
   245  		showDeprecationOnProps()
   246  	}
   247  	return nil
   248  }
   249  
   250  func fileSpecValidationError(fieldA, fieldB string) error {
   251  	return errors.New(fmt.Sprintf("Spec cannot include both '%s' and '%s.'", fieldA, fieldB))
   252  }
   253  
   254  func showDeprecationOnExcludePatterns() {
   255  	log.Warn(`The --exclude-patterns command option and the 'excludePatterns' File Spec property are deprecated. 
   256  	Please use the --exclusions command option or the 'exclusions' File Spec property instead.
   257  	Unlike exclude-patterns, exclusions take into account the repository as part of the pattern.
   258  	For example: 
   259  	"excludePatterns": ["a.zip"]
   260  	can be translated to
   261  	"exclusions": ["repo-name/a.zip"]
   262  	or
   263  	"exclusions": ["*/a.zip"]`)
   264  }
   265  
   266  func showDeprecationOnProps() {
   267  	log.Warn(`The --props command option and the 'Props' File Spec property are deprecated in Upload.
   268  	Please use the --target-props command option or the 'targetProps' File Spec property instead.`)
   269  }