Skip to content

Commit 73bf5e5

Browse files
authored
Implementing dotnet pack with nuspec files (#49813)
adds support for packing NuGet packages directly from a .nuspec file using the dotnet pack command without needing a csproj file
1 parent 209e114 commit 73bf5e5

40 files changed

+462
-6
lines changed

src/Cli/dotnet/CliStrings.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,4 +823,7 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is
823823
<data name="SDKSchemaCommandDefinition" xml:space="preserve">
824824
<value>Display the command schema as JSON.</value>
825825
</data>
826-
</root>
826+
<data name="PackCmd_OneNuspecAllowed" xml:space="preserve">
827+
<value>Only one .nuspec file can be packed at a time</value>
828+
</data>
829+
</root>

src/Cli/dotnet/Commands/CliCommandStrings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,4 +2634,10 @@ Proceed?</value>
26342634
<data name="TestCommandUseTestModules" xml:space="preserve">
26352635
<value>Specifying dlls or executables for 'dotnet test' should be via '--test-modules'.</value>
26362636
</data>
2637+
<data name="PackCmdVersionDescription" xml:space="preserve">
2638+
<value>The version of the package to create</value>
2639+
</data>
2640+
<data name="PackCmdVersion" xml:space="preserve">
2641+
<value>VERSION</value>
2642+
</data>
26372643
</root>

src/Cli/dotnet/Commands/Pack/PackCommand.cs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.ObjectModel;
45
using System.CommandLine;
6+
using System.CommandLine.Parsing;
7+
using System.Configuration;
8+
using Microsoft.DotNet.Cli.Commands.Build;
59
using Microsoft.DotNet.Cli.Commands.Restore;
610
using Microsoft.DotNet.Cli.Extensions;
11+
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
712
using Microsoft.DotNet.Cli.Utils;
13+
using NuGet.Commands;
14+
using NuGet.Common;
15+
using NuGet.Packaging;
16+
using NuGet.Packaging.Core;
817

918
namespace Microsoft.DotNet.Cli.Commands.Pack;
1019

@@ -22,8 +31,6 @@ public static PackCommand FromArgs(string[] args, string? msbuildPath = null)
2231

2332
public static PackCommand FromParseResult(ParseResult parseResult, string? msbuildPath = null)
2433
{
25-
parseResult.ShowHelpOrErrorIfAppropriate();
26-
2734
var msbuildArgs = parseResult.OptionValuesToBeForwarded(PackCommandParser.GetCommand()).Concat(parseResult.GetValue(PackCommandParser.SlnOrProjectArgument) ?? []);
2835

2936
ReleasePropertyProjectLocator projectLocator = new(parseResult, MSBuildPropertyNames.PACK_RELEASE,
@@ -46,10 +53,73 @@ public static PackCommand FromParseResult(ParseResult parseResult, string? msbui
4653
msbuildPath);
4754
}
4855

56+
private static LogLevel MappingVerbosityToNugetLogLevel(VerbosityOptions? verbosity)
57+
{
58+
return verbosity switch
59+
{
60+
VerbosityOptions.diagnostic or VerbosityOptions.diag => LogLevel.Debug,
61+
VerbosityOptions.minimal or VerbosityOptions.m => LogLevel.Minimal,
62+
VerbosityOptions.normal or VerbosityOptions.n => LogLevel.Information,
63+
VerbosityOptions.detailed or VerbosityOptions.d => LogLevel.Verbose,
64+
_ => LogLevel.Minimal
65+
};
66+
}
67+
68+
public static int RunPackCommand(ParseResult parseResult)
69+
{
70+
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectArgument)?.ToList() ?? new List<string>();
71+
72+
if (args.Count != 1)
73+
{
74+
Console.Error.WriteLine(CliStrings.PackCmd_OneNuspecAllowed);
75+
return 1;
76+
}
77+
78+
var nuspecPath = args[0];
79+
80+
var packArgs = new PackArgs()
81+
{
82+
Logger = new NuGetConsoleLogger(),
83+
Exclude = new List<string>(),
84+
OutputDirectory = parseResult.GetValue(PackCommandParser.OutputOption),
85+
LogLevel = MappingVerbosityToNugetLogLevel(parseResult.GetValue(BuildCommandParser.VerbosityOption)),
86+
Arguments = [nuspecPath]
87+
};
88+
89+
packArgs.Path = PackCommandRunner.GetInputFile(packArgs);
90+
packArgs.BasePath = Path.GetDirectoryName(packArgs.Path);
91+
PackCommandRunner.SetupCurrentDirectory(packArgs);
92+
93+
var globalProperties = parseResult.GetResult("--property") is OptionResult propResult ? propResult.GetValueOrDefault<ReadOnlyDictionary<string, string>?>() : null;
94+
if (globalProperties != null)
95+
packArgs.Properties.AddRange(globalProperties);
96+
97+
var version = parseResult.GetValue(PackCommandParser.VersionOption);
98+
if (version != null)
99+
packArgs.Version = version.ToNormalizedString();
100+
101+
var configuration = parseResult.GetValue(PackCommandParser.ConfigurationOption) ?? "Debug";
102+
packArgs.Properties["configuration"] = configuration;
103+
104+
var packCommandRunner = new PackCommandRunner(packArgs, null);
105+
if (!packCommandRunner.RunPackageBuild())
106+
return 1;
107+
return 0;
108+
}
109+
49110
public static int Run(ParseResult parseResult)
50111
{
51112
parseResult.HandleDebugSwitch();
113+
parseResult.ShowHelpOrErrorIfAppropriate();
114+
115+
var args = parseResult.GetValue(PackCommandParser.SlnOrProjectArgument)?.ToList() ?? new List<string>();
116+
117+
if (args.Count > 0 && Path.GetExtension(args[0]).Equals(".nuspec", StringComparison.OrdinalIgnoreCase))
118+
{
119+
return RunPackCommand(parseResult);
120+
}
52121

122+
// Fallback to MSBuild-based packing
53123
return FromParseResult(parseResult).Execute();
54124
}
55125
}

