github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/generic/upload.go (about)

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