Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ The default is 'false.' However, when targeting .NET 7 or lower, the default is
<data name="PackageIdentityArgumentDescription" xml:space="preserve">
<value>Package reference in the form of a package identifier like '{0}' or package identifier and version separated by '@' like '{0}@{1}'.</value>
</data>
<data name="SdkIdentityArgumentDescription" xml:space="preserve">
<value>SDK reference in the form of an SDK name like '{0}' or SDK name and version separated by '@' like '{0}@{1}'.</value>
</data>
<data name="SdkIdentityArgumentIdIsNull" xml:space="preserve">
<value>SDK reference name must not be null or empty.</value>
</data>
<data name="SdkIdentityArgumentVersionIsEmpty" xml:space="preserve">
<value>SDK version must not be empty when specified using the '@' separator.</value>
</data>
<data name="PackageIdentityArgumentIdOrVersionIsNull" xml:space="preserve">
<value>Package reference id and version must not be null.</value>
</data>
Expand Down Expand Up @@ -539,6 +548,9 @@ This is equivalent to deleting project.assets.json.</value>
<data name="CmdPackage" xml:space="preserve">
<value>PACKAGE_NAME</value>
</data>
<data name="CmdSdk" xml:space="preserve">
<value>SDK_NAME</value>
</data>
<data name="CmdPackageDirectory" xml:space="preserve">
<value>PACKAGE_DIR</value>
</data>
Expand Down Expand Up @@ -904,6 +916,18 @@ If not specified the file will be generated inside the default 'TestResults' dir
<data name="PackageRemoveAppHelpText" xml:space="preserve">
<value>The package reference to remove.</value>
</data>
<data name="SdkAddAppFullName" xml:space="preserve">
<value>Add an SDK reference to the project.</value>
</data>
<data name="SdkAddCmdNoRestoreDescription" xml:space="preserve">
<value>Add the SDK reference without running restore.</value>
</data>
<data name="SdkRemoveAppFullName" xml:space="preserve">
<value>Remove an SDK reference from the project.</value>
</data>
<data name="SdkRemoveAppHelpText" xml:space="preserve">
<value>The SDK reference to remove.</value>
</data>
<data name="PackageSearchCommandDescription" xml:space="preserve">
<value>Searches one or more package sources for packages that match a search term. If no sources are specified, all sources defined in the NuGet.Config are used.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Commands.Hidden.Add.Package;
using Microsoft.DotNet.Cli.Commands.Hidden.Add.Reference;
using Microsoft.DotNet.Cli.Commands.Hidden.Add.Sdk;
using Microsoft.DotNet.Cli.Commands.Package;

namespace Microsoft.DotNet.Cli.Commands.Hidden.Add;
Expand All @@ -16,6 +17,7 @@ internal sealed class AddCommandDefinition : Command

public readonly AddPackageCommandDefinition PackageCommand = new();
public readonly AddReferenceCommandDefinition ReferenceCommand = new();
public readonly AddSdkCommandDefinition SdkCommand = new();

public readonly Argument<string> ProjectOrFileArgument = PackageCommandDefinition.CreateProjectOrFileArgument();

Expand All @@ -28,5 +30,6 @@ public AddCommandDefinition()
Arguments.Add(ProjectOrFileArgument);
Subcommands.Add(PackageCommand);
Subcommands.Add(ReferenceCommand);
Subcommands.Add(SdkCommand);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Microsoft.DotNet.Cli.Commands.Sdk.Add;

namespace Microsoft.DotNet.Cli.Commands.Hidden.Add.Sdk;

internal sealed class AddSdkCommandDefinition() : SdkAddCommandDefinitionBase(Name)
{
public new const string Name = "sdk";

public AddCommandDefinition Parent => (AddCommandDefinition)Parents.Single();

public override Argument<string>? GetProjectOrFileArgument()
=> Parent.ProjectOrFileArgument;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Commands.Hidden.Remove.Package;
using Microsoft.DotNet.Cli.Commands.Hidden.Remove.Reference;
using Microsoft.DotNet.Cli.Commands.Hidden.Remove.Sdk;
using Microsoft.DotNet.Cli.Commands.Package;

namespace Microsoft.DotNet.Cli.Commands.Hidden.Remove;
Expand All @@ -19,6 +20,7 @@ internal sealed class RemoveCommandDefinition : Command

public readonly RemovePackageCommandDefinition PackageCommand = new();
public readonly RemoveReferenceCommandDefinition ReferenceCommand = new();
public readonly RemoveSdkCommandDefinition SdkCommand = new();

public RemoveCommandDefinition()
: base(Name, CommandDefinitionStrings.NetRemoveCommand)
Expand All @@ -29,5 +31,6 @@ public RemoveCommandDefinition()
Arguments.Add(ProjectOrFileArgument);
Subcommands.Add(PackageCommand);
Subcommands.Add(ReferenceCommand);
Subcommands.Add(SdkCommand);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Microsoft.DotNet.Cli.Commands.Sdk.Remove;

namespace Microsoft.DotNet.Cli.Commands.Hidden.Remove.Sdk;

internal sealed class RemoveSdkCommandDefinition() : SdkRemoveCommandDefinitionBase(Name)
{
public new const string Name = "sdk";

public RemoveCommandDefinition Parent => (RemoveCommandDefinition)Parents.Single();

public override Argument<string>? GetProjectOrFileArgument()
=> Parent.ProjectOrFileArgument;
}
Original file line number Diff line number Diff line change
@@ -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 System.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Commands.Package;

namespace Microsoft.DotNet.Cli.Commands.Sdk.Add;

internal abstract class SdkAddCommandDefinitionBase : Command
{
public static Option<string?> CreateVersionOption() => new Option<string?>("--version", "-v")
{
Description = CommandDefinitionStrings.CmdVersionDescription,
HelpName = CommandDefinitionStrings.CmdVersion,
};

public static Option<bool> CreateNoRestoreOption() => new("--no-restore", "-n")
{
Description = CommandDefinitionStrings.SdkAddCmdNoRestoreDescription,
Arity = ArgumentArity.Zero
};

public static Option<bool> CreateInteractiveOption() => CommonOptions.CreateInteractiveOption().ForwardIfEnabled("--interactive");

public readonly Argument<SdkReferenceIdentity> SdkIdArgument = CommonArguments.CreateRequiredSdkReferenceIdentityArgument();
public readonly Option<string?> VersionOption = CreateVersionOption();
public readonly Option<bool> NoRestoreOption = CreateNoRestoreOption();
public readonly Option<bool> InteractiveOption = CreateInteractiveOption();
public readonly Option<string?> ProjectOption = PackageCommandDefinition.CreateProjectOption();
public readonly Option<string?> FileOption = PackageCommandDefinition.CreateFileOption();

public SdkAddCommandDefinitionBase(string name)
: base(name, CommandDefinitionStrings.SdkAddAppFullName)
{
VersionOption.Validators.Add(result =>
{
if (result.Parent?.GetValue(SdkIdArgument).HasVersion == true)
{
result.AddError(CommandDefinitionStrings.ValidationFailedDuplicateVersion);
}
});

Arguments.Add(SdkIdArgument);

Options.Add(VersionOption);
Options.Add(NoRestoreOption);
Options.Add(InteractiveOption);
Options.Add(ProjectOption);
Options.Add(FileOption);
}

public abstract Argument<string>? GetProjectOrFileArgument();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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 Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Commands.Package;

namespace Microsoft.DotNet.Cli.Commands.Sdk.Remove;

internal abstract class SdkRemoveCommandDefinitionBase : Command
{
public readonly Argument<string[]> SdkIdArgument = new(CommonArguments.SdkIdArgumentName)
{
Description = CommandDefinitionStrings.SdkRemoveAppHelpText,
HelpName = CommandDefinitionStrings.CmdSdk,
Arity = ArgumentArity.OneOrMore,
};

public readonly Option<bool> InteractiveOption = CommonOptions.CreateInteractiveOption().ForwardIfEnabled("--interactive");
public readonly Option<string?> ProjectOption = PackageCommandDefinition.CreateProjectOption();
public readonly Option<string?> FileOption = PackageCommandDefinition.CreateFileOption();

public SdkRemoveCommandDefinitionBase(string name)
: base(name, CommandDefinitionStrings.SdkRemoveAppFullName)
{
Arguments.Add(SdkIdArgument);
Options.Add(InteractiveOption);
Options.Add(ProjectOption);
Options.Add(FileOption);
}

public abstract Argument<string>? GetProjectOrFileArgument();
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,78 @@ public static Argument<PackageIdentityWithRange> CreateRequiredPackageIdentityAr

return new PackageIdentityWithRange(packageId, versionRange);
}

public const string SdkIdArgumentName = "sdkId";

public static Argument<SdkReferenceIdentity> CreateRequiredSdkReferenceIdentityArgument(
string exampleSdk = "Cake.Sdk",
string exampleVersion = "6.2.0") =>
new(SdkIdArgumentName)
{
Description = string.Format(CommandDefinitionStrings.SdkIdentityArgumentDescription, exampleSdk, exampleVersion),
CustomParser = argumentResult =>
{
SdkReferenceIdentity? identity = ParseSdkReferenceIdentity(argumentResult.Tokens.FirstOrDefault()?.Value);
if (identity is null)
{
throw new GracefulException(CommandDefinitionStrings.SdkIdentityArgumentIdIsNull);
}

return identity.Value;
},
Arity = ArgumentArity.ExactlyOne,
IsDynamic = true
};
Comment thread
devlead marked this conversation as resolved.

public static string GetSdkIdFromIdentityArgument(string sdkIdentity)
{
SdkReferenceIdentity? identity = ParseSdkReferenceIdentity(sdkIdentity);
if (identity is null)
{
throw new GracefulException(CommandDefinitionStrings.SdkIdentityArgumentIdIsNull);
}

return identity.Value.Id;
}

private static SdkReferenceIdentity? ParseSdkReferenceIdentity(string? sdkIdentity, char versionSeparator = '@')
{
if (string.IsNullOrEmpty(sdkIdentity))
{
return null;
}

string[] splitSdkIdentity = sdkIdentity.Split(versionSeparator);
var sdkId = splitSdkIdentity.ElementAtOrDefault(0);
var version = splitSdkIdentity.ElementAtOrDefault(1);

if (string.IsNullOrEmpty(sdkId))
{
throw new GracefulException(CommandDefinitionStrings.SdkIdentityArgumentIdIsNull);
}
Comment thread
devlead marked this conversation as resolved.

if (splitSdkIdentity.Length > 2)
{
version = string.Join(versionSeparator, splitSdkIdentity.Skip(1));
}

if (sdkIdentity.Contains(versionSeparator) && string.IsNullOrWhiteSpace(version))
{
throw new GracefulException(CommandDefinitionStrings.SdkIdentityArgumentVersionIsEmpty);
}

return new SdkReferenceIdentity(sdkId, string.IsNullOrEmpty(version) ? null : version);
}
}

public readonly record struct PackageIdentityWithRange(string Id, VersionRange? VersionRange)
{
[MemberNotNullWhen(returnValue: true, nameof(VersionRange))]
public bool HasVersion => VersionRange != null;
}

public readonly record struct SdkReferenceIdentity(string Id, string? Version)
{
public bool HasVersion => Version != null;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading