Improve the help text (#5002)

* WIP Improve help text

* Improve help text

* Address PR comments

* Address PR comments

* Address PR comments
This commit is contained in:
Justin Goshi 2016-12-13 14:31:35 -10:00 committed by GitHub
parent 148351c12d
commit 76722fd403
20 changed files with 486 additions and 640 deletions

View file

@ -48,5 +48,7 @@ namespace Microsoft.DotNet.Cli.Utils
};
public static readonly string MSBUILD_EXE_PATH = "MSBUILD_EXE_PATH";
public static readonly string ProjectOrSolutionArgumentName = "<PROJECT_OR_SOLUTION>";
}
}

View file

@ -13,6 +13,14 @@ namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandLineApplication
{
private enum ParseOptionResult
{
Succeeded,
ShowHelp,
ShowVersion,
UnexpectedArgs,
}
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
@ -45,8 +53,14 @@ namespace Microsoft.DotNet.Cli.CommandLine
public List<CommandLineApplication> Commands { get; private set; }
public bool HandleResponseFiles { get; set; }
public bool AllowArgumentSeparator { get; set; }
public bool HandleRemainingArguments { get; set; }
public string ArgumentSeparatorHelpText { get; set; }
public CommandLineApplication Command(string name, bool throwOnUnexpectedArg = true)
{
return Command(name, _ => { }, throwOnUnexpectedArg);
}
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
{
@ -103,7 +117,6 @@ namespace Microsoft.DotNet.Cli.CommandLine
public int Execute(params string[] args)
{
CommandLineApplication command = this;
CommandOption option = null;
IEnumerator<CommandArgument> arguments = null;
if (HandleResponseFiles)
@ -114,172 +127,159 @@ namespace Microsoft.DotNet.Cli.CommandLine
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
var processed = false;
if (!processed && option == null)
bool isLongOption = arg.StartsWith("--");
if (isLongOption || arg.StartsWith("-"))
{
string[] longOption = null;
string[] shortOption = null;
if (arg.StartsWith("--"))
CommandOption option;
var result = ParseOption(isLongOption, command, args, ref index, out option);
if (result == ParseOptionResult.ShowHelp)
{
longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2);
command.ShowHelp();
return 0;
}
else if (arg.StartsWith("-"))
else if (result == ParseOptionResult.ShowVersion)
{
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
command.ShowVersion();
return 0;
}
if (longOption != null)
else if (result == ParseOptionResult.UnexpectedArgs)
{
processed = true;
string longOptionName = longOption[0];
option = command.Options.SingleOrDefault(opt => string.Equals(opt.LongName, longOptionName, StringComparison.Ordinal));
if (option == null)
{
if (string.IsNullOrEmpty(longOptionName) && !command._throwOnUnexpectedArg && AllowArgumentSeparator)
{
// a stand-alone "--" is the argument separator, so skip it and
// handle the rest of the args as unexpected args
index++;
}
HandleUnexpectedArg(command, args, index, argTypeName: "option");
break;
}
// If we find a help/version option, show information and stop parsing
if (command.OptionHelp == option)
{
command.ShowHelp();
return 0;
}
else if (command.OptionVersion == option)
{
command.ShowVersion();
return 0;
}
if (longOption.Length == 2)
{
if (!option.TryParse(longOption[1]))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'");
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue || option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
option = null;
}
}
if (shortOption != null)
{
processed = true;
option = command.Options.SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal));
// If not a short option, try symbol option
if (option == null)
{
option = command.Options.SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal));
}
if (option == null)
{
HandleUnexpectedArg(command, args, index, argTypeName: "option");
break;
}
// If we find a help/version option, show information and stop parsing
if (command.OptionHelp == option)
{
command.ShowHelp();
return 0;
}
else if (command.OptionVersion == option)
{
command.ShowVersion();
return 0;
}
if (shortOption.Length == 2)
{
if (!option.TryParse(shortOption[1]))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'");
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue || option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
option = null;
}
break;
}
}
if (!processed && option != null)
else
{
processed = true;
if (!option.TryParse(arg))
var subcommand = ParseSubCommand(arg, command);
if (subcommand != null)
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'");
command = subcommand;
}
option = null;
}
if (!processed && arguments == null)
{
var currentCommand = command;
foreach (var subcommand in command.Commands)
else
{
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
if (arguments == null)
{
processed = true;
command = subcommand;
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
arguments.Current.Values.Add(arg);
}
else
{
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
break;
}
}
// If we detect a subcommand
if (command != currentCommand)
{
processed = true;
}
}
if (!processed)
{
if (arguments == null)
{
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
processed = true;
arguments.Current.Values.Add(arg);
}
}
if (!processed)
{
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
break;
}
}
if (option != null)
{
command.ShowHint();
throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'");
}
return command.Invoke();
}
private ParseOptionResult ParseOption(
bool isLongOption,
CommandLineApplication command,
string[] args,
ref int index,
out CommandOption option)
{
option = null;
ParseOptionResult result = ParseOptionResult.Succeeded;
var arg = args[index];
int optionPrefixLength = isLongOption ? 2 : 1;
string[] optionComponents = arg.Substring(optionPrefixLength).Split(new[] { ':', '=' }, 2);
string optionName = optionComponents[0];
if (isLongOption)
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.LongName, optionName, StringComparison.Ordinal));
}
else
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.ShortName, optionName, StringComparison.Ordinal));
if (option == null)
{
option = command.Options.SingleOrDefault(
opt => string.Equals(opt.SymbolName, optionName, StringComparison.Ordinal));
}
}
if (option == null)
{
if (isLongOption && string.IsNullOrEmpty(optionName) &&
!command._throwOnUnexpectedArg && AllowArgumentSeparator)
{
// a stand-alone "--" is the argument separator, so skip it and
// handle the rest of the args as unexpected args
index++;
}
HandleUnexpectedArg(command, args, index, argTypeName: "option");
result = ParseOptionResult.UnexpectedArgs;
}
else if (command.OptionHelp == option)
{
result = ParseOptionResult.ShowHelp;
}
else if (command.OptionVersion == option)
{
result = ParseOptionResult.ShowVersion;
}
else
{
if (optionComponents.Length == 2)
{
if (!option.TryParse(optionComponents[1]))
{
command.ShowHint();
throw new CommandParsingException(command,
$"Unexpected value '{optionComponents[1]}' for option '{optionName}'");
}
}
else
{
if (option.OptionType == CommandOptionType.NoValue ||
option.OptionType == CommandOptionType.BoolValue)
{
// No value is needed for this option
option.TryParse(null);
}
else
{
index++;
arg = args[index];
if (!option.TryParse(arg))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{optionName}'");
}
}
}
}
return result;
}
private CommandLineApplication ParseSubCommand(string arg, CommandLineApplication command)
{
foreach (var subcommand in command.Commands)
{
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
{
return subcommand;
}
}
return null;
}
// Helper method that adds a help option
public CommandOption HelpOption(string template)
{
@ -331,10 +331,19 @@ namespace Microsoft.DotNet.Cli.CommandLine
public void ShowHelp(string commandName = null)
{
var headerBuilder = new StringBuilder("Usage:");
var usagePrefixLength = headerBuilder.Length;
for (var cmd = this; cmd != null; cmd = cmd.Parent)
{
cmd.IsShowingInformation = true;
headerBuilder.Insert(6, string.Format(" {0}", cmd.Name));
if (cmd != this && cmd.Arguments.Any())
{
var args = string.Join(" ", cmd.Arguments.Select(arg => arg.Name));
headerBuilder.Insert(usagePrefixLength, string.Format(" {0} {1}", cmd.Name, args));
}
else
{
headerBuilder.Insert(usagePrefixLength, string.Format(" {0}", cmd.Name));
}
}
CommandLineApplication target;
@ -364,18 +373,39 @@ namespace Microsoft.DotNet.Cli.CommandLine
var argumentsBuilder = new StringBuilder();
var argumentSeparatorBuilder = new StringBuilder();
if (target.Arguments.Any())
int maxArgLen = 0;
for (var cmd = target; cmd != null; cmd = cmd.Parent)
{
headerBuilder.Append(" [arguments]");
argumentsBuilder.AppendLine();
argumentsBuilder.AppendLine("Arguments:");
var maxArgLen = MaxArgumentLength(target.Arguments);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxArgLen + 2);
foreach (var arg in target.Arguments)
if (cmd.Arguments.Any())
{
argumentsBuilder.AppendFormat(outputFormat, arg.Name, arg.Description);
argumentsBuilder.AppendLine();
if (cmd == target)
{
headerBuilder.Append(" [arguments]");
}
if (argumentsBuilder.Length == 0)
{
argumentsBuilder.AppendLine();
argumentsBuilder.AppendLine("Arguments:");
}
maxArgLen = Math.Max(maxArgLen, MaxArgumentLength(cmd.Arguments));
}
}
for (var cmd = target; cmd != null; cmd = cmd.Parent)
{
if (cmd.Arguments.Any())
{
var outputFormat = " {0}{1}";
foreach (var arg in cmd.Arguments)
{
argumentsBuilder.AppendFormat(
outputFormat,
arg.Name.PadRight(maxArgLen + 2),
arg.Description);
argumentsBuilder.AppendLine();
}
}
}
@ -416,9 +446,17 @@ namespace Microsoft.DotNet.Cli.CommandLine
}
}
if (target.AllowArgumentSeparator)
if (target.AllowArgumentSeparator || target.HandleRemainingArguments)
{
headerBuilder.Append(" [[--] <arg>...]]");
if (target.AllowArgumentSeparator)
{
headerBuilder.Append(" [[--] <arg>...]]");
}
else
{
headerBuilder.Append(" [args]");
}
if (!string.IsNullOrEmpty(target.ArgumentSeparatorHelpText))
{
argumentSeparatorBuilder.AppendLine();

View file

@ -2,17 +2,9 @@
{
internal class CommonLocalizableStrings
{
public const string CouldNotFindAnyProjectInDirectory = "Could not find any project in `{0}`.";
public const string MoreThanOneProjectInDirectory = "Found more than one project in `{0}`. Please specify which one to use.";
public const string ProjectAlreadyHasAreference = "Project already has a reference to `{0}`.";
public const string ProjectReferenceCouldNotBeFound = "Project reference `{0}` could not be found.";
public const string ProjectReferenceRemoved = "Project reference `{0}` removed.";
// General purpose words
public const string RequiredArgument = "Required argument";
public const string Option = "Option";
public const string Argument = "Argument";
public const string Help = "Help";
// Project related
public const string Project = "Project";
@ -30,9 +22,7 @@
public const string Library = "Library";
public const string Program = "Program";
public const string Application = "Application";
public const string ReferenceDoesNotExist = "Reference {0} does not exist. If you still want to add it, please use --force option. Please note that this may have adverse effects on the project. ";
public const string ReferenceAddedToTheProject = "Reference `{0}` added to the project.";
// Verbs
public const string Add = "Add";
@ -101,9 +91,9 @@
// dotnet <verb>
/// Project
public const string CouldNotFindProjectIn = "Could not find any project in `{0}`.";
public const string CouldNotFindAnyProjectInDirectory = "Could not find any project in `{0}`.";
public const string CouldNotFindProjectOrDirectory = "Could not find project or directory `{0}`.";
public const string FoundMoreThanOneProjectIn = "Found more than one project in `{0}`. Please specify which one to use.";
public const string MoreThanOneProjectInDirectory = "Found more than one project in `{0}`. Please specify which one to use.";
public const string FoundInvalidProject = "Found a project `{0}` but it is invalid.";
public const string InvalidProject = "Invalid project `{0}`.";
@ -117,15 +107,15 @@
public const string SolutionAlreadyContainsAProject = "Solution {0} already contains project {1}.";
/// add p2p
public const string ReferenceDoesNotExistForce = "Reference {0} does not exist. If you still want to add it, please use --force option. Please note that this may have adverse effects on the project. ";
public const string ReferenceDoesNotExist = "Reference {0} does not exist.";
public const string ReferenceIsInvalid = "Reference `{0}` is invalid.";
public const string SpecifyAtLeastOneReferenceToAdd = "You must specify at least one reference to add. Please run dotnet add --help for more information.";
public const string SpecifyAtLeastOneReferenceToAdd = "You must specify at least one reference to add.";
public const string ProjectAlreadyHasAReference = "Project {0} already has a reference `{1}`.";
/// add package
public const string PackageReferenceDoesNotExist = "Package reference `{0}` does not exist.";
public const string PackageReferenceIsInvalid = "Package reference `{0}` is invalid.";
public const string SpecifyAtLeastOnePackageReferenceToAdd = "You must specify at least one reference to add. Please run dotnet add --help for more information.";
public const string SpecifyAtLeastOnePackageReferenceToAdd = "You must specify at least one package to add.";
public const string PackageReferenceAddedToTheProject = "Package reference `{0}` added to the project.";
public const string ProjectAlreadyHasAPackageReference = "Project {0} already has a reference `{1}`.";
public const string PleaseSpecifyVersion = "Please specify a version of the package.";
@ -133,7 +123,7 @@
/// add sln
public const string ProjectDoesNotExist = "Project `{0}` does not exist.";
public const string ProjectIsInvalid = "Project `{0}` is invalid.";
public const string SpecifyAtLeastOneProjectToAdd = "You must specify at least one project to add. Please run dotnet add --help for more information.";
public const string SpecifyAtLeastOneProjectToAdd = "You must specify at least one project to add.";
public const string ProjectAddedToTheSolution = "Project `{0}` added to the solution.";
public const string SolutionAlreadyHasAProject = "Solution {0} already contains project {1}.";
@ -162,6 +152,12 @@
public const string NoReferencesFound = "There are no {0} references in project {1}. ;; {0} is the type of the item being requested (project, package, p2p) and {1} is the object operated on (a project file or a solution file). ";
public const string NoProjectsFound = "No projects found in the solution.";
/// arguments
public const string ArgumentsProjectOrSolutionDescription = "The project or solution to operation on. If a file is not specified, the current directory is searched.";
/// commands
public const string CmdFramework = "FRAMEWORK";
/// update pkg
public const string PleaseSpecifyNewVersion = "Please specify new version of the package.";
public const string PleaseSpecifyWhichPackageToUpdate = "Please specify which package to update.";

View file

@ -1,76 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.DotNet.Cli.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools
{
public abstract class DispatchCommand
{
protected abstract string HelpText { get; }
protected abstract Dictionary<string, Func<string[], int>> BuiltInCommands { get; }
public int Start(string[] args)
{
DebugHelper.HandleDebugSwitch(ref args);
if (args.Length == 0 || args[0] == "--help" || args[0] == "-h")
{
Reporter.Output.WriteLine(HelpText);
return 0;
}
string commandObject;
string command;
if (IsValidCommandName(args[0]))
{
command = args[0];
commandObject = GetCurrentDirectoryWithDirSeparator();
args = args.Skip(1).Prepend(commandObject).ToArray();
}
else if (args.Length == 1)
{
Reporter.Error.WriteLine(string.Format(CommonLocalizableStrings.RequiredArgumentNotPassed, "<command>").Red());
Reporter.Output.WriteLine(HelpText);
return 1;
}
else
{
commandObject = args[0];
command = args[1];
args = args.Skip(2).Prepend(commandObject).ToArray();
}
Func<string[], int> builtin;
if (BuiltInCommands.TryGetValue(command, out builtin))
{
return builtin(args);
}
Reporter.Error.WriteLine(string.Format(CommonLocalizableStrings.RequiredArgumentIsInvalid, "<command>").Red());
Reporter.Output.WriteLine(HelpText);
return 1;
}
private bool IsValidCommandName(string s)
{
return BuiltInCommands.ContainsKey(s);
}
private static string GetCurrentDirectoryWithDirSeparator()
{
string ret = Directory.GetCurrentDirectory();
if (ret[ret.Length - 1] != Path.DirectorySeparatorChar)
{
ret += Path.DirectorySeparatorChar;
}
return ret;
}
}
}

View file

@ -0,0 +1,57 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
namespace Microsoft.DotNet.Cli
{
public abstract class DotNetTopLevelCommandBase
{
protected abstract string CommandName { get; }
protected abstract string FullCommandNameLocalized { get; }
internal abstract List<Func<CommandLineApplication, CommandLineApplication>> SubCommands { get; }
public int RunCommand(string[] args)
{
DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: true)
{
Name = $"dotnet {CommandName}",
FullName = FullCommandNameLocalized,
};
app.HelpOption("-h|--help");
app.Argument(
Constants.ProjectOrSolutionArgumentName,
CommonLocalizableStrings.ArgumentsProjectOrSolutionDescription);
foreach (var subCommandCreator in SubCommands)
{
subCommandCreator(app);
}
try
{
return app.Execute(args);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
catch (CommandParsingException e)
{
Reporter.Error.WriteLine(e.Message.Red());
return 1;
}
}
}
}

View file

@ -3,23 +3,5 @@ namespace Microsoft.DotNet.Tools.Add
internal class LocalizableStrings
{
public const string NetAddCommand = ".NET Add Command";
public const string Usage = "Usage";
public const string Options = "Options";
public const string HelpDefinition = "Show help information";
public const string Arguments = "Arguments";
public const string ArgumentsObjectDefinition = "The object of the operation. If a project file is not specified, it defaults to the current directory.";
public const string ArgumentsCommandDefinition = "Command to be executed on <object>.";
public const string ArgsDefinition = "Any extra arguments passed to the command. Use `dotnet add <command> --help` to get help about these arguments.";
public const string Commands = "Commands";
public const string CommandP2PDefinition = "Add project to project (p2p) reference to a project";
}
}

View file

@ -1,47 +1,28 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using System;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.DotNet.ProjectJsonMigration;
using NuGet.Frameworks;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
namespace Microsoft.DotNet.Tools.Add
{
public class AddCommand : DispatchCommand
public class AddCommand : DotNetTopLevelCommandBase
{
protected override string HelpText => $@"{LocalizableStrings.NetAddCommand}
{LocalizableStrings.Usage}: dotnet add [options] <object> <command> [[--] <arg>...]]
{LocalizableStrings.Options}:
-h|--help {LocalizableStrings.HelpDefinition}
{LocalizableStrings.Arguments}:
<object> {LocalizableStrings.ArgumentsObjectDefinition}
<command> {LocalizableStrings.ArgumentsCommandDefinition}
Args:
{LocalizableStrings.ArgsDefinition}
{LocalizableStrings.Commands}:
p2p {LocalizableStrings.CommandP2PDefinition}";
protected override Dictionary<string, Func<string[], int>> BuiltInCommands => new Dictionary<string, Func<string[], int>>
{
["p2p"] = AddProjectToProjectReferenceCommand.Run,
};
protected override string CommandName => "add";
protected override string FullCommandNameLocalized => LocalizableStrings.NetAddCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
{
AddProjectToProjectReferenceCommand.CreateApplication,
};
public static int Run(string[] args)
{
var cmd = new AddCommand();
return cmd.Start(args);
var command = new AddCommand();
return command.RunCommand(args);
}
}
}

View file

@ -5,21 +5,9 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
public const string AppFullName = ".NET Add Project to Project (p2p) reference Command";
public const string AppDescription = "Command to add project to project (p2p) reference";
public const string SpecifyAtLeastOneReferenceToAdd = "You must specify at least one reference to add. Please run dotnet add --help for more information.";
public const string AppHelpText = "Project to project references to add";
public const string CmdProject = "PROJECT";
public const string CmdProjectDescription = "The project file to modify. If a project file is not specified, it searches the current working directory for an MSBuild file that has a file extension that ends in `proj` and uses that file.";
public const string CmdFramework = "FRAMEWORK";
public const string CmdFrameworkDescription = "Add reference only when targetting a specific framework";
public const string CmdForceDescription = "Add reference even if it does not exist, do not convert paths to relative";
public const string ProjectException = "Project";
}
}

