diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Broken/Broken.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Broken/Broken.csproj
new file mode 100644
index 000000000..3203e50a0
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Broken/Broken.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.cs
new file mode 100644
index 000000000..4c665f47a
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.cs
@@ -0,0 +1,3 @@
+public class EmptyItemGroup
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.csproj
similarity index 73%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.csproj
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.csproj
index 3466eb925..3db580ead 100644
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.csproj
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/EmptyItemGroup/EmptyItemGroup.csproj
@@ -18,12 +18,8 @@
1.0.1
-
- $(DefineConstants);NETCOREAPP1_0
-
-
- $(DefineConstants);NET451
-
-
+
+
+
-
\ No newline at end of file
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.cs
new file mode 100644
index 000000000..e4708deab
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.cs
@@ -0,0 +1,4 @@
+// Dummy reference - it can be used as an existing reference in any of the projects
+public class Lib
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.csproj
new file mode 100644
index 000000000..b61db6f8d
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib/Lib.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+
+ 1.0.1
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.cs
deleted file mode 100644
index 9452473dc..000000000
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using NSLib4;
-
-namespace NSLib2
-{
- public class Lib2
- {
-#if NETCOREAPP1_0
- public static void HelloNCA()
- {
- Console.WriteLine("Hello World from Lib2! (netcoreapp)");
- Lib4.HelloNCA();
- }
-#endif
-
-#if NET451
- public static void HelloNet451()
- {
- Console.WriteLine("Hello World from Lib2! (net45)");
- Lib4.HelloNet451();
- }
-#endif
- }
-}
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.cs
deleted file mode 100644
index b86a60de4..000000000
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib3/Lib3.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace NSLib3
-{
- public class Lib3
- {
-#if NETCOREAPP1_0
- public static void HelloNCA()
- {
- Console.WriteLine("Hello World from Lib3! (netcoreapp)");
- }
-#endif
-
-#if NET451
- public static void HelloNet451()
- {
- Console.WriteLine("Hello World from Lib3! (net45)");
- }
-#endif
- }
-}
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/SomeSourceFile.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/SomeSourceFile.cs
new file mode 100644
index 000000000..3e8c40581
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/SomeSourceFile.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace SomeNS
+{
+ public class SomeClass
+ {
+ }
+}
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/a.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/a.csproj
new file mode 100644
index 000000000..7a03821ea
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/a.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+ Library
+ netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+ 1.0.1
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/b.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/b.csproj
new file mode 100644
index 000000000..7a03821ea
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/MoreThanOne/b.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+ Library
+ netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+ 1.0.1
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.cs
new file mode 100644
index 000000000..f250057d8
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.cs
@@ -0,0 +1,5 @@
+// Dummy reference - it should not be referenced by any other project directly
+// it should be used as a reference passed to the dotnet add p2p
+public class ValidRef
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.csproj
new file mode 100644
index 000000000..b61db6f8d
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/ValidRef/ValidRef.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+
+ 1.0.1
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.cs
new file mode 100644
index 000000000..15d976dc2
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.cs
@@ -0,0 +1,3 @@
+public class WithExistingRefCondOnItem
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.csproj
similarity index 59%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.csproj
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.csproj
index e4d8997f8..a85516e34 100644
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib2/Lib2.csproj
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondOnItem/WithExistingRefCondOnItem.csproj
@@ -19,18 +19,7 @@
-
-
+
-
-
-
-
- $(DefineConstants);NETCOREAPP1_0
-
-
- $(DefineConstants);NET451
-
-
-
\ No newline at end of file
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.cs
new file mode 100644
index 000000000..4de50b9d8
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.cs
@@ -0,0 +1,3 @@
+public class WithExistingRefCondWhitespaces
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.csproj
new file mode 100644
index 000000000..79aca8ec9
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithExistingRefCondWhitespaces/WithExistingRefCondWhitespaces.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+
+ 1.0.1
+
+
+
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.cs
new file mode 100644
index 000000000..d827b8018
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.cs
@@ -0,0 +1,3 @@
+public class WithRefCondNonUniform
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.csproj
new file mode 100644
index 000000000..0f5e7d1b7
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefCondNonUniform/WithRefCondNonUniform.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+
+ 1.0.1
+
+
+
+
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.cs
new file mode 100644
index 000000000..c71d17552
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.cs
@@ -0,0 +1,3 @@
+public class WithRefNoCondNonUniform
+{
+}
\ No newline at end of file
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.csproj
new file mode 100644
index 000000000..a4f9328b0
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/WithRefNoCondNonUniform/WithRefNoCondNonUniform.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+ Library
+ net451;netcoreapp1.0
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+
+ 1.0.1
+
+
+
+
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/App/App.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/AppE2E/App.csproj
similarity index 99%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/App/App.csproj
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/AppE2E/App.csproj
index 2df913261..a476f96b3 100644
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/App/App.csproj
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/AppE2E/App.csproj
@@ -27,6 +27,5 @@
$(DefineConstants);NET451
-
-
\ No newline at end of file
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/App/Program.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/AppE2E/Program.cs
similarity index 100%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/App/Program.cs
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/AppE2E/Program.cs
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib1/Lib1.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib1/Lib1.cs
similarity index 100%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib1/Lib1.cs
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib1/Lib1.cs
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib1/Lib1.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib1/Lib1.csproj
similarity index 99%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib1/Lib1.csproj
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib1/Lib1.csproj
index 3466eb925..a5ea660c6 100644
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib1/Lib1.csproj
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib1/Lib1.csproj
@@ -24,6 +24,5 @@
$(DefineConstants);NET451
-
-
\ No newline at end of file
+
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib4/Lib4.cs b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib4/Lib4.cs
similarity index 100%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib4/Lib4.cs
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib4/Lib4.cs
diff --git a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib4/Lib4.csproj b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib4/Lib4.csproj
similarity index 99%
rename from TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib4/Lib4.csproj
rename to TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib4/Lib4.csproj
index 76b8b884d..55cecb538 100644
--- a/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/Lib4/Lib4.csproj
+++ b/TestAssets/NonRestoredTestProjects/DotnetAddP2PProjects/_remove_me_/Lib4/Lib4.csproj
@@ -27,6 +27,5 @@
$(DefineConstants);NET451
-
-
\ No newline at end of file
+
diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs
index 2d0d9bbfd..1cd3440a5 100644
--- a/src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs
+++ b/src/Microsoft.DotNet.ProjectJsonMigration/MSBuildExtensions.cs
@@ -27,14 +27,18 @@ namespace Microsoft.DotNet.ProjectJsonMigration
// Different includes
if (item.IntersectIncludes(otherItem).Count() != item.Includes().Count())
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(MSBuildExtensions)}.{nameof(IsEquivalentTo)} includes not equivalent.");
+#endif
return false;
}
// Different Excludes
if (item.IntersectExcludes(otherItem).Count() != item.Excludes().Count())
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(MSBuildExtensions)}.{nameof(IsEquivalentTo)} excludes not equivalent.");
+#endif
return false;
}
@@ -46,7 +50,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration
// Different remove
if (item.Remove != otherItem.Remove)
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(MSBuildExtensions)}.{nameof(IsEquivalentTo)} removes not equivalent.");
+#endif
return false;
}
@@ -61,13 +67,17 @@ namespace Microsoft.DotNet.ProjectJsonMigration
var otherMetadata = itemToCompare.GetMetadataWithName(metadata.Name);
if (otherMetadata == null)
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(MSBuildExtensions)}.{nameof(IsEquivalentTo)} metadata doesn't exist {{ {metadata.Name} {metadata.Value} }}");
+#endif
return false;
}
if (!metadata.ValueEquals(otherMetadata))
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(MSBuildExtensions)}.{nameof(IsEquivalentTo)} metadata has another value {{ {metadata.Name} {metadata.Value} {otherMetadata.Value} }}");
+#endif
return false;
}
}
@@ -197,7 +207,9 @@ namespace Microsoft.DotNet.ProjectJsonMigration
if (existingMetadata == default(ProjectMetadataElement))
{
+#if !DISABLE_TRACE
MigrationTrace.Instance.WriteLine($"{nameof(AddMetadata)}: Adding metadata to {item.ItemType} item: {{ {metadata.Name}, {metadata.Value} }}");
+#endif
item.AddMetadata(metadata.Name, metadata.Value);
}
}
diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs
index 5265a75e2..46241701f 100644
--- a/src/dotnet/Program.cs
+++ b/src/dotnet/Program.cs
@@ -3,12 +3,12 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Text;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Configurer;
using Microsoft.DotNet.PlatformAbstractions;
+using Microsoft.DotNet.Tools.Add;
using Microsoft.DotNet.Tools.Build;
using Microsoft.DotNet.Tools.Clean;
using Microsoft.DotNet.Tools.Help;
@@ -24,7 +24,6 @@ using Microsoft.DotNet.Tools.Run;
using Microsoft.DotNet.Tools.Test;
using Microsoft.DotNet.Tools.VSTest;
using NuGet.Frameworks;
-using Microsoft.DotNet.Tools.Add;
namespace Microsoft.DotNet.Cli
{
@@ -32,6 +31,7 @@ namespace Microsoft.DotNet.Cli
{
private static Dictionary> s_builtIns = new Dictionary>
{
+ ["add"] = AddCommand.Run,
["build"] = BuildCommand.Run,
["clean"] = CleanCommand.Run,
["help"] = HelpCommand.Run,
@@ -46,7 +46,6 @@ namespace Microsoft.DotNet.Cli
["run"] = RunCommand.Run,
["test"] = TestCommand.Run,
["vstest"] = VSTestCommand.Run,
- ["add"] = AddCommand.Run,
};
public static int Main(string[] args)
diff --git a/src/dotnet/commands/dotnet-add-p2p/MsbuildProjectExtensions.cs b/src/dotnet/commands/dotnet-add-p2p/MsbuildProjectExtensions.cs
new file mode 100644
index 000000000..1e3bd9488
--- /dev/null
+++ b/src/dotnet/commands/dotnet-add-p2p/MsbuildProjectExtensions.cs
@@ -0,0 +1,84 @@
+using Microsoft.Build.Construction;
+using Microsoft.DotNet.ProjectJsonMigration;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
+{
+ internal static class MsbuildProjectExtensions
+ {
+ public static bool IsConditionalOnFramework(this ProjectElement el, string framework)
+ {
+ string conditionStr;
+ if (!TryGetFrameworkConditionString(framework, out conditionStr))
+ {
+ return el.ConditionChain().Count == 0;
+ }
+
+ var condChain = el.ConditionChain();
+ return condChain.Count == 1 && condChain.First().Trim() == conditionStr;
+ }
+
+ public static ProjectItemGroupElement LastItemGroup(this ProjectRootElement root)
+ {
+ return root.ItemGroupsReversed.FirstOrDefault();
+ }
+
+ public static ProjectItemGroupElement FindUniformOrCreateItemGroupWithCondition(this ProjectRootElement root, string projectItemElementType, string framework)
+ {
+ var lastMatchingItemGroup = FindExistingUniformItemGroupWithCondition(root, projectItemElementType, framework);
+
+ if (lastMatchingItemGroup != null)
+ {
+ return lastMatchingItemGroup;
+ }
+
+ ProjectItemGroupElement ret = root.CreateItemGroupElement();
+ string condStr;
+ if (TryGetFrameworkConditionString(framework, out condStr))
+ {
+ ret.Condition = condStr;
+ }
+
+ root.InsertAfterChild(ret, root.LastItemGroup());
+ return ret;
+ }
+
+ public static ProjectItemGroupElement FindExistingUniformItemGroupWithCondition(this ProjectRootElement root, string projectItemElementType, string framework)
+ {
+ return root.ItemGroupsReversed.FirstOrDefault((ig) => ig.IsConditionalOnFramework(framework) && ig.IsUniformItemElementType(projectItemElementType));
+ }
+
+ public static bool IsUniformItemElementType(this ProjectItemGroupElement group, string projectItemElementType)
+ {
+ return group.Items.All((it) => it.ItemType == projectItemElementType);
+ }
+
+ public static IEnumerable FindExistingItemsWithCondition(this ProjectRootElement root, string framework, string include)
+ {
+ return root.Items.Where((el) => el.IsConditionalOnFramework(framework) && el.HasInclude(include));
+ }
+
+ public static bool HasExistingItemWithCondition(this ProjectRootElement root, string framework, string include)
+ {
+ return root.FindExistingItemsWithCondition(framework, include).Count() != 0;
+ }
+
+ public static bool HasInclude(this ProjectItemElement el, string include)
+ {
+ return el.Includes().Contains(include);
+ }
+
+ private static bool TryGetFrameworkConditionString(string framework, out string condition)
+ {
+ if (string.IsNullOrEmpty(framework))
+ {
+ condition = null;
+ return false;
+ }
+
+ condition = $"'$(TargetFramework)' == '{framework}'";
+ return true;
+ }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-add-p2p/Program.cs b/src/dotnet/commands/dotnet-add-p2p/Program.cs
index 611e5ee7d..42dd41997 100644
--- a/src/dotnet/commands/dotnet-add-p2p/Program.cs
+++ b/src/dotnet/commands/dotnet-add-p2p/Program.cs
@@ -8,7 +8,7 @@ using System;
using System.IO;
using System.Linq;
using Microsoft.Build.Construction;
-using Microsoft.DotNet.ProjectJsonMigration;
+using Microsoft.Build.Evaluation;
namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
@@ -22,31 +22,40 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
Name = "dotnet add p2p",
FullName = ".NET Add Project to Project (p2p) reference Command",
- Description = "Command to add project to project (p2p) reference"
+ Description = "Command to add project to project (p2p) reference",
+ AllowArgumentSeparator = true,
+ ArgumentSeparatorHelpText = "Project to project references to add"
};
+
app.HelpOption("-h|--help");
CommandArgument projectArgument = app.Argument("",
- "The MSBuild project file to modify. If a project file is not specified," +
+ "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.");
CommandOption frameworkOption = app.Option("-f|--framework ", "Add reference only when targetting a specific framework", CommandOptionType.SingleValue);
- CommandOption referenceOption = app.Option("-r|--reference ", "Add project to project to ", CommandOptionType.MultipleValue);
-
app.OnExecute(() => {
- ProjectRootElement project = projectArgument.Value != null ?
- GetProjectFromFileOrThrow(projectArgument.Value) :
- GetProjectFromCurrentDirectoryOrThrow();
+ if (projectArgument.Value == null)
+ {
+ throw new GracefulException("Argument is required.");
+ }
- if (referenceOption.Values.Count == 0)
+ ProjectRootElement project = File.Exists(projectArgument.Value) ?
+ GetProjectFromFileOrThrow(projectArgument.Value) :
+ GetProjectFromDirectoryOrThrow(projectArgument.Value);
+
+ if (app.RemainingArguments.Count == 0)
{
throw new GracefulException("You must specify at least one reference to add.");
}
- AddProjectToProjectReference(project, frameworkOption.Value(), referenceOption.Values);
+ int numberOfAddedReferences = AddProjectToProjectReference(project, frameworkOption.Value(), app.RemainingArguments);
- //project.Save();
+ if (numberOfAddedReferences != 0)
+ {
+ project.Save();
+ }
return 0;
});
@@ -57,7 +66,8 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
}
catch (GracefulException e)
{
- Reporter.Error.WriteLine(e.Message);
+ Reporter.Error.WriteLine(e.Message.Red());
+ app.ShowHelp();
return 1;
}
}
@@ -68,7 +78,7 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
try
{
- return ProjectRootElement.Open(filename);
+ return ProjectRootElement.Open(filename, new ProjectCollection(), preserveFormatting: true);
}
catch (Microsoft.Build.Exceptions.InvalidProjectFileException)
{
@@ -86,19 +96,34 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
var project = TryOpenProject(filename);
if (project == null)
{
- throw new GracefulException($"Invalid MSBuild project `{filename}`.");
+ throw new GracefulException($"Invalid project `{filename}`.");
}
return project;
}
- public static ProjectRootElement GetProjectFromCurrentDirectoryOrThrow()
+ // TODO: improve errors
+ public static ProjectRootElement GetProjectFromDirectoryOrThrow(string directory)
{
- DirectoryInfo currDir = new DirectoryInfo(Directory.GetCurrentDirectory());
- FileInfo[] files = currDir.GetFiles("*proj");
+ DirectoryInfo dir;
+ try
+ {
+ dir = new DirectoryInfo(directory);
+ }
+ catch (ArgumentException)
+ {
+ throw new GracefulException($"Could not find project or directory `{directory}`.");
+ }
+
+ if (!dir.Exists)
+ {
+ throw new GracefulException($"Could not find project or directory `{directory}`.");
+ }
+
+ FileInfo[] files = dir.GetFiles("*proj");
if (files.Length == 0)
{
- throw new GracefulException("Could not find any MSBuild project in the current directory.");
+ throw new GracefulException($"Could not find any project in `{directory}`.");
}
if (files.Length > 1)
@@ -110,123 +135,40 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
if (!projectFile.Exists)
{
- throw new GracefulException("Could not find any project in the current directory.");
+ throw new GracefulException($"Could not find any project in `{directory}`.");
}
var ret = TryOpenProject(projectFile.FullName);
if (ret == null)
{
- throw new GracefulException($"Found an MSBuild project `{projectFile.FullName}` in the current directory but it is invalid.");
+ throw new GracefulException($"Found a project `{projectFile.FullName}` but it is invalid.");
}
return ret;
}
- public static Func AndPred(params Func[] preds)
- {
- return (el) => preds.All((pred) => pred == null || pred(el));
- }
-
- public static string GetFrameworkConditionString(string framework)
- {
- if (string.IsNullOrEmpty(framework))
- {
- return null;
- }
-
- return $" '$(TargetFramework)' == '{framework}' ";
- }
-
- public static Func FrameworkPred(string framework) where T : ProjectElement
- {
- string conditionStr = GetFrameworkConditionString(framework);
- if (conditionStr == null)
- {
- return (ig) => {
- var condChain = ig.ConditionChain();
- return condChain.Count == 0;
- };
- }
-
- conditionStr = conditionStr.Trim();
- return (ig) => {
- var condChain = ig.ConditionChain();
- return condChain.Count == 1 && condChain.First().Trim() == conditionStr;
- };
- }
-
- public static Func UniformItemElementTypePred(string projectItemElementType)
- {
- return (ig) => ig.Items.All((it) => it.ItemType == projectItemElementType);
- }
-
- public static Func IncludePred(string include)
- {
- return (it) => it.Include == include;
- }
-
- public static ProjectItemElement[] FindExistingItemsWithCondition(ProjectRootElement root, string framework, string include)
- {
- return root.Items
- .Where(
- AndPred(
- FrameworkPred(framework),
- IncludePred(include)))
- .ToArray();
- }
-
- public static ProjectItemGroupElement FindExistingUniformItemGroupWithCondition(ProjectRootElement root, string projectItemElementType, string framework)
- {
- return root.ItemGroupsReversed
- .FirstOrDefault(
- AndPred(
- // When adding more predicates which operate on ItemGroup.Condition
- // some slightly more advanced logic need to be used:
- // i.e. ConditionPred(FrameworkConditionPred(framework), RuntimeConditionPred(runtime))
- // FrameworkConditionPred and RuntimeConditionPred would need to operate on a single condition
- // and ConditionPred would need to check if whole Condition Chain is satisfied
- FrameworkPred(framework),
- UniformItemElementTypePred(projectItemElementType)));
- }
-
- public static ProjectItemGroupElement FindUniformOrCreateItemGroupWithCondition(ProjectRootElement root, string projectItemElementType, string framework)
- {
- var lastMatchingItemGroup = FindExistingUniformItemGroupWithCondition(root, projectItemElementType, framework);
-
- if (lastMatchingItemGroup != null)
- {
- return lastMatchingItemGroup;
- }
-
- ProjectItemGroupElement ret = root.CreateItemGroupElement();
- string condStr = GetFrameworkConditionString(framework);
- if (condStr != null)
- {
- ret.Condition = condStr;
- }
-
- root.AppendChild(ret);
- return ret;
- }
-
- public static void AddProjectToProjectReference(ProjectRootElement root, string framework, IEnumerable refs)
+ public static int AddProjectToProjectReference(ProjectRootElement root, string framework, IEnumerable refs)
{
+ int numberOfAddedReferences = 0;
const string ProjectItemElementType = "ProjectReference";
ProjectItemGroupElement ig = null;
foreach (var @ref in refs)
{
- if (FindExistingItemsWithCondition(root, framework, @ref).Length == 0)
+ if (root.HasExistingItemWithCondition(framework, @ref))
{
- Reporter.Output.WriteLine($"Item {ProjectItemElementType} including `{@ref}` is already present.");
+ Reporter.Output.WriteLine($"Project already has a reference to `{@ref}`.");
continue;
}
- ig = ig ?? FindUniformOrCreateItemGroupWithCondition(root, ProjectItemElementType, framework);
+ numberOfAddedReferences++;
+ ig = ig ?? root.FindUniformOrCreateItemGroupWithCondition(ProjectItemElementType, framework);
ig.AppendChild(root.CreateItemElement(ProjectItemElementType, @ref));
- Reporter.Output.WriteLine($"Item {ProjectItemElementType} including `{@ref}` added to project.");
+ Reporter.Output.WriteLine($"Reference `{@ref}` added to the project.");
}
+
+ return numberOfAddedReferences;
}
}
}
diff --git a/src/dotnet/commands/dotnet-add/Program.cs b/src/dotnet/commands/dotnet-add/Program.cs
index faf32a201..1e3b2b29a 100644
--- a/src/dotnet/commands/dotnet-add/Program.cs
+++ b/src/dotnet/commands/dotnet-add/Program.cs
@@ -16,15 +16,22 @@ namespace Microsoft.DotNet.Tools.Add
{
public class AddCommand
{
- public const string CommandName = "dotnet-add";
- public const string UsageText = @"Usage: dotnet add [command] [arguments]
+ public const string HelpText = @".NET Add Command
+
+Usage: dotnet add [options] [object] [[--] ...]]
Arguments:
- [command] The command to execute
- [arguments] Arguments to pass to the command
+