github.com/jfrog/jfrog-cli-core/v2@v2.51.0/utils/progressbar/transferprogressbarmanager.go (about)

     1  package progressbar
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/gookit/color"
     8  	"github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/state"
     9  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
    10  	"github.com/jfrog/jfrog-client-go/utils/log"
    11  	"github.com/vbauerster/mpb/v7/decor"
    12  )
    13  
    14  const (
    15  	phase1HeadLine          = "Phase 1: Transferring all files in the repository"
    16  	phase2HeadLine          = "Phase 2: Transferring newly created and modified files"
    17  	phase3HeadLine          = "Phase 3: Retrying transfer failures and transfer delayed files"
    18  	DelayedFilesContentNote = "Files to be transferred last, after all other files"
    19  	RetryFailureContentNote = "In Phase 3 and in subsequent executions, we'll retry transferring the failed files"
    20  )
    21  
    22  type transferLabels struct {
    23  	Repositories     string
    24  	Files            string
    25  	Storage          string
    26  	TransferSpeed    string
    27  	EstimatedTime    string
    28  	VisitedFolders   string
    29  	DelayedFiles     string
    30  	TransferFailures string
    31  	WorkingThreads   string
    32  	RunningFor       string
    33  }
    34  
    35  func formatString(emoji, key string, windows bool) string {
    36  	if len(emoji) > 0 {
    37  		if windows {
    38  			emoji = "โ—"
    39  		}
    40  		key = emoji + " " + key
    41  	}
    42  	return key
    43  }
    44  
    45  func initProgressBarLabels(windows bool) transferLabels {
    46  	pbs := transferLabels{}
    47  	pbs.Repositories = formatString("๐Ÿ“ฆ", " Repositories", windows)
    48  	pbs.Files = formatString("๐Ÿ“„", " Files", windows)
    49  	pbs.Storage = formatString("๐Ÿ—„ ", " Storage", windows)
    50  	pbs.TransferSpeed = formatString(" โšก", " Transfer speed: ", windows)
    51  	pbs.EstimatedTime = formatString(" โŒ›", " Estimated time remaining: ", windows)
    52  	pbs.TransferFailures = formatString(" โŒ", " Transfer failures: ", windows)
    53  	pbs.WorkingThreads = formatString(" ๐Ÿงต", " Working threads: ", windows)
    54  	pbs.RunningFor = formatString(" ๐Ÿƒ๐Ÿผ", " Running for: ", windows)
    55  	pbs.VisitedFolders = formatString(" ๐Ÿ“", " Visited folders: ", windows)
    56  	pbs.DelayedFiles = formatString(" โœ‹", " Delayed files: ", windows)
    57  	return pbs
    58  }
    59  
    60  type TransferProgressMng struct {
    61  	barMng                *ProgressBarMng
    62  	stateMng              *state.TransferStateManager
    63  	transferLabels        transferLabels
    64  	wg                    sync.WaitGroup
    65  	reposWg               sync.WaitGroup
    66  	allRepos              []string
    67  	ignoreState           bool
    68  	currentRepoShouldStop bool
    69  	generalShouldStop     bool
    70  }
    71  
    72  func InitTransferProgressBarMng(state *state.TransferStateManager, allRepos []string) (mng *TransferProgressMng, shouldInit bool, err error) {
    73  	mng = &TransferProgressMng{}
    74  	mng.barMng, shouldInit, err = NewBarsMng()
    75  	mng.stateMng = state
    76  	mng.allRepos = allRepos
    77  	mng.generalShouldStop = false
    78  	mng.transferLabels = initProgressBarLabels(coreutils.IsWindows())
    79  	return
    80  }
    81  
    82  func (tpm *TransferProgressMng) StopCurrentRepoProgressBars(shouldStop bool) {
    83  	tpm.currentRepoShouldStop = shouldStop
    84  }
    85  
    86  func (tpm *TransferProgressMng) StopGlobalProgressBars() {
    87  	tpm.generalShouldStop = true
    88  }
    89  
    90  func (tpm *TransferProgressMng) NewPhase1ProgressBar() *TasksWithHeadlineProg {
    91  	getVals := func() (transferredStorage, totalStorage, transferredFiles, totalFiles *int64, err error) {
    92  		err = tpm.stateMng.Action(func(*state.TransferState) error {
    93  			transferredStorage = &tpm.stateMng.CurrentRepo.Phase1Info.TransferredSizeBytes
    94  			totalStorage = &tpm.stateMng.CurrentRepo.Phase1Info.TotalSizeBytes
    95  			transferredFiles = &tpm.stateMng.CurrentRepo.Phase1Info.TransferredUnits
    96  			totalFiles = &tpm.stateMng.CurrentRepo.Phase1Info.TotalUnits
    97  			return nil
    98  		})
    99  		return transferredStorage, totalStorage, transferredFiles, totalFiles, err
   100  	}
   101  	pb := tpm.barMng.newDoubleHeadLineProgressBar(phase1HeadLine, tpm.transferLabels.Storage, tpm.transferLabels.Files, getVals)
   102  
   103  	tpm.wg.Add(1)
   104  	go func() {
   105  		defer tpm.wg.Done()
   106  		for {
   107  			if tpm.currentRepoShouldStop {
   108  				return
   109  			}
   110  			ptr1, ptr2, _, _, err := getVals()
   111  			if err != nil {
   112  				log.Error("Error: Couldn't get needed information about transfer status from state")
   113  			}
   114  			if pb == nil {
   115  				log.Error("Error: We Couldn't initialize the progress bar so we can't set values to it")
   116  				return
   117  			}
   118  			if pb.GetTasksProgressBar() != nil {
   119  				pb.GetTasksProgressBar().SetGeneralProgressTotal(*ptr2)
   120  				pb.GetTasksProgressBar().GetBar().SetCurrent(*ptr1)
   121  			}
   122  			time.Sleep(1 * time.Second)
   123  		}
   124  	}()
   125  	return pb
   126  }
   127  
   128  func (tpm *TransferProgressMng) NewPhase2ProgressBar() *TasksWithHeadlineProg {
   129  	getVals := func() (transferresStorage, totalStorage, transferredFiles, totalFiles *int64, err error) {
   130  		err = tpm.stateMng.Action(func(*state.TransferState) error {
   131  			transferresStorage = &tpm.stateMng.CurrentRepo.Phase2Info.TransferredSizeBytes
   132  			totalStorage = &tpm.stateMng.CurrentRepo.Phase2Info.TotalSizeBytes
   133  			transferredFiles = &tpm.stateMng.CurrentRepo.Phase2Info.TransferredUnits
   134  			totalFiles = &tpm.stateMng.CurrentRepo.Phase2Info.TotalUnits
   135  			return nil
   136  		})
   137  		return transferresStorage, totalStorage, transferredFiles, totalFiles, err
   138  	}
   139  	pb := tpm.barMng.newDoubleHeadLineProgressBar(phase2HeadLine, tpm.transferLabels.Storage, tpm.transferLabels.Files, getVals)
   140  
   141  	tpm.wg.Add(1)
   142  	go func() {
   143  		defer tpm.wg.Done()
   144  		for {
   145  			if tpm.currentRepoShouldStop {
   146  				return
   147  			}
   148  			ptr1, ptr2, _, _, err := getVals()
   149  			if err != nil {
   150  				log.Error("Error: Couldn't get needed information about transfer status from state")
   151  			}
   152  			if pb == nil {
   153  				log.Error("Error: We Couldn't initialize the progress bar so we can't set values to it")
   154  				return
   155  			}
   156  			if pb.GetTasksProgressBar() != nil {
   157  				pb.GetTasksProgressBar().SetGeneralProgressTotal(*ptr2)
   158  				pb.GetTasksProgressBar().GetBar().SetCurrent(*ptr1)
   159  			}
   160  			time.Sleep(1 * time.Second)
   161  		}
   162  	}()
   163  	return pb
   164  }
   165  
   166  func (tpm *TransferProgressMng) NewPhase3ProgressBar() *TasksWithHeadlineProg {
   167  	getVals := func() (transferredStorage, totalStorage, transferredFiles, totalFiles *int64, err error) {
   168  		err = tpm.stateMng.Action(func(*state.TransferState) error {
   169  			transferredStorage = &tpm.stateMng.CurrentRepo.Phase3Info.TransferredSizeBytes
   170  			totalStorage = &tpm.stateMng.CurrentRepo.Phase3Info.TotalSizeBytes
   171  			transferredFiles = &tpm.stateMng.CurrentRepo.Phase3Info.TransferredUnits
   172  			totalFiles = &tpm.stateMng.CurrentRepo.Phase3Info.TotalUnits
   173  			return nil
   174  		})
   175  		return transferredStorage, totalStorage, transferredFiles, totalFiles, err
   176  	}
   177  	pb := tpm.barMng.newDoubleHeadLineProgressBar(phase3HeadLine, tpm.transferLabels.Storage, tpm.transferLabels.Files, getVals)
   178  
   179  	tpm.wg.Add(1)
   180  	go func() {
   181  		defer tpm.wg.Done()
   182  		for {
   183  			if tpm.currentRepoShouldStop {
   184  				return
   185  			}
   186  			ptr1, ptr2, _, _, err := getVals()
   187  			if err != nil {
   188  				log.Error("Error: Couldn't get needed information about transfer status from state")
   189  			}
   190  			if pb == nil {
   191  				log.Error("Error: We Couldn't initialize the progress bar so we can't set values to it")
   192  				return
   193  			}
   194  			if pb.GetTasksProgressBar() != nil {
   195  				pb.GetTasksProgressBar().SetGeneralProgressTotal(*ptr2)
   196  				pb.GetTasksProgressBar().GetBar().SetCurrent(*ptr1)
   197  			}
   198  			time.Sleep(1 * time.Second)
   199  		}
   200  	}()
   201  	return pb
   202  }
   203  
   204  func (tpm *TransferProgressMng) NewRepositoriesProgressBar() *TasksWithHeadlineProg {
   205  	getVals := func() (totalRepos, transferredRepos *int64) {
   206  		totalRepos = &tpm.stateMng.TotalRepositories.TotalUnits
   207  		transferredRepos = &tpm.stateMng.TotalRepositories.TransferredUnits
   208  		return transferredRepos, totalRepos
   209  	}
   210  	pb := tpm.barMng.newHeadlineTaskProgressBar(getVals, "Transferring your repositories", tpm.transferLabels.Repositories)
   211  
   212  	tpm.reposWg.Add(1)
   213  	go func() {
   214  		defer tpm.reposWg.Done()
   215  		for {
   216  			if tpm.generalShouldStop {
   217  				return
   218  			}
   219  			transferredRepos, totalRepos := getVals()
   220  			if pb == nil {
   221  				log.Error("We Couldn't initialize the progress bar so we can't set values to it")
   222  				return
   223  			}
   224  			if pb.GetTasksProgressBar() != nil {
   225  				pb.GetTasksProgressBar().SetGeneralProgressTotal(*totalRepos)
   226  				pb.GetTasksProgressBar().GetBar().SetCurrent(*transferredRepos)
   227  			}
   228  			time.Sleep(time.Second)
   229  		}
   230  	}()
   231  	return pb
   232  }
   233  
   234  func (tpm *TransferProgressMng) NewGeneralProgBar() *TasksProgressBar {
   235  	getVals := func() (transferredStorage, totalStorage, transferredFiles, totalFiles *int64, err error) {
   236  		err = tpm.stateMng.Action(func(*state.TransferState) error {
   237  			transferredStorage = &tpm.stateMng.OverallTransfer.TransferredSizeBytes
   238  			totalStorage = &tpm.stateMng.OverallTransfer.TotalSizeBytes
   239  			transferredFiles = &tpm.stateMng.OverallTransfer.TransferredUnits
   240  			totalFiles = &tpm.stateMng.OverallTransfer.TotalUnits
   241  			return nil
   242  		})
   243  		return transferredStorage, totalStorage, transferredFiles, totalFiles, err
   244  	}
   245  	pb := tpm.barMng.newDoubleValueProgressBar(getVals, tpm.transferLabels.Storage, tpm.transferLabels.Files)
   246  
   247  	tpm.reposWg.Add(1)
   248  	go func() {
   249  		defer tpm.reposWg.Done()
   250  		for {
   251  			if tpm.generalShouldStop {
   252  				return
   253  			}
   254  			transferredStorage, totalStorage, _, _, err := getVals()
   255  			if err != nil {
   256  				log.Error(err)
   257  			}
   258  			pb.SetGeneralProgressTotal(*totalStorage)
   259  			pb.GetBar().SetCurrent(*transferredStorage)
   260  			time.Sleep(time.Second)
   261  		}
   262  	}()
   263  	return pb
   264  }
   265  
   266  func (tpm *TransferProgressMng) NewWorkingThreadsProg() *TasksProgressBar {
   267  	getVal := func() (workingThreadsNum int, err error) {
   268  		err = tpm.stateMng.Action(func(*state.TransferState) error {
   269  			workingThreadsNum = tpm.stateMng.WorkingThreads
   270  			return nil
   271  		})
   272  		return workingThreadsNum, err
   273  	}
   274  
   275  	return tpm.barMng.newCounterProgressBar(getVal, tpm.transferLabels.WorkingThreads, nil)
   276  }
   277  
   278  func (tpm *TransferProgressMng) GetBarMng() *ProgressBarMng {
   279  	return tpm.barMng
   280  }
   281  
   282  func (tpm *TransferProgressMng) NewRunningTimeProgressBar() *TasksProgressBar {
   283  	return tpm.barMng.NewStringProgressBar(tpm.transferLabels.RunningFor, func() string {
   284  		runningTime := tpm.stateMng.GetRunningTimeString()
   285  		if runningTime == "" {
   286  			runningTime = "Running time not available"
   287  		}
   288  		return color.Green.Render(runningTime)
   289  	})
   290  }
   291  
   292  func (tpm *TransferProgressMng) NewSpeedProgBar() *TasksProgressBar {
   293  	return tpm.barMng.NewStringProgressBar(tpm.transferLabels.TransferSpeed, func() string {
   294  		return color.Green.Render(tpm.stateMng.GetSpeedString())
   295  	})
   296  }
   297  
   298  func (tpm *TransferProgressMng) NewTimeEstBar() *TasksProgressBar {
   299  	return tpm.barMng.NewStringProgressBar(tpm.transferLabels.EstimatedTime, func() string {
   300  		return color.Green.Render(tpm.stateMng.GetEstimatedRemainingTimeString())
   301  	})
   302  }
   303  
   304  func (tpm *TransferProgressMng) NewVisitedFoldersBar() *TasksProgressBar {
   305  	getVals := func() (int, error) {
   306  		if tpm.ignoreState {
   307  			return 0, nil
   308  		}
   309  		return int(tpm.stateMng.VisitedFolders), nil
   310  	}
   311  	return tpm.barMng.newCounterProgressBar(getVals, tpm.transferLabels.VisitedFolders, nil)
   312  }
   313  
   314  func (tpm *TransferProgressMng) NewDelayedBar() *TasksProgressBar {
   315  	getVals := func() (int, error) {
   316  		if tpm.ignoreState {
   317  			return 0, nil
   318  		}
   319  		return int(tpm.stateMng.DelayedFiles), nil
   320  	}
   321  	counterDescription := func() string { return DelayedFilesContentNote }
   322  	return tpm.barMng.newCounterProgressBar(getVals, tpm.transferLabels.DelayedFiles, tpm.createCounterDescription(counterDescription))
   323  }
   324  
   325  func (tpm *TransferProgressMng) NewErrorBar() *TasksProgressBar {
   326  	getVals := func() (transferFailures int, err error) {
   327  		if tpm.ignoreState {
   328  			return 0, nil
   329  		}
   330  		return int(tpm.stateMng.TransferFailures), nil
   331  	}
   332  	counterDescription := func() string {
   333  		if tpm.ignoreState || tpm.stateMng.TransferFailures == 0 {
   334  			return ""
   335  		}
   336  		return RetryFailureContentNote
   337  	}
   338  	return tpm.barMng.newCounterProgressBar(getVals, tpm.transferLabels.TransferFailures, tpm.createCounterDescription(counterDescription))
   339  }
   340  
   341  func (tpm *TransferProgressMng) createCounterDescription(getVal func() (value string)) decor.Decorator {
   342  	return decor.Any(func(decor.Statistics) string {
   343  		return color.Gray.Render(getVal())
   344  	})
   345  }
   346  
   347  func (tpm *TransferProgressMng) WaitForPhasesGoRoutinesToFinish() {
   348  	tpm.wg.Wait()
   349  }
   350  
   351  func (tpm *TransferProgressMng) WaitForReposGoRoutineToFinish() {
   352  	tpm.reposWg.Wait()
   353  }
   354  
   355  func (tpm *TransferProgressMng) QuitDoubleHeadLineProgWithBar(prog *TasksWithHeadlineProg) {
   356  	prog.headlineBar.Abort(true)
   357  	prog.headlineBar = nil
   358  	prog.tasksProgressBar.bar.Abort(true)
   359  	prog.tasksProgressBar = nil
   360  	prog.emptyLine.Abort(true)
   361  	prog.emptyLine = nil
   362  	tpm.barMng.barsWg.Done()
   363  }