File: Publishing\DockerContainerRuntime.cs
Web Access
Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Hosting.Dcp.Process;
using Microsoft.Extensions.Logging;
 
namespace Aspire.Hosting.Publishing;
 
internal sealed class DockerContainerRuntime(ILogger<DockerContainerRuntime> logger) : IContainerRuntime
{
    private async Task<int> RunDockerBuildAsync(string contextPath, string dockerfilePath, string imageName, CancellationToken cancellationToken)
    {
        var spec = new ProcessSpec("docker")
        {
            Arguments = $"build --file {dockerfilePath} --tag {imageName} {contextPath}",
            OnOutputData = output =>
            {
                logger.LogInformation("docker build (stdout): {Output}", output);
            },
            OnErrorData = error =>
            {
                logger.LogInformation("docker build (stderr): {Error}", error);
            },
            ThrowOnNonZeroReturnCode = false,
            InheritEnv = true
        };
 
        logger.LogInformation("Running Docker CLI with arguments: {ArgumentList}", spec.Arguments);
        var (pendingProcessResult, processDisposable) = ProcessUtil.Run(spec);
 
        await using (processDisposable)
        {
            var processResult = await pendingProcessResult
                .WaitAsync(cancellationToken)
                .ConfigureAwait(false);
 
            if (processResult.ExitCode != 0)
            {
                logger.LogError("Docker build for {ImageName} failed with exit code {ExitCode}.", imageName, processResult.ExitCode);
                return processResult.ExitCode;
            }
            
            logger.LogInformation("Docker build for {ImageName} succeeded.", imageName);
            return processResult.ExitCode;
        }
    }
 
    public async Task BuildImageAsync(string contextPath, string dockerfilePath, string imageName, CancellationToken cancellationToken)
    {
        var exitCode = await RunDockerBuildAsync(
            contextPath,
            dockerfilePath,
            imageName,
            cancellationToken).ConfigureAwait(false);
 
        if (exitCode != 0)
        {
            throw new DistributedApplicationException($"Docker build failed with exit code {exitCode}.");
        }
    }
}