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.
This commit is contained in:
parent
e9706a98cd
commit
bcf13b93cc
26 changed files with 271 additions and 20 deletions
|
@ -0,0 +1,2 @@
|
|||
This directory is intentionally empty.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,2 @@
|
|||
This directory is intentionally empty.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -330,13 +330,14 @@ namespace Microsoft.DotNet.Tools.Common
|
|||
|
||||
public static void EnsureAllPathsExist(
|
||||
IReadOnlyCollection<string> paths,
|
||||
string pathDoesNotExistLocalizedFormatString)
|
||||
string pathDoesNotExistLocalizedFormatString,
|
||||
bool allowDirectories = false)
|
||||
{
|
||||
var notExisting = new List<string>();
|
||||
|
||||
foreach (var p in paths)
|
||||
{
|
||||
if (!File.Exists(p))
|
||||
if (!File.Exists(p) && (!allowDirectories || !Directory.Exists(p)))
|
||||
{
|
||||
notExisting.Add(p);
|
||||
}
|
||||
|
|
|
@ -384,6 +384,9 @@
|
|||
<data name="ProjectAddedToTheSolution" xml:space="preserve">
|
||||
<value>Project `{0}` added to the solution.</value>
|
||||
</data>
|
||||
<data name="ProjectRemovedFromTheSolution" xml:space="preserve">
|
||||
<value>Project `{0}` removed from the solution.</value>
|
||||
</data>
|
||||
<data name="SolutionAlreadyContainsProject" xml:space="preserve">
|
||||
<value>Solution {0} already contains project {1}.</value>
|
||||
</data>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Při spuštění příkazu neprovede implicitní obnovení.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Führt beim Ausführen des Befehls keine implizite Wiederherstellung durch.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">No realiza una restauración implícita al ejecutar el comando.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Ne fait pas de restauration implicite durant l'exécution de la commande.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Non esegue un ripristino implicito durante l'esecuzione del comando.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">コマンドを実行するときに暗黙的復元を行いません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">명령을 실행할 때 암시적 복원을 수행하지 않습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Nie wykonuje niejawnego przywracania podczas wykonywania polecenia.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Não faz uma restauração implícita ao executar o comando.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Не выполняет неявное восстановление при выполнении команды.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">Komut yürütülürken örtük geri yükleme gerçekleştirmez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">请勿在执行命令时进行隐式还原。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -674,6 +674,11 @@
|
|||
<target state="translated">執行此命令時,請勿進行隱含還原。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ProjectRemovedFromTheSolution">
|
||||
<source>Project `{0}` removed from the solution.</source>
|
||||
<target state="new">Project `{0}` removed from the solution.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue