From 78d95b423e28e1d5938a8e44faa2aee1e4254853 Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Tue, 29 Nov 2016 14:00:44 -0800 Subject: [PATCH] dotnet-remove-p2p implementation complete - no tests --- src/dotnet/LocalizableStrings.cs | 2 + src/dotnet/P2PHelpers.cs | 67 +++++++++++++++++-- src/dotnet/commands/dotnet-add-p2p/Program.cs | 2 +- .../commands/dotnet-remove-p2p/Program.cs | 4 +- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/dotnet/LocalizableStrings.cs b/src/dotnet/LocalizableStrings.cs index 3019825be..5a7a4f6a8 100644 --- a/src/dotnet/LocalizableStrings.cs +++ b/src/dotnet/LocalizableStrings.cs @@ -24,5 +24,7 @@ namespace Microsoft.DotNet.Tools public const string ReferenceDoesNotExist = "Reference `{0}` does not exist."; public const string SpecifyAtLeastOneReferenceToAdd = "You must specify at least one reference to add."; public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to remove."; + public const string ProjectReferenceCouldNotBeFound = "Project reference `{0}` could not be found."; + public const string ProjectReferenceRemoved = "Project reference `{0}` removed."; } } diff --git a/src/dotnet/P2PHelpers.cs b/src/dotnet/P2PHelpers.cs index d35bdfb76..dbb2eff8c 100644 --- a/src/dotnet/P2PHelpers.cs +++ b/src/dotnet/P2PHelpers.cs @@ -14,6 +14,8 @@ namespace Microsoft.DotNet.Tools { internal static class P2PHelpers { + const string ProjectItemElementType = "ProjectReference"; + public static void EnsureAllReferencesExist(List references) { var notExisting = new List(); @@ -45,10 +47,9 @@ namespace Microsoft.DotNet.Tools return path.Replace('/', '\\'); } - public static int AddProjectToProjectReference(ProjectRootElement root, string framework, IEnumerable refs) + public static int AddProjectToProjectReferences(ProjectRootElement root, string framework, IEnumerable refs) { int numberOfAddedReferences = 0; - const string ProjectItemElementType = "ProjectReference"; ProjectItemGroupElement itemGroup = root.FindUniformOrCreateItemGroupWithCondition(ProjectItemElementType, framework); foreach (var @ref in refs.Select((r) => NormalizeSlashesForMsbuild(r))) @@ -68,9 +69,67 @@ namespace Microsoft.DotNet.Tools return numberOfAddedReferences; } - public static int RemoveProjectToProjectReference(ProjectRootElement root, string framework, IEnumerable refs) + public static int RemoveProjectToProjectReferences(MsbuildProject msbuildProject, string framework, IEnumerable refs) { - throw new NotImplementedException(); + int totalNumberOfRemovedReferences = 0; + + foreach (var @ref in refs) + { + totalNumberOfRemovedReferences += RemoveProjectToProjectReferenceAlternatives(msbuildProject, framework, @ref); + } + + return totalNumberOfRemovedReferences; + } + + private static int RemoveProjectToProjectReferenceAlternatives(MsbuildProject msbuildProject, string framework, string reference) + { + int numberOfRemovedRefs = 0; + foreach (var r in GetIncludeAlternativesForRemoval(msbuildProject, reference)) + { + foreach (var existingItem in msbuildProject.Project.FindExistingItemsWithCondition(framework, r)) + { + ProjectElementContainer itemGroup = existingItem.Parent; + itemGroup.RemoveChild(existingItem); + if (itemGroup.Children.Count == 0) + { + itemGroup.Parent.RemoveChild(itemGroup); + } + + numberOfRemovedRefs++; + Reporter.Output.WriteLine(string.Format(LocalizableStrings.ProjectReferenceRemoved, r)); + } + } + + if (numberOfRemovedRefs == 0) + { + Reporter.Output.WriteLine(string.Format(LocalizableStrings.ProjectReferenceCouldNotBeFound, reference)); + } + + return numberOfRemovedRefs; + } + + // Easiest way to explain rationale for this function is on the example. Let's consider following directory structure: + // .../a/b/p.proj + // .../a/d/ref.proj + // .../a/e/f/ + // Project = /some/path/a/b/p.proj + // + // We do not know the format of passed reference so + // directories to consider for removal are following: + // - full path to ref.proj [/some/path/a/d/ref.proj] + // - string which is passed as reference is relative to project [../d/ref.proj] + // - string which is passed as reference is relative to current dir [../../d/ref.proj] + private static IEnumerable GetIncludeAlternativesForRemoval(MsbuildProject msbuildProject, string reference) + { + // We do not care about duplicates in case when i.e. reference is already full path + var ret = new List(); + ret.Add(reference); + + string fullPath = Path.GetFullPath(reference); + ret.Add(fullPath); + ret.Add(PathUtility.GetRelativePath(msbuildProject.ProjectDirectory, fullPath)); + + return ret; } } } diff --git a/src/dotnet/commands/dotnet-add-p2p/Program.cs b/src/dotnet/commands/dotnet-add-p2p/Program.cs index 8f4c88f9d..5d07f0ba7 100644 --- a/src/dotnet/commands/dotnet-add-p2p/Program.cs +++ b/src/dotnet/commands/dotnet-add-p2p/Program.cs @@ -60,7 +60,7 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference P2PHelpers.ConvertPathsToRelative(msbuildProj.ProjectDirectory, ref references); } - int numberOfAddedReferences = P2PHelpers.AddProjectToProjectReference( + int numberOfAddedReferences = P2PHelpers.AddProjectToProjectReferences( msbuildProj.Project, frameworkOption.Value(), references); diff --git a/src/dotnet/commands/dotnet-remove-p2p/Program.cs b/src/dotnet/commands/dotnet-remove-p2p/Program.cs index 628be3780..561eb12d9 100644 --- a/src/dotnet/commands/dotnet-remove-p2p/Program.cs +++ b/src/dotnet/commands/dotnet-remove-p2p/Program.cs @@ -50,8 +50,8 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference List references = app.RemainingArguments; - int numberOfRemovedReferences = P2PHelpers.RemoveProjectToProjectReference( - msbuildProj.Project, + int numberOfRemovedReferences = P2PHelpers.RemoveProjectToProjectReferences( + msbuildProj, frameworkOption.Value(), references);