Remove P2PHelpers and simplify constructors in MsbuildProject

This commit is contained in:
Krzysztof Wicher 2016-11-30 13:43:43 -08:00
parent 26442c8769
commit 1f56e84b7e
5 changed files with 126 additions and 156 deletions

View file

@ -14,22 +14,15 @@ namespace Microsoft.DotNet.Tools
{
internal class MsbuildProject
{
const string ProjectItemElementType = "ProjectReference";
public ProjectRootElement Project { get; private set; }
public string ProjectPath { get; private set; }
public string ProjectDirectory { get; private set; }
private MsbuildProject(ProjectRootElement project, string projectPath, string projectDirectory)
private MsbuildProject(ProjectRootElement project)
{
Project = project;
ProjectPath = projectPath;
ProjectDirectory = PathUtility.EnsureTrailingSlash(projectDirectory);
}
private MsbuildProject(ProjectRootElement project, string projectPath)
{
Project = project;
ProjectPath = projectPath;
ProjectDirectory = PathUtility.EnsureTrailingSlash(new FileInfo(projectPath).DirectoryName);
ProjectDirectory = PathUtility.EnsureTrailingSlash(Project.DirectoryPath);
}
public static MsbuildProject FromFileOrDirectory(string fileOrDirectory)
@ -57,7 +50,7 @@ namespace Microsoft.DotNet.Tools
throw new GracefulException(LocalizableStrings.ProjectIsInvalid, projectPath);
}
return new MsbuildProject(project, Path.GetFullPath(projectPath));
return new MsbuildProject(project);
}
public static MsbuildProject FromDirectory(string projectDirectory)
@ -66,7 +59,6 @@ namespace Microsoft.DotNet.Tools
try
{
dir = new DirectoryInfo(projectDirectory);
projectDirectory = dir.FullName;
}
catch (ArgumentException)
{
@ -102,7 +94,122 @@ namespace Microsoft.DotNet.Tools
throw new GracefulException(LocalizableStrings.FoundInvalidProject, projectFile.FullName);
}
return new MsbuildProject(project, projectFile.FullName, projectDirectory);
return new MsbuildProject(project);
}
public int AddProjectToProjectReferences(string framework, IEnumerable<string> refs)
{
int numberOfAddedReferences = 0;
ProjectItemGroupElement itemGroup = Project.FindUniformOrCreateItemGroupWithCondition(ProjectItemElementType, framework);
foreach (var @ref in refs.Select((r) => NormalizeSlashes(r)))
{
if (Project.HasExistingItemWithCondition(framework, @ref))
{
Reporter.Output.WriteLine(string.Format(LocalizableStrings.ProjectAlreadyHasAreference, @ref));
continue;
}
numberOfAddedReferences++;
itemGroup.AppendChild(Project.CreateItemElement(ProjectItemElementType, @ref));
Reporter.Output.WriteLine(string.Format(LocalizableStrings.ReferenceAddedToTheProject, @ref));
}
return numberOfAddedReferences;
}
public int RemoveProjectToProjectReferences(string framework, IEnumerable<string> refs)
{
int totalNumberOfRemovedReferences = 0;
foreach (var @ref in refs)
{
totalNumberOfRemovedReferences += RemoveProjectToProjectReferenceAlternatives(framework, @ref);
}
return totalNumberOfRemovedReferences;
}
public void ConvertPathsToRelative(ref List<string> references)
{
references = references.Select((r) => PathUtility.GetRelativePath(ProjectDirectory, Path.GetFullPath(r))).ToList();
}
public static string NormalizeSlashes(string path)
{
return path.Replace('/', '\\');
}
public static void EnsureAllReferencesExist(List<string> references)
{
var notExisting = new List<string>();
foreach (var r in references)
{
if (!File.Exists(r))
{
notExisting.Add(r);
}
}
if (notExisting.Count > 0)
{
throw new GracefulException(
string.Join(
Environment.NewLine,
notExisting.Select((r) => string.Format(LocalizableStrings.ReferenceDoesNotExist, r))));
}
}
private int RemoveProjectToProjectReferenceAlternatives(string framework, string reference)
{
int numberOfRemovedRefs = 0;
foreach (var r in GetIncludeAlternativesForRemoval(reference))
{
foreach (var existingItem in 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 <project>
// .../a/d/ref.proj <reference>
// .../a/e/f/ <current working directory>
// Project = /some/path/a/b/p.proj
//
// We do not know the format of passed reference so
// path references 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 IEnumerable<string> GetIncludeAlternativesForRemoval(string reference)
{
// We do not care about duplicates in case when i.e. reference is already full path
var ret = new List<string>();
ret.Add(reference);
string fullPath = Path.GetFullPath(reference);
ret.Add(fullPath);
ret.Add(PathUtility.GetRelativePath(ProjectDirectory, fullPath));
return ret;
}
// There is ProjectRootElement.TryOpen but it does not work as expected

View file

@ -95,7 +95,7 @@ namespace Microsoft.DotNet.Tools
private static string NormalizeIncludeForComparison(string include)
{
return P2PHelpers.NormalizeSlashesForMsbuild(include.ToLower());
return MsbuildProject.NormalizeSlashes(include.ToLower());
}
}
}

View file

@ -1,135 +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.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools
{
internal static class P2PHelpers
{
const string ProjectItemElementType = "ProjectReference";
public static void EnsureAllReferencesExist(List<string> references)
{
var notExisting = new List<string>();
foreach (var r in references)
{
if (!File.Exists(r))
{
notExisting.Add(r);
}
}
if (notExisting.Count > 0)
{
throw new GracefulException(
string.Join(
Environment.NewLine,
notExisting.Select((r) => string.Format(LocalizableStrings.ReferenceDoesNotExist, r))));
}
}
public static void ConvertPathsToRelative(string root, ref List<string> references)
{
root = PathUtility.EnsureTrailingSlash(Path.GetFullPath(root));
references = references.Select((r) => PathUtility.GetRelativePath(root, Path.GetFullPath(r))).ToList();
}
public static string NormalizeSlashesForMsbuild(string path)
{
return path.Replace('/', '\\');
}
public static int AddProjectToProjectReferences(ProjectRootElement root, string framework, IEnumerable<string> refs)
{
int numberOfAddedReferences = 0;
ProjectItemGroupElement itemGroup = root.FindUniformOrCreateItemGroupWithCondition(ProjectItemElementType, framework);
foreach (var @ref in refs.Select((r) => NormalizeSlashesForMsbuild(r)))
{
if (root.HasExistingItemWithCondition(framework, @ref))
{
Reporter.Output.WriteLine(string.Format(LocalizableStrings.ProjectAlreadyHasAreference, @ref));
continue;
}
numberOfAddedReferences++;
itemGroup.AppendChild(root.CreateItemElement(ProjectItemElementType, @ref));
Reporter.Output.WriteLine(string.Format(LocalizableStrings.ReferenceAddedToTheProject, @ref));
}
return numberOfAddedReferences;
}
public static int RemoveProjectToProjectReferences(MsbuildProject msbuildProject, string framework, IEnumerable<string> refs)
{
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 <project>
// .../a/d/ref.proj <reference>
// .../a/e/f/ <current working directory>
// Project = /some/path/a/b/p.proj
//
// We do not know the format of passed reference so
// path references 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<string> 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<string>();
ret.Add(reference);
string fullPath = Path.GetFullPath(reference);
ret.Add(fullPath);
ret.Add(PathUtility.GetRelativePath(msbuildProject.ProjectDirectory, fullPath));
return ret;
}
}
}

View file

@ -56,12 +56,11 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
List<string> references = app.RemainingArguments;
if (!forceOption.HasValue())
{
P2PHelpers.EnsureAllReferencesExist(references);
P2PHelpers.ConvertPathsToRelative(msbuildProj.ProjectDirectory, ref references);
MsbuildProject.EnsureAllReferencesExist(references);
msbuildProj.ConvertPathsToRelative(ref references);
}
int numberOfAddedReferences = P2PHelpers.AddProjectToProjectReferences(
msbuildProj.Project,
int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
frameworkOption.Value(),
references);

View file

@ -50,8 +50,7 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference
List<string> references = app.RemainingArguments;
int numberOfRemovedReferences = P2PHelpers.RemoveProjectToProjectReferences(
msbuildProj,
int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences(
frameworkOption.Value(),
references);