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

     1  package transferfiles
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/api"
    11  	"github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/state"
    12  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
    13  	"github.com/jfrog/jfrog-cli-core/v2/utils/progressbar"
    14  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    15  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    16  	"github.com/jfrog/jfrog-client-go/utils/log"
    17  )
    18  
    19  const sizeUnits = "KMGTPE"
    20  
    21  func ShowStatus() error {
    22  	var output strings.Builder
    23  	stateManager, err := state.NewTransferStateManager(true)
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	isRunning, err := stateManager.InitStartTimestamp()
    29  	if err != nil {
    30  		return err
    31  	}
    32  	if !isRunning {
    33  		addString(&output, "๐Ÿ”ด", "Status", "Not running", 0)
    34  		log.Output(output.String())
    35  		return nil
    36  	}
    37  	isStopping, err := isStopping()
    38  	if err != nil {
    39  		return err
    40  	}
    41  	if isStopping {
    42  		addString(&output, "๐ŸŸก", "Status", "Stopping", 0)
    43  		log.Output(output.String())
    44  		return nil
    45  	}
    46  
    47  	addOverallStatus(stateManager, &output, stateManager.GetRunningTimeString())
    48  	if stateManager.CurrentRepoKey != "" {
    49  		transferState, exists, err := state.LoadTransferState(stateManager.CurrentRepoKey, false)
    50  		if err != nil {
    51  			return err
    52  		}
    53  		if !exists {
    54  			return errorutils.CheckErrorf("could not find the state file of repository '%s'. Aborting", stateManager.CurrentRepoKey)
    55  		}
    56  		stateManager.TransferState = transferState
    57  		output.WriteString("\n")
    58  		setRepositoryStatus(stateManager, &output)
    59  	}
    60  	addStaleChunks(stateManager, &output)
    61  	log.Output(output.String())
    62  	return nil
    63  }
    64  
    65  func isStopping() (bool, error) {
    66  	transferDir, err := coreutils.GetJfrogTransferDir()
    67  	if err != nil {
    68  		return false, err
    69  	}
    70  
    71  	return fileutils.IsFileExists(filepath.Join(transferDir, StopFileName), false)
    72  }
    73  
    74  func addOverallStatus(stateManager *state.TransferStateManager, output *strings.Builder, runningTime string) {
    75  	addTitle(output, "Overall Transfer Status")
    76  	addString(output, coreutils.RemoveEmojisIfNonSupportedTerminal("๐ŸŸข"), "Status", "Running", 3)
    77  	addString(output, "๐Ÿƒ", "Running for", runningTime, 3)
    78  	addString(output, "๐Ÿ—„ ", "Storage", sizeToString(stateManager.OverallTransfer.TransferredSizeBytes)+" / "+sizeToString(stateManager.OverallTransfer.TotalSizeBytes)+calcPercentageInt64(stateManager.OverallTransfer.TransferredSizeBytes, stateManager.OverallTransfer.TotalSizeBytes), 3)
    79  	addString(output, "๐Ÿ“ฆ", "Repositories", fmt.Sprintf("%d / %d", stateManager.TotalRepositories.TransferredUnits, stateManager.TotalRepositories.TotalUnits)+calcPercentageInt64(stateManager.TotalRepositories.TransferredUnits, stateManager.TotalRepositories.TotalUnits), 2)
    80  	addString(output, "๐Ÿงต", "Working threads", strconv.Itoa(stateManager.WorkingThreads), 2)
    81  	addString(output, "โšก", "Transfer speed", stateManager.GetSpeedString(), 2)
    82  	addString(output, "โŒ›", "Estimated time remaining", stateManager.GetEstimatedRemainingTimeString(), 1)
    83  	failureTxt := strconv.FormatUint(stateManager.TransferFailures, 10)
    84  	if stateManager.TransferFailures > 0 {
    85  		failureTxt += " (" + progressbar.RetryFailureContentNote + ")"
    86  	}
    87  	addString(output, "โŒ", "Transfer failures", failureTxt, 2)
    88  }
    89  
    90  func calcPercentageInt64(transferred, total int64) string {
    91  	if transferred == 0 || total == 0 {
    92  		return ""
    93  	}
    94  	return fmt.Sprintf(" (%.1f%%)", float64(transferred)/float64(total)*100)
    95  }
    96  
    97  func setRepositoryStatus(stateManager *state.TransferStateManager, output *strings.Builder) {
    98  	addTitle(output, "Current Repository Status")
    99  	addString(output, "๐Ÿท ", "Name", stateManager.CurrentRepoKey, 3)
   100  	currentRepo := stateManager.CurrentRepo
   101  	switch stateManager.CurrentRepoPhase {
   102  	case api.Phase1, api.Phase3:
   103  		if stateManager.CurrentRepoPhase == api.Phase1 {
   104  			addString(output, "๐Ÿ”ข", "Phase", "Transferring all files in the repository (1/3)", 3)
   105  		} else {
   106  			addString(output, "๐Ÿ”ข", "Phase", "Retrying transfer failures and transfer delayed files (3/3)", 3)
   107  		}
   108  		addString(output, "๐Ÿ—„ ", "Storage", sizeToString(currentRepo.Phase1Info.TransferredSizeBytes)+" / "+sizeToString(currentRepo.Phase1Info.TotalSizeBytes)+calcPercentageInt64(currentRepo.Phase1Info.TransferredSizeBytes, currentRepo.Phase1Info.TotalSizeBytes), 3)
   109  		addString(output, "๐Ÿ“„", "Files", fmt.Sprintf("%d / %d", currentRepo.Phase1Info.TransferredUnits, currentRepo.Phase1Info.TotalUnits)+calcPercentageInt64(currentRepo.Phase1Info.TransferredUnits, currentRepo.Phase1Info.TotalUnits), 3)
   110  	case api.Phase2:
   111  		addString(output, "๐Ÿ”ข", "Phase", "Transferring newly created and modified files (2/3)", 3)
   112  	}
   113  	if stateManager.CurrentRepoPhase == api.Phase1 {
   114  		addString(output, "๐Ÿ“", "Visited folders", strconv.FormatUint(stateManager.VisitedFolders, 10), 2)
   115  	}
   116  	delayedTxt := strconv.FormatUint(stateManager.DelayedFiles, 10)
   117  	if stateManager.DelayedFiles > 0 {
   118  		delayedTxt += " (" + progressbar.DelayedFilesContentNote + ")"
   119  	}
   120  	addString(output, "โœ‹", "Delayed files", delayedTxt, 2)
   121  }
   122  
   123  func addStaleChunks(stateManager *state.TransferStateManager, output *strings.Builder) {
   124  	if len(stateManager.StaleChunks) == 0 {
   125  		return
   126  	}
   127  	output.WriteString("\n")
   128  	addTitle(output, "File Chunks in Transit for More than 30 Minutes")
   129  
   130  	for _, nodeStaleChunks := range stateManager.StaleChunks {
   131  		addString(output, "๐Ÿท๏ธ ", "Node ID", nodeStaleChunks.NodeID, 1)
   132  		for _, staleChunks := range nodeStaleChunks.Chunks {
   133  			addString(output, "  ๐Ÿท๏ธ ", "Chunk ID", staleChunks.ChunkID, 1)
   134  			sent := time.Unix(staleChunks.Sent, 0)
   135  			runningSecs := int64(time.Since(sent).Seconds())
   136  			addString(output, "  โฑ๏ธ ", "Sent", sent.Format(time.DateTime)+" ("+state.SecondsToLiteralTime(runningSecs, "")+")", 1)
   137  			for _, file := range staleChunks.Files {
   138  				output.WriteString("\t\t๐Ÿ“„ " + file + "\n")
   139  			}
   140  		}
   141  	}
   142  }
   143  
   144  func addTitle(output *strings.Builder, title string) {
   145  	output.WriteString(coreutils.PrintBoldTitle(title + "\n"))
   146  }
   147  
   148  func addString(output *strings.Builder, emoji, key, value string, tabsCount int) {
   149  	indentation := strings.Repeat("\t", tabsCount)
   150  	if indentation == "" {
   151  		indentation = " "
   152  	}
   153  	if len(emoji) > 0 {
   154  		if coreutils.IsWindows() {
   155  			emoji = "โ—"
   156  		}
   157  		emoji += " "
   158  	}
   159  	key = emoji + key + ":"
   160  	// PrintBold removes emojis if they are unsupported. After they are removed, the string is also trimmed, so we should avoid adding trailing spaces to the key.
   161  	output.WriteString(coreutils.PrintBold(key))
   162  	output.WriteString(indentation + value + "\n")
   163  }
   164  
   165  func sizeToString(sizeInBytes int64) string {
   166  	var divider int64 = 1024
   167  	sizeUnitIndex := 0
   168  	for ; sizeUnitIndex < len(sizeUnits)-1 && (sizeInBytes >= divider<<10); sizeUnitIndex++ {
   169  		divider <<= 10
   170  	}
   171  	return fmt.Sprintf("%.1f %ciB", float64(sizeInBytes)/float64(divider), sizeUnits[sizeUnitIndex])
   172  }