src/Cli/dotnet/Commands/Pack/PackCommandParser.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.ObjectModel;
45
using System.CommandLine;
56
using Microsoft.DotNet.Cli.Commands.Build;
67
using Microsoft.DotNet.Cli.Commands.Restore;
78
using Microsoft.DotNet.Cli.Extensions;
9+
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
10+
using NuGet.Commands;
11+
using NuGet.Common;
12+
using NuGet.Versioning;
13+
using static Microsoft.DotNet.Cli.Commands.Run.CSharpDirective;
814

915
namespace Microsoft.DotNet.Cli.Commands.Pack;
1016

@@ -61,6 +67,25 @@ internal static class PackCommandParser
6167
public static readonly Option<string[]> TargetOption = CommonOptions.RequiredMSBuildTargetOption("Pack", [("_IsPacking", "true")]);
6268
public static readonly Option<Utils.VerbosityOptions?> VerbosityOption = BuildCommandParser.VerbosityOption;
6369

70+
public static Option<NuGetVersion> VersionOption =
71+
new ForwardedOption<NuGetVersion>("--version")
72+
{
73+
Description = CliCommandStrings.PackCmdVersionDescription,
74+
HelpName = CliCommandStrings.PackCmdVersion,
75+
Arity = ArgumentArity.ExactlyOne,
76+
CustomParser = r =>
77+
{
78+
if (r.Tokens.Count == 0)
79+
return null;
80+
var value = r.Tokens[0].Value;
81+
if (NuGetVersion.TryParse(value, out var version))
82+
return version;
83+
r.AddError(string.Format(CliStrings.InvalidVersion, value));
84+
return null;
85+
86+
}
87+
}.ForwardAsSingle(o => $"--property:PackageVersion={o}");
88+
6489
private static readonly Command Command = ConstructCommand();
6590

6691
public static Command GetCommand()
@@ -84,6 +109,7 @@ private static Command ConstructCommand()
84109
command.Options.Add(NoRestoreOption);
85110
command.Options.Add(VerbosityOption);
86111
command.Options.Add(CommonOptions.VersionSuffixOption);
112+
command.Options.Add(VersionOption);
87113
command.Options.Add(ConfigurationOption);
88114
command.Options.Add(CommonOptions.DisableBuildServersOption);
89115
command.Options.Add(TargetOption);

src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)