| File: ApplicationModel\Docker\DockerfileStatements.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. #pragma warning disable ASPIREDOCKERFILEBUILDER001 // Type is for evaluation purposes only and is subject to change or removal in future updates using System.Text.Encodings.Web; using System.Text.Json; namespace Aspire.Hosting.ApplicationModel.Docker; /// <summary> /// Represents a FROM statement in a Dockerfile. /// </summary> internal class DockerfileFromStatement : DockerfileStatement { private readonly string _imageReference; private readonly string? _stageName; public DockerfileFromStatement(string imageReference, string? stageName = null) { _imageReference = imageReference; _stageName = stageName; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { var statement = _stageName is not null ? $"FROM {_imageReference} AS {_stageName}" : $"FROM {_imageReference}"; await writer.WriteLineAsync(statement).ConfigureAwait(false); } } /// <summary> /// Represents a WORKDIR statement in a Dockerfile. /// </summary> internal class DockerfileWorkDirStatement : DockerfileStatement { private readonly string _path; public DockerfileWorkDirStatement(string path) { _path = path; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"WORKDIR {_path}").ConfigureAwait(false); } } /// <summary> /// Represents a RUN statement in a Dockerfile. /// </summary> internal class DockerfileRunStatement : DockerfileStatement { private readonly string _command; public DockerfileRunStatement(string command) { _command = command; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"RUN {_command}").ConfigureAwait(false); } } /// <summary> /// Represents a COPY statement in a Dockerfile. /// </summary> internal class DockerfileCopyStatement : DockerfileStatement { private readonly string _source; private readonly string _destination; public DockerfileCopyStatement(string source, string destination) { _source = source; _destination = destination; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"COPY {_source} {_destination}").ConfigureAwait(false); } } /// <summary> /// Represents a COPY --from statement in a Dockerfile. /// </summary> internal class DockerfileCopyFromStatement : DockerfileStatement { private readonly string _stage; private readonly string _source; private readonly string _destination; public DockerfileCopyFromStatement(string stage, string source, string destination) { _stage = stage; _source = source; _destination = destination; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"COPY --from={_stage} {_source} {_destination}").ConfigureAwait(false); } } /// <summary> /// Represents an ENV statement in a Dockerfile. /// </summary> internal class DockerfileEnvStatement : DockerfileStatement { private readonly string _name; private readonly string _value; public DockerfileEnvStatement(string name, string value) { _name = name; _value = value; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"ENV {_name}={_value}").ConfigureAwait(false); } } /// <summary> /// Represents an EXPOSE statement in a Dockerfile. /// </summary> internal class DockerfileExposeStatement : DockerfileStatement { private readonly int _port; public DockerfileExposeStatement(int port) { _port = port; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"EXPOSE {_port}").ConfigureAwait(false); } } /// <summary> /// Represents a CMD statement in a Dockerfile. /// </summary> internal class DockerfileCmdStatement : DockerfileStatement { private readonly string[] _command; public DockerfileCmdStatement(string[] command) { _command = command; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; var commandJson = JsonSerializer.Serialize(_command, options); await writer.WriteLineAsync($"CMD {commandJson}").ConfigureAwait(false); } } /// <summary> /// Represents a USER statement in a Dockerfile. /// </summary> internal class DockerfileUserStatement : DockerfileStatement { private readonly string _user; public DockerfileUserStatement(string user) { _user = user; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"USER {_user}").ConfigureAwait(false); } } /// <summary> /// Represents an ARG statement in a Dockerfile. /// </summary> internal class DockerfileArgStatement : DockerfileStatement { private readonly string _name; private readonly string? _defaultValue; public DockerfileArgStatement(string name) { _name = name; _defaultValue = null; } public DockerfileArgStatement(string name, string defaultValue) { _name = name; _defaultValue = defaultValue; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { var statement = _defaultValue is not null ? $"ARG {_name}={_defaultValue}" : $"ARG {_name}"; await writer.WriteLineAsync(statement).ConfigureAwait(false); } } /// <summary> /// Represents an ENTRYPOINT statement in a Dockerfile. /// </summary> internal class DockerfileEntrypointStatement : DockerfileStatement { private readonly string[] _command; public DockerfileEntrypointStatement(string[] command) { _command = command; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; var commandJson = JsonSerializer.Serialize(_command, options); await writer.WriteLineAsync($"ENTRYPOINT {commandJson}").ConfigureAwait(false); } } /// <summary> /// Represents a RUN statement with mount options in a Dockerfile. /// </summary> internal class DockerfileRunWithMountsStatement : DockerfileStatement { private readonly string _command; private readonly List<string> _mounts; public DockerfileRunWithMountsStatement(string command, IEnumerable<string> mounts) { _command = command; _mounts = mounts.ToList(); } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { var mountOptions = string.Join(" ", _mounts.Select(m => $"--mount={m}")); await writer.WriteLineAsync($"RUN {mountOptions} \\\n {_command}").ConfigureAwait(false); } } /// <summary> /// Represents an empty line in a Dockerfile. /// </summary> internal class DockerfileEmptyLineStatement : DockerfileStatement { public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync().ConfigureAwait(false); } } /// <summary> /// Represents a COPY statement with chown option in a Dockerfile. /// </summary> internal class DockerfileCopyWithChownStatement : DockerfileStatement { private readonly string _source; private readonly string _destination; private readonly string _chown; public DockerfileCopyWithChownStatement(string source, string destination, string chown) { _source = source; _destination = destination; _chown = chown; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"COPY --chown={_chown} {_source} {_destination}").ConfigureAwait(false); } } /// <summary> /// Represents a COPY --from statement with chown option in a Dockerfile. /// </summary> internal class DockerfileCopyFromWithChownStatement : DockerfileStatement { private readonly string _stage; private readonly string _source; private readonly string _destination; private readonly string _chown; public DockerfileCopyFromWithChownStatement(string stage, string source, string destination, string chown) { _stage = stage; _source = source; _destination = destination; _chown = chown; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { await writer.WriteLineAsync($"COPY --from={_stage} --chown={_chown} {_source} {_destination}").ConfigureAwait(false); } } /// <summary> /// Represents a comment in a Dockerfile. /// </summary> internal class DockerfileCommentStatement : DockerfileStatement { private readonly string _comment; public DockerfileCommentStatement(string comment) { _comment = comment; } public override async Task WriteStatementAsync(StreamWriter writer, CancellationToken cancellationToken = default) { // Split by newlines to handle multi-line comments var lines = _comment.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); foreach (var line in lines) { await writer.WriteLineAsync($"# {line}").ConfigureAwait(false); } } }