diff --git a/container.go b/container.go index 5ee0aac881..35be60fb81 100644 --- a/container.go +++ b/container.go @@ -77,7 +77,7 @@ type ImageBuildInfo interface { GetDockerfile() string // the relative path to the Dockerfile, including the file itself GetRepo() string // get repo label for image GetTag() string // get tag label for image - ShouldPrintBuildLog() bool // allow build log to be printed to stdout + BuildLogWriter() io.Writer // for output of build log, use io.Discard to disable the output ShouldBuildImage() bool // return true if the image needs to be built GetBuildArgs() map[string]*string // return the environment args used to build the from Dockerfile GetAuthConfigs() map[string]registry.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Return the auth configs to be able to pull from an authenticated docker registry @@ -92,7 +92,8 @@ type FromDockerfile struct { Repo string // the repo label for image, defaults to UUID Tag string // the tag label for image, defaults to UUID BuildArgs map[string]*string // enable user to pass build args to docker daemon - PrintBuildLog bool // enable user to print build log + PrintBuildLog bool // Deprecated: Use BuildLogWriter instead + BuildLogWriter io.Writer // for output of build log, defaults to io.Discard AuthConfigs map[string]registry.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Enable auth configs to be able to pull from an authenticated docker registry // KeepImage describes whether DockerContainer.Terminate should not delete the // container image. Useful for images that are built from a Dockerfile and take a @@ -410,8 +411,20 @@ func (c *ContainerRequest) ShouldKeepBuiltImage() bool { return c.FromDockerfile.KeepImage } -func (c *ContainerRequest) ShouldPrintBuildLog() bool { - return c.FromDockerfile.PrintBuildLog +// BuildLogWriter returns the io.Writer for output of log when building a Docker image from +// a Dockerfile. It returns the BuildLogWriter from the ContainerRequest, defaults to io.Discard. +// For backward compatibility, if BuildLogWriter is default and PrintBuildLog is true, +// the function returns os.Stderr. +func (c *ContainerRequest) BuildLogWriter() io.Writer { + if c.FromDockerfile.BuildLogWriter != nil { + return c.FromDockerfile.BuildLogWriter + } + if c.FromDockerfile.PrintBuildLog { + c.FromDockerfile.BuildLogWriter = os.Stderr + } else { + c.FromDockerfile.BuildLogWriter = io.Discard + } + return c.FromDockerfile.BuildLogWriter } // BuildOptions returns the image build options when building a Docker image from a Dockerfile. diff --git a/docker.go b/docker.go index 296fe6743c..b10b14b7ff 100644 --- a/docker.go +++ b/docker.go @@ -1004,10 +1004,7 @@ func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (st } defer resp.Body.Close() - output := io.Discard - if img.ShouldPrintBuildLog() { - output = os.Stderr - } + output := img.BuildLogWriter() // Always process the output, even if it is not printed // to ensure that errors during the build process are diff --git a/docker_test.go b/docker_test.go index 3fa686632f..eb92e15060 100644 --- a/docker_test.go +++ b/docker_test.go @@ -705,6 +705,37 @@ func Test_BuildContainerFromDockerfileWithBuildLog(t *testing.T) { assert.Regexpf(t, `^Step\s*1/\d+\s*:\s*FROM alpine$`, temp[0], "Expected stdout first line to be %s. Got '%s'.", "Step 1/* : FROM alpine", temp[0]) } +func Test_BuildContainerFromDockerfileWithBuildLogWriter(t *testing.T) { + var buffer bytes.Buffer + + ctx := context.Background() + + // fromDockerfile { + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: filepath.Join(".", "testdata"), + Dockerfile: "buildlog.Dockerfile", + BuildLogWriter: &buffer, + }, + } + // } + + genContainerReq := GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: req, + Started: true, + } + + c, err := GenericContainer(ctx, genContainerReq) + CleanupContainer(t, c) + require.NoError(t, err) + + out := buffer.String() + temp := strings.Split(out, "\n") + require.NotEmpty(t, temp) + require.Regexpf(t, `^Step\s*1/\d+\s*:\s*FROM alpine$`, temp[0], "Expected stdout first line to be %s. Got '%s'.", "Step 1/* : FROM alpine", temp[0]) +} + func TestContainerCreationWaitsForLogAndPortContextTimeout(t *testing.T) { ctx := context.Background() req := ContainerRequest{