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  }