terminal: use stderr for terminal progress output, etc

Avoid mixing rclone command output with progress output by sending
terminal output to stderr.

Discussion:

The --progress option produces output designed for the terminal, and the
terminal library sent all its output to stdout.

This is a problem for any command that produces output for further
processing, when combined with --progress, because the main command
output and the progress output are then sent together to stdout.

This is most obviously a problem for the rclone 'cat' command.  Say you
want to retrieve a large file but output to a pipe for further
processing, rather than write it to a file.  But you also want rclone to
display its progress output as you wait for the transfer.  Because both
the 'cat' output and the progress output go to stdout, this leaves the
progress output as garbage data within the streamed cat output, and also
prevents the progress output from being displayed.

Notably, other rclone commands like 'ls', 'lsjson', and even 'm5dsum',
produce meaningful progress output with the --progress option, but when
mixed with the regular command output, it makes both the progress output
and the command output unusable.

The simple solution here is to send output intended for the terminal
(including progress output) to stderr instead of stdout.  This way the
rclone command output can be redirected as desired from stdout, and the
progress output will still go to the terminal attached to stderr.

If for some reason the user wants to capture/redirect the
terminal/progress output for some other purpose, stderr can be
redirected instead.
This commit is contained in:
Carl Edquist 2022-09-30 08:06:49 -05:00
parent 4e078765f9
commit 7130a6d2e4

View File

@ -73,12 +73,12 @@ var (
// Start the terminal - must be called before use
func Start() {
once.Do(func() {
f := os.Stdout
f := os.Stderr
if !IsTerminal(int(f.Fd())) {
// If stdout not a tty then remove escape codes
// If stderr not a tty then remove escape codes
Out = colorable.NewNonColorable(f)
} else if runtime.GOOS == "windows" && os.Getenv("TERM") != "" {
// If TERM is set just use stdout
// If TERM is set just use stderr
Out = f
} else {
Out = colorable.NewColorable(f)