| File: NuGet\Commands\LayoutCommand.cs | Web Access |
| Project: src\src\Aspire.Managed\Aspire.Managed.csproj (aspire-managed) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; using System.Globalization; namespace Aspire.Managed.NuGet.Commands; /// <summary> /// Layout command - creates a flat DLL layout from a project.assets.json file. /// This enables the AppHost Server to load integration assemblies via probing paths. /// </summary> public static class LayoutCommand { /// <summary> /// Creates the layout command. /// </summary> public static Command Create() { var command = new Command("layout", "Create flat DLL layout from project.assets.json"); var assetsOption = new Option<string>("--assets", "-a") { Description = "Path to project.assets.json file", Required = true }; command.Options.Add(assetsOption); var outputOption = new Option<string>("--output", "-o") { Description = "Output directory for flat DLL layout", Required = true }; command.Options.Add(outputOption); var frameworkOption = new Option<string>("--framework", "-f") { Description = "Target framework (default: net10.0)", DefaultValueFactory = _ => "net10.0" }; command.Options.Add(frameworkOption); var runtimeIdentifierOption = new Option<string?>("--runtime-identifier", "--rid") { Description = "Runtime identifier used to prefer runtime-specific assets (defaults to the current runtime)" }; command.Options.Add(runtimeIdentifierOption); var verboseOption = new Option<bool>("--verbose", "-v") { Description = "Enable verbose output" }; command.Options.Add(verboseOption); command.SetAction((parseResult, ct) => { var assetsPath = parseResult.GetValue(assetsOption)!; var outputPath = parseResult.GetValue(outputOption)!; var framework = parseResult.GetValue(frameworkOption)!; var runtimeIdentifier = parseResult.GetValue(runtimeIdentifierOption); var verbose = parseResult.GetValue(verboseOption); return Task.FromResult(ExecuteLayout(assetsPath, outputPath, framework, runtimeIdentifier, verbose)); }); return command; } private static int ExecuteLayout( string assetsPath, string outputPath, string framework, string? runtimeIdentifier, bool verbose) { if (!File.Exists(assetsPath)) { Console.Error.WriteLine($"Error: Assets file not found: {assetsPath}"); return 1; } try { var resolution = NuGetPackageAssetResolver.Resolve( assetsPath, framework, runtimeIdentifier, verbose ? Console.WriteLine : null); // Create output directory Directory.CreateDirectory(outputPath); var copiedCount = 0; if (verbose) { Console.WriteLine($"Using packages path: {resolution.PackagesPath}"); Console.WriteLine($"Target framework: {resolution.TargetFramework}"); Console.WriteLine($"Runtime identifier: {resolution.RuntimeIdentifier}"); Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Libraries: {0}", resolution.LibraryCount)); } foreach (var asset in resolution.Assets) { var destPath = Path.Combine(outputPath, asset.RelativePath.Replace('/', Path.DirectorySeparatorChar)); if (CopyIfNewer(asset.SourcePath, destPath, createDirectory: asset.RelativePath.Contains('/'))) { copiedCount++; if (verbose) { Console.WriteLine($" Copy: {asset.SourcePath} -> {destPath}"); } } } Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Layout created: {0} files copied to {1}", copiedCount, outputPath)); if (resolution.SkippedPackageCount > 0 && verbose) { Console.WriteLine(string.Format(CultureInfo.InvariantCulture, " ({0} packages skipped - not found in cache)", resolution.SkippedPackageCount)); } return 0; } catch (Exception ex) { Console.Error.WriteLine($"Error: {ex.Message}"); if (verbose) { Console.Error.WriteLine(ex.StackTrace); } return 1; } } private static bool CopyIfNewer(string sourcePath, string destPath, bool createDirectory) { if (File.Exists(destPath) && File.GetLastWriteTimeUtc(sourcePath) <= File.GetLastWriteTimeUtc(destPath)) { return false; } if (createDirectory) { Directory.CreateDirectory(Path.GetDirectoryName(destPath)!); } File.Copy(sourcePath, destPath, overwrite: true); return true; } }