mirror of
https://github.com/docker/compose.git
synced 2026-02-09 01:59:22 +08:00
Add streamOverrideWrapper to intercepts command.Cli stream methods and transparently returns custom streams when provided via options
Add new GetConfiguredStreams function to Compose API definition Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
This commit is contained in:
committed by
Nicolas De loof
parent
e1678c5c43
commit
86e91e010d
@@ -99,6 +99,9 @@ type Compose interface {
|
||||
Generate(ctx context.Context, options GenerateOptions) (*types.Project, error)
|
||||
// Volumes executes the equivalent to a `docker volume ls`
|
||||
Volumes(ctx context.Context, project string, options VolumesOptions) ([]VolumesSummary, error)
|
||||
// GetConfiguredStreams returns the configured I/O streams (stdout, stderr, stdin).
|
||||
// If no custom streams were configured, it returns the dockerCli streams.
|
||||
GetConfiguredStreams() (stdout io.Writer, stderr io.Writer, stdin io.Reader)
|
||||
}
|
||||
|
||||
type VolumesOptions struct {
|
||||
|
||||
@@ -177,7 +177,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
||||
if options.Progress == progress.ModeAuto {
|
||||
options.Progress = os.Getenv("BUILDKIT_PROGRESS")
|
||||
}
|
||||
w, err = xprogress.NewPrinter(progressCtx, os.Stdout, progressui.DisplayMode(options.Progress),
|
||||
w, err = xprogress.NewPrinter(progressCtx, s.stdout(), progressui.DisplayMode(options.Progress),
|
||||
xprogress.WithDesc(
|
||||
fmt.Sprintf("building with %q instance using %s driver", b.Name, b.Driver),
|
||||
fmt.Sprintf("%s:%s", b.Driver, b.Name),
|
||||
|
||||
@@ -142,7 +142,7 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
|
||||
if displayMode == progress.ModeAuto && !s.stdout().IsTerminal() {
|
||||
displayMode = progressui.PlainMode
|
||||
}
|
||||
out = os.Stdout // should be s.stdout(), but NewDisplay require access to the underlying *File
|
||||
out = s.stdout()
|
||||
}
|
||||
display, err := progressui.NewDisplay(out, displayMode)
|
||||
if err != nil {
|
||||
|
||||
@@ -94,6 +94,12 @@ func NewComposeService(dockerCli command.Cli, options ...Option) (api.Compose, e
|
||||
return defaultValue, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If custom streams were provided, wrap the Docker CLI to use them
|
||||
if s.outStream != nil || s.errStream != nil || s.inStream != nil {
|
||||
s.dockerCli = s.wrapDockerCliWithStreams(dockerCli)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -141,7 +147,7 @@ func WithContextInfo(info api.ContextInfo) Option {
|
||||
|
||||
// WithProxyConfig sets custom HTTP proxy configuration for builds
|
||||
func WithProxyConfig(config map[string]string) Option {
|
||||
return func(s *composeService) error{
|
||||
return func(s *composeService) error {
|
||||
s.proxyConfig = config
|
||||
return nil
|
||||
}
|
||||
@@ -238,28 +244,15 @@ func (s *composeService) getProxyConfig() map[string]string {
|
||||
return storeutil.GetProxyConfig(s.dockerCli)
|
||||
}
|
||||
|
||||
|
||||
func (s *composeService) stdout() *streams.Out {
|
||||
// If stream overrides are provided, use them
|
||||
if s.outStream != nil {
|
||||
return streams.NewOut(s.outStream)
|
||||
}
|
||||
return s.dockerCli.Out()
|
||||
}
|
||||
|
||||
func (s *composeService) stdin() *streams.In {
|
||||
// If stream overrides are provided, use them
|
||||
if s.inStream != nil {
|
||||
return streams.NewIn(&readCloserAdapter{r: s.inStream})
|
||||
}
|
||||
return s.dockerCli.In()
|
||||
}
|
||||
|
||||
func (s *composeService) stderr() *streams.Out {
|
||||
// If stream overrides are provided, use them
|
||||
if s.errStream != nil {
|
||||
return streams.NewOut(s.errStream)
|
||||
}
|
||||
return s.dockerCli.Err()
|
||||
}
|
||||
|
||||
@@ -270,6 +263,11 @@ func (s *composeService) stdinfo() *streams.Out {
|
||||
return s.stderr()
|
||||
}
|
||||
|
||||
// GetConfiguredStreams returns the configured I/O streams (implements api.Compose interface)
|
||||
func (s *composeService) GetConfiguredStreams() (io.Writer, io.Writer, io.Reader) {
|
||||
return s.stdout(), s.stderr(), s.stdin()
|
||||
}
|
||||
|
||||
// readCloserAdapter adapts io.Reader to io.ReadCloser
|
||||
type readCloserAdapter struct {
|
||||
r io.Reader
|
||||
@@ -283,6 +281,55 @@ func (r *readCloserAdapter) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrapDockerCliWithStreams wraps the Docker CLI to intercept and override stream methods
|
||||
func (s *composeService) wrapDockerCliWithStreams(baseCli command.Cli) command.Cli {
|
||||
wrapper := &streamOverrideWrapper{
|
||||
Cli: baseCli,
|
||||
}
|
||||
|
||||
// Wrap custom streams in Docker CLI's stream types
|
||||
if s.outStream != nil {
|
||||
wrapper.outStream = streams.NewOut(s.outStream)
|
||||
}
|
||||
if s.errStream != nil {
|
||||
wrapper.errStream = streams.NewOut(s.errStream)
|
||||
}
|
||||
if s.inStream != nil {
|
||||
wrapper.inStream = streams.NewIn(&readCloserAdapter{r: s.inStream})
|
||||
}
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
// streamOverrideWrapper wraps command.Cli to override streams with custom implementations
|
||||
type streamOverrideWrapper struct {
|
||||
command.Cli
|
||||
outStream *streams.Out
|
||||
errStream *streams.Out
|
||||
inStream *streams.In
|
||||
}
|
||||
|
||||
func (w *streamOverrideWrapper) Out() *streams.Out {
|
||||
if w.outStream != nil {
|
||||
return w.outStream
|
||||
}
|
||||
return w.Cli.Out()
|
||||
}
|
||||
|
||||
func (w *streamOverrideWrapper) Err() *streams.Out {
|
||||
if w.errStream != nil {
|
||||
return w.errStream
|
||||
}
|
||||
return w.Cli.Err()
|
||||
}
|
||||
|
||||
func (w *streamOverrideWrapper) In() *streams.In {
|
||||
if w.inStream != nil {
|
||||
return w.inStream
|
||||
}
|
||||
return w.Cli.In()
|
||||
}
|
||||
|
||||
func getCanonicalContainerName(c container.Summary) string {
|
||||
if len(c.Names) == 0 {
|
||||
// corner case, sometime happens on removal. return short ID as a safeguard value
|
||||
|
||||
Reference in New Issue
Block a user