mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:47:50 +00:00
consolidate checks whether stdin/stdout is terminal
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/restic/restic/internal/dump"
|
||||
"github.com/restic/restic/internal/errors"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
"github.com/restic/restic/internal/terminal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -199,7 +200,7 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
|
||||
}
|
||||
|
||||
func checkStdoutArchive() error {
|
||||
if stdoutIsTerminal() {
|
||||
if terminal.StdoutIsTerminal() {
|
||||
return fmt.Errorf("stdout is the terminal, please redirect output")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/restic/restic/internal/errors"
|
||||
"github.com/restic/restic/internal/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -71,7 +72,7 @@ func writeManpages(root *cobra.Command, dir string) error {
|
||||
}
|
||||
|
||||
func writeCompletion(filename string, shell string, generate func(w io.Writer) error) (err error) {
|
||||
if stdoutIsTerminal() {
|
||||
if terminal.StdoutIsTerminal() {
|
||||
Verbosef("writing %s completion file to %v\n", shell, filename)
|
||||
}
|
||||
var outWriter io.Writer
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/restic/restic/internal/filter"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
"github.com/restic/restic/internal/restorer"
|
||||
"github.com/restic/restic/internal/terminal"
|
||||
"github.com/restic/restic/internal/ui"
|
||||
restoreui "github.com/restic/restic/internal/ui/restore"
|
||||
"github.com/restic/restic/internal/ui/termstatus"
|
||||
@@ -260,7 +261,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
|
||||
}
|
||||
var count int
|
||||
t0 := time.Now()
|
||||
bar := newTerminalProgressMax(!gopts.Quiet && !gopts.JSON && stdoutIsTerminal(), 0, "files verified", term)
|
||||
bar := newTerminalProgressMax(!gopts.Quiet && !gopts.JSON && terminal.StdoutIsTerminal(), 0, "files verified", term)
|
||||
count, err = res.VerifyFiles(ctx, opts.Target, countRestoredFiles, bar)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -199,28 +199,6 @@ func collectBackends() *location.Registry {
|
||||
return backends
|
||||
}
|
||||
|
||||
func stdinIsTerminal() bool {
|
||||
return term.IsTerminal(int(os.Stdin.Fd()))
|
||||
}
|
||||
|
||||
func stdoutIsTerminal() bool {
|
||||
// mintty on windows can use pipes which behave like a posix terminal,
|
||||
// but which are not a terminal handle
|
||||
return term.IsTerminal(int(os.Stdout.Fd())) || stdoutCanUpdateStatus()
|
||||
}
|
||||
|
||||
func stdoutCanUpdateStatus() bool {
|
||||
return terminal.CanUpdateStatus(os.Stdout.Fd())
|
||||
}
|
||||
|
||||
func stdoutTerminalWidth() int {
|
||||
w, _, err := term.GetSize(int(os.Stdout.Fd()))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// ClearLine creates a platform dependent string to clear the current
|
||||
// line, so it can be overwritten.
|
||||
//
|
||||
@@ -232,7 +210,7 @@ func clearLine(w int) string {
|
||||
|
||||
// ANSI sequences are not supported on Windows cmd shell.
|
||||
if w <= 0 {
|
||||
if w = stdoutTerminalWidth(); w <= 0 {
|
||||
if w = terminal.StdoutTerminalWidth(); w <= 0 {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -399,11 +377,11 @@ func ReadPassword(ctx context.Context, opts GlobalOptions, prompt string) (strin
|
||||
err error
|
||||
)
|
||||
|
||||
if stdinIsTerminal() {
|
||||
if terminal.StdinIsTerminal() {
|
||||
password, err = readPasswordTerminal(ctx, os.Stdin, os.Stderr, prompt)
|
||||
} else {
|
||||
password, err = readPassword(os.Stdin)
|
||||
if stdoutIsTerminal() {
|
||||
if terminal.StdoutIsTerminal() {
|
||||
Verbosef("reading repository password from stdin\n")
|
||||
}
|
||||
}
|
||||
@@ -427,7 +405,7 @@ func ReadPasswordTwice(ctx context.Context, gopts GlobalOptions, prompt1, prompt
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if stdinIsTerminal() {
|
||||
if terminal.StdinIsTerminal() {
|
||||
pw2, err := ReadPassword(ctx, gopts, prompt2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -490,7 +468,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||
}
|
||||
|
||||
passwordTriesLeft := 1
|
||||
if stdinIsTerminal() && opts.password == "" && !opts.InsecureNoPassword {
|
||||
if terminal.StdinIsTerminal() && opts.password == "" && !opts.InsecureNoPassword {
|
||||
passwordTriesLeft = 3
|
||||
}
|
||||
|
||||
@@ -520,7 +498,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||
return nil, errors.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
if stdoutIsTerminal() && !opts.JSON {
|
||||
if terminal.StdoutIsTerminal() && !opts.JSON {
|
||||
id := s.Config().ID
|
||||
if len(id) > 8 {
|
||||
id = id[:8]
|
||||
@@ -544,7 +522,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||
return s, nil
|
||||
}
|
||||
|
||||
if c.Created && !opts.JSON && stdoutIsTerminal() {
|
||||
if c.Created && !opts.JSON && terminal.StdoutIsTerminal() {
|
||||
Verbosef("created new cache in %v\n", c.Base)
|
||||
}
|
||||
|
||||
@@ -563,7 +541,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||
|
||||
// cleanup old cache dirs if instructed to do so
|
||||
if opts.CleanupCache {
|
||||
if stdoutIsTerminal() && !opts.JSON {
|
||||
if terminal.StdoutIsTerminal() && !opts.JSON {
|
||||
Verbosef("removing %d old cache dirs from %v\n", len(oldCacheDirs), c.Base)
|
||||
}
|
||||
for _, item := range oldCacheDirs {
|
||||
@@ -574,7 +552,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if stdoutIsTerminal() {
|
||||
if terminal.StdoutIsTerminal() {
|
||||
Verbosef("found %d old cache directories in %v, run `restic cache --cleanup` to remove them\n",
|
||||
len(oldCacheDirs), c.Base)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/restic/restic/internal/terminal"
|
||||
"github.com/restic/restic/internal/ui"
|
||||
"github.com/restic/restic/internal/ui/progress"
|
||||
"github.com/restic/restic/internal/ui/termstatus"
|
||||
@@ -23,7 +24,7 @@ func calculateProgressInterval(show bool, json bool) time.Duration {
|
||||
fps = 60
|
||||
}
|
||||
interval = time.Duration(float64(time.Second) / fps)
|
||||
} else if !json && !stdoutCanUpdateStatus() || !show {
|
||||
} else if !json && !terminal.StdoutCanUpdateStatus() || !show {
|
||||
interval = 0
|
||||
}
|
||||
return interval
|
||||
@@ -68,9 +69,9 @@ func newProgressMax(show bool, max uint64, description string) *progress.Counter
|
||||
|
||||
func printProgress(status string, final bool) {
|
||||
|
||||
canUpdateStatus := stdoutCanUpdateStatus()
|
||||
canUpdateStatus := terminal.StdoutCanUpdateStatus()
|
||||
|
||||
w := stdoutTerminalWidth()
|
||||
w := terminal.StdoutTerminalWidth()
|
||||
if w > 0 {
|
||||
if w < 3 {
|
||||
status = termstatus.Truncate(status, w)
|
||||
@@ -103,11 +104,11 @@ func printProgress(status string, final bool) {
|
||||
}
|
||||
|
||||
func newIndexProgress(quiet bool, json bool) *progress.Counter {
|
||||
return newProgressMax(!quiet && !json && stdoutIsTerminal(), 0, "index files loaded")
|
||||
return newProgressMax(!quiet && !json && terminal.StdoutIsTerminal(), 0, "index files loaded")
|
||||
}
|
||||
|
||||
func newIndexTerminalProgress(quiet bool, json bool, term *termstatus.Terminal) *progress.Counter {
|
||||
return newTerminalProgressMax(!quiet && !json && stdoutIsTerminal(), 0, "index files loaded", term)
|
||||
return newTerminalProgressMax(!quiet && !json && terminal.StdoutIsTerminal(), 0, "index files loaded", term)
|
||||
}
|
||||
|
||||
type terminalProgressPrinter struct {
|
||||
|
||||
29
internal/terminal/stdio.go
Normal file
29
internal/terminal/stdio.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func StdinIsTerminal() bool {
|
||||
return term.IsTerminal(int(os.Stdin.Fd()))
|
||||
}
|
||||
|
||||
func StdoutIsTerminal() bool {
|
||||
// mintty on windows can use pipes which behave like a posix terminal,
|
||||
// but which are not a terminal handle
|
||||
return term.IsTerminal(int(os.Stdout.Fd())) || StdoutCanUpdateStatus()
|
||||
}
|
||||
|
||||
func StdoutCanUpdateStatus() bool {
|
||||
return CanUpdateStatus(os.Stdout.Fd())
|
||||
}
|
||||
|
||||
func StdoutTerminalWidth() int {
|
||||
w, _, err := term.GetSize(int(os.Stdout.Fd()))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return w
|
||||
}
|
||||
@@ -13,7 +13,7 @@ const (
|
||||
PosixControlClearLine = "\x1b[2K"
|
||||
)
|
||||
|
||||
// posixClearCurrentLine removes all characters from the current line and resets the
|
||||
// PosixClearCurrentLine removes all characters from the current line and resets the
|
||||
// cursor position to the first column.
|
||||
func PosixClearCurrentLine(wr io.Writer, _ uintptr) {
|
||||
// clear current line
|
||||
@@ -24,7 +24,7 @@ func PosixClearCurrentLine(wr io.Writer, _ uintptr) {
|
||||
}
|
||||
}
|
||||
|
||||
// posixMoveCursorUp moves the cursor to the line n lines above the current one.
|
||||
// PosixMoveCursorUp moves the cursor to the line n lines above the current one.
|
||||
func PosixMoveCursorUp(wr io.Writer, _ uintptr, n int) {
|
||||
data := []byte(PosixControlMoveCursorHome)
|
||||
data = append(data, bytes.Repeat([]byte(PosixControlMoveCursorUp), n)...)
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// clearCurrentLine removes all characters from the current line and resets the
|
||||
// ClearCurrentLine removes all characters from the current line and resets the
|
||||
// cursor position to the first column.
|
||||
func ClearCurrentLine(_ uintptr) func(io.Writer, uintptr) {
|
||||
return PosixClearCurrentLine
|
||||
}
|
||||
|
||||
// moveCursorUp moves the cursor to the line n lines above the current one.
|
||||
// MoveCursorUp moves the cursor to the line n lines above the current one.
|
||||
func MoveCursorUp(_ uintptr) func(io.Writer, uintptr, int) {
|
||||
return PosixMoveCursorUp
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user