Implement dotnet add project (#5022)

* Implement dotnet add project

* Addressed PR comments
This commit is contained in:
Justin Goshi 2016-12-14 13:53:11 -10:00 committed by GitHub
parent 88ac88802b
commit 441277ccfa
38 changed files with 932 additions and 55 deletions

View file

@ -0,0 +1 @@
This is a test of an invalid solution.

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="1.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
using System;
namespace Lib
{
public class Library
{
public static string GetMessage()
{
return "Message from Lib";
}
}
}

View file

@ -0,0 +1,34 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{7072A694-548F-4CAE-A58F-12D257D5F486}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,9 @@
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello");
}
}

View file

@ -0,0 +1,34 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{7072A694-548F-4CAE-A58F-12D257D5F486}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,34 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{7072A694-548F-4CAE-A58F-12D257D5F486}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lib\Lib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,10 @@
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello from the main app");
Console.WriteLine(Lib.Library.GetMessage());
}
}

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="1.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
using System;
namespace Lib
{
public class Library
{
public static string GetMessage()
{
return "Message from Lib";
}
}
}

View file

@ -0,0 +1,34 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{7072A694-548F-4CAE-A58F-12D257D5F486}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lib\Lib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,10 @@
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello from the main app");
Console.WriteLine(Lib.Library.GetMessage());
}
}

View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<ProjectGuid>{84A45D44-B677-492D-A6DA-B3A71135AB8E}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="1.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
using System;
namespace Lib
{
public class Library
{
public static string GetMessage()
{
return "Message from Lib";
}
}
}

View file

@ -0,0 +1,36 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{7072A694-548F-4CAE-A58F-12D257D5F486}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lib", "Lib\Lib.csproj", "{B38B1FA5-B4C9-456A-8B71-8FCD62ACF400}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lib\Lib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,10 @@
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello from the main app");
Console.WriteLine(Lib.Library.GetMessage());
}
}

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="1.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,12 @@
using System;
namespace Lib
{
public class Library
{
public static string GetMessage()
{
return "Message from Lib";
}
}
}

View file

@ -0,0 +1,11 @@
// 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.
namespace Microsoft.DotNet.Cli.Sln.Internal
{
public static class ProjectTypeGuids
{
public const string CPSProjectTypeGuid = "{13B669BE-BB05-4DDF-9536-439F39A36129}";
public const string CSharpProjectTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
}
}

View file

@ -2,7 +2,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.PlatformAbstractions;
namespace Microsoft.DotNet.Tools.Common
@ -257,5 +260,25 @@ namespace Microsoft.DotNet.Tools.Common
return Path.GetFullPath(path);
}
public static void EnsureAllPathsExist(List<string> paths, string pathDoesNotExistLocalizedFormatString)
{
var notExisting = new List<string>();
foreach (var p in paths)
{
if (!File.Exists(p))
{
notExisting.Add(p);
}
}
if (notExisting.Count > 0)
{
throw new GracefulException(
string.Join(
Environment.NewLine,
notExisting.Select((p) => string.Format(pathDoesNotExistLocalizedFormatString, p))));
}
}
}
}

View file

@ -100,12 +100,10 @@
/// Solution
public const string CouldNotFindSolutionIn = "Specified solution file {0} does not exist, or there is no solution file in the directory.";
public const string CouldNotFindSolutionOrDirectory = "Could not find solution or directory `{0}`.";
public const string FoundMoreThanOneSolutionIn = "Found more than one solution file in {0}. Please specify which one to use.";
public const string FoundInvalidSolution = "The solution file {0} seems to be invalid. Please check if it is a valid solution file.";
public const string MoreThanOneSolutionInDirectory = "Found more than one solution file in {0}. Please specify which one to use.";
public const string InvalidSolution = "Invalid solution `{0}`.";
public const string SolutionDoesNotExist = "Specified solution file {0} does not exist, or there is no solution file in the directory.";
public const string SolutionAlreadyContainsAProject = "Solution {0} already contains project {1}.";
/// add p2p
public const string ReferenceDoesNotExist = "Reference {0} does not exist.";
public const string ReferenceIsInvalid = "Reference `{0}` is invalid.";
@ -125,28 +123,25 @@
public const string ProjectIsInvalid = "Project `{0}` is invalid.";
public const string SpecifyAtLeastOneProjectToAdd = "You must specify at least one project to add.";
public const string ProjectAddedToTheSolution = "Project `{0}` added to the solution.";
public const string SolutionAlreadyHasAProject = "Solution {0} already contains project {1}.";
public const string SolutionAlreadyContainsProject = "Solution {0} already contains project {1}.";
/// del p2p
public const string ReferenceNotFoundInTheProject = "Specified reference {0} does not exist in project {1}.";
public const string ReferenceRemoved = "Reference `{0}` deleted from the project.";
public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to delete. Please run dotnet delete --help for more information.";
public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to remove.";
public const string ReferenceDeleted = "Reference `{0}` deleted.";
public const string SpecifyAtLeastOneReferenceToDelete = "You must specify at least one reference to delete. Please run dotnet delete --help for more information.";
/// del pkg
public const string PackageReferenceNotFoundInTheProject = "Package reference `{0}` could not be found in the project.";
public const string PackageReferenceRemoved = "Reference `{0}` deleted from the project.";
public const string SpecifyAtLeastOnePackageReferenceToRemove = "You must specify at least one reference to delete. Please run dotnet delete --help for more information.";
public const string SpecifyAtLeastOnePackageReferenceToRemove = "You must specify at least one package reference to remove.";
public const string PackageReferenceDeleted = "Package reference `{0}` deleted.";
public const string SpecifyAtLeastOnePackageReferenceToDelete = "You must specify at least one package reference to delete.";
/// del sln
public const string ProjectNotFoundInTheSolution = "Project `{0}` could not be found in the solution.";
public const string ProjectRemoved = "Project `{0}` removed from solution.";
public const string SpecifyAtLeastOneProjectToRemove = "You must specify at least one project to remove.";
public const string ProjectDeleted = "Project `{0}` deleted from solution.";
public const string SpecifyAtLeastOneProjectToDelete = "You must specify at least one project to delete from solution.";
/// list
public const string NoReferencesFound = "There are no {0} references in project {1}. ;; {0} is the type of the item being requested (project, package, p2p) and {1} is the object operated on (a project file or a solution file). ";

View file

@ -115,7 +115,7 @@ namespace Microsoft.DotNet.Tools
ProjectItemGroupElement itemGroup = ProjectRootElement.FindUniformOrCreateItemGroupWithCondition(
ProjectItemElementType,
framework);
foreach (var @ref in refs.Select((r) => NormalizeSlashes(r)))
foreach (var @ref in refs.Select((r) => PathUtility.GetPathWithBackSlashes(r)))
{
if (ProjectRootElement.HasExistingItemWithCondition(framework, @ref))
{
@ -151,40 +151,6 @@ namespace Microsoft.DotNet.Tools
return ProjectRootElement.GetAllItemsWithElementType(ProjectItemElementType);
}
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(CommonLocalizableStrings.ReferenceDoesNotExist, r))));
}
}
public IEnumerable<NuGetFramework> GetTargetFrameworks()
{
if (_cachedTfms != null)

View file

@ -3,6 +3,7 @@
using Microsoft.Build.Construction;
using Microsoft.DotNet.ProjectJsonMigration;
using Microsoft.DotNet.Tools.Common;
using System.Collections.Generic;
using System.Linq;
@ -100,7 +101,7 @@ namespace Microsoft.DotNet.Tools
private static string NormalizeIncludeForComparison(string include)
{
return MsbuildProject.NormalizeSlashes(include.ToLower());
return PathUtility.GetPathWithBackSlashes(include.ToLower());
}
}
}

View file

@ -0,0 +1,86 @@
// 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 System;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Common
{
public static class SlnFileFactory
{
public static SlnFile CreateFromFileOrDirectory(string fileOrDirectory)
{
if (File.Exists(fileOrDirectory))
{
return FromFile(fileOrDirectory);
}
else
{
return FromDirectory(fileOrDirectory);
}
}
private static SlnFile FromFile(string solutionPath)
{
SlnFile slnFile = null;
try
{
slnFile = SlnFile.Read(solutionPath);
}
catch
{
throw new GracefulException(CommonLocalizableStrings.InvalidSolution, solutionPath);
}
return slnFile;
}
private static SlnFile FromDirectory(string solutionDirectory)
{
DirectoryInfo dir;
try
{
dir = new DirectoryInfo(solutionDirectory);
if (!dir.Exists)
{
throw new GracefulException(
CommonLocalizableStrings.CouldNotFindSolutionOrDirectory,
solutionDirectory);
}
}
catch (ArgumentException)
{
throw new GracefulException(
CommonLocalizableStrings.CouldNotFindSolutionOrDirectory,
solutionDirectory);
}
FileInfo[] files = dir.GetFiles("*.sln");
if (files.Length == 0)
{
throw new GracefulException(
CommonLocalizableStrings.CouldNotFindSolutionIn,
solutionDirectory);
}
if (files.Length > 1)
{
throw new GracefulException(
CommonLocalizableStrings.MoreThanOneSolutionInDirectory,
solutionDirectory);
}
FileInfo solutionFile = files.Single();
if (!solutionFile.Exists)
{
throw new GracefulException(
CommonLocalizableStrings.CouldNotFindSolutionIn,
solutionDirectory);
}
return FromFile(solutionFile.FullName);
}
}
}

View file

@ -6,6 +6,7 @@ using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
using Microsoft.DotNet.Tools.Add.ProjectToSolution;
namespace Microsoft.DotNet.Tools.Add
{
@ -16,6 +17,7 @@ namespace Microsoft.DotNet.Tools.Add
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
{
AddProjectToSolutionCommand.CreateApplication,
AddProjectToProjectReferenceCommand.CreateApplication,
};

View file

@ -55,7 +55,7 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
string frameworkString = frameworkOption.Value();
List<string> references = app.RemainingArguments;
MsbuildProject.EnsureAllReferencesExist(references);
PathUtility.EnsureAllPathsExist(references, CommonLocalizableStrings.ReferenceDoesNotExist);
IEnumerable<MsbuildProject> refs = references.Select((r) => MsbuildProject.FromFile(projects, r));
if (frameworkString == null)
@ -95,11 +95,12 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
}
}
msbuildProj.ConvertPathsToRelative(ref references);
var relativePathReferences = references.Select((r) =>
PathUtility.GetRelativePath(msbuildProj.ProjectDirectory, Path.GetFullPath(r))).ToList();
int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
frameworkOption.Value(),
references);
relativePathReferences);
if (numberOfAddedReferences != 0)
{

View file

@ -0,0 +1,14 @@
// 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.
namespace Microsoft.DotNet.Tools.Add.ProjectToSolution
{
internal class LocalizableStrings
{
public const string AppFullName = ".NET Add Project to Solution Command";
public const string AppDescription = "Command to add project to solution";
public const string AppHelpText = "Projects to add to solution";
}
}

View file

@ -0,0 +1,131 @@
// 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.CommandLine;
using Microsoft.DotNet.Cli.Sln.Internal;
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.Add.ProjectToSolution
{
public class AddProjectToSolutionCommand
{
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
CommandLineApplication app = parentApp.Command("project", throwOnUnexpectedArg: false);
app.FullName = LocalizableStrings.AppFullName;
app.Description = LocalizableStrings.AppDescription;
app.HandleRemainingArguments = true;
app.ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText;
app.HelpOption("-h|--help");
app.OnExecute(() =>
{
try
{
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
SlnFile slnFile = SlnFileFactory.CreateFromFileOrDirectory(projectOrDirectory);
if (app.RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd);
}
List<string> projectPaths = app.RemainingArguments;
PathUtility.EnsureAllPathsExist(projectPaths, CommonLocalizableStrings.ProjectDoesNotExist);
var relativeProjectPaths = projectPaths.Select((p) =>
PathUtility.GetRelativePath(
PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory),
Path.GetFullPath(p))).ToList();
int preAddProjectCount = slnFile.Projects.Count;
foreach (var project in relativeProjectPaths)
{
AddProject(slnFile, project);
}
if (slnFile.Projects.Count > preAddProjectCount)
{
slnFile.Write();
}
return 0;
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
});
return app;
}
private static void AddProject(SlnFile slnFile, string projectPath)
{
var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath);
if (slnFile.Projects.Any((p) =>
string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)))
{
Reporter.Output.WriteLine(string.Format(
CommonLocalizableStrings.SolutionAlreadyContainsProject,
slnFile.FullPath,
projectPath));
}
else
{
string projectGuidString = null;
if (File.Exists(projectPath))
{
var projectElement = ProjectRootElement.Open(
projectPath,
new ProjectCollection(),
preserveFormatting: true);
var projectGuidProperty = projectElement.Properties.Where((p) =>
string.Equals(p.Name, "ProjectGuid", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (projectGuidProperty != null)
{
projectGuidString = projectGuidProperty.Value;
}
}
var projectGuid = (projectGuidString == null)
? Guid.NewGuid()
: new Guid(projectGuidString);
var slnProject = new SlnProject
{
Id = projectGuid.ToString("B").ToUpper(),
TypeGuid = ProjectTypeGuids.CPSProjectTypeGuid,
Name = Path.GetFileNameWithoutExtension(projectPath),
FilePath = projectPathNormalized
};
slnFile.Projects.Add(slnProject);
Reporter.Output.WriteLine(
string.Format(CommonLocalizableStrings.ProjectAddedToTheSolution, projectPath));
}
}
}
}

View file

@ -19,8 +19,6 @@ namespace Microsoft.DotNet.Tools.Migrate
{
public partial class MigrateCommand
{
private const string CSharpProjectTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
private SlnFile _slnFile;
private readonly DirectoryInfo _workspaceDirectory;
private readonly DirectoryInfo _backupDirectory;
@ -125,7 +123,7 @@ namespace Microsoft.DotNet.Tools.Migrate
if (csprojFiles.Count() == 1)
{
project.FilePath = Path.Combine(Path.GetDirectoryName(project.FilePath), csprojFiles.First().Name);
project.TypeGuid = CSharpProjectTypeGuid;
project.TypeGuid = ProjectTypeGuids.CSharpProjectTypeGuid;
}
}

View file

@ -14,7 +14,7 @@ namespace Microsoft.DotNet.Cli.Sln.Internal.Tests
public class GivenAnSlnFile : TestBase
{
[Fact]
public void It_reads_an_sln_file()
public void WhenGivenAValidPathItReadsAnSlnFile()
{
var solutionDirectory =
TestAssetsManager.CreateTestInstance("TestAppWithSln", callingMethod: "p").Path;
@ -39,7 +39,7 @@ namespace Microsoft.DotNet.Cli.Sln.Internal.Tests
}
[Fact]
public void It_writes_an_sln_file()
public void WhenGivenAValidPathItReadsModifiesThenWritesAnSln()
{
var solutionDirectory =
TestAssetsManager.CreateTestInstance("TestAppWithSln", callingMethod: "p").Path;

View file

@ -0,0 +1,203 @@
// 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 FluentAssertions;
using Microsoft.Build.Construction;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Tools.Test.Utilities;
using System;
using System.IO;
using System.Linq;
using Xunit;
namespace Microsoft.DotNet.Cli.Add.Proj.Tests
{
public class GivenDotnetAddProj : TestBase
{
[Theory]
[InlineData("--help")]
[InlineData("-h")]
public void WhenHelpOptionIsPassedItPrintsUsage(string helpArg)
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add project {helpArg}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Usage");
}
[Theory]
[InlineData("idontexist.sln")]
[InlineData("ihave?invalidcharacters")]
[InlineData("ihaveinv@lidcharacters")]
[InlineData("ihaveinvalid/characters")]
[InlineData("ihaveinvalidchar\\acters")]
public void WhenNonExistingSolutionIsPassedItPrintsErrorAndUsage(string solutionName)
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add {solutionName} project p.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Could not find");
cmd.StdOut.Should().Contain("Usage:");
}
[Fact]
public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution")
.WithLockFiles()
.Path;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add InvalidSolution.sln project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution ");
cmd.StdOut.Should().Contain("Usage:");
}
[Fact]
public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution")
.WithLockFiles()
.Path;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution ");
cmd.StdOut.Should().Contain("Usage:");
}
[Fact]
public void WhenNoProjectIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput(@"add App.sln project");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("You must specify at least one project to add.");
cmd.StdOut.Should().Contain("Usage:");
}
[Fact]
public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var cmd = new DotnetCommand()
.WithWorkingDirectory(Path.Combine(projectDirectory, "App"))
.ExecuteWithCapturedOutput(@"add project App.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdOut.Should().Contain("Usage:");
}
[Fact]
public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithMultipleSlnFiles")
.WithLockFiles()
.Path;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("more than one");
cmd.StdOut.Should().Contain("Usage");
}
[Theory]
[InlineData("TestAppWithSlnAndCsprojFiles", "")]
[InlineData("TestAppWithSlnAndCsprojProjectGuidFiles", "{84A45D44-B677-492D-A6DA-B3A71135AB8E}")]
public void WhenValidProjectIsPassedItGetsNormalizedAndAddedAndSlnBuilds(
string testAsset,
string projectGuid)
{
var projectDirectory = TestAssetsManager.CreateTestInstance(testAsset)
.WithLockFiles()
.Path;
var projectToAdd = "Lib/Lib.csproj";
var normalizedProjectPath = @"Lib\Lib.csproj";
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the solution");
cmd.StdErr.Should().BeEmpty();
var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln"));
var matchingProjects = slnFile.Projects
.Where((p) => p.Name == "Lib")
.ToList();
matchingProjects.Count.Should().Be(1);
var slnProject = matchingProjects[0];
slnProject.FilePath.Should().Be(normalizedProjectPath);
slnProject.TypeGuid.Should().Be(ProjectTypeGuids.CPSProjectTypeGuid);
if (!string.IsNullOrEmpty(projectGuid))
{
slnProject.Id.Should().Be(projectGuid);
}
var restoreCmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.Execute($"restore {Path.Combine("App", "App.csproj")}");
var buildCmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.Execute("build App.sln");
buildCmd.Should().Pass();
}
[Fact]
public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndExistingCsprojReferences")
.WithLockFiles()
.Path;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already contains project");
cmd.StdErr.Should().BeEmpty();
}
[Fact]
public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var slnFullPath = Path.Combine(projectDirectory, "App.sln");
var contentBefore = File.ReadAllText(slnFullPath);
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd} idonotexist.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdErr.Should().NotMatchRegex("(.*does not exist.*){2,}");
File.ReadAllText(slnFullPath)
.Should().BeEquivalentTo(contentBefore);
}
}
}

View file

@ -0,0 +1 @@
https://github.com/Microsoft/msbuild/issues/927

View file

@ -0,0 +1 @@
https://github.com/Microsoft/msbuild/issues/927

View file

@ -0,0 +1,51 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<AssemblyName>dotnet-add-proj.Tests</AssemblyName>
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);dotnet5.4;portable-net451+win8</PackageTargetFallback>
<DefineConstants>$(DefineConstants);DISABLE_TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<Reference Include="System.Runtime" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk">
<Version>$(CLI_NETSDK_Version)</Version>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk">
<Version>15.0.0-preview-20161024-02</Version>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio">
<Version>2.2.0-beta4-build1194</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.App">
<Version>1.0.1</Version>
</PackageReference>
<PackageReference Include="xunit">
<Version>2.2.0-beta4-build3444</Version>
</PackageReference>
<PackageReference Include="Microsoft.Build">
<Version>$(CLI_MSBuild_Version)</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>