View file

@ -4,8 +4,10 @@
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using NuGet.Frameworks;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@ -13,53 +15,46 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
public class AddProjectToProjectReferenceCommand
{
public static int Run(string[] args)
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: false)
{
Name = "dotnet add p2p",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
AllowArgumentSeparator = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText
};
CommandLineApplication app = parentApp.Command("p2p", throwOnUnexpectedArg: false);
app.FullName = LocalizableStrings.AppFullName;
app.Description = LocalizableStrings.AppDescription;
app.HandleRemainingArguments = true;
app.ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText;
app.HelpOption("-h|--help");
CommandArgument projectArgument = app.Argument(
$"<{LocalizableStrings.CmdProject}>",
LocalizableStrings.CmdProjectDescription);
CommandOption frameworkOption = app.Option(
$"-f|--framework <{LocalizableStrings.CmdFramework}>",
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
CommandOption forceOption = app.Option(
"--force",
LocalizableStrings.CmdForceDescription,
CommandOptionType.NoValue);
app.OnExecute(() => {
if (string.IsNullOrEmpty(projectArgument.Value))
app.OnExecute(() =>
{
try
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, $"<{LocalizableStrings.ProjectException}>");
}
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projects = new ProjectCollection();
var msbuildProj = MsbuildProject.FromFileOrDirectory(projects, projectArgument.Value);
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
if (app.RemainingArguments.Count == 0)
{
throw new GracefulException(LocalizableStrings.SpecifyAtLeastOneReferenceToAdd);
}
var projects = new ProjectCollection();
var msbuildProj = MsbuildProject.FromFileOrDirectory(projects, projectOrDirectory);
string frameworkString = frameworkOption.Value();
List<string> references = app.RemainingArguments;
if (!forceOption.HasValue())
{
if (app.RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToAdd);
}
string frameworkString = frameworkOption.Value();
List<string> references = app.RemainingArguments;
MsbuildProject.EnsureAllReferencesExist(references);
IEnumerable<MsbuildProject> refs = references.Select((r) => MsbuildProject.FromFile(projects, r));
@ -101,30 +96,27 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
}
msbuildProj.ConvertPathsToRelative(ref references);
}
int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
frameworkOption.Value(),
references);
if (numberOfAddedReferences != 0)
int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
frameworkOption.Value(),
references);
if (numberOfAddedReferences != 0)
{
msbuildProj.ProjectRootElement.Save();
}
return 0;
}
catch (GracefulException e)
{
msbuildProj.ProjectRootElement.Save();
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
return 0;
});
try
{
return app.Execute(args);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
return app;
}
private static string GetProjectNotCompatibleWithFrameworksDisplayString(MsbuildProject project, IEnumerable<string> frameworksDisplayStrings)

