diff --git a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs
index ab491ed4f..224234d9a 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs
@@ -5,8 +5,5 @@
///
/// The name of the resource.
/// The working directory to use for the command.
-public class RustAppExecutableResource(string name, string workingDirectory)
- : ExecutableResource(name, "cargo", workingDirectory), IResourceWithServiceDiscovery
-{
-
-}
+public class RustAppExecutableResource(string name, string workingDirectory, string command = "cargo")
+ : ExecutableResource(name, command, workingDirectory), IResourceWithServiceDiscovery;
\ No newline at end of file
diff --git a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs
index 6e2211d94..2f39d8980 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs
@@ -11,7 +11,7 @@ namespace Aspire.Hosting;
public static class RustAppHostingExtension
{
///
- /// Adds a Rust application to the application model. Executes the executable Rust app.
+ /// Adds a Rust application to the application model, using the cargo cli.
///
/// The to add the resource to.
/// The name of the resource.
@@ -19,22 +19,64 @@ public static class RustAppHostingExtension
/// The optional arguments to be passed to the executable when it is started.
/// A reference to the .
[AspireExport("addRustApp", Description = "Adds a Rust application to the application model")]
- public static IResourceBuilder AddRustApp(this IDistributedApplicationBuilder builder, [ResourceName] string name, string workingDirectory, string[]? args = null)
+ public static IResourceBuilder AddRustApp(
+ this IDistributedApplicationBuilder builder,
+ [ResourceName] string name,
+ string workingDirectory,
+ string[]? args = null
+ )
{
- ArgumentNullException.ThrowIfNull(builder, nameof(builder));
- ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name));
- ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory, nameof(workingDirectory));
+ ArgumentNullException.ThrowIfNull(builder);
+ ArgumentException.ThrowIfNullOrWhiteSpace(name);
+ ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);
string[] allArgs = args is { Length: > 0 }
? ["run", .. args]
: ["run"];
+ return builder.AddRustApp(name, workingDirectory, command: "cargo", allArgs);
+ }
+
+ ///
+ /// Adds a Rust application to the application model, using the bacon cli.
+ ///
+ /// The to add the resource to.
+ /// The name of the resource.
+ /// The working directory to use for the command.
+ /// The optional arguments to be passed to the executable when it is started.
+ /// A reference to the .
+ [AspireExport("addBaconApp", Description = "Adds a Rust application to the application model")]
+ public static IResourceBuilder AddBaconApp(
+ this IDistributedApplicationBuilder builder,
+ [ResourceName] string name,
+ string workingDirectory,
+ string[]? args = null
+ )
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+ ArgumentException.ThrowIfNullOrWhiteSpace(name);
+ ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory);
+
+ string[] allArgs = args is { Length: > 0 }
+ ? args
+ : ["run"];
+
+ return builder.AddRustApp(name, workingDirectory, command: "bacon", allArgs);
+ }
+
+ private static IResourceBuilder AddRustApp(
+ this IDistributedApplicationBuilder builder,
+ string name,
+ string workingDirectory,
+ string command,
+ string[] args)
+ {
workingDirectory = Path.Combine(builder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform();
- var resource = new RustAppExecutableResource(name, workingDirectory);
+ var resource = new RustAppExecutableResource(name, workingDirectory, command);
return builder.AddResource(resource)
.WithRustDefaults()
- .WithArgs(allArgs)
+ .WithArgs(args)
.PublishAsDockerFile();
}
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs
new file mode 100644
index 000000000..c607a8341
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs
@@ -0,0 +1,54 @@
+// 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;
+using CommunityToolkit.Aspire.Utils;
+using CommunityToolkit.Aspire.Testing;
+
+namespace CommunityToolkit.Aspire.Hosting.Rust.Tests;
+public class AddBaconAppTests
+{
+ [Fact]
+ public async Task AddBaconAppAddsAnnotationMetadata()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ var workingDirectory = "../../examples/rust/actix_api";
+ var baconApp = appBuilder.AddBaconApp("bacon-app", workingDirectory);
+
+ await using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var resource = Assert.Single(appModel.Resources.OfType());
+ workingDirectory = Path.Combine(appBuilder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform();
+ Assert.Equal("bacon-app", resource.Name);
+ Assert.Equal(workingDirectory, resource.WorkingDirectory);
+ Assert.Equal("bacon", resource.Command);
+ var args = await resource.GetArgumentListAsync();
+ Assert.Collection(args,
+ arg => Assert.Equal("run", arg));
+ }
+
+ [Fact]
+ public async Task AddBaconAppWithArgsAddsAnnotationMetadata()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ var workingDirectory = "../../examples/rust/actix_api";
+ var baconApp = appBuilder.AddBaconApp("bacon-app", workingDirectory, ["check"]);
+
+ await using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var resource = Assert.Single(appModel.Resources.OfType());
+ workingDirectory = Path.Combine(appBuilder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform();
+ Assert.Equal("bacon-app", resource.Name);
+ Assert.Equal(workingDirectory, resource.WorkingDirectory);
+ Assert.Equal("bacon", resource.Command);
+ var args = await resource.GetArgumentListAsync();
+ Assert.Collection(args,
+ arg => Assert.Equal("check", arg));
+ }
+}
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs
new file mode 100644
index 000000000..f1b8931b1
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs
@@ -0,0 +1,47 @@
+// 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;
+
+namespace CommunityToolkit.Aspire.Hosting.Rust.Tests;
+
+public class BaconAppPublicApiTests
+{
+ [Fact]
+ public void AddBaconAppShouldThrowWhenBuilderIsNull()
+ {
+ IDistributedApplicationBuilder builder = null!;
+ const string name = "bacon-app";
+ const string workingDirectory = "bacon_app";
+ var action = () => builder.AddBaconApp(name, workingDirectory);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(builder), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddBaconAppShouldThrowWhenNameIsNull()
+ {
+ IDistributedApplicationBuilder builder = new DistributedApplicationBuilder([]);
+ const string name = null!;
+ const string workingDirectory = "bacon_app";
+
+ var action = () => builder.AddBaconApp(name!, workingDirectory);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(name), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddBaconAppShouldThrowWhenWorkingDirectoryIsNull()
+ {
+ IDistributedApplicationBuilder builder = new DistributedApplicationBuilder([]);
+ const string name = "bacon-app";
+ const string workingDirectory = null!;
+
+ var action = () => builder.AddBaconApp(name, workingDirectory!);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(workingDirectory), exception.ParamName);
+ }
+}