mirror of
https://github.com/restic/restic.git
synced 2026-04-25 05:59:26 +00:00
termstatus: add stdin and inject into backup command
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func StdinIsTerminal() bool {
|
||||
return term.IsTerminal(int(os.Stdin.Fd()))
|
||||
func InputIsTerminal(fd uintptr) bool {
|
||||
return term.IsTerminal(int(fd))
|
||||
}
|
||||
|
||||
func OutputIsTerminal(fd uintptr) bool {
|
||||
|
||||
@@ -25,6 +25,14 @@ func (m *MockTerminal) CanUpdateStatus() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MockTerminal) InputRaw() io.ReadCloser {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockTerminal) InputIsTerminal() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MockTerminal) OutputRaw() io.Writer {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ type Terminal interface {
|
||||
SetStatus(lines []string)
|
||||
// CanUpdateStatus returns true if the terminal can update the status lines.
|
||||
CanUpdateStatus() bool
|
||||
InputRaw() io.ReadCloser
|
||||
InputIsTerminal() bool
|
||||
// OutputRaw returns the output writer. Should only be used if there is no
|
||||
// other option. Must not be used in combination with Print, Error, SetStatus
|
||||
// or any other method that writes to the terminal.
|
||||
|
||||
@@ -17,14 +17,16 @@ var _ ui.Terminal = &Terminal{}
|
||||
// updated. When the output is redirected to a file, the status lines are not
|
||||
// printed.
|
||||
type Terminal struct {
|
||||
rd io.ReadCloser
|
||||
wr io.Writer
|
||||
fd uintptr
|
||||
errWriter io.Writer
|
||||
msg chan message
|
||||
status chan status
|
||||
lastStatusLen int
|
||||
inputIsTerminal bool
|
||||
outputIsTerminal bool
|
||||
canUpdateStatus bool
|
||||
lastStatusLen int
|
||||
|
||||
// will be closed when the goroutine which runs Run() terminates, so it'll
|
||||
// yield a default value immediately
|
||||
@@ -56,12 +58,12 @@ type fder interface {
|
||||
// defer cancel()
|
||||
// // do stuff
|
||||
// ```
|
||||
func Setup(stdout, stderr io.Writer, quiet bool) (*Terminal, func()) {
|
||||
func Setup(stdin io.ReadCloser, stdout, stderr io.Writer, quiet bool) (*Terminal, func()) {
|
||||
var wg sync.WaitGroup
|
||||
// only shutdown once cancel is called to ensure that no output is lost
|
||||
cancelCtx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
term := New(stdout, stderr, quiet)
|
||||
term := New(stdin, stdout, stderr, quiet)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -82,8 +84,9 @@ func Setup(stdout, stderr io.Writer, quiet bool) (*Terminal, func()) {
|
||||
// normal output (via Print/Printf) are written to wr, error messages are
|
||||
// written to errWriter. If disableStatus is set to true, no status messages
|
||||
// are printed even if the terminal supports it.
|
||||
func New(wr io.Writer, errWriter io.Writer, disableStatus bool) *Terminal {
|
||||
func New(rd io.ReadCloser, wr io.Writer, errWriter io.Writer, disableStatus bool) *Terminal {
|
||||
t := &Terminal{
|
||||
rd: rd,
|
||||
wr: wr,
|
||||
errWriter: errWriter,
|
||||
msg: make(chan message),
|
||||
@@ -95,6 +98,12 @@ func New(wr io.Writer, errWriter io.Writer, disableStatus bool) *Terminal {
|
||||
return t
|
||||
}
|
||||
|
||||
if d, ok := rd.(fder); ok {
|
||||
if terminal.InputIsTerminal(d.Fd()) {
|
||||
t.inputIsTerminal = true
|
||||
}
|
||||
}
|
||||
|
||||
if d, ok := wr.(fder); ok {
|
||||
if terminal.CanUpdateStatus(d.Fd()) {
|
||||
// only use the fancy status code when we're running on a real terminal.
|
||||
@@ -111,6 +120,16 @@ func New(wr io.Writer, errWriter io.Writer, disableStatus bool) *Terminal {
|
||||
return t
|
||||
}
|
||||
|
||||
// InputIsTerminal returns whether the input is a terminal.
|
||||
func (t *Terminal) InputIsTerminal() bool {
|
||||
return t.inputIsTerminal
|
||||
}
|
||||
|
||||
// InputRaw returns the input reader.
|
||||
func (t *Terminal) InputRaw() io.ReadCloser {
|
||||
return t.rd
|
||||
}
|
||||
|
||||
// CanUpdateStatus return whether the status output is updated in place.
|
||||
func (t *Terminal) CanUpdateStatus() bool {
|
||||
return t.canUpdateStatus
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
func TestSetStatus(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
term := New(&buf, io.Discard, false)
|
||||
term := New(nil, &buf, io.Discard, false)
|
||||
|
||||
term.canUpdateStatus = true
|
||||
term.fd = ^uintptr(0)
|
||||
|
||||
Reference in New Issue
Block a user