From e9706a98cd9ed8de052312e12f4ef16f9069bf28 Mon Sep 17 00:00:00 2001 From: Nick Guerrera Date: Thu, 7 Dec 2017 14:31:07 -0800 Subject: [PATCH 1/3] Treat xlf as text --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 50950c656..4422d1501 100644 --- a/.gitattributes +++ b/.gitattributes @@ -51,4 +51,5 @@ *.vbproj text=auto *.fsproj text=auto *.dbproj text=auto +*.xlf text=auto *.sln text=auto eol=crlf \ No newline at end of file From bcf13b93ccd98abc9110086241fd67b1f857044b Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 7 Dec 2017 17:22:29 -0800 Subject: [PATCH 2/3] Add support for accepting directories to sln add and remove commands. This commit adds support for specifying directories containing a single project to both the `sln add` and `sln remove` commands. Additionally, the output from `sln remove` has been improved to not mention "project references". Fixes issue #7343. --- .../TestAppWithSlnAndCsprojFiles/Empty/README | 2 + .../Multiple/First.csproj | 7 ++ .../Multiple/Second.csproj | 7 ++ .../Empty/README | 2 + .../Multiple/First.csproj | 7 ++ .../Multiple/Second.csproj | 7 ++ src/Microsoft.DotNet.Cli.Utils/PathUtility.cs | 5 +- src/dotnet/CommonLocalizableStrings.resx | 3 + src/dotnet/SlnFileExtensions.cs | 4 +- src/dotnet/commands/dotnet-sln/add/Program.cs | 11 ++- .../commands/dotnet-sln/remove/Program.cs | 15 ++-- .../xlf/CommonLocalizableStrings.cs.xlf | 5 ++ .../xlf/CommonLocalizableStrings.de.xlf | 5 ++ .../xlf/CommonLocalizableStrings.es.xlf | 5 ++ .../xlf/CommonLocalizableStrings.fr.xlf | 5 ++ .../xlf/CommonLocalizableStrings.it.xlf | 5 ++ .../xlf/CommonLocalizableStrings.ja.xlf | 5 ++ .../xlf/CommonLocalizableStrings.ko.xlf | 5 ++ .../xlf/CommonLocalizableStrings.pl.xlf | 5 ++ .../xlf/CommonLocalizableStrings.pt-BR.xlf | 5 ++ .../xlf/CommonLocalizableStrings.ru.xlf | 5 ++ .../xlf/CommonLocalizableStrings.tr.xlf | 5 ++ .../xlf/CommonLocalizableStrings.zh-Hans.xlf | 5 ++ .../xlf/CommonLocalizableStrings.zh-Hant.xlf | 5 ++ .../dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs | 77 +++++++++++++++++- .../GivenDotnetSlnRemove.cs | 79 +++++++++++++++++-- 26 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Empty/README create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/First.csproj create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/Second.csproj create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Empty/README create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/First.csproj create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/Second.csproj diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Empty/README b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Empty/README new file mode 100644 index 000000000..439cfe9c7 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Empty/README @@ -0,0 +1,2 @@ +This directory is intentionally empty. + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/First.csproj b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/First.csproj new file mode 100644 index 000000000..9f5c4f4ab --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/First.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/Second.csproj b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/Second.csproj new file mode 100644 index 000000000..9f5c4f4ab --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/Multiple/Second.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Empty/README b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Empty/README new file mode 100644 index 000000000..439cfe9c7 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Empty/README @@ -0,0 +1,2 @@ +This directory is intentionally empty. + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/First.csproj b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/First.csproj new file mode 100644 index 000000000..9f5c4f4ab --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/First.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/Second.csproj b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/Second.csproj new file mode 100644 index 000000000..9f5c4f4ab --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndCsprojToRemove/Multiple/Second.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/src/Microsoft.DotNet.Cli.Utils/PathUtility.cs b/src/Microsoft.DotNet.Cli.Utils/PathUtility.cs index e0ad71840..32620e0d5 100644 --- a/src/Microsoft.DotNet.Cli.Utils/PathUtility.cs +++ b/src/Microsoft.DotNet.Cli.Utils/PathUtility.cs @@ -330,13 +330,14 @@ namespace Microsoft.DotNet.Tools.Common public static void EnsureAllPathsExist( IReadOnlyCollection paths, - string pathDoesNotExistLocalizedFormatString) + string pathDoesNotExistLocalizedFormatString, + bool allowDirectories = false) { var notExisting = new List(); foreach (var p in paths) { - if (!File.Exists(p)) + if (!File.Exists(p) && (!allowDirectories || !Directory.Exists(p))) { notExisting.Add(p); } diff --git a/src/dotnet/CommonLocalizableStrings.resx b/src/dotnet/CommonLocalizableStrings.resx index d165ca59e..3733b73f5 100644 --- a/src/dotnet/CommonLocalizableStrings.resx +++ b/src/dotnet/CommonLocalizableStrings.resx @@ -384,6 +384,9 @@ Project `{0}` added to the solution. + + Project `{0}` removed from the solution. + Solution {0} already contains project {1}. diff --git a/src/dotnet/SlnFileExtensions.cs b/src/dotnet/SlnFileExtensions.cs index 789318476..84ce82b0d 100644 --- a/src/dotnet/SlnFileExtensions.cs +++ b/src/dotnet/SlnFileExtensions.cs @@ -221,7 +221,7 @@ namespace Microsoft.DotNet.Tools.Common if (projectsToRemove.Count == 0) { Reporter.Output.WriteLine(string.Format( - CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, + CommonLocalizableStrings.ProjectNotFoundInTheSolution, projectPath)); } else @@ -244,7 +244,7 @@ namespace Microsoft.DotNet.Tools.Common slnFile.Projects.Remove(slnProject); Reporter.Output.WriteLine( - string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, slnProject.FilePath)); + string.Format(CommonLocalizableStrings.ProjectRemovedFromTheSolution, slnProject.FilePath)); } foreach (var project in slnFile.Projects) diff --git a/src/dotnet/commands/dotnet-sln/add/Program.cs b/src/dotnet/commands/dotnet-sln/add/Program.cs index 9ce0a7d09..d49398ba1 100644 --- a/src/dotnet/commands/dotnet-sln/add/Program.cs +++ b/src/dotnet/commands/dotnet-sln/add/Program.cs @@ -40,11 +40,14 @@ namespace Microsoft.DotNet.Tools.Sln.Add throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd); } - PathUtility.EnsureAllPathsExist(_appliedCommand.Arguments, CommonLocalizableStrings.ProjectDoesNotExist); + PathUtility.EnsureAllPathsExist(_appliedCommand.Arguments, CommonLocalizableStrings.CouldNotFindProjectOrDirectory, true); - var fullProjectPaths = _appliedCommand.Arguments - .Select(Path.GetFullPath) - .ToList(); + var fullProjectPaths = _appliedCommand.Arguments.Select(p => { + var fullPath = Path.GetFullPath(p); + return Directory.Exists(fullPath) ? + MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : + fullPath; + }).ToList(); var preAddProjectCount = slnFile.Projects.Count; diff --git a/src/dotnet/commands/dotnet-sln/remove/Program.cs b/src/dotnet/commands/dotnet-sln/remove/Program.cs index 973294c6e..4952b7c24 100644 --- a/src/dotnet/commands/dotnet-sln/remove/Program.cs +++ b/src/dotnet/commands/dotnet-sln/remove/Program.cs @@ -40,11 +40,16 @@ namespace Microsoft.DotNet.Tools.Sln.Remove { SlnFile slnFile = SlnFileFactory.CreateFromFileOrDirectory(_fileOrDirectory); - var relativeProjectPaths = _appliedCommand.Arguments.Select(p => - Path.GetRelativePath( - PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory), - Path.GetFullPath(p))) - .ToList(); + var baseDirectory = PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory); + var relativeProjectPaths = _appliedCommand.Arguments.Select(p => { + var fullPath = Path.GetFullPath(p); + return Path.GetRelativePath( + baseDirectory, + Directory.Exists(fullPath) ? + MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : + fullPath + ); + }); bool slnChanged = false; foreach (var path in relativeProjectPaths) diff --git a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf index 56caa7e29..9b36d6610 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf @@ -674,6 +674,11 @@ Při spuštění příkazu neprovede implicitní obnovení. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf index b2c179985..d530378af 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf @@ -674,6 +674,11 @@ Führt beim Ausführen des Befehls keine implizite Wiederherstellung durch. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf index f1a9c6402..65dc74bad 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf @@ -674,6 +674,11 @@ No realiza una restauración implícita al ejecutar el comando. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf index b33c6611e..09daf3906 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf @@ -674,6 +674,11 @@ Ne fait pas de restauration implicite durant l'exécution de la commande. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf index b1714f3e5..d6f24164c 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf @@ -674,6 +674,11 @@ Non esegue un ripristino implicito durante l'esecuzione del comando. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf index f95dbf451..ded00eee1 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf @@ -674,6 +674,11 @@ コマンドを実行するときに暗黙的復元を行いません。 + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf index 029bc8c0c..8e3256909 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf @@ -674,6 +674,11 @@ 명령을 실행할 때 암시적 복원을 수행하지 않습니다. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf index 1db654dd8..9f6b7e9cf 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf @@ -674,6 +674,11 @@ Nie wykonuje niejawnego przywracania podczas wykonywania polecenia. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf index 89cc1e55d..85b8cfa1b 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf @@ -674,6 +674,11 @@ Não faz uma restauração implícita ao executar o comando. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf index a63e439a0..b89bef3de 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf @@ -674,6 +674,11 @@ Не выполняет неявное восстановление при выполнении команды. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf index 6584fc018..552aa93f6 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf @@ -674,6 +674,11 @@ Komut yürütülürken örtük geri yükleme gerçekleştirmez. + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf index 2fdb31f54..9c68c45f7 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf @@ -674,6 +674,11 @@ 请勿在执行命令时进行隐式还原。 + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf index 2e0845e40..e22c55fa5 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf @@ -674,6 +674,11 @@ 執行此命令時,請勿進行隱含還原。 + + Project `{0}` removed from the solution. + Project `{0}` removed from the solution. + + \ No newline at end of file diff --git a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs index 3d245115f..13fe61606 100644 --- a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs +++ b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs @@ -359,6 +359,81 @@ EndGlobal .Should().BeVisuallyEquivalentTo(expectedSlnContents); } + [Fact] + public void WhenDirectoryContainingProjectIsGivenProjectIsAdded() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojFiles") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput("sln add Lib"); + cmd.Should().Pass(); + + var slnPath = Path.Combine(projectDirectory, "App.sln"); + var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingLibProj); + File.ReadAllText(slnPath) + .Should().BeVisuallyEquivalentTo(expectedSlnContents); + } + + [Fact] + public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojFiles") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var slnFullPath = Path.Combine(projectDirectory, "App.sln"); + var contentBefore = File.ReadAllText(slnFullPath); + var directoryToAdd = "Empty"; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln add {directoryToAdd}"); + cmd.Should().Fail(); + cmd.StdErr.Should().Be( + string.Format( + CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, + Path.Combine(projectDirectory, directoryToAdd))); + + File.ReadAllText(slnFullPath) + .Should().BeVisuallyEquivalentTo(contentBefore); + } + + [Fact] + public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojFiles") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var slnFullPath = Path.Combine(projectDirectory, "App.sln"); + var contentBefore = File.ReadAllText(slnFullPath); + var directoryToAdd = "Multiple"; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln add {directoryToAdd}"); + cmd.Should().Fail(); + cmd.StdErr.Should().Be( + string.Format( + CommonLocalizableStrings.MoreThanOneProjectInDirectory, + Path.Combine(projectDirectory, directoryToAdd))); + + File.ReadAllText(slnFullPath) + .Should().BeVisuallyEquivalentTo(contentBefore); + } + [Fact] public void WhenProjectDirectoryIsAddedSolutionFoldersAreNotCreated() { @@ -597,7 +672,7 @@ EndGlobal .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"sln App.sln add {projectToAdd} idonotexist.csproj"); cmd.Should().Fail(); - cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.ProjectDoesNotExist, "idonotexist.csproj")); + cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "idonotexist.csproj")); File.ReadAllText(slnFullPath) .Should().BeVisuallyEquivalentTo(contentBefore); diff --git a/test/dotnet-sln-remove.Tests/GivenDotnetSlnRemove.cs b/test/dotnet-sln-remove.Tests/GivenDotnetSlnRemove.cs index 0b0b6a7e2..50c6f00e5 100644 --- a/test/dotnet-sln-remove.Tests/GivenDotnetSlnRemove.cs +++ b/test/dotnet-sln-remove.Tests/GivenDotnetSlnRemove.cs @@ -367,7 +367,7 @@ EndGlobal .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln remove referenceDoesNotExistInSln.csproj"); cmd.Should().Pass(); - cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "referenceDoesNotExistInSln.csproj")); + cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectNotFoundInTheSolution, "referenceDoesNotExistInSln.csproj")); File.ReadAllText(solutionPath) .Should().BeVisuallyEquivalentTo(contentBefore); } @@ -391,7 +391,7 @@ EndGlobal .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"sln remove {projectToRemove}"); cmd.Should().Pass(); - cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove)); + cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectRemovedFromTheSolution, projectToRemove)); slnFile = SlnFile.Read(solutionPath); slnFile.Projects.Count.Should().Be(1); @@ -418,7 +418,7 @@ EndGlobal .ExecuteWithCapturedOutput($"sln remove {projectToRemove}"); cmd.Should().Pass(); - string outputText = string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove); + string outputText = string.Format(CommonLocalizableStrings.ProjectRemovedFromTheSolution, projectToRemove); outputText += Environment.NewLine + outputText; cmd.StdOut.Should().BeVisuallyEquivalentTo(outputText); @@ -447,9 +447,9 @@ EndGlobal .ExecuteWithCapturedOutput($"sln remove idontexist.csproj {projectToRemove} idontexisteither.csproj"); cmd.Should().Pass(); - string outputText = $@"{string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "idontexist.csproj")} -{string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove)} -{string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "idontexisteither.csproj")}"; + string outputText = $@"{string.Format(CommonLocalizableStrings.ProjectNotFoundInTheSolution, "idontexist.csproj")} +{string.Format(CommonLocalizableStrings.ProjectRemovedFromTheSolution, projectToRemove)} +{string.Format(CommonLocalizableStrings.ProjectNotFoundInTheSolution, "idontexisteither.csproj")}"; cmd.StdOut.Should().BeVisuallyEquivalentTo(outputText); @@ -482,6 +482,73 @@ EndGlobal .Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemove); } + [Fact] + public void WhenDirectoryContainingProjectIsGivenProjectIsRemoved() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojToRemove") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var solutionPath = Path.Combine(projectDirectory, "App.sln"); + SlnFile slnFile = SlnFile.Read(solutionPath); + slnFile.Projects.Count.Should().Be(2); + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput("sln remove Lib"); + cmd.Should().Pass(); + + File.ReadAllText(solutionPath) + .Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemove); + } + + [Fact] + public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojToRemove") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + var directoryToRemove = "Empty"; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln remove {directoryToRemove}"); + cmd.Should().Fail(); + cmd.StdErr.Should().Be( + string.Format( + CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, + Path.Combine(projectDirectory, directoryToRemove))); + cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + } + + [Fact] + public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojToRemove") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + var directoryToRemove = "Multiple"; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln remove {directoryToRemove}"); + cmd.Should().Fail(); + cmd.StdErr.Should().Be( + string.Format( + CommonLocalizableStrings.MoreThanOneProjectInDirectory, + Path.Combine(projectDirectory, directoryToRemove))); + cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + } + [Fact] public void WhenReferenceIsRemovedSlnBuilds() { From 1ddf5c87c7add3e1b9b9dcc81c2dc4aee536ed4d Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 7 Dec 2017 17:19:51 -0800 Subject: [PATCH 3/3] Add support for accepting directories to add and remove reference commands. This commit adds support for specifying directories containing a single project to both the `add reference` and `remove reference` commands. Fixes issue #7343. --- .../DotnetAddP2PProjects/Empty/README | 2 + src/dotnet/CommonLocalizableStrings.resx | 3 -- .../dotnet-add-reference/Program.cs | 11 ++-- .../dotnet-remove-reference/Program.cs | 15 +++++- .../xlf/CommonLocalizableStrings.cs.xlf | 5 -- .../xlf/CommonLocalizableStrings.de.xlf | 5 -- .../xlf/CommonLocalizableStrings.es.xlf | 5 -- .../xlf/CommonLocalizableStrings.fr.xlf | 5 -- .../xlf/CommonLocalizableStrings.it.xlf | 5 -- .../xlf/CommonLocalizableStrings.ja.xlf | 5 -- .../xlf/CommonLocalizableStrings.ko.xlf | 5 -- .../xlf/CommonLocalizableStrings.pl.xlf | 5 -- .../xlf/CommonLocalizableStrings.pt-BR.xlf | 5 -- .../xlf/CommonLocalizableStrings.ru.xlf | 5 -- .../xlf/CommonLocalizableStrings.tr.xlf | 5 -- .../xlf/CommonLocalizableStrings.zh-Hans.xlf | 5 -- .../xlf/CommonLocalizableStrings.zh-Hant.xlf | 5 -- .../GivenDotnetAddReference.cs | 54 ++++++++++++++++++- .../GivenDotnetRemoveP2P.cs | 51 ++++++++++++++++++ 19 files changed, 125 insertions(+), 76 deletions(-) create mode 100644 TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Empty/README diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Empty/README b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Empty/README new file mode 100644 index 000000000..439cfe9c7 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Empty/README @@ -0,0 +1,2 @@ +This directory is intentionally empty. + diff --git a/src/dotnet/CommonLocalizableStrings.resx b/src/dotnet/CommonLocalizableStrings.resx index 3733b73f5..e51b2a473 100644 --- a/src/dotnet/CommonLocalizableStrings.resx +++ b/src/dotnet/CommonLocalizableStrings.resx @@ -345,9 +345,6 @@ Specified solution file {0} does not exist, or there is no solution file in the directory. - - Reference {0} does not exist. - Reference `{0}` is invalid. diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-reference/Program.cs b/src/dotnet/commands/dotnet-add/dotnet-add-reference/Program.cs index e79ebfc0c..31d1f716f 100644 --- a/src/dotnet/commands/dotnet-add/dotnet-add-reference/Program.cs +++ b/src/dotnet/commands/dotnet-add/dotnet-add-reference/Program.cs @@ -45,9 +45,9 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference var frameworkString = _appliedCommand.ValueOrDefault("framework"); - PathUtility.EnsureAllPathsExist(_appliedCommand.Arguments, CommonLocalizableStrings.ReferenceDoesNotExist); + PathUtility.EnsureAllPathsExist(_appliedCommand.Arguments, CommonLocalizableStrings.CouldNotFindProjectOrDirectory, true); List refs = _appliedCommand.Arguments - .Select((r) => MsbuildProject.FromFile(projects, r)) + .Select((r) => MsbuildProject.FromFileOrDirectory(projects, r)) .ToList(); if (frameworkString == null) @@ -90,9 +90,10 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference } } - var relativePathReferences = _appliedCommand.Arguments.Select((r) => - Path.GetRelativePath(msbuildProj.ProjectDirectory, Path.GetFullPath(r))) - .ToList(); + var relativePathReferences = refs.Select((r) => + Path.GetRelativePath( + msbuildProj.ProjectDirectory, + r.ProjectRootElement.FullPath)).ToList(); int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences( frameworkString, diff --git a/src/dotnet/commands/dotnet-remove/dotnet-remove-reference/Program.cs b/src/dotnet/commands/dotnet-remove/dotnet-remove-reference/Program.cs index e813dda3a..4f8fabb61 100644 --- a/src/dotnet/commands/dotnet-remove/dotnet-remove-reference/Program.cs +++ b/src/dotnet/commands/dotnet-remove/dotnet-remove-reference/Program.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.IO; using System.Linq; using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli; @@ -42,10 +43,22 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference public override int Execute() { var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), _fileOrDirectory); + var references = _appliedCommand.Arguments.Select(p => { + var fullPath = Path.GetFullPath(p); + if (!Directory.Exists(fullPath)) + { + return p; + } + + return Path.GetRelativePath( + msbuildProj.ProjectRootElement.FullPath, + MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName + ); + }); int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences( _appliedCommand.ValueOrDefault("framework"), - _appliedCommand.Arguments); + references); if (numberOfRemovedReferences != 0) { diff --git a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf index 9b36d6610..ccc70ef3d 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.cs.xlf @@ -97,11 +97,6 @@ Aplikace - - Reference {0} does not exist. - Odkaz na {0} neexistuje. - - Reference `{0}` added to the project. Odkaz na {0} byl přidán do projektu. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf index d530378af..ec92f7055 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.de.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.de.xlf @@ -97,11 +97,6 @@ Anwendung - - Reference {0} does not exist. - Der Verweis "{0}" ist nicht vorhanden. - - Reference `{0}` added to the project. Der Verweis "{0}" wurde dem Projekt hinzugefügt. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf index 65dc74bad..e00b791e1 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.es.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.es.xlf @@ -97,11 +97,6 @@ Aplicación - - Reference {0} does not exist. - La referencia {0} no existe. - - Reference `{0}` added to the project. Se ha agregado la referencia "{0}" al proyecto. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf index 09daf3906..cd9ba1cee 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.fr.xlf @@ -97,11 +97,6 @@ Application - - Reference {0} does not exist. - La référence {0} n'existe pas. - - Reference `{0}` added to the project. Référence '{0}' ajoutée au projet. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf index d6f24164c..5ab33a95b 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.it.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.it.xlf @@ -97,11 +97,6 @@ Applicazione - - Reference {0} does not exist. - Il riferimento {0} non esiste. - - Reference `{0}` added to the project. Il riferimento `{0}` è stato aggiunto al progetto. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf index ded00eee1..4d025f02b 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ja.xlf @@ -97,11 +97,6 @@ アプリケーション - - Reference {0} does not exist. - 参照 {0} は存在しません。 - - Reference `{0}` added to the project. 参照 `{0}` がプロジェクトに追加されました。 diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf index 8e3256909..f9f9a96c0 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ko.xlf @@ -97,11 +97,6 @@ 응용 프로그램 - - Reference {0} does not exist. - {0} 참조가 없습니다. - - Reference `{0}` added to the project. 프로젝트에 '{0}' 참조가 추가되었습니다. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf index 9f6b7e9cf..ca40ba7d5 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pl.xlf @@ -97,11 +97,6 @@ Aplikacja - - Reference {0} does not exist. - Odwołanie {0} nie istnieje. - - Reference `{0}` added to the project. Do projektu zostało dodane odwołanie „{0}”. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf index 85b8cfa1b..1fe5abd21 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.pt-BR.xlf @@ -97,11 +97,6 @@ Aplicativo - - Reference {0} does not exist. - A referência {0} não existe. - - Reference `{0}` added to the project. A referência ‘{0}’ foi adicionada ao projeto. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf index b89bef3de..5f250b68d 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.ru.xlf @@ -97,11 +97,6 @@ Приложение - - Reference {0} does not exist. - Ссылка {0} не существует. - - Reference `{0}` added to the project. Ссылка "{0}" добавлена в проект. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf index 552aa93f6..7ddbad9b0 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.tr.xlf @@ -97,11 +97,6 @@ Uygulama - - Reference {0} does not exist. - {0} başvurusu yok. - - Reference `{0}` added to the project. `{0}` başvurusu projeye eklendi. diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf index 9c68c45f7..c3bf2ce59 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hans.xlf @@ -97,11 +97,6 @@ 应用程序 - - Reference {0} does not exist. - 引用 {0} 不存在。 - - Reference `{0}` added to the project. 已将引用“{0}”添加到项目。 diff --git a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf index e22c55fa5..4a6eedb67 100644 --- a/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf +++ b/src/dotnet/xlf/CommonLocalizableStrings.zh-Hant.xlf @@ -97,11 +97,6 @@ 應用程式 - - Reference {0} does not exist. - 參考 {0} 不存在。 - - Reference `{0}` added to the project. 參考 `{0}` 已新增至專案。 diff --git a/test/dotnet-add-reference.Tests/GivenDotnetAddReference.cs b/test/dotnet-add-reference.Tests/GivenDotnetAddReference.cs index ba37b1e73..75269124f 100644 --- a/test/dotnet-add-reference.Tests/GivenDotnetAddReference.cs +++ b/test/dotnet-add-reference.Tests/GivenDotnetAddReference.cs @@ -559,7 +559,7 @@ Commands: .WithProject(lib.CsProjName) .Execute("\"IDoNotExist.csproj\""); cmd.Should().Fail(); - cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.ReferenceDoesNotExist, "IDoNotExist.csproj")); + cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "IDoNotExist.csproj")); lib.CsProjContent().Should().BeEquivalentTo(contentBefore); } @@ -575,7 +575,7 @@ Commands: .WithProject(lib.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\" \"IDoNotExist.csproj\""); cmd.Should().Fail(); - cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.ReferenceDoesNotExist, "IDoNotExist.csproj")); + cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "IDoNotExist.csproj")); lib.CsProjContent().Should().BeEquivalentTo(contentBefore); } @@ -693,5 +693,55 @@ Commands: cmd.StdErr.Should().MatchRegex(" - net45"); net45lib.CsProjContent().Should().BeEquivalentTo(csProjContent); } + + [Fact] + public void WhenDirectoryContainingProjectIsGivenReferenceIsAdded() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + + var result = new AddReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute($"\"{Path.GetDirectoryName(setup.ValidRefCsprojPath)}\""); + + result.Should().Pass(); + result.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); + result.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + + var reference = "Empty"; + var result = new AddReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute(reference); + + result.Should().Fail(); + result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, reference)); + } + + [Fact] + public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + + var reference = "MoreThanOne"; + var result = new AddReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute(reference); + + result.Should().Fail(); + result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneProjectInDirectory, reference)); + } } } diff --git a/test/dotnet-remove-reference.Tests/GivenDotnetRemoveP2P.cs b/test/dotnet-remove-reference.Tests/GivenDotnetRemoveP2P.cs index 65da417b2..b557ff5df 100644 --- a/test/dotnet-remove-reference.Tests/GivenDotnetRemoveP2P.cs +++ b/test/dotnet-remove-reference.Tests/GivenDotnetRemoveP2P.cs @@ -506,5 +506,56 @@ Commands: csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1); csproj.NumberOfProjectReferencesWithIncludeContaining(validref.Name).Should().Be(0); } + + [Fact] + public void WhenDirectoryContainingProjectIsGivenReferenceIsRemoved() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + var libref = AddLibRef(setup, lib); + + var result = new RemoveReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute($"\"{libref.CsProjPath}\""); + + result.Should().Pass(); + result.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, Path.Combine("Lib", setup.LibCsprojName))); + result.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + + var reference = "Empty"; + var result = new RemoveReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute(reference); + + result.Should().Fail(); + result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, Path.Combine(setup.TestRoot, reference))); + } + + [Fact] + public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation() + { + var setup = Setup(); + var lib = NewLibWithFrameworks(dir: setup.TestRoot); + + var reference = "MoreThanOne"; + var result = new RemoveReferenceCommand() + .WithWorkingDirectory(setup.TestRoot) + .WithProject(lib.CsProjPath) + .Execute(reference); + + result.Should().Fail(); + result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); + result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneProjectInDirectory, Path.Combine(setup.TestRoot, reference))); + } } }