mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:47:50 +00:00
replace globalOptions.stdout with termstatus.OutputWriter
This commit is contained in:
@@ -161,7 +161,7 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string, term ui.Ter
|
||||
})
|
||||
}
|
||||
|
||||
_ = tab.Write(gopts.stdout)
|
||||
_ = tab.Write(gopts.term.OutputWriter())
|
||||
printer.S("%d cache dirs in %s", len(dirs), cachedir)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -23,15 +23,13 @@ func testRunCheckMustFail(t testing.TB, gopts GlobalOptions) {
|
||||
}
|
||||
|
||||
func testRunCheckOutput(t testing.TB, gopts GlobalOptions, checkUnused bool) (string, error) {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
opts := CheckOptions{
|
||||
ReadData: true,
|
||||
CheckUnused: checkUnused,
|
||||
}
|
||||
_, err := runCheck(context.TODO(), opts, gopts, nil, gopts.term)
|
||||
return err
|
||||
})
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
opts := CheckOptions{
|
||||
ReadData: true,
|
||||
CheckUnused: checkUnused,
|
||||
}
|
||||
_, err := runCheck(context.TODO(), opts, gopts, nil, gopts.term)
|
||||
return err
|
||||
})
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
@@ -200,20 +200,20 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string, term
|
||||
|
||||
switch tpe {
|
||||
case "indexes":
|
||||
return dumpIndexes(ctx, repo, gopts.stdout, printer)
|
||||
return dumpIndexes(ctx, repo, gopts.term.OutputWriter(), printer)
|
||||
case "snapshots":
|
||||
return debugPrintSnapshots(ctx, repo, gopts.stdout)
|
||||
return debugPrintSnapshots(ctx, repo, gopts.term.OutputWriter())
|
||||
case "packs":
|
||||
return printPacks(ctx, repo, gopts.stdout, printer)
|
||||
return printPacks(ctx, repo, gopts.term.OutputWriter(), printer)
|
||||
case "all":
|
||||
printer.S("snapshots:")
|
||||
err := debugPrintSnapshots(ctx, repo, gopts.stdout)
|
||||
err := debugPrintSnapshots(ctx, repo, gopts.term.OutputWriter())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printer.S("indexes:")
|
||||
err = dumpIndexes(ctx, repo, gopts.stdout, printer)
|
||||
err = dumpIndexes(ctx, repo, gopts.term.OutputWriter(), printer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
|
||||
}
|
||||
|
||||
if gopts.JSON {
|
||||
enc := json.NewEncoder(gopts.stdout)
|
||||
enc := json.NewEncoder(gopts.term.OutputWriter())
|
||||
c.printChange = func(change *Change) {
|
||||
err := enc.Encode(change)
|
||||
if err != nil {
|
||||
@@ -458,7 +458,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
|
||||
updateBlobs(repo, stats.BlobsAfter.Sub(both).Sub(stats.BlobsCommon), &stats.Added, printer.E)
|
||||
|
||||
if gopts.JSON {
|
||||
err := json.NewEncoder(gopts.stdout).Encode(stats)
|
||||
err := json.NewEncoder(gopts.term.OutputWriter()).Encode(stats)
|
||||
if err != nil {
|
||||
printer.E("JSON encode failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -15,13 +15,11 @@ import (
|
||||
)
|
||||
|
||||
func testRunDiffOutput(t testing.TB, gopts GlobalOptions, firstSnapshotID string, secondSnapshotID string) (string, error) {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
opts := DiffOptions{
|
||||
ShowMetadata: false,
|
||||
}
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runDiff(ctx, opts, gopts, []string{firstSnapshotID, secondSnapshotID}, gopts.term)
|
||||
})
|
||||
return runDiff(ctx, opts, gopts, []string{firstSnapshotID, secondSnapshotID}, gopts.term)
|
||||
})
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ Exit status is 1 if there was any error.
|
||||
for _, flag := range flags {
|
||||
tab.AddRow(flag)
|
||||
}
|
||||
return tab.Write(globalOptions.stdout)
|
||||
return tab.Write(globalOptions.term.OutputWriter())
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,10 @@ import (
|
||||
)
|
||||
|
||||
func testRunFind(t testing.TB, wantJSON bool, opts FindOptions, gopts GlobalOptions, pattern string) []byte {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.JSON = wantJSON
|
||||
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runFind(ctx, opts, gopts, []string{pattern}, gopts.term)
|
||||
})
|
||||
return runFind(ctx, opts, gopts, []string{pattern}, gopts.term)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
return buf.Bytes()
|
||||
|
||||
@@ -251,7 +251,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
|
||||
}
|
||||
|
||||
if gopts.Verbose >= 1 && !gopts.JSON {
|
||||
err = PrintSnapshotGroupHeader(gopts.stdout, k)
|
||||
err = PrintSnapshotGroupHeader(gopts.term.OutputWriter(), k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -274,7 +274,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
|
||||
}
|
||||
if len(keep) != 0 && !gopts.Quiet && !gopts.JSON {
|
||||
printer.P("keep %d snapshots:\n", len(keep))
|
||||
if err := PrintSnapshots(gopts.stdout, keep, reasons, opts.Compact); err != nil {
|
||||
if err := PrintSnapshots(gopts.term.OutputWriter(), keep, reasons, opts.Compact); err != nil {
|
||||
return err
|
||||
}
|
||||
printer.P("\n")
|
||||
@@ -283,7 +283,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
|
||||
|
||||
if len(remove) != 0 && !gopts.Quiet && !gopts.JSON {
|
||||
printer.P("remove %d snapshots:\n", len(remove))
|
||||
if err := PrintSnapshots(gopts.stdout, remove, nil, opts.Compact); err != nil {
|
||||
if err := PrintSnapshots(gopts.term.OutputWriter(), remove, nil, opts.Compact); err != nil {
|
||||
return err
|
||||
}
|
||||
printer.P("\n")
|
||||
@@ -328,7 +328,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
|
||||
}
|
||||
|
||||
if gopts.JSON && len(jsonGroups) > 0 {
|
||||
err = printJSONForget(gopts.stdout, jsonGroups)
|
||||
err = printJSONForget(gopts.term.OutputWriter(), jsonGroups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func writeCompletion(filename string, shell string, generate func(w io.Writer) e
|
||||
defer func() { err = outFile.Close() }()
|
||||
outWriter = outFile
|
||||
} else {
|
||||
outWriter = gopts.stdout
|
||||
outWriter = gopts.term.OutputWriter()
|
||||
}
|
||||
|
||||
err = generate(outWriter)
|
||||
|
||||
@@ -9,10 +9,8 @@ import (
|
||||
)
|
||||
|
||||
func testRunGenerate(t testing.TB, gopts GlobalOptions, opts generateOptions) ([]byte, error) {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runGenerate(opts, gopts, []string{}, gopts.term)
|
||||
})
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runGenerate(opts, gopts, []string{}, gopts.term)
|
||||
})
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
||||
ID: s.Config().ID,
|
||||
Repository: location.StripPassword(gopts.backends, gopts.Repo),
|
||||
}
|
||||
return json.NewEncoder(gopts.stdout).Encode(status)
|
||||
return json.NewEncoder(gopts.term.OutputWriter()).Encode(status)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -16,10 +16,8 @@ import (
|
||||
)
|
||||
|
||||
func testRunKeyListOtherIDs(t testing.TB, gopts GlobalOptions) []string {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runKeyList(ctx, gopts, []string{}, gopts.term)
|
||||
})
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runKeyList(ctx, gopts, []string{}, gopts.term)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions
|
||||
}
|
||||
|
||||
if gopts.JSON {
|
||||
return json.NewEncoder(gopts.stdout).Encode(keys)
|
||||
return json.NewEncoder(gopts.term.OutputWriter()).Encode(keys)
|
||||
}
|
||||
|
||||
tab := table.New()
|
||||
@@ -108,5 +108,5 @@ func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions
|
||||
tab.AddRow(key)
|
||||
}
|
||||
|
||||
return tab.Write(gopts.stdout)
|
||||
return tab.Write(gopts.term.OutputWriter())
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ import (
|
||||
)
|
||||
|
||||
func testRunList(t testing.TB, gopts GlobalOptions, tpe string) restic.IDs {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runList(ctx, gopts, []string{tpe}, gopts.term)
|
||||
})
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runList(ctx, gopts, []string{tpe}, gopts.term)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
return parseIDsFromReader(t, buf)
|
||||
|
||||
@@ -382,11 +382,11 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
|
||||
|
||||
if gopts.JSON {
|
||||
printer = &jsonLsPrinter{
|
||||
enc: json.NewEncoder(gopts.stdout),
|
||||
enc: json.NewEncoder(gopts.term.OutputWriter()),
|
||||
}
|
||||
} else if opts.Ncdu {
|
||||
printer = &ncduLsPrinter{
|
||||
out: gopts.stdout,
|
||||
out: gopts.term.OutputWriter(),
|
||||
}
|
||||
} else {
|
||||
printer = &textLsPrinter{
|
||||
|
||||
@@ -13,11 +13,9 @@ import (
|
||||
)
|
||||
|
||||
func testRunLsWithOpts(t testing.TB, gopts GlobalOptions, opts LsOptions, args []string) []byte {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.Quiet = true
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runLs(context.TODO(), opts, gopts, args, gopts.term)
|
||||
})
|
||||
return runLs(context.TODO(), opts, gopts, args, gopts.term)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
return buf.Bytes()
|
||||
|
||||
@@ -89,7 +89,7 @@ func createPrunableRepo(t *testing.T, env *testEnvironment) {
|
||||
}
|
||||
|
||||
func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.JSON = true
|
||||
opts := ForgetOptions{
|
||||
DryRun: true,
|
||||
@@ -98,9 +98,7 @@ func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) {
|
||||
pruneOpts := PruneOptions{
|
||||
MaxUnused: "5%",
|
||||
}
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runForget(context.TODO(), opts, pruneOpts, gopts, gopts.term, args)
|
||||
})
|
||||
return runForget(context.TODO(), opts, pruneOpts, gopts, gopts.term, args)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
|
||||
func testRunRebuildIndex(t testing.TB, gopts GlobalOptions) {
|
||||
rtest.OK(t, withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.stdout = io.Discard
|
||||
gopts.Quiet = true
|
||||
return runRebuildIndex(context.TODO(), RepairIndexOptions{}, gopts, gopts.term)
|
||||
}))
|
||||
}
|
||||
@@ -129,7 +129,7 @@ func TestRebuildIndexFailsOnAppendOnly(t *testing.T) {
|
||||
return &appendOnlyBackend{r}, nil
|
||||
}
|
||||
err := withTermStatus(t, env.gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.stdout = io.Discard
|
||||
gopts.Quiet = true
|
||||
return runRebuildIndex(context.TODO(), RepairIndexOptions{}, gopts, gopts.term)
|
||||
})
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions
|
||||
}
|
||||
|
||||
if gopts.JSON {
|
||||
err := printSnapshotGroupJSON(gopts.stdout, snapshotGroups, grouped)
|
||||
err := printSnapshotGroupJSON(gopts.term.OutputWriter(), snapshotGroups, grouped)
|
||||
if err != nil {
|
||||
printer.E("error printing snapshots: %v", err)
|
||||
}
|
||||
@@ -116,12 +116,12 @@ func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions
|
||||
}
|
||||
|
||||
if grouped {
|
||||
err := PrintSnapshotGroupHeader(gopts.stdout, k)
|
||||
err := PrintSnapshotGroupHeader(gopts.term.OutputWriter(), k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := PrintSnapshots(gopts.stdout, list, nil, opts.Compact)
|
||||
err := PrintSnapshots(gopts.term.OutputWriter(), list, nil, opts.Compact)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,13 +10,11 @@ import (
|
||||
)
|
||||
|
||||
func testRunSnapshots(t testing.TB, gopts GlobalOptions) (newest *Snapshot, snapmap map[restic.ID]Snapshot) {
|
||||
buf, err := withCaptureStdout(gopts, func(gopts GlobalOptions) error {
|
||||
buf, err := withCaptureStdout(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
gopts.JSON = true
|
||||
|
||||
opts := SnapshotOptions{}
|
||||
return withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
|
||||
return runSnapshots(ctx, opts, gopts, []string{}, gopts.term)
|
||||
})
|
||||
return runSnapshots(ctx, opts, gopts, []string{}, gopts.term)
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args
|
||||
}
|
||||
|
||||
if gopts.JSON {
|
||||
err = json.NewEncoder(gopts.stdout).Encode(stats)
|
||||
err = json.NewEncoder(gopts.term.OutputWriter()).Encode(stats)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encoding output: %v", err)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ Exit status is 1 if there was any error.
|
||||
GoArch: runtime.GOARCH,
|
||||
}
|
||||
|
||||
err := json.NewEncoder(globalOptions.stdout).Encode(jsonS)
|
||||
err := json.NewEncoder(globalOptions.term.OutputWriter()).Encode(jsonS)
|
||||
if err != nil {
|
||||
printer.E("JSON encode failed: %v\n", err)
|
||||
return
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -74,7 +73,6 @@ type GlobalOptions struct {
|
||||
limiter.Limits
|
||||
|
||||
password string
|
||||
stdout io.Writer
|
||||
term ui.Terminal
|
||||
|
||||
backends *location.Registry
|
||||
|
||||
@@ -212,10 +212,6 @@ func withTestEnvironment(t testing.TB) (env *testEnvironment, cleanup func()) {
|
||||
Quiet: true,
|
||||
CacheDir: env.cache,
|
||||
password: rtest.TestPassword,
|
||||
// stdout and stderr are written to by Warnf etc. That is the written data
|
||||
// usually consists of one or multiple lines and therefore can be handled well
|
||||
// by t.Log.
|
||||
stdout: &logOutputter{t},
|
||||
extended: make(options.Options),
|
||||
|
||||
// replace this hook with "nil" if listing a filetype more than once is necessary
|
||||
@@ -416,18 +412,24 @@ func testFileSize(filename string, size int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func withCaptureStdout(gopts GlobalOptions, inner func(gopts GlobalOptions) error) (*bytes.Buffer, error) {
|
||||
func withCaptureStdout(t testing.TB, gopts GlobalOptions, callback func(ctx context.Context, gopts GlobalOptions) error) (*bytes.Buffer, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
gopts.stdout = buf
|
||||
err := inner(gopts)
|
||||
err := withTermStatusRaw(os.Stdin, buf, &logOutputter{t: t}, gopts, callback)
|
||||
return buf, err
|
||||
}
|
||||
|
||||
func withTermStatus(t testing.TB, gopts GlobalOptions, callback func(ctx context.Context, gopts GlobalOptions) error) error {
|
||||
// stdout and stderr are written to by printer functions etc. That is the written data
|
||||
// usually consists of one or multiple lines and therefore can be handled well
|
||||
// by t.Log.
|
||||
return withTermStatusRaw(os.Stdin, &logOutputter{t: t}, &logOutputter{t: t}, gopts, callback)
|
||||
}
|
||||
|
||||
func withTermStatusRaw(stdin io.ReadCloser, stdout, stderr io.Writer, gopts GlobalOptions, callback func(ctx context.Context, gopts GlobalOptions) error) error {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
var wg sync.WaitGroup
|
||||
|
||||
term := termstatus.New(os.Stdin, gopts.stdout, &logOutputter{t: t}, gopts.Quiet)
|
||||
term := termstatus.New(stdin, stdout, stderr, gopts.Quiet)
|
||||
gopts.term = term
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
|
||||
@@ -173,13 +173,11 @@ func main() {
|
||||
version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
globalOptions := GlobalOptions{
|
||||
stdout: os.Stdout,
|
||||
backends: collectBackends(),
|
||||
}
|
||||
func() {
|
||||
term, cancel := termstatus.Setup(os.Stdin, os.Stdout, os.Stderr, globalOptions.Quiet)
|
||||
defer cancel()
|
||||
globalOptions.stdout = termstatus.WrapStdout(term)
|
||||
globalOptions.term = term
|
||||
ctx := createGlobalContext(os.Stderr)
|
||||
err = newRootCommand(&globalOptions).ExecuteContext(ctx)
|
||||
|
||||
@@ -40,6 +40,10 @@ func (m *MockTerminal) ReadPassword(_ context.Context, _ string) (string, error)
|
||||
return "password", nil
|
||||
}
|
||||
|
||||
func (m *MockTerminal) OutputWriter() io.Writer {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockTerminal) OutputRaw() io.Writer {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@ type Terminal interface {
|
||||
SetStatus(lines []string)
|
||||
// CanUpdateStatus returns true if the terminal can update the status lines.
|
||||
CanUpdateStatus() bool
|
||||
|
||||
InputRaw() io.ReadCloser
|
||||
InputIsTerminal() bool
|
||||
ReadPassword(ctx context.Context, prompt string) (string, error)
|
||||
|
||||
OutputWriter() io.Writer
|
||||
// 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.
|
||||
|
||||
@@ -30,6 +30,9 @@ type Terminal struct {
|
||||
outputIsTerminal bool
|
||||
canUpdateStatus bool
|
||||
|
||||
outputWriter io.WriteCloser
|
||||
outputWriterOnce sync.Once
|
||||
|
||||
// will be closed when the goroutine which runs Run() terminates, so it'll
|
||||
// yield a default value immediately
|
||||
closed chan struct{}
|
||||
@@ -73,6 +76,9 @@ func Setup(stdin io.ReadCloser, stdout, stderr io.Writer, quiet bool) (*Terminal
|
||||
}()
|
||||
|
||||
return term, func() {
|
||||
if term.outputWriter != nil {
|
||||
_ = term.outputWriter.Close()
|
||||
}
|
||||
// shutdown termstatus
|
||||
cancel()
|
||||
wg.Wait()
|
||||
@@ -158,6 +164,13 @@ func (t *Terminal) CanUpdateStatus() bool {
|
||||
return t.canUpdateStatus
|
||||
}
|
||||
|
||||
func (t *Terminal) OutputWriter() io.Writer {
|
||||
t.outputWriterOnce.Do(func() {
|
||||
t.outputWriter = newLineWriter(t.Print)
|
||||
})
|
||||
return t.outputWriter
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -6,12 +6,6 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// WrapStdout returns line-buffering replacements for os.Stdout.
|
||||
// On Close, the remaining bytes are written, followed by a line break.
|
||||
func WrapStdout(term *Terminal) (stdout io.WriteCloser) {
|
||||
return newLineWriter(term.Print)
|
||||
}
|
||||
|
||||
type lineWriter struct {
|
||||
m sync.Mutex
|
||||
buf bytes.Buffer
|
||||
|
||||
Reference in New Issue
Block a user