github.com/jfrog/jfrog-cli-core/v2@v2.51.0/common/spec/specfiles.go (about) 1 package spec 2 3 import ( 4 "encoding/json" 5 6 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 7 "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 8 clientutils "github.com/jfrog/jfrog-client-go/utils" 9 "github.com/jfrog/jfrog-client-go/utils/errorutils" 10 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 11 ) 12 13 type SpecFiles struct { 14 Files []File 15 } 16 17 func (spec *SpecFiles) Get(index int) *File { 18 if index < len(spec.Files) { 19 return &spec.Files[index] 20 } 21 return new(File) 22 } 23 24 func CreateSpecFromFile(specFilePath string, specVars map[string]string) (spec *SpecFiles, err error) { 25 spec = new(SpecFiles) 26 content, err := fileutils.ReadFile(specFilePath) 27 if errorutils.CheckError(err) != nil { 28 return 29 } 30 31 if len(specVars) > 0 { 32 content = coreutils.ReplaceVars(content, specVars) 33 } 34 35 err = json.Unmarshal(content, spec) 36 if errorutils.CheckError(err) != nil { 37 return 38 } 39 return 40 } 41 42 type File struct { 43 Aql utils.Aql 44 PathMapping utils.PathMapping 45 Pattern string 46 Exclusions []string 47 Target string 48 Explode string 49 BypassArchiveInspection string 50 Props string 51 TargetProps string 52 ExcludeProps string 53 SortOrder string 54 SortBy []string 55 Offset int 56 Limit int 57 Build string 58 Project string 59 ExcludeArtifacts string 60 IncludeDeps string 61 Bundle string 62 PublicGpgKey string `json:"gpg-key,omitempty"` 63 Recursive string 64 Flat string 65 Regexp string 66 Ant string 67 IncludeDirs string 68 ArchiveEntries string 69 ValidateSymlinks string 70 Archive string 71 Symlinks string 72 Transitive string 73 TargetPathInArchive string 74 include []string 75 } 76 77 func (f File) GetInclude() []string { 78 return f.include 79 } 80 81 func (f File) IsFlat(defaultValue bool) (bool, error) { 82 return clientutils.StringToBool(f.Flat, defaultValue) 83 } 84 85 func (f File) IsExplode(defaultValue bool) (bool, error) { 86 return clientutils.StringToBool(f.Explode, defaultValue) 87 } 88 89 func (f File) IsBypassArchiveInspection(defaultValue bool) (bool, error) { 90 return clientutils.StringToBool(f.BypassArchiveInspection, defaultValue) 91 } 92 93 func (f File) IsRegexp(defaultValue bool) (bool, error) { 94 return clientutils.StringToBool(f.Regexp, defaultValue) 95 } 96 97 func (f File) IsAnt(defaultValue bool) (bool, error) { 98 return clientutils.StringToBool(f.Ant, defaultValue) 99 } 100 101 func (f File) IsRecursive(defaultValue bool) (bool, error) { 102 return clientutils.StringToBool(f.Recursive, defaultValue) 103 } 104 105 func (f File) IsIncludeDirs(defaultValue bool) (bool, error) { 106 return clientutils.StringToBool(f.IncludeDirs, defaultValue) 107 } 108 109 func (f File) IsValidateSymlinks(defaultValue bool) (bool, error) { 110 return clientutils.StringToBool(f.ValidateSymlinks, defaultValue) 111 } 112 113 func (f File) IsExcludeArtifacts(defaultValue bool) (bool, error) { 114 return clientutils.StringToBool(f.ExcludeArtifacts, defaultValue) 115 } 116 117 func (f File) IsIncludeDeps(defaultValue bool) (bool, error) { 118 return clientutils.StringToBool(f.IncludeDeps, defaultValue) 119 } 120 121 func (f File) IsSymlinks(defaultValue bool) (bool, error) { 122 return clientutils.StringToBool(f.Symlinks, defaultValue) 123 } 124 125 func (f File) IsTransitive(defaultValue bool) (bool, error) { 126 return clientutils.StringToBool(f.Transitive, defaultValue) 127 } 128 129 func (f File) GetPatternType() (patternType clientutils.PatternType) { 130 if regex, _ := f.IsRegexp(false); regex { 131 return clientutils.RegExp 132 } 133 if ant, _ := f.IsAnt(false); ant { 134 return clientutils.AntPattern 135 } 136 return clientutils.WildCardPattern 137 } 138 139 func (f File) GetPublicGpgKey() string { 140 return f.PublicGpgKey 141 } 142 143 func (f *File) ToCommonParams() (*utils.CommonParams, error) { 144 var err error 145 params := new(utils.CommonParams) 146 params.TargetProps, err = utils.ParseProperties(f.TargetProps) 147 if err != nil { 148 return nil, err 149 } 150 151 params.Aql = f.Aql 152 params.PathMapping = f.PathMapping 153 params.Pattern = f.Pattern 154 params.Exclusions = f.Exclusions 155 params.Target = f.Target 156 params.Props = f.Props 157 params.ExcludeProps = f.ExcludeProps 158 params.Build = f.Build 159 params.Project = f.Project 160 params.Bundle = f.Bundle 161 params.SortOrder = f.SortOrder 162 params.SortBy = f.SortBy 163 params.Offset = f.Offset 164 params.Limit = f.Limit 165 params.ArchiveEntries = f.ArchiveEntries 166 return params, nil 167 } 168 169 func ValidateSpec(files []File, isTargetMandatory, isSearchBasedSpec bool) error { 170 if len(files) == 0 { 171 return errorutils.CheckErrorf("spec must include at least one file group") 172 } 173 174 for _, file := range files { 175 isAql := len(file.Aql.ItemsFind) > 0 176 isPathMapping := len(file.PathMapping.Input) > 0 && len(file.PathMapping.Output) > 0 177 isPattern := len(file.Pattern) > 0 178 isExclusions := len(file.Exclusions) > 0 && len(file.Exclusions[0]) > 0 179 isTarget := len(file.Target) > 0 180 isSortOrder := len(file.SortOrder) > 0 181 isSortBy := len(file.SortBy) > 0 182 isBuild := len(file.Build) > 0 183 isExcludeArtifacts, _ := file.IsExcludeArtifacts(false) 184 isIncludeDeps, _ := file.IsIncludeDeps(false) 185 isBundle := len(file.Bundle) > 0 186 isGPGKey := len(file.PublicGpgKey) > 0 187 isOffset := file.Offset > 0 188 isLimit := file.Limit > 0 189 isValidSortOrder := file.SortOrder == "asc" || file.SortOrder == "desc" 190 isExcludeProps := len(file.ExcludeProps) > 0 191 isArchive := len(file.Archive) > 0 192 isValidArchive := file.Archive == "zip" 193 isSymlinks, _ := file.IsSymlinks(false) 194 isRegexp := file.Regexp == "true" 195 isAnt := file.Ant == "true" 196 isExplode, _ := file.IsExplode(false) 197 isBypassArchiveInspection, _ := file.IsBypassArchiveInspection(false) 198 isTransitive, _ := file.IsTransitive(false) 199 if isPathMapping { 200 if !isAql { 201 return errorutils.CheckErrorf("pathMapping is supported only with aql") 202 } 203 if isTarget { 204 return fileSpecValidationError("pathMapping", "target") 205 } 206 if isPattern { 207 return fileSpecValidationError("pathMapping", "pattern") 208 } 209 } 210 if isTargetMandatory && !isTarget { 211 return errorutils.CheckErrorf("spec must include target") 212 } 213 if !isSearchBasedSpec && !isPattern { 214 return errorutils.CheckErrorf("spec must include a pattern") 215 } 216 if isBuild && isBundle { 217 return fileSpecValidationError("build", "bundle") 218 } 219 if isSearchBasedSpec && !isAql && !isPattern && !isBuild && !isBundle { 220 return errorutils.CheckErrorf("spec must include either aql, pattern, build or bundle") 221 } 222 if isOffset { 223 if isBuild { 224 return fileSpecValidationError("build", "offset") 225 } 226 if isBundle { 227 return fileSpecValidationError("bundle", "offset") 228 } 229 } 230 if isTransitive && isOffset { 231 return fileSpecValidationError("transitive", "offset") 232 } 233 if isLimit { 234 if isBuild { 235 return fileSpecValidationError("build", "limit") 236 } 237 if isBundle { 238 return fileSpecValidationError("bundle", "limit") 239 } 240 } 241 if isAql && isPattern { 242 return fileSpecValidationError("aql", "pattern") 243 } 244 if isAql && isExclusions { 245 return fileSpecValidationError("aql", "exclusions") 246 } 247 if isAql && isExcludeProps { 248 return fileSpecValidationError("aql", "excludeProps") 249 } 250 if !isSortBy && isSortOrder { 251 return errorutils.CheckErrorf("spec cannot include 'sort-order' if 'sort-by' is not included") 252 } 253 if isSortOrder && !isValidSortOrder { 254 return errorutils.CheckErrorf("the value of 'sort-order' can only be 'asc' or 'desc'") 255 } 256 if isTransitive && isSortBy { 257 return fileSpecValidationError("transitive", "sort-by") 258 } 259 if !isBuild && (isExcludeArtifacts || isIncludeDeps) { 260 return errorutils.CheckErrorf("spec cannot include 'exclude-artifacts' or 'include-deps' if 'build' is not included") 261 } 262 if isRegexp && isAnt { 263 return errorutils.CheckErrorf("can not use the option of regexp and ant together") 264 } 265 if isArchive && isSymlinks && isExplode { 266 return errorutils.CheckErrorf("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 filewith properties describing the symlink.\\nThis symlink representation is not yet supported by Artifactory when exploding symlinks from a zip") 267 } 268 if isArchive && !isValidArchive { 269 return errorutils.CheckErrorf("the value of 'archive' (if provided) must be 'zip'") 270 } 271 if isGPGKey && !isBundle { 272 return errorutils.CheckErrorf("spec cannot include 'gpg-key' if 'bundle' is not included") 273 } 274 if isBypassArchiveInspection && !isExplode { 275 return errorutils.CheckErrorf("spec cannot include 'bypass-archive-inspection' if 'explode' is not included") 276 } 277 } 278 return nil 279 } 280 281 func fileSpecValidationError(fieldA, fieldB string) error { 282 return errorutils.CheckErrorf("spec cannot include both '%s' and '%s'", fieldA, fieldB) 283 }