github.com/cobalt77/jfrog-client-go@v0.14.5/artifactory/services/movecopy.go (about)

     1  package services
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"path"
     7  	"strconv"
     8  	"strings"
     9  
    10  	rthttpclient "github.com/cobalt77/jfrog-client-go/artifactory/httpclient"
    11  	"github.com/cobalt77/jfrog-client-go/artifactory/services/utils"
    12  	"github.com/cobalt77/jfrog-client-go/auth"
    13  	clientutils "github.com/cobalt77/jfrog-client-go/utils"
    14  	"github.com/cobalt77/jfrog-client-go/utils/errorutils"
    15  	"github.com/cobalt77/jfrog-client-go/utils/io/content"
    16  	"github.com/cobalt77/jfrog-client-go/utils/io/fileutils"
    17  	"github.com/cobalt77/jfrog-client-go/utils/log"
    18  )
    19  
    20  const (
    21  	MOVE MoveType = "move"
    22  	COPY MoveType = "copy"
    23  )
    24  
    25  type MoveCopyService struct {
    26  	moveType   MoveType
    27  	client     *rthttpclient.ArtifactoryHttpClient
    28  	DryRun     bool
    29  	ArtDetails auth.ServiceDetails
    30  }
    31  
    32  func NewMoveCopyService(client *rthttpclient.ArtifactoryHttpClient, moveType MoveType) *MoveCopyService {
    33  	return &MoveCopyService{moveType: moveType, client: client}
    34  }
    35  
    36  func (mc *MoveCopyService) GetArtifactoryDetails() auth.ServiceDetails {
    37  	return mc.ArtDetails
    38  }
    39  
    40  func (mc *MoveCopyService) SetArtifactoryDetails(rt auth.ServiceDetails) {
    41  	mc.ArtDetails = rt
    42  }
    43  
    44  func (mc *MoveCopyService) IsDryRun() bool {
    45  	return mc.DryRun
    46  }
    47  
    48  func (mc *MoveCopyService) GetJfrogHttpClient() (*rthttpclient.ArtifactoryHttpClient, error) {
    49  	return mc.client, nil
    50  }
    51  
    52  func (mc *MoveCopyService) MoveCopyServiceMoveFilesWrapper(moveSpec MoveCopyParams) (successCount, failedCount int, err error) {
    53  	var resultReader *content.ContentReader
    54  	log.Info("Searching items...")
    55  
    56  	switch moveSpec.GetSpecType() {
    57  	case utils.BUILD:
    58  		resultReader, err = utils.SearchBySpecWithBuild(moveSpec.GetFile(), mc)
    59  	case utils.AQL:
    60  		resultReader, err = utils.SearchBySpecWithAql(moveSpec.GetFile(), mc, utils.NONE)
    61  	case utils.WILDCARD:
    62  		moveSpec.SetIncludeDir(true)
    63  		resultReader, err = utils.SearchBySpecWithPattern(moveSpec.GetFile(), mc, utils.NONE)
    64  	}
    65  	if err != nil {
    66  		return 0, 0, err
    67  	}
    68  	defer resultReader.Close()
    69  	successCount, failedCount, err = mc.moveFiles(resultReader, moveSpec)
    70  	if err != nil {
    71  		return 0, 0, err
    72  	}
    73  
    74  	log.Debug(moveMsgs[mc.moveType].MovedMsg, strconv.Itoa(successCount), "artifacts.")
    75  	if failedCount > 0 {
    76  		err = errorutils.CheckError(errors.New("Failed " + moveMsgs[mc.moveType].MovingMsg + " " + strconv.Itoa(failedCount) + " artifacts."))
    77  	}
    78  	return
    79  }
    80  
    81  func reduceMovePaths(cr *content.ContentReader, params MoveCopyParams) (*content.ContentReader, error) {
    82  	if params.IsFlat() {
    83  		return utils.ReduceBottomChainDirResult(cr)
    84  	}
    85  	return utils.ReduceTopChainDirResult(cr)
    86  }
    87  
    88  func (mc *MoveCopyService) moveFiles(reader *content.ContentReader, params MoveCopyParams) (successCount, failedCount int, err error) {
    89  	successCount, failedCount = 0, 0
    90  	reduceMovePathsReader, err := reduceMovePaths(reader, params)
    91  	if err != nil {
    92  		return
    93  	}
    94  	defer reduceMovePathsReader.Close()
    95  	length, err := reduceMovePathsReader.Length()
    96  	if err != nil {
    97  		return
    98  	}
    99  	utils.LogSearchResults(length)
   100  	for resultItem := new(utils.ResultItem); reduceMovePathsReader.NextRecord(resultItem) == nil; resultItem = new(utils.ResultItem) {
   101  		destPathLocal := params.GetFile().Target
   102  		if !params.IsFlat() {
   103  			if strings.Contains(destPathLocal, "/") {
   104  				file, dir := fileutils.GetFileAndDirFromPath(destPathLocal)
   105  				destPathLocal = clientutils.TrimPath(dir + "/" + resultItem.Path + "/" + file)
   106  			} else {
   107  				destPathLocal = clientutils.TrimPath(destPathLocal + "/" + resultItem.Path + "/")
   108  			}
   109  		}
   110  		destFile, err := clientutils.BuildTargetPath(params.GetFile().Pattern, resultItem.GetItemRelativePath(), destPathLocal, true)
   111  		if err != nil {
   112  			log.Error(err)
   113  			continue
   114  		}
   115  		if strings.HasSuffix(destFile, "/") {
   116  			if resultItem.Type != "folder" {
   117  				destFile += resultItem.Name
   118  			} else {
   119  				mc.createPathForMoveAction(destFile)
   120  			}
   121  		}
   122  		success, err := mc.moveFile(resultItem.GetItemRelativePath(), destFile)
   123  		if err != nil {
   124  			log.Error(err)
   125  			continue
   126  		}
   127  
   128  		successCount += clientutils.Bool2Int(success)
   129  		failedCount += clientutils.Bool2Int(!success)
   130  	}
   131  	return
   132  }
   133  
   134  func (mc *MoveCopyService) moveFile(sourcePath, destPath string) (bool, error) {
   135  	message := moveMsgs[mc.moveType].MovingMsg + " artifact: " + sourcePath + " to: " + destPath
   136  	moveUrl := mc.GetArtifactoryDetails().GetUrl()
   137  	restApi := path.Join("api", string(mc.moveType), sourcePath)
   138  	params := map[string]string{"to": destPath}
   139  	if mc.IsDryRun() {
   140  		log.Info("[Dry run]", message)
   141  		params["dry"] = "1"
   142  	} else {
   143  		log.Info(message)
   144  	}
   145  	requestFullUrl, err := utils.BuildArtifactoryUrl(moveUrl, restApi, params)
   146  	if err != nil {
   147  		return false, err
   148  	}
   149  	httpClientsDetails := mc.GetArtifactoryDetails().CreateHttpClientDetails()
   150  
   151  	resp, body, err := mc.client.SendPost(requestFullUrl, nil, &httpClientsDetails)
   152  	if err != nil {
   153  		return false, err
   154  	}
   155  
   156  	if resp.StatusCode != http.StatusOK {
   157  		log.Error("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))
   158  	}
   159  
   160  	log.Debug("Artifactory response:", resp.Status)
   161  	return resp.StatusCode == http.StatusOK, nil
   162  }
   163  
   164  // Create destPath in Artifactory
   165  func (mc *MoveCopyService) createPathForMoveAction(destPath string) (bool, error) {
   166  	if mc.IsDryRun() == true {
   167  		log.Info("[Dry run]", "Create path:", destPath)
   168  		return true, nil
   169  	}
   170  
   171  	return mc.createPathInArtifactory(destPath, mc)
   172  }
   173  
   174  func (mc *MoveCopyService) createPathInArtifactory(destPath string, conf utils.CommonConf) (bool, error) {
   175  	rtUrl := conf.GetArtifactoryDetails().GetUrl()
   176  	requestFullUrl, err := utils.BuildArtifactoryUrl(rtUrl, destPath, map[string]string{})
   177  	if err != nil {
   178  		return false, err
   179  	}
   180  	httpClientsDetails := conf.GetArtifactoryDetails().CreateHttpClientDetails()
   181  	resp, body, err := mc.client.SendPut(requestFullUrl, nil, &httpClientsDetails)
   182  	if err != nil {
   183  		return false, err
   184  	}
   185  
   186  	if resp.StatusCode != http.StatusCreated {
   187  		log.Error("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))
   188  	}
   189  
   190  	log.Debug("Artifactory response:", resp.Status)
   191  	return resp.StatusCode == http.StatusOK, nil
   192  }
   193  
   194  var moveMsgs = map[MoveType]MoveOptions{
   195  	MOVE: {MovingMsg: "Moving", MovedMsg: "Moved"},
   196  	COPY: {MovingMsg: "Copying", MovedMsg: "Copied"},
   197  }
   198  
   199  type MoveOptions struct {
   200  	MovingMsg string
   201  	MovedMsg  string
   202  }
   203  
   204  type MoveType string
   205  
   206  type MoveCopyParams struct {
   207  	*utils.ArtifactoryCommonParams
   208  	Flat bool
   209  }
   210  
   211  func (mc *MoveCopyParams) GetFile() *utils.ArtifactoryCommonParams {
   212  	return mc.ArtifactoryCommonParams
   213  }
   214  
   215  func (mc *MoveCopyParams) SetIncludeDir(isIncludeDir bool) {
   216  	mc.GetFile().IncludeDirs = isIncludeDir
   217  }
   218  
   219  func (mc *MoveCopyParams) IsFlat() bool {
   220  	return mc.Flat
   221  }
   222  
   223  func NewMoveCopyParams() MoveCopyParams {
   224  	return MoveCopyParams{ArtifactoryCommonParams: &utils.ArtifactoryCommonParams{}}
   225  }