| File: Commands\Package\Add\PackageAddCommand.cs | Web Access |
| Project: src\sdk\src\Cli\dotnet\dotnet.csproj (dotnet) |
// 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.Diagnostics; using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Commands.MSBuild; using Microsoft.DotNet.Cli.Commands.NuGet; using Microsoft.DotNet.Cli.Commands.Run; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.FileBasedPrograms; namespace Microsoft.DotNet.Cli.Commands.Package.Add; internal sealed class PackageAddCommand : CommandBase<PackageAddCommandDefinitionBase> { private readonly PackageIdentityWithRange _packageId; public PackageAddCommand(ParseResult parseResult) : base(parseResult) { _packageId = parseResult.GetValue(Definition.PackageIdArgument); } public override int Execute() { var (fileOrDirectory, allowedAppKinds) = PackageCommandParser.ProcessPathOptions(Definition.FileOption, Definition.ProjectOption, Definition.GetProjectOrFileArgument(), _parseResult); bool isFileBasedApp = allowedAppKinds.HasFlag(AppKinds.FileBased) && VirtualProjectBuilder.IsValidEntryPointPath(fileOrDirectory); Debug.Assert(isFileBasedApp || allowedAppKinds.HasFlag(AppKinds.ProjectBased)); string projectFilePath; if (!File.Exists(fileOrDirectory)) { Debug.Assert(!isFileBasedApp); projectFilePath = MsbuildProject.GetProjectFileFromDirectory(fileOrDirectory); } else { projectFilePath = fileOrDirectory; } if (isFileBasedApp) { projectFilePath = Path.GetFullPath(projectFilePath); } var tempDgFilePath = string.Empty; if (!_parseResult.GetValue(Definition.NoRestoreOption)) { try { // Create a Dependency Graph file for the project tempDgFilePath = Path.GetTempFileName(); } catch (IOException ioex) { // Catch IOException from Path.GetTempFileName() and throw a graceful exception to the user. throw new GracefulException(string.Format(CliCommandStrings.CmdDGFileIOException, projectFilePath), ioex); } GetProjectDependencyGraph(projectFilePath, tempDgFilePath, isFileBasedApp); } var args = TransformArgs( _packageId, tempDgFilePath, projectFilePath); var result = NuGetCommand.Run(args, isFileBasedApp); DisposeTemporaryFile(tempDgFilePath); return result; } private static void GetProjectDependencyGraph(string projectFilePath, string dgFilePath, bool isFileBasedApp) { int result; if (isFileBasedApp) { result = new VirtualProjectBuildingCommand( projectFilePath, MSBuildArgs .FromProperties(new Dictionary<string, string> { { "RestoreGraphOutputPath", dgFilePath }, { "RestoreRecursive", "false" }, { "RestoreDotnetCliToolReferences", "false" }, }.AsReadOnly()) .CloneWithVerbosity(VerbosityOptions.quiet) .CloneWithAdditionalTargets("GenerateRestoreGraphFile")) { NoRestore = true, NoCache = true, NoWriteBuildMarkers = true, }.Execute(); } else { result = new MSBuildForwardingApp( [ // Pass the project file path projectFilePath, // Pass the task as generate restore Dependency Graph file "-target:GenerateRestoreGraphFile", // Pass Dependency Graph file output path $"-property:RestoreGraphOutputPath=\"{dgFilePath}\"", // Turn off recursive restore "-property:RestoreRecursive=false", // Turn off restore for Dotnet cli tool references so that we do not generate extra dg specs "-property:RestoreDotnetCliToolReferences=false", // Output should not include MSBuild version header "--nologo", // Set verbosity to quiet to avoid cluttering the output for this 'inner' build "-v:quiet" ]).Execute(); } if (result != 0) { throw new GracefulException(string.Format(CliCommandStrings.CmdDGFileException, projectFilePath)); } } private static void DisposeTemporaryFile(string filePath) { if (File.Exists(filePath)) { File.Delete(filePath); } } private string[] TransformArgs(PackageIdentityWithRange packageId, string tempDgFilePath, string projectFilePath) { List<string> args = [ "package", "add", "--package", packageId.Id, "--project", projectFilePath ]; if (packageId.HasVersion) { args.Add("--version"); args.Add(packageId.VersionRange.OriginalString ?? string.Empty); } args.AddRange(_parseResult .OptionValuesToBeForwarded() .SelectMany(a => a.Split(' ', 2))); if (_parseResult.GetValue(Definition.NoRestoreOption)) { args.Add("--no-restore"); } else { args.Add("--dg-file"); args.Add(tempDgFilePath); } return [.. args]; } }