progress writer uses dockercli.Err stream

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2023-03-08 15:11:32 +00:00 committed by Nicolas De loof
parent fc4d2dfdd8
commit bbe1b77a67
21 changed files with 57 additions and 71 deletions

View File

@ -271,7 +271,7 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
return cmd.Help() return cmd.Help()
} }
if version { if version {
return versionCommand().Execute() return versionCommand(streams).Execute()
} }
_ = cmd.Help() _ = cmd.Help()
return dockercli.StatusError{ return dockercli.StatusError{
@ -371,7 +371,7 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
eventsCommand(&opts, streams, backend), eventsCommand(&opts, streams, backend),
portCommand(&opts, streams, backend), portCommand(&opts, streams, backend),
imagesCommand(&opts, streams, backend), imagesCommand(&opts, streams, backend),
versionCommand(), versionCommand(streams),
buildCommand(&opts, streams, backend), buildCommand(&opts, streams, backend),
pushCommand(&opts, backend), pushCommand(&opts, backend),
pullCommand(&opts, backend), pullCommand(&opts, backend),

View File

@ -147,7 +147,7 @@ func runCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *co
return err return err
} }
opts.ignoreOrphans = utils.StringToBool(project.Environment["COMPOSE_IGNORE_ORPHANS"]) opts.ignoreOrphans = utils.StringToBool(project.Environment["COMPOSE_IGNORE_ORPHANS"])
return runRun(ctx, backend, project, opts, createOpts) return runRun(ctx, backend, project, opts, createOpts, streams)
}), }),
ValidArgsFunction: completeServiceNames(p), ValidArgsFunction: completeServiceNames(p),
} }
@ -189,7 +189,7 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(name) return pflag.NormalizedName(name)
} }
func runRun(ctx context.Context, backend api.Service, project *types.Project, opts runOptions, createOpts createOptions) error { func runRun(ctx context.Context, backend api.Service, project *types.Project, opts runOptions, createOpts createOptions, streams api.Streams) error {
err := opts.apply(project) err := opts.apply(project)
if err != nil { if err != nil {
return err return err
@ -202,7 +202,7 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
err = progress.Run(ctx, func(ctx context.Context) error { err = progress.Run(ctx, func(ctx context.Context) error {
return startDependencies(ctx, backend, *project, opts.Service, opts.ignoreOrphans) return startDependencies(ctx, backend, *project, opts.Service, opts.ignoreOrphans)
}) }, streams.Err())
if err != nil { if err != nil {
return err return err
} }

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/cmd/formatter" "github.com/docker/compose/v2/cmd/formatter"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -32,14 +33,14 @@ type versionOptions struct {
short bool short bool
} }
func versionCommand() *cobra.Command { func versionCommand(streams command.Cli) *cobra.Command {
opts := versionOptions{} opts := versionOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "version [OPTIONS]", Use: "version [OPTIONS]",
Short: "Show the Docker Compose version information", Short: "Show the Docker Compose version information",
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error { RunE: func(cmd *cobra.Command, _ []string) error {
runVersion(opts) runVersion(opts, streams)
return nil return nil
}, },
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
@ -56,14 +57,14 @@ func versionCommand() *cobra.Command {
return cmd return cmd
} }
func runVersion(opts versionOptions) { func runVersion(opts versionOptions, streams command.Cli) {
if opts.short { if opts.short {
fmt.Println(strings.TrimPrefix(internal.Version, "v")) fmt.Fprintln(streams.Out(), strings.TrimPrefix(internal.Version, "v"))
return return
} }
if opts.format == formatter.JSON { if opts.format == formatter.JSON {
fmt.Printf("{\"version\":%q}\n", internal.Version) fmt.Fprintf(streams.Out(), "{\"version\":%q}\n", internal.Version)
return return
} }
fmt.Println("Docker Compose version", internal.Version) fmt.Fprintln(streams.Out(), "Docker Compose version", internal.Version)
} }

View File

@ -46,7 +46,7 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
_, err := s.build(ctx, project, options) _, err := s.build(ctx, project, options)
return err return err
}) }, s.stderr())
} }
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) { func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) {

View File

@ -51,7 +51,7 @@ import (
func (s *composeService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error { func (s *composeService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.create(ctx, project, options) return s.create(ctx, project, options)
}) }, s.stderr())
} }
func (s *composeService) create(ctx context.Context, project *types.Project, options api.CreateOptions) error { func (s *composeService) create(ctx context.Context, project *types.Project, options api.CreateOptions) error {

View File

@ -41,7 +41,7 @@ type downOp func() error
func (s *composeService) Down(ctx context.Context, projectName string, options api.DownOptions) error { func (s *composeService) Down(ctx context.Context, projectName string, options api.DownOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.down(ctx, strings.ToLower(projectName), options) return s.down(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error { func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error {

View File

@ -19,10 +19,12 @@ package compose
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strings" "strings"
"testing" "testing"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/streams"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
containerType "github.com/docker/docker/api/types/container" containerType "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
@ -39,12 +41,10 @@ func TestDown(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return( api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(
[]moby.Container{ []moby.Container{
@ -90,12 +90,10 @@ func TestDownRemoveOrphans(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(true)).Return( api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(true)).Return(
[]moby.Container{ []moby.Container{
@ -130,12 +128,10 @@ func TestDownRemoveVolumes(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return( api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(
[]moby.Container{testContainer("service1", "123", false)}, nil) []moby.Container{testContainer("service1", "123", false)}, nil)
@ -173,12 +169,10 @@ func TestDownRemoveImages(t *testing.T) {
}, },
} }
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)). api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).
Return([]moby.Container{ Return([]moby.Container{
@ -264,12 +258,10 @@ func TestDownRemoveImages_NoLabel(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
container := testContainer("service1", "123", false) container := testContainer("service1", "123", false)
@ -303,3 +295,12 @@ func TestDownRemoveImages_NoLabel(t *testing.T) {
err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{Images: "local"}) err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{Images: "local"})
assert.NilError(t, err) assert.NilError(t, err)
} }
func prepareMocks(mockCtrl *gomock.Controller) (*mocks.MockAPIClient, *mocks.MockCli) {
api := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
cli.EXPECT().Client().Return(api).AnyTimes()
cli.EXPECT().Err().Return(os.Stderr).AnyTimes()
cli.EXPECT().Out().Return(streams.NewOut(os.Stdout)).AnyTimes()
return api, cli
}

View File

@ -31,7 +31,7 @@ import (
func (s *composeService) Kill(ctx context.Context, projectName string, options api.KillOptions) error { func (s *composeService) Kill(ctx context.Context, projectName string, options api.KillOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.kill(ctx, strings.ToLower(projectName), options) return s.kill(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) kill(ctx context.Context, projectName string, options api.KillOptions) error { func (s *composeService) kill(ctx context.Context, projectName string, options api.KillOptions) error {

View File

@ -30,7 +30,6 @@ import (
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
compose "github.com/docker/compose/v2/pkg/api" compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
) )
const testProject = "testProject" const testProject = "testProject"
@ -39,12 +38,10 @@ func TestKillAll(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
name := strings.ToLower(testProject) name := strings.ToLower(testProject)
@ -72,12 +69,10 @@ func TestKillSignal(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
name := strings.ToLower(testProject) name := strings.ToLower(testProject)
listOptions := moby.ContainerListOptions{ listOptions := moby.ContainerListOptions{

View File

@ -33,19 +33,16 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
compose "github.com/docker/compose/v2/pkg/api" compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
) )
func TestComposeService_Logs_Demux(t *testing.T) { func TestComposeService_Logs_Demux(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
name := strings.ToLower(testProject) name := strings.ToLower(testProject)
@ -113,12 +110,10 @@ func TestComposeService_Logs_ServiceFiltering(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
name := strings.ToLower(testProject) name := strings.ToLower(testProject)

View File

@ -30,7 +30,7 @@ import (
func (s *composeService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error { func (s *composeService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.pause(ctx, strings.ToLower(projectName), options) return s.pause(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) pause(ctx context.Context, projectName string, options api.PauseOptions) error { func (s *composeService) pause(ctx context.Context, projectName string, options api.PauseOptions) error {
@ -62,7 +62,7 @@ func (s *composeService) pause(ctx context.Context, projectName string, options
func (s *composeService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error { func (s *composeService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.unPause(ctx, strings.ToLower(projectName), options) return s.unPause(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) unPause(ctx context.Context, projectName string, options api.PauseOptions) error { func (s *composeService) unPause(ctx context.Context, projectName string, options api.PauseOptions) error {

View File

@ -25,7 +25,6 @@ import (
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
compose "github.com/docker/compose/v2/pkg/api" compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
) )
@ -34,12 +33,10 @@ func TestPs(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
ctx := context.Background() ctx := context.Background()
args := filters.NewArgs(projectFilter(strings.ToLower(testProject)), hasConfigHashLabel()) args := filters.NewArgs(projectFilter(strings.ToLower(testProject)), hasConfigHashLabel())

View File

@ -44,7 +44,7 @@ func (s *composeService) Pull(ctx context.Context, project *types.Project, optio
} }
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.pull(ctx, project, options) return s.pull(ctx, project, options)
}) }, s.stderr())
} }
func (s *composeService) pull(ctx context.Context, project *types.Project, opts api.PullOptions) error { //nolint:gocyclo func (s *composeService) pull(ctx context.Context, project *types.Project, opts api.PullOptions) error { //nolint:gocyclo
@ -327,7 +327,7 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
} }
} }
return err return err
}) }, s.stderr())
} }
func isServiceImageToBuild(service types.ServiceConfig, services []types.ServiceConfig) bool { func isServiceImageToBuild(service types.ServiceConfig, services []types.ServiceConfig) bool {

View File

@ -42,7 +42,7 @@ func (s *composeService) Push(ctx context.Context, project *types.Project, optio
} }
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.push(ctx, project, options) return s.push(ctx, project, options)
}) }, s.stderr())
} }
func (s *composeService) push(ctx context.Context, project *types.Project, options api.PushOptions) error { func (s *composeService) push(ctx context.Context, project *types.Project, options api.PushOptions) error {

View File

@ -71,7 +71,7 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
} }
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.remove(ctx, stoppedContainers, options) return s.remove(ctx, stoppedContainers, options)
}) }, s.stderr())
} }
func (s *composeService) remove(ctx context.Context, containers Containers, options api.RemoveOptions) error { func (s *composeService) remove(ctx context.Context, containers Containers, options api.RemoveOptions) error {

View File

@ -31,7 +31,7 @@ import (
func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error { func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.restart(ctx, strings.ToLower(projectName), options) return s.restart(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error { func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {

View File

@ -36,7 +36,7 @@ import (
func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error { func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.start(ctx, strings.ToLower(projectName), options, nil) return s.start(ctx, strings.ToLower(projectName), options, nil)
}) }, s.stderr())
} }
func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error { func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error {

View File

@ -28,7 +28,7 @@ import (
func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error { func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.stop(ctx, strings.ToLower(projectName), options) return s.stop(ctx, strings.ToLower(projectName), options)
}) }, s.stderr())
} }
func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error { func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {

View File

@ -25,7 +25,6 @@ import (
"github.com/docker/compose/v2/pkg/utils" "github.com/docker/compose/v2/pkg/utils"
compose "github.com/docker/compose/v2/pkg/api" compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
containerType "github.com/docker/docker/api/types/container" containerType "github.com/docker/docker/api/types/container"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
@ -39,12 +38,10 @@ func TestStopTimeout(t *testing.T) {
mockCtrl := gomock.NewController(t) mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish() defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl) api, cli := prepareMocks(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested := composeService{ tested := composeService{
dockerCli: cli, dockerCli: cli,
} }
cli.EXPECT().Client().Return(api).AnyTimes()
ctx := context.Background() ctx := context.Background()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return( api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(

View File

@ -40,7 +40,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
return s.start(ctx, project.Name, options.Start, nil) return s.start(ctx, project.Name, options.Start, nil)
} }
return nil return nil
}) }, s.stderr())
if err != nil { if err != nil {
return err return err
} }
@ -70,7 +70,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
Services: options.Create.Services, Services: options.Create.Services,
Project: project, Project: project,
}) })
}) }, s.stderr())
} }
go func() { go func() {
<-signalChan <-signalChan

View File

@ -18,7 +18,7 @@ package progress
import ( import (
"context" "context"
"os" "io"
"sync" "sync"
"github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/api"
@ -58,17 +58,17 @@ type progressFunc func(context.Context) error
type progressFuncWithStatus func(context.Context) (string, error) type progressFuncWithStatus func(context.Context) (string, error)
// Run will run a writer and the progress function in parallel // Run will run a writer and the progress function in parallel
func Run(ctx context.Context, pf progressFunc) error { func Run(ctx context.Context, pf progressFunc, out io.Writer) error {
_, err := RunWithStatus(ctx, func(ctx context.Context) (string, error) { _, err := RunWithStatus(ctx, func(ctx context.Context) (string, error) {
return "", pf(ctx) return "", pf(ctx)
}) }, out)
return err return err
} }
// RunWithStatus will run a writer and the progress function in parallel and return a status // RunWithStatus will run a writer and the progress function in parallel and return a status
func RunWithStatus(ctx context.Context, pf progressFuncWithStatus) (string, error) { func RunWithStatus(ctx context.Context, pf progressFuncWithStatus, out io.Writer) (string, error) {
eg, _ := errgroup.WithContext(ctx) eg, _ := errgroup.WithContext(ctx)
w, err := NewWriter(ctx, os.Stderr) w, err := NewWriter(ctx, out)
var result string var result string
if err != nil { if err != nil {
return "", err return "", err
@ -105,17 +105,17 @@ const (
var Mode = ModeAuto var Mode = ModeAuto
// NewWriter returns a new multi-progress writer // NewWriter returns a new multi-progress writer
func NewWriter(ctx context.Context, out console.File) (Writer, error) { func NewWriter(ctx context.Context, out io.Writer) (Writer, error) {
_, isTerminal := term.GetFdInfo(out) _, isTerminal := term.GetFdInfo(out)
dryRun, ok := ctx.Value(api.DryRunKey{}).(bool) dryRun, ok := ctx.Value(api.DryRunKey{}).(bool)
if !ok { if !ok {
dryRun = false dryRun = false
} }
if Mode == ModeAuto && isTerminal { if Mode == ModeAuto && isTerminal {
return newTTYWriter(out, dryRun) return newTTYWriter(out.(console.File), dryRun)
} }
if Mode == ModeTTY { if Mode == ModeTTY {
return newTTYWriter(out, dryRun) return newTTYWriter(out.(console.File), dryRun)
} }
return &plainWriter{ return &plainWriter{
out: out, out: out,