Skip to content

Commit 471e770

Browse files
Copilotcaptainsafia
andcommitted
Fix argument quoting, use docker buildx, and restore missing else case
Co-authored-by: captainsafia <[email protected]>
1 parent 6c585a3 commit 471e770

File tree

3 files changed

+96
-21
lines changed

3 files changed

+96
-21
lines changed

src/Aspire.Hosting/Publishing/DockerContainerRuntime.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ internal sealed class DockerContainerRuntime(ILogger<DockerContainerRuntime> log
1313
public string Name => "Docker";
1414
private async Task<int> RunDockerBuildAsync(string contextPath, string dockerfilePath, string imageName, ContainerBuildOptions? options, CancellationToken cancellationToken)
1515
{
16-
var arguments = $"build --file {dockerfilePath} --tag {imageName}";
16+
var arguments = $"buildx build --file \"{dockerfilePath}\" --tag \"{imageName}\"";
1717

1818
// Add platform support if specified
1919
if (!string.IsNullOrEmpty(options?.TargetPlatform))
2020
{
21-
arguments += $" --platform {options.TargetPlatform}";
21+
arguments += $" --platform \"{options.TargetPlatform}\"";
2222
}
2323

2424
// Add output format support if specified
@@ -35,13 +35,13 @@ private async Task<int> RunDockerBuildAsync(string contextPath, string dockerfil
3535

3636
if (!string.IsNullOrEmpty(options?.OutputPath))
3737
{
38-
outputType += $",dest={options.OutputPath}";
38+
outputType += $",dest=\"{options.OutputPath}\"";
3939
}
4040

41-
arguments += $" --output {outputType}";
41+
arguments += $" --output \"{outputType}\"";
4242
}
4343

44-
arguments += $" {contextPath}";
44+
arguments += $" \"{contextPath}\"";
4545

4646
var spec = new ProcessSpec("docker")
4747
{
@@ -97,14 +97,14 @@ public Task<bool> CheckIfRunningAsync(CancellationToken cancellationToken)
9797
{
9898
var spec = new ProcessSpec("docker")
9999
{
100-
Arguments = "info",
100+
Arguments = "buildx version",
101101
OnOutputData = output =>
102102
{
103-
logger.LogInformation("docker info (stdout): {Output}", output);
103+
logger.LogInformation("docker buildx version (stdout): {Output}", output);
104104
},
105105
OnErrorData = error =>
106106
{
107-
logger.LogInformation("docker info (stderr): {Error}", error);
107+
logger.LogInformation("docker buildx version (stderr): {Error}", error);
108108
},
109109
ThrowOnNonZeroReturnCode = false,
110110
InheritEnv = true
@@ -113,22 +113,21 @@ public Task<bool> CheckIfRunningAsync(CancellationToken cancellationToken)
113113
logger.LogInformation("Running Docker CLI with arguments: {ArgumentList}", spec.Arguments);
114114
var (pendingProcessResult, processDisposable) = ProcessUtil.Run(spec);
115115

116-
return CheckDockerInfoAsync(pendingProcessResult, processDisposable, cancellationToken);
116+
return CheckDockerBuildxAsync(pendingProcessResult, processDisposable, cancellationToken);
117117

118-
async Task<bool> CheckDockerInfoAsync(Task<ProcessResult> pendingResult, IAsyncDisposable processDisposable, CancellationToken ct)
118+
async Task<bool> CheckDockerBuildxAsync(Task<ProcessResult> pendingResult, IAsyncDisposable processDisposable, CancellationToken ct)
119119
{
120120
await using (processDisposable)
121121
{
122122
var processResult = await pendingResult.WaitAsync(ct).ConfigureAwait(false);
123123

124124
if (processResult.ExitCode != 0)
125125
{
126-
logger.LogError("Docker info failed with exit code {ExitCode}.", processResult.ExitCode);
126+
logger.LogError("Docker buildx version failed with exit code {ExitCode}.", processResult.ExitCode);
127127
return false;
128128
}
129129

130-
// Optionally, parse output for health, but exit code 0 is usually sufficient.
131-
logger.LogInformation("Docker is running and healthy.");
130+
logger.LogInformation("Docker buildx is available and running.");
132131
return true;
133132
}
134133
}

src/Aspire.Hosting/Publishing/PodmanContainerRuntime.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ internal sealed class PodmanContainerRuntime(ILogger<PodmanContainerRuntime> log
1313
public string Name => "Podman";
1414
private async Task<int> RunPodmanBuildAsync(string contextPath, string dockerfilePath, string imageName, ContainerBuildOptions? options, CancellationToken cancellationToken)
1515
{
16-
var arguments = $"build --file {dockerfilePath} --tag {imageName}";
16+
var arguments = $"build --file \"{dockerfilePath}\" --tag \"{imageName}\"";
1717

1818
// Add platform support if specified
1919
if (!string.IsNullOrEmpty(options?.TargetPlatform))
2020
{
21-
arguments += $" --platform {options.TargetPlatform}";
21+
arguments += $" --platform \"{options.TargetPlatform}\"";
2222
}
2323

2424
// Add format support if specified
@@ -31,10 +31,10 @@ private async Task<int> RunPodmanBuildAsync(string contextPath, string dockerfil
3131
ContainerImageFormat.Docker => "docker",
3232
_ => throw new ArgumentOutOfRangeException(nameof(options), options.ImageFormat, "Invalid container image format")
3333
};
34-
arguments += $" --format {format}";
34+
arguments += $" --format \"{format}\"";
3535
}
3636

37-
arguments += $" {contextPath}";
37+
arguments += $" \"{contextPath}\"";
3838

3939
// Note: Podman doesn't support --output like Docker buildx, so OutputPath is not directly supported
4040
// For Podman, users would need to save/export the image separately after building

src/Aspire.Hosting/Publishing/ResourceContainerImageBuilder.cs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,14 @@ private async Task BuildProjectContainerImageAsync(IResource resource, IPublishi
200200
throw new DistributedApplicationException($"The resource '{projectMetadata}' does not have a project metadata annotation.");
201201
}
202202

203-
var arguments = $"publish {projectMetadata.ProjectPath} --configuration Release /t:PublishContainer /p:ContainerRepository={resource.Name}";
203+
var arguments = $"publish \"{projectMetadata.ProjectPath}\" --configuration Release /t:PublishContainer /p:ContainerRepository=\"{resource.Name}\"";
204204

205205
// Add additional arguments based on options
206206
if (options is not null)
207207
{
208208
if (!string.IsNullOrEmpty(options.OutputPath))
209209
{
210-
arguments += $" /p:ContainerArchiveOutputPath={options.OutputPath}";
210+
arguments += $" /p:ContainerArchiveOutputPath=\"{options.OutputPath}\"";
211211
}
212212

213213
if (options.ImageFormat.HasValue)
@@ -219,12 +219,12 @@ private async Task BuildProjectContainerImageAsync(IResource resource, IPublishi
219219
ContainerImageFormat.DockerTar => "DockerTar",
220220
_ => throw new ArgumentOutOfRangeException(nameof(options), options.ImageFormat, "Invalid container image format")
221221
};
222-
arguments += $" /p:ContainerImageFormat={format}";
222+
arguments += $" /p:ContainerImageFormat=\"{format}\"";
223223
}
224224

225225
if (!string.IsNullOrEmpty(options.TargetPlatform))
226226
{
227-
arguments += $" /p:ContainerRuntimeIdentifier={options.TargetPlatform}";
227+
arguments += $" /p:ContainerRuntimeIdentifier=\"{options.TargetPlatform}\"";
228228
}
229229
}
230230

@@ -272,6 +272,82 @@ private async Task BuildProjectContainerImageAsync(IResource resource, IPublishi
272272
}
273273
}
274274
}
275+
else
276+
{
277+
// Handle case when publishingTask is null (no step provided)
278+
// This is a resource project so we'll use the .NET SDK to build the container image.
279+
if (!resource.TryGetLastAnnotation<IProjectMetadata>(out var projectMetadata))
280+
{
281+
throw new DistributedApplicationException($"The resource '{projectMetadata}' does not have a project metadata annotation.");
282+
}
283+
284+
var arguments = $"publish \"{projectMetadata.ProjectPath}\" --configuration Release /t:PublishContainer /p:ContainerRepository=\"{resource.Name}\"";
285+
286+
// Add additional arguments based on options
287+
if (options is not null)
288+
{
289+
if (!string.IsNullOrEmpty(options.OutputPath))
290+
{
291+
arguments += $" /p:ContainerArchiveOutputPath=\"{options.OutputPath}\"";
292+
}
293+
294+
if (options.ImageFormat.HasValue)
295+
{
296+
var format = options.ImageFormat.Value switch
297+
{
298+
ContainerImageFormat.Docker => "Docker",
299+
ContainerImageFormat.OciTar => "OciTar",
300+
ContainerImageFormat.DockerTar => "DockerTar",
301+
_ => throw new ArgumentOutOfRangeException(nameof(options), options.ImageFormat, "Invalid container image format")
302+
};
303+
arguments += $" /p:ContainerImageFormat=\"{format}\"";
304+
}
305+
306+
if (!string.IsNullOrEmpty(options.TargetPlatform))
307+
{
308+
arguments += $" /p:ContainerRuntimeIdentifier=\"{options.TargetPlatform}\"";
309+
}
310+
}
311+
312+
var spec = new ProcessSpec("dotnet")
313+
{
314+
Arguments = arguments,
315+
OnOutputData = output =>
316+
{
317+
logger.LogInformation("dotnet publish {ProjectPath} (stdout): {Output}", projectMetadata.ProjectPath, output);
318+
},
319+
OnErrorData = error =>
320+
{
321+
logger.LogError("dotnet publish {ProjectPath} (stderr): {Error}", projectMetadata.ProjectPath, error);
322+
}
323+
};
324+
325+
logger.LogInformation(
326+
"Starting .NET CLI with arguments: {Arguments}",
327+
string.Join(" ", spec.Arguments)
328+
);
329+
330+
var (pendingProcessResult, processDisposable) = ProcessUtil.Run(spec);
331+
332+
await using (processDisposable)
333+
{
334+
var processResult = await pendingProcessResult
335+
.WaitAsync(cancellationToken)
336+
.ConfigureAwait(false);
337+
338+
if (processResult.ExitCode != 0)
339+
{
340+
logger.LogError("dotnet publish for project {ProjectPath} failed with exit code {ExitCode}.", projectMetadata.ProjectPath, processResult.ExitCode);
341+
throw new DistributedApplicationException($"Failed to build container image.");
342+
}
343+
else
344+
{
345+
logger.LogDebug(
346+
".NET CLI completed with exit code: {ExitCode}",
347+
processResult.ExitCode);
348+
}
349+
}
350+
}
275351
}
276352

277353
private async Task BuildContainerImageFromDockerfileAsync(string resourceName, string contextPath, string dockerfilePath, string imageName, IPublishingStep? step, ContainerBuildOptions? options, CancellationToken cancellationToken)

0 commit comments

Comments
 (0)