View file

@ -2,24 +2,6 @@
{
internal class LocalizableStrings
{
public const string Usage = "Usage";
public const string Arguments = "Arguments";
public const string ExtraArgs = "Args";
public const string ListCommandDescription = ".NET List Command";
public const string Commands = "Commands";
public const string CommandDefinition = "Command to be executed on <object>.";
public const string ExtraArgumentsDefinition = "Any extra arguments passed to the command. Use `dotnet list <command> --help` to get help about these arguments.";
public const string HelpDefinition = "Show help";
public const string ObjectDefinition = "The object of the operation. If a project file is not specified, it defaults to the current directory.";
public const string P2PsDefinition = "List project to project (p2p) references from a project";
public const string NetListCommand = ".NET List Command";
}
}

View file

@ -3,38 +3,26 @@
using System;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.List.ProjectToProjectReferences;
namespace Microsoft.DotNet.Tools.List
{
public class ListCommand : DispatchCommand
public class ListCommand : DotNetTopLevelCommandBase
{
protected override string HelpText => $@"{LocalizableStrings.ListCommandDescription}
{LocalizableStrings.Usage}: dotnet list [options] <object> <command> [[--] <arg>...]]
Options:
-h|--help {LocalizableStrings.HelpDefinition}
{LocalizableStrings.Arguments}:
<object> {LocalizableStrings.ObjectDefinition}
<command> {LocalizableStrings.CommandDefinition}
{LocalizableStrings.ExtraArgs}:
{LocalizableStrings.ExtraArgumentsDefinition}
{LocalizableStrings.Commands}:
p2ps {LocalizableStrings.P2PsDefinition}";
protected override Dictionary<string, Func<string[], int>> BuiltInCommands => new Dictionary<string, Func<string[], int>>
{
["p2ps"] = ListProjectToProjectReferencesCommand.Run,
};
protected override string CommandName => "list";
protected override string FullCommandNameLocalized => LocalizableStrings.NetListCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
{
ListProjectToProjectReferencesCommand.CreateApplication,
};
public static int Run(string[] args)
{
var cmd = new ListCommand();
return cmd.Start(args);
var command = new ListCommand();
return command.RunCommand(args);
}
}
}

View file

@ -6,10 +6,6 @@ namespace Microsoft.DotNet.Tools.List.ProjectToProjectReferences
public const string AppDescription = "Command to list project to project (p2p) references";
public const string ProjectArgumentValueName = "PROJECT";
public const string ProjectArgumentDescription = "The project file to modify. If a project file is not specified, it searches the current working directory for an MSBuild file that has a file extension that ends in `proj` and uses that file.";
public const string NoReferencesFound = "There are no {0} references in project {1}.\n{0} is the type of the item being requested (project, package, p2p) and {1} is the object operated on (a project file or a solution file). ";
}
}

View file

@ -4,63 +4,64 @@
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools.List.ProjectToProjectReferences
{
public class ListProjectToProjectReferencesCommand
{
public static int Run(string[] args)
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: false)
{
Name = "dotnet list p2ps",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription
};
CommandLineApplication app = parentApp.Command("p2ps", throwOnUnexpectedArg: false);
app.FullName = LocalizableStrings.AppFullName;
app.Description = LocalizableStrings.AppDescription;
app.HelpOption("-h|--help");
CommandArgument projectArgument = app.Argument($"<{LocalizableStrings.ProjectArgumentValueName}>", LocalizableStrings.ProjectArgumentDescription);
app.OnExecute(() => {
if (string.IsNullOrEmpty(projectArgument.Value))
try
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, $"<{LocalizableStrings.ProjectArgumentValueName}>");
}
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), projectArgument.Value);
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), projectOrDirectory);
var p2ps = msbuildProj.GetProjectToProjectReferences();
if (p2ps.Count() == 0)
{
Reporter.Output.WriteLine(string.Format(LocalizableStrings.NoReferencesFound, CommonLocalizableStrings.P2P, projectOrDirectory));
return 0;
}
Reporter.Output.WriteLine($"{CommonLocalizableStrings.ProjectReferenceOneOrMore}");
Reporter.Output.WriteLine(new string('-', CommonLocalizableStrings.ProjectReferenceOneOrMore.Length));
foreach (var p2p in p2ps)
{
Reporter.Output.WriteLine(p2p.Include);
}
var p2ps = msbuildProj.GetProjectToProjectReferences();
if (p2ps.Count() == 0)
{
Reporter.Output.WriteLine(string.Format(LocalizableStrings.NoReferencesFound, CommonLocalizableStrings.P2P, projectArgument.Value));
return 0;
}
Reporter.Output.WriteLine($"{CommonLocalizableStrings.ProjectReferenceOneOrMore}");
Reporter.Output.WriteLine(new string('-', CommonLocalizableStrings.ProjectReferenceOneOrMore.Length));
foreach (var p2p in p2ps)
catch (GracefulException e)
{
Reporter.Output.WriteLine(p2p.Include);
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
return 0;
});
try
{
return app.Execute(args);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
return app;
}
}
}

View file

@ -3,23 +3,5 @@ namespace Microsoft.DotNet.Tools.Remove
internal class LocalizableStrings
{
public const string NetRemoveCommand = ".NET Remove Command";
public const string Usage = "Usage";
public const string Options = "Options";
public const string HelpDefinition = "Show help information";
public const string Arguments = "Arguments";
public const string ArgumentsObjectDefinition = "The object of the operation. If a project file is not specified, it defaults to the current directory.";
public const string ArgumentsCommandDefinition = "Command to be executed on <object>.";
public const string ArgsDefinition = "Any extra arguments passed to the command. Use `dotnet add <command> --help` to get help about these arguments.";
public const string Commands = "Commands";
public const string CommandP2PDefinition = "Remove project to project (p2p) reference from a project";
}
}

View file

@ -1,47 +1,28 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using System;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
using Microsoft.DotNet.ProjectJsonMigration;
using NuGet.Frameworks;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Remove.ProjectToProjectReference;
namespace Microsoft.DotNet.Tools.Remove
{
public class RemoveCommand : DispatchCommand
public class RemoveCommand : DotNetTopLevelCommandBase
{
protected override string HelpText => $@"{LocalizableStrings.NetRemoveCommand};
{LocalizableStrings.Usage}: dotnet remove [options] <object> <command> [[--] <arg>...]]
{LocalizableStrings.Options}:
-h|--help {LocalizableStrings.HelpDefinition}
{LocalizableStrings.Arguments}:
<object> {LocalizableStrings.ArgumentsObjectDefinition}
<command> {LocalizableStrings.ArgumentsCommandDefinition}
Args:
{LocalizableStrings.ArgsDefinition}
{LocalizableStrings.Commands}:
p2p {LocalizableStrings.CommandP2PDefinition}";
protected override Dictionary<string, Func<string[], int>> BuiltInCommands => new Dictionary<string, Func<string[], int>>
{
["p2p"] = RemoveProjectToProjectReferenceCommand.Run,
};
protected override string CommandName => "remove";
protected override string FullCommandNameLocalized => LocalizableStrings.NetRemoveCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
{
RemoveProjectToProjectReferenceCommand.CreateApplication,
};
public static int Run(string[] args)
{
var cmd = new RemoveCommand();
return cmd.Start(args);
var command = new RemoveCommand();
return command.RunCommand(args);
}
}
}

View file

@ -6,46 +6,10 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference
public const string AppDescription = "Command to remove project to project (p2p) reference";
public const string AppArgumentSeparatorHelpText = "Project to project references to remove";
public const string CmdArgProject = "PROJECT";
public const string CmdArgumentDescription = "The project file to modify. If a project file is not specified, it searches the current working directory for an MSBuild file that has a file extension that ends in `proj` and uses that file.";
public const string CmdFramework = "FRAMEWORK";
public const string AppHelpText = "Project to project references to remove";
public const string CmdFrameworkDescription = "Remove reference only when targetting a specific framework";
public const string ProjectException = "Project";
public const string ReferenceNotFoundInTheProject = "Specified reference {0} does not exist in project {1}.";
public const string ReferenceRemoved = "Reference `{0}` deleted from the project.";
public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to delete. Please run dotnet delete --help for more information.";
public const string ReferenceDeleted = "Reference `{0}` deleted.";
public const string SpecifyAtLeastOneReferenceToDelete = "You must specify at least one reference to delete. Please run dotnet delete --help for more information.";
public const string NetRemoveCommand = ".NET Remove Command";
public const string Usage = "Usage";
public const string Options = "Options";
public const string HelpDefinition = "Show help information";
public const string Arguments = "Arguments";
public const string ArgumentsObjectDefinition = "The object of the operation. If a project file is not specified, it defaults to the current directory.";
public const string ArgumentsCommandDefinition = "Command to be executed on <object>.";
public const string ArgsDefinition = "Any extra arguments passed to the command. Use `dotnet add <command> --help` to get help about these arguments.";
public const string Commands = "Commands";
public const string CommandP2PDefinition = "Remove project to project (p2p) reference from a project";
}
}

View file

@ -4,73 +4,73 @@
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference
{
public class RemoveProjectToProjectReferenceCommand
{
public static int Run(string[] args)
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: false)
{
Name = "dotnet remove p2p",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
AllowArgumentSeparator = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppArgumentSeparatorHelpText
};
CommandLineApplication app = parentApp.Command("p2p", throwOnUnexpectedArg: false);
app.FullName = LocalizableStrings.AppFullName;
app.Description = LocalizableStrings.AppDescription;
app.HandleRemainingArguments = true;
app.ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText;
app.HelpOption("-h|--help");
CommandArgument projectArgument = app.Argument(
$"<{LocalizableStrings.CmdArgProject}>",
LocalizableStrings.CmdArgumentDescription);
CommandOption frameworkOption = app.Option(
$"-f|--framework <{LocalizableStrings.CmdFramework}>",
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
app.OnExecute(() => {
if (string.IsNullOrEmpty(projectArgument.Value))
try
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, $"<{LocalizableStrings.ProjectException}>");
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), projectOrDirectory);
if (app.RemainingArguments.Count == 0)
{
throw new GracefulException(LocalizableStrings.SpecifyAtLeastOneReferenceToRemove);
}
List<string> references = app.RemainingArguments;
int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences(
frameworkOption.Value(),
references);
if (numberOfRemovedReferences != 0)
{
msbuildProj.ProjectRootElement.Save();
}
return 0;
}
var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), projectArgument.Value);
if (app.RemainingArguments.Count == 0)
catch (GracefulException e)
{
throw new GracefulException(LocalizableStrings.SpecifyAtLeastOneReferenceToRemove);
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
List<string> references = app.RemainingArguments;
int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences(
frameworkOption.Value(),
references);
if (numberOfRemovedReferences != 0)
{
msbuildProj.ProjectRootElement.Save();
}
return 0;
});
try
{
return app.Execute(args);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
return app;
}
}
}

View file

@ -80,6 +80,16 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
cmd.StdOut.Should().Contain("Usage");
}
[Fact]
public void WhenTooManyArgumentsArePassedItPrintsError()
{
var cmd = new AddP2PCommand()
.WithProject("one two three")
.Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Unrecognized command or argument");
}
[Theory]
[InlineData("idontexist.csproj")]
[InlineData("ihave?inv@lid/char\\acters")]
@ -569,25 +579,6 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
lib.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
[Fact]
public void WhenPassedReferenceDoesNotExistAndForceSwitchIsPassedItAddsIt()
{
var lib = NewLibWithFrameworks();
const string nonExisting = "IDoNotExist.csproj";
int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new AddP2PCommand()
.WithWorkingDirectory(lib.Path)
.WithProject(lib.CsProjName)
.Execute($"--force \"{nonExisting}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(nonExisting).Should().Be(1);
}
[Fact]
public void WhenPassedReferenceIsUsingSlashesItNormalizesItToBackslashes()
{
@ -598,13 +589,13 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
var cmd = new AddP2PCommand()
.WithWorkingDirectory(lib.Path)
.WithProject(lib.CsProjName)
.Execute($"--force \"{setup.ValidRefCsprojPath.Replace('\\', '/')}\"");
.Execute($"\"{setup.ValidRefCsprojPath.Replace('\\', '/')}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojPath.Replace('/', '\\')).Should().Be(1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojRelPath.Replace('/', '\\')).Should().Be(1);
}
[Fact]
@ -626,25 +617,6 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojRelToOtherProjPath.Replace('/', '\\')).Should().Be(1);
}
[Fact]
public void WhenReferenceIsRelativeAndProjectIsNotInCurrentDirectoryAndForceSwitchIsPassedItDoesNotChangeIt()
{
var setup = Setup();
var proj = new ProjDir(setup.LibDir);
int noCondBefore = proj.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new AddP2PCommand()
.WithWorkingDirectory(setup.TestRoot)
.WithProject(setup.LibCsprojPath)
.Execute($"--force \"{setup.ValidRefCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdErr.Should().BeEmpty();
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojRelPath.Replace('/', '\\')).Should().Be(1);
}
[Fact]
public void ItCanAddReferenceWithConditionOnCompatibleFramework()
{

View file

@ -17,7 +17,7 @@ namespace Microsoft.DotNet.Cli.List.P2P.Tests
const string ConditionFrameworkNet451 = "== 'net451'";
const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0";
const string ConditionFrameworkNetCoreApp10 = "== 'netcoreapp1.0'";
const string UsageText = "Usage: dotnet list p2ps";
const string UsageText = "Usage: dotnet list <PROJECT_OR_SOLUTION> p2ps";
[Theory]
[InlineData("--help")]
@ -29,6 +29,16 @@ namespace Microsoft.DotNet.Cli.List.P2P.Tests
cmd.StdOut.Should().Contain("Usage");
}
[Fact]
public void WhenTooManyArgumentsArePassedItPrintsError()
{
var cmd = new AddP2PCommand()
.WithProject("one two three")
.Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Unrecognized command or argument");
}
[Theory]
[InlineData("idontexist.csproj")]
[InlineData("ihave?inv@lid/char\\acters")]
@ -101,38 +111,38 @@ namespace Microsoft.DotNet.Cli.List.P2P.Tests
[Fact]
public void ItPrintsSingleReference()
{
var lib = NewLib();
string ref1 = "someref.csproj";
AddFakeRef(ref1, lib);
var lib = NewLib("ItPrintsSingleReference", "lib");
string ref1 = NewLib("ItPrintsSingleReference", "ref").CsProjPath;
AddValidRef(ref1, lib);
var cmd = new ListP2PsCommand()
.WithProject(lib.CsProjPath)
.Execute();
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Project reference(s)");
cmd.StdOut.Should().Contain(ref1);
cmd.StdOut.Should().Contain(@"..\ItPrintsSingleReferenceref\ItPrintsSingleReferenceref.csproj");
}
[Fact]
public void ItPrintsMultipleReferences()
{
var lib = NewLib();
string ref1 = "someref.csproj";
string ref2 = @"..\someref2.csproj";
string ref3 = @"..\abc\abc.csproj";
var lib = NewLib("ItPrintsSingleReference", "lib");
string ref1 = NewLib("ItPrintsSingleReference", "ref1").CsProjPath;
string ref2 = NewLib("ItPrintsSingleReference", "ref2").CsProjPath;
string ref3 = NewLib("ItPrintsSingleReference", "ref3").CsProjPath;
AddFakeRef(ref1, lib);
AddFakeRef(ref2, lib);
AddFakeRef(ref3, lib);
AddValidRef(ref1, lib);
AddValidRef(ref2, lib);
AddValidRef(ref3, lib);
var cmd = new ListP2PsCommand()
.WithProject(lib.CsProjPath)
.Execute();
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Project reference(s)");
cmd.StdOut.Should().Contain(ref1);
cmd.StdOut.Should().Contain(ref2);
cmd.StdOut.Should().Contain(ref3);
cmd.StdOut.Should().Contain(@"..\ItPrintsSingleReferenceref1\ItPrintsSingleReferenceref1.csproj");
cmd.StdOut.Should().Contain(@"..\ItPrintsSingleReferenceref2\ItPrintsSingleReferenceref2.csproj");
cmd.StdOut.Should().Contain(@"..\ItPrintsSingleReferenceref3\ItPrintsSingleReferenceref3.csproj");
}
private TestSetup Setup([System.Runtime.CompilerServices.CallerMemberName] string callingMethod = nameof(Setup), string identifier = "")
@ -169,11 +179,11 @@ namespace Microsoft.DotNet.Cli.List.P2P.Tests
return dir;
}
private void AddFakeRef(string path, ProjDir proj)
private void AddValidRef(string path, ProjDir proj)
{
new AddP2PCommand()
.WithProject(proj.CsProjPath)
.Execute($"--force \"{path}\"")
.Execute($"\"{path}\"")
.Should().Pass();
}
}

View file

@ -106,6 +106,16 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
cmd.StdOut.Should().Contain("Usage");
}
[Fact]
public void WhenTooManyArgumentsArePassedItPrintsError()
{
var cmd = new AddP2PCommand()
.WithProject("one two three")
.Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Unrecognized command or argument");
}
[Theory]
[InlineData("idontexist.csproj")]
[InlineData("ihave?inv@lid/char\\acters")]
@ -356,7 +366,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
{
var setup = Setup();
var lib = GetLibRef(setup);
var libref = AddValidRef(setup, lib, "--force");
var libref = AddValidRef(setup, lib);
int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new RemoveP2PCommand()