2018-06-30 17:05:31 +02:00
|
|
|
// Show the dynamic progress bar
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2019-07-28 19:47:38 +02:00
|
|
|
"github.com/rclone/rclone/fs"
|
|
|
|
"github.com/rclone/rclone/fs/accounting"
|
|
|
|
"github.com/rclone/rclone/fs/log"
|
2020-12-18 13:45:58 +01:00
|
|
|
"github.com/rclone/rclone/fs/operations"
|
2019-09-26 22:14:47 +02:00
|
|
|
"github.com/rclone/rclone/lib/terminal"
|
2018-06-30 17:05:31 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// interval between progress prints
|
|
|
|
defaultProgressInterval = 500 * time.Millisecond
|
|
|
|
// time format for logging
|
2023-10-05 18:37:21 +02:00
|
|
|
logTimeFormat = "2006/01/02 15:04:05"
|
2018-06-30 17:05:31 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// startProgress starts the progress bar printing
|
|
|
|
//
|
2018-10-03 22:46:18 +02:00
|
|
|
// It returns a func which should be called to stop the stats.
|
|
|
|
func startProgress() func() {
|
2018-06-30 17:05:31 +02:00
|
|
|
stopStats := make(chan struct{})
|
2024-06-07 12:42:52 +02:00
|
|
|
oldLogOutput := fs.LogOutput
|
2020-12-18 13:45:58 +01:00
|
|
|
oldSyncPrint := operations.SyncPrintf
|
|
|
|
|
2018-06-30 17:05:31 +02:00
|
|
|
if !log.Redirected() {
|
|
|
|
// Intercept the log calls if not logging to file or syslog
|
2024-06-07 12:42:52 +02:00
|
|
|
fs.LogOutput = func(level fs.LogLevel, text string) {
|
2018-06-30 17:05:31 +02:00
|
|
|
printProgress(fmt.Sprintf("%s %-6s: %s", time.Now().Format(logTimeFormat), level, text))
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2020-12-18 13:45:58 +01:00
|
|
|
|
|
|
|
// Intercept output from functions such as HashLister to stdout
|
|
|
|
operations.SyncPrintf = func(format string, a ...interface{}) {
|
|
|
|
printProgress(fmt.Sprintf(format, a...))
|
|
|
|
}
|
|
|
|
|
2018-10-03 22:46:18 +02:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(1)
|
2018-06-30 17:05:31 +02:00
|
|
|
go func() {
|
2018-10-03 22:46:18 +02:00
|
|
|
defer wg.Done()
|
2018-06-30 17:05:31 +02:00
|
|
|
progressInterval := defaultProgressInterval
|
2018-09-04 15:39:48 +02:00
|
|
|
if ShowStats() && *statsInterval > 0 {
|
2018-06-30 17:05:31 +02:00
|
|
|
progressInterval = *statsInterval
|
|
|
|
}
|
|
|
|
ticker := time.NewTicker(progressInterval)
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
|
|
|
printProgress("")
|
|
|
|
case <-stopStats:
|
|
|
|
ticker.Stop()
|
2018-11-11 10:57:37 +01:00
|
|
|
printProgress("")
|
2024-06-07 12:42:52 +02:00
|
|
|
fs.LogOutput = oldLogOutput
|
2020-12-18 13:45:58 +01:00
|
|
|
operations.SyncPrintf = oldSyncPrint
|
2018-06-30 17:05:31 +02:00
|
|
|
fmt.Println("")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2018-10-03 22:46:18 +02:00
|
|
|
return func() {
|
|
|
|
close(stopStats)
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2018-06-30 17:05:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// state for the progress printing
|
|
|
|
var (
|
2023-03-03 15:17:02 +01:00
|
|
|
nlines = 0 // number of lines in the previous stats block
|
2018-06-30 17:05:31 +02:00
|
|
|
)
|
|
|
|
|
2019-04-30 14:06:24 +02:00
|
|
|
// printProgress prints the progress with an optional log
|
2018-06-30 17:05:31 +02:00
|
|
|
func printProgress(logMessage string) {
|
2023-03-03 15:17:02 +01:00
|
|
|
operations.StdoutMutex.Lock()
|
|
|
|
defer operations.StdoutMutex.Unlock()
|
2019-08-08 16:19:41 +02:00
|
|
|
|
2018-06-30 17:05:31 +02:00
|
|
|
var buf bytes.Buffer
|
2019-09-26 22:14:47 +02:00
|
|
|
w, _ := terminal.GetSize()
|
2019-07-18 12:13:54 +02:00
|
|
|
stats := strings.TrimSpace(accounting.GlobalStats().String())
|
2018-06-30 17:05:31 +02:00
|
|
|
logMessage = strings.TrimSpace(logMessage)
|
|
|
|
|
|
|
|
out := func(s string) {
|
|
|
|
buf.WriteString(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
if logMessage != "" {
|
|
|
|
out("\n")
|
2019-09-26 22:14:47 +02:00
|
|
|
out(terminal.MoveUp)
|
2018-06-30 17:05:31 +02:00
|
|
|
}
|
|
|
|
// Move to the start of the block we wrote erasing all the previous lines
|
|
|
|
for i := 0; i < nlines-1; i++ {
|
2019-09-26 22:14:47 +02:00
|
|
|
out(terminal.EraseLine)
|
|
|
|
out(terminal.MoveUp)
|
2018-06-30 17:05:31 +02:00
|
|
|
}
|
2019-09-26 22:14:47 +02:00
|
|
|
out(terminal.EraseLine)
|
|
|
|
out(terminal.MoveToStartOfLine)
|
2018-06-30 17:05:31 +02:00
|
|
|
if logMessage != "" {
|
2019-09-26 22:14:47 +02:00
|
|
|
out(terminal.EraseLine)
|
2018-06-30 17:05:31 +02:00
|
|
|
out(logMessage + "\n")
|
|
|
|
}
|
|
|
|
fixedLines := strings.Split(stats, "\n")
|
|
|
|
nlines = len(fixedLines)
|
|
|
|
for i, line := range fixedLines {
|
|
|
|
if len(line) > w {
|
|
|
|
line = line[:w]
|
|
|
|
}
|
|
|
|
out(line)
|
|
|
|
if i != nlines-1 {
|
|
|
|
out("\n")
|
|
|
|
}
|
|
|
|
}
|
2019-09-26 22:14:47 +02:00
|
|
|
terminal.Write(buf.Bytes())
|
2018-06-30 17:05:31 +02:00
|
|
|
}
|