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 }