github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/commands/generic/upload.go (about)

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