cp: do not emit progress if stderr is not a term

This fixes a case where a non-tty will have control characters + the log
line for every single read operation.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2023-03-29 23:05:54 +00:00
parent 88924b1802
commit f27927d934
1 changed files with 34 additions and 16 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
@ -51,13 +52,15 @@ type copyProgressPrinter struct {
toContainer bool toContainer bool
total *float64 total *float64
writer io.Writer writer io.Writer
isTerm bool
} }
func (pt *copyProgressPrinter) Read(p []byte) (int, error) { func (pt *copyProgressPrinter) Read(p []byte) (int, error) {
n, err := pt.ReadCloser.Read(p) n, err := pt.ReadCloser.Read(p)
if n > 0 {
*pt.total += float64(n) *pt.total += float64(n)
if err == nil { if pt.isTerm {
fmt.Fprint(pt.writer, aec.Restore) fmt.Fprint(pt.writer, aec.Restore)
fmt.Fprint(pt.writer, aec.EraseLine(aec.EraseModes.All)) fmt.Fprint(pt.writer, aec.EraseLine(aec.EraseModes.All))
if pt.toContainer { if pt.toContainer {
@ -66,6 +69,7 @@ func (pt *copyProgressPrinter) Read(p []byte) (int, error) {
fmt.Fprintln(pt.writer, "Copying from container - "+units.HumanSize(*pt.total)) fmt.Fprintln(pt.writer, "Copying from container - "+units.HumanSize(*pt.total))
} }
} }
}
return n, err return n, err
} }
@ -211,6 +215,8 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
RebaseName: rebaseName, RebaseName: rebaseName,
} }
stderrIsTerm := streams.NewOut(dockerCli.Err()).IsTerminal()
var copiedSize float64 var copiedSize float64
if !copyConfig.quiet { if !copyConfig.quiet {
content = &copyProgressPrinter{ content = &copyProgressPrinter{
@ -218,6 +224,7 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
toContainer: false, toContainer: false,
writer: dockerCli.Err(), writer: dockerCli.Err(),
total: &copiedSize, total: &copiedSize,
isTerm: stderrIsTerm,
} }
} }
@ -231,11 +238,15 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
return archive.CopyTo(preArchive, srcInfo, dstPath) return archive.CopyTo(preArchive, srcInfo, dstPath)
} }
if stderrIsTerm {
fmt.Fprint(dockerCli.Err(), aec.Save) fmt.Fprint(dockerCli.Err(), aec.Save)
fmt.Fprintln(dockerCli.Err(), "Preparing to copy...") fmt.Fprintln(dockerCli.Err(), "Preparing to copy...")
}
res := archive.CopyTo(preArchive, srcInfo, dstPath) res := archive.CopyTo(preArchive, srcInfo, dstPath)
if stderrIsTerm {
fmt.Fprint(dockerCli.Err(), aec.Restore) fmt.Fprint(dockerCli.Err(), aec.Restore)
fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All)) fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All))
}
fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", dstPath) fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", dstPath)
return res return res
@ -296,6 +307,8 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
copiedSize float64 copiedSize float64
) )
stderrIsTerm := streams.NewOut(dockerCli.Err()).IsTerminal()
if srcPath == "-" { if srcPath == "-" {
content = os.Stdin content = os.Stdin
resolvedDstPath = dstInfo.Path resolvedDstPath = dstInfo.Path
@ -341,6 +354,7 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
toContainer: true, toContainer: true,
writer: dockerCli.Err(), writer: dockerCli.Err(),
total: &copiedSize, total: &copiedSize,
isTerm: stderrIsTerm,
} }
} }
} }
@ -354,11 +368,15 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
return client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options) return client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
} }
if stderrIsTerm {
fmt.Fprint(dockerCli.Err(), aec.Save) fmt.Fprint(dockerCli.Err(), aec.Save)
fmt.Fprintln(dockerCli.Err(), "Preparing to copy...") fmt.Fprintln(dockerCli.Err(), "Preparing to copy...")
}
res := client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options) res := client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
if stderrIsTerm {
fmt.Fprint(dockerCli.Err(), aec.Restore) fmt.Fprint(dockerCli.Err(), aec.Restore)
fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All)) fmt.Fprint(dockerCli.Err(), aec.EraseLine(aec.EraseModes.All))
}
fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", copyConfig.container+":"+dstInfo.Path) fmt.Fprintln(dockerCli.Err(), "Successfully copied", units.HumanSize(copiedSize), "to", copyConfig.container+":"+dstInfo.Path)
return res return res