File: ApplicationModel\Docker\DockerfileBuilder.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 System.Diagnostics.CodeAnalysis;
 
namespace Aspire.Hosting.ApplicationModel.Docker;
 
/// <summary>
/// Builder for creating Dockerfiles programmatically.
/// </summary>
[Experimental("ASPIREDOCKERFILEBUILDER001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
public class DockerfileBuilder
{
    private readonly List<DockerfileStage> _stages = [];
 
    /// <summary>
    /// Initializes a new instance of the <see cref="DockerfileBuilder"/> class.
    /// </summary>
    public DockerfileBuilder()
    {
    }
 
    /// <summary>
    /// Gets the stages in this Dockerfile.
    /// </summary>
    public IReadOnlyList<DockerfileStage> Stages => _stages.AsReadOnly();
 
    /// <summary>
    /// Adds a FROM statement to start a new named stage.
    /// </summary>
    /// <param name="image">The image reference (e.g., 'node:18' or 'alpine:latest').</param>
    /// <param name="stageName">The stage name for multi-stage builds.</param>
    /// <returns>A stage builder for the new stage.</returns>
    [Experimental("ASPIREDOCKERFILEBUILDER001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
    public DockerfileStage From(string image, string stageName)
    {
        ArgumentException.ThrowIfNullOrEmpty(image);
        ArgumentException.ThrowIfNullOrEmpty(stageName);
 
        var stageBuilder = new DockerfileStage(stageName, image);
        _stages.Add(stageBuilder);
        return stageBuilder;
    }
 
    /// <summary>
    /// Adds a FROM statement to start a new stage.
    /// </summary>
    /// <param name="image">The image reference (e.g., 'node:18' or 'alpine:latest').</param>
    /// <returns>A stage builder for the new stage.</returns>
    [Experimental("ASPIREDOCKERFILEBUILDER001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
    public DockerfileStage From(string image)
    {
        ArgumentException.ThrowIfNullOrEmpty(image);
 
        var stageBuilder = new DockerfileStage(null, image);
        _stages.Add(stageBuilder);
        return stageBuilder;
    }
 
    /// <summary>
    /// Writes the Dockerfile content to the specified <see cref="StreamWriter"/>.
    /// </summary>
    /// <param name="writer">The <see cref="StreamWriter"/> to write to.</param>
    /// <param name="cancellationToken">A cancellation token.</param>
    /// <returns>A task representing the asynchronous write operation.</returns>
    public async Task WriteAsync(StreamWriter writer, CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(writer);
        
        foreach (var stage in _stages)
        {
            await stage.WriteStatementAsync(writer, cancellationToken).ConfigureAwait(false);
            
            // Add a blank line between stages
            if (stage != _stages.Last())
            {
                await writer.WriteLineAsync().ConfigureAwait(false);
            }
        }
        
        await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
    }
}