github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/commands/generic/upload.go (about) 1 package generic 2 3 import ( 4 "errors" 5 "os" 6 "strconv" 7 "time" 8 9 "github.com/jfrog/jfrog-cli-core/artifactory/spec" 10 "github.com/jfrog/jfrog-cli-core/artifactory/utils" 11 "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 12 "github.com/jfrog/jfrog-client-go/artifactory/services" 13 clientutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 14 "github.com/jfrog/jfrog-client-go/utils/errorutils" 15 ioUtils "github.com/jfrog/jfrog-client-go/utils/io" 16 "github.com/jfrog/jfrog-client-go/utils/io/content" 17 "github.com/jfrog/jfrog-client-go/utils/log" 18 ) 19 20 type UploadCommand struct { 21 GenericCommand 22 uploadConfiguration *utils.UploadConfiguration 23 buildConfiguration *utils.BuildConfiguration 24 progress ioUtils.ProgressMgr 25 } 26 27 func NewUploadCommand() *UploadCommand { 28 return &UploadCommand{GenericCommand: *NewGenericCommand()} 29 } 30 31 func (uc *UploadCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *UploadCommand { 32 uc.buildConfiguration = buildConfiguration 33 return uc 34 } 35 36 func (uc *UploadCommand) UploadConfiguration() *utils.UploadConfiguration { 37 return uc.uploadConfiguration 38 } 39 40 func (uc *UploadCommand) SetUploadConfiguration(uploadConfiguration *utils.UploadConfiguration) *UploadCommand { 41 uc.uploadConfiguration = uploadConfiguration 42 return uc 43 } 44 45 func (uc *UploadCommand) SetProgress(progress ioUtils.ProgressMgr) { 46 uc.progress = progress 47 } 48 49 func (uc *UploadCommand) ShouldPrompt() bool { 50 return uc.syncDelete() && !uc.Quiet() 51 } 52 53 func (uc *UploadCommand) syncDelete() bool { 54 return !uc.DryRun() && uc.SyncDeletesPath() != "" 55 } 56 57 func (uc *UploadCommand) CommandName() string { 58 return "rt_upload" 59 } 60 61 func (uc *UploadCommand) Run() error { 62 return uc.upload() 63 } 64 65 // Uploads the artifacts in the specified local path pattern to the specified target path. 66 // Returns the total number of artifacts successfully uploaded. 67 func (uc *UploadCommand) upload() error { 68 // In case of sync-delete get the user to confirm first, and save the operation timestamp. 69 syncDeletesProp := "" 70 if uc.syncDelete() { 71 timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10) 72 syncDeletesProp = ";sync.deletes.timestamp=" + timestamp 73 } 74 75 // Create Service Manager: 76 var err error 77 uc.uploadConfiguration.MinChecksumDeploySize, err = getMinChecksumDeploySize() 78 if err != nil { 79 return err 80 } 81 rtDetails, err := uc.RtDetails() 82 if errorutils.CheckError(err) != nil { 83 return err 84 } 85 servicesManager, err := utils.CreateUploadServiceManager(rtDetails, uc.uploadConfiguration.Threads, uc.DryRun(), uc.progress) 86 if err != nil { 87 return err 88 } 89 90 addVcsProps := false 91 buildProps := "" 92 // Build Info Collection: 93 isCollectBuildInfo := len(uc.buildConfiguration.BuildName) > 0 && len(uc.buildConfiguration.BuildNumber) > 0 94 if isCollectBuildInfo && !uc.DryRun() { 95 addVcsProps = true 96 if err := utils.SaveBuildGeneralDetails(uc.buildConfiguration.BuildName, uc.buildConfiguration.BuildNumber); err != nil { 97 return err 98 } 99 buildProps, err = utils.CreateBuildProperties(uc.buildConfiguration.BuildName, uc.buildConfiguration.BuildNumber) 100 if err != nil { 101 return err 102 } 103 } 104 105 var errorOccurred = false 106 var uploadParamsArray []services.UploadParams 107 // Create UploadParams for all File-Spec groups. 108 for i := 0; i < len(uc.Spec().Files); i++ { 109 file := uc.Spec().Get(i) 110 file.Props += syncDeletesProp 111 uploadParams, err := getUploadParams(file, uc.uploadConfiguration, buildProps, addVcsProps) 112 if err != nil { 113 errorOccurred = true 114 log.Error(err) 115 continue 116 } 117 uploadParamsArray = append(uploadParamsArray, uploadParams) 118 } 119 120 // Perform upload. 121 // In case of build-info collection or a detailed summary request, we use the upload service which provides results file reader, 122 // otherwise we use the upload service which provides only general counters. 123 var successCount, failCount int 124 var resultsReader *content.ContentReader = nil 125 if uc.DetailedSummary() || isCollectBuildInfo { 126 resultsReader, successCount, failCount, err = servicesManager.UploadFilesWithResultReader(uploadParamsArray...) 127 uc.result.SetReader(resultsReader) 128 } else { 129 successCount, failCount, err = servicesManager.UploadFiles(uploadParamsArray...) 130 } 131 if err != nil { 132 errorOccurred = true 133 log.Error(err) 134 } 135 result := uc.Result() 136 result.SetSuccessCount(successCount) 137 result.SetFailCount(failCount) 138 // If the 'details summary' was requested, then the reader should not be closed now. 139 // It will be closed after it will be used to generate the summary. 140 if resultsReader != nil && !uc.DetailedSummary() { 141 defer func() { 142 resultsReader.Close() 143 uc.result.SetReader(nil) 144 }() 145 } 146 if errorOccurred { 147 err = errors.New("Upload finished with errors, Please review the logs.") 148 return err 149 } 150 if failCount > 0 { 151 return err 152 } 153 154 // Handle sync-deletes 155 if uc.syncDelete() { 156 err = uc.handleSyncDeletes(syncDeletesProp) 157 if err != nil { 158 return err 159 } 160 } 161 162 // Build info 163 if !uc.DryRun() && isCollectBuildInfo { 164 err, resultBuildInfo := utils.ReadResultBuildInfo(resultsReader) 165 if err != nil { 166 return err 167 } 168 buildArtifacts := convertFileInfoToBuildArtifacts(resultBuildInfo.FilesInfo) 169 populateFunc := func(partial *buildinfo.Partial) { 170 partial.Artifacts = buildArtifacts 171 partial.ModuleId = uc.buildConfiguration.Module 172 partial.ModuleType = buildinfo.Generic 173 } 174 err = utils.SavePartialBuildInfo(uc.buildConfiguration.BuildName, uc.buildConfiguration.BuildNumber, populateFunc) 175 176 } 177 return err 178 } 179 180 func convertFileInfoToBuildArtifacts(filesInfo []clientutils.FileInfo) []buildinfo.Artifact { 181 buildArtifacts := make([]buildinfo.Artifact, len(filesInfo)) 182 for i, fileInfo := range filesInfo { 183 buildArtifacts[i] = fileInfo.ToBuildArtifacts() 184 } 185 return buildArtifacts 186 } 187 188 func getMinChecksumDeploySize() (int64, error) { 189 minChecksumDeploySize := os.Getenv("JFROG_CLI_MIN_CHECKSUM_DEPLOY_SIZE_KB") 190 if minChecksumDeploySize == "" { 191 return 10240, nil 192 } 193 minSize, err := strconv.ParseInt(minChecksumDeploySize, 10, 64) 194 err = errorutils.CheckError(err) 195 if err != nil { 196 return 0, err 197 } 198 return minSize * 1000, nil 199 } 200 201 func getUploadParams(f *spec.File, configuration *utils.UploadConfiguration, bulidProps string, addVcsProps bool) (uploadParams services.UploadParams, err error) { 202 uploadParams = services.NewUploadParams() 203 uploadParams.ArtifactoryCommonParams = f.ToArtifactoryCommonParams() 204 uploadParams.Deb = configuration.Deb 205 uploadParams.Symlink = configuration.Symlink 206 uploadParams.MinChecksumDeploy = configuration.MinChecksumDeploySize 207 uploadParams.Retries = configuration.Retries 208 uploadParams.AddVcsProps = addVcsProps 209 uploadParams.BuildProps = bulidProps 210 211 uploadParams.Recursive, err = f.IsRecursive(true) 212 if err != nil { 213 return 214 } 215 216 uploadParams.Regexp, err = f.IsRegexp(false) 217 if err != nil { 218 return 219 } 220 221 uploadParams.IncludeDirs, err = f.IsIncludeDirs(false) 222 if err != nil { 223 return 224 } 225 226 uploadParams.Flat, err = f.IsFlat(true) 227 if err != nil { 228 return 229 } 230 231 uploadParams.ExplodeArchive, err = f.IsExplode(false) 232 if err != nil { 233 return 234 } 235 236 return 237 } 238 239 func (uc *UploadCommand) handleSyncDeletes(syncDeletesProp string) error { 240 servicesManager, err := utils.CreateServiceManager(uc.rtDetails, false) 241 if err != nil { 242 return err 243 } 244 deleteSpec := createDeleteSpecForSync(uc.SyncDeletesPath(), syncDeletesProp) 245 deleteParams, err := getDeleteParams(deleteSpec.Get(0)) 246 if err != nil { 247 return err 248 } 249 resultItems, err := servicesManager.GetPathsToDelete(deleteParams) 250 if err != nil { 251 return err 252 } 253 defer resultItems.Close() 254 _, err = servicesManager.DeleteFiles(resultItems) 255 return err 256 } 257 258 func createDeleteSpecForSync(deletePattern string, syncDeletesProp string) *spec.SpecFiles { 259 return spec.NewBuilder(). 260 Pattern(deletePattern). 261 ExcludeProps(syncDeletesProp). 262 Recursive(true). 263 BuildSpec() 264 }