124 lines · 2.5 KB · Go
RawDownload
// Show the dynamic progress bar package cmd import (	"bytes"	"fmt"	"os"	"strings"	"sync"	"time" 	"github.com/ncw/rclone/fs"	"github.com/ncw/rclone/fs/accounting"	"github.com/ncw/rclone/fs/log"	"golang.org/x/crypto/ssh/terminal") const (	// interval between progress prints	defaultProgressInterval = 500 * time.Millisecond	// time format for logging	logTimeFormat = "2006-01-02 15:04:05") // startProgress starts the progress bar printing//// It returns a func which should be called to stop the stats.func startProgress() func() {	stopStats := make(chan struct{})	oldLogPrint := fs.LogPrint	if !log.Redirected() {		// Intercept the log calls if not logging to file or syslog		fs.LogPrint = func(level fs.LogLevel, text string) {			printProgress(fmt.Sprintf("%s %-6s: %s", time.Now().Format(logTimeFormat), level, text)) 		}	}	var wg sync.WaitGroup	wg.Add(1)	go func() {		defer wg.Done()		progressInterval := defaultProgressInterval		if ShowStats() && *statsInterval > 0 {			progressInterval = *statsInterval		}		ticker := time.NewTicker(progressInterval)		for {			select {			case <-ticker.C:				printProgress("")			case <-stopStats:				ticker.Stop()				fs.LogPrint = oldLogPrint				fmt.Println("")				return			}		}	}()	return func() {		close(stopStats)		wg.Wait()	}} // VT100 codesconst (	eraseLine         = "\x1b[2K"	moveToStartOfLine = "\x1b[0G"	moveUp            = "\x1b[A") // state for the progress printingvar (	nlines     = 0 // number of lines in the previous stats block	progressMu sync.Mutex) // printProgress prings the progress with an optional logfunc printProgress(logMessage string) {	progressMu.Lock()	defer progressMu.Unlock() 	var buf bytes.Buffer	w, h, err := terminal.GetSize(int(os.Stdout.Fd()))	if err != nil {		w, h = 80, 25	}	_ = h	stats := strings.TrimSpace(accounting.Stats.String())	logMessage = strings.TrimSpace(logMessage) 	out := func(s string) {		buf.WriteString(s)	} 	if logMessage != "" {		out("\n")		out(moveUp)	}	// Move to the start of the block we wrote erasing all the previous lines	for i := 0; i < nlines-1; i++ {		out(eraseLine)		out(moveUp)	}	out(eraseLine)	out(moveToStartOfLine)	if logMessage != "" {		out(eraseLine)		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")		}	}	writeToTerminal(buf.Bytes())}