forked from TrueCloudLab/rclone
fs: Fix interaction between --progress and --interactive
Before this change if both --progress and --interactive were set then the screen display could become muddled. This change makes --progress and --interactive use the same lock so while rclone is asking for interactive questions, the progress will be paused. Fixes #6755
This commit is contained in:
parent
cdfa0beafb
commit
e042d9089f
3 changed files with 22 additions and 12 deletions
|
@ -75,14 +75,13 @@ func startProgress() func() {
|
||||||
|
|
||||||
// state for the progress printing
|
// state for the progress printing
|
||||||
var (
|
var (
|
||||||
nlines = 0 // number of lines in the previous stats block
|
nlines = 0 // number of lines in the previous stats block
|
||||||
progressMu sync.Mutex
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// printProgress prints the progress with an optional log
|
// printProgress prints the progress with an optional log
|
||||||
func printProgress(logMessage string) {
|
func printProgress(logMessage string) {
|
||||||
progressMu.Lock()
|
operations.StdoutMutex.Lock()
|
||||||
defer progressMu.Unlock()
|
defer operations.StdoutMutex.Unlock()
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w, _ := terminal.GetSize()
|
w, _ := terminal.GetSize()
|
||||||
|
|
|
@ -46,6 +46,9 @@ func ReadNonEmptyLine(prompt string) string {
|
||||||
|
|
||||||
// CommandDefault - choose one. If return is pressed then it will
|
// CommandDefault - choose one. If return is pressed then it will
|
||||||
// chose the defaultIndex if it is >= 0
|
// chose the defaultIndex if it is >= 0
|
||||||
|
//
|
||||||
|
// Must not call fs.Log anything from here to avoid deadlock in
|
||||||
|
// --interactive --progress
|
||||||
func CommandDefault(commands []string, defaultIndex int) byte {
|
func CommandDefault(commands []string, defaultIndex int) byte {
|
||||||
opts := []string{}
|
opts := []string{}
|
||||||
for i, text := range commands {
|
for i, text := range commands {
|
||||||
|
|
|
@ -836,8 +836,8 @@ func ListFn(ctx context.Context, f fs.Fs, fn func(fs.Object)) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex for synchronized output
|
// StdoutMutex mutex for synchronized output on stdout
|
||||||
var outMutex sync.Mutex
|
var StdoutMutex sync.Mutex
|
||||||
|
|
||||||
// SyncPrintf is a global var holding the Printf function used in syncFprintf so that it can be overridden
|
// SyncPrintf is a global var holding the Printf function used in syncFprintf so that it can be overridden
|
||||||
// Note, despite name, does not provide sync and should not be called directly
|
// Note, despite name, does not provide sync and should not be called directly
|
||||||
|
@ -853,8 +853,8 @@ var SyncPrintf = func(format string, a ...interface{}) {
|
||||||
// Updated to print to terminal if no writer is defined
|
// Updated to print to terminal if no writer is defined
|
||||||
// This special behavior is used to allow easier replacement of the print to terminal code by progress
|
// This special behavior is used to allow easier replacement of the print to terminal code by progress
|
||||||
func syncFprintf(w io.Writer, format string, a ...interface{}) {
|
func syncFprintf(w io.Writer, format string, a ...interface{}) {
|
||||||
outMutex.Lock()
|
StdoutMutex.Lock()
|
||||||
defer outMutex.Unlock()
|
defer StdoutMutex.Unlock()
|
||||||
if w == nil || w == os.Stdout {
|
if w == nil || w == os.Stdout {
|
||||||
SyncPrintf(format, a...)
|
SyncPrintf(format, a...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2282,7 +2282,7 @@ func GetFsInfo(f fs.Fs) *FsInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
interactiveMu sync.Mutex
|
interactiveMu sync.Mutex // protects the following variables
|
||||||
skipped = map[string]bool{}
|
skipped = map[string]bool{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2290,14 +2290,22 @@ var (
|
||||||
//
|
//
|
||||||
// Call with interactiveMu held
|
// Call with interactiveMu held
|
||||||
func skipDestructiveChoose(ctx context.Context, subject interface{}, action string) (skip bool) {
|
func skipDestructiveChoose(ctx context.Context, subject interface{}, action string) (skip bool) {
|
||||||
fmt.Printf("rclone: %s \"%v\"?\n", action, subject)
|
// Lock the StdoutMutex - must not call fs.Log anything
|
||||||
switch i := config.CommandDefault([]string{
|
// otherwise it will deadlock with --interactive --progress
|
||||||
|
StdoutMutex.Lock()
|
||||||
|
|
||||||
|
fmt.Printf("\nrclone: %s \"%v\"?\n", action, subject)
|
||||||
|
i := config.CommandDefault([]string{
|
||||||
"yYes, this is OK",
|
"yYes, this is OK",
|
||||||
"nNo, skip this",
|
"nNo, skip this",
|
||||||
fmt.Sprintf("sSkip all %s operations with no more questions", action),
|
fmt.Sprintf("sSkip all %s operations with no more questions", action),
|
||||||
fmt.Sprintf("!Do all %s operations with no more questions", action),
|
fmt.Sprintf("!Do all %s operations with no more questions", action),
|
||||||
"qExit rclone now.",
|
"qExit rclone now.",
|
||||||
}, 0); i {
|
}, 0)
|
||||||
|
|
||||||
|
StdoutMutex.Unlock()
|
||||||
|
|
||||||
|
switch i {
|
||||||
case 'y':
|
case 'y':
|
||||||
skip = false
|
skip = false
|
||||||
case 'n':
|
case 'n':
|
||||||
|
|
Loading…
Reference in a new issue