Browse Source

Add a script to search the project reference graph and add all to a .sln file (#7066)

Nate McMaster 7 years ago
parent
commit
4eca8f02e1

+ 18 - 0
build/repo.targets

@@ -38,6 +38,24 @@
     <CodeSignDependsOn>$(CodeSignDependsOn);RemoveSharedFrameworkOnlyRefsFromNuspec</CodeSignDependsOn>
   </PropertyGroup>
 
+  <Target Name="ShowProjectClosure" DependsOnTargets="ResolveProjects">
+    <MSBuild Targets="_CustomCollectProjectReference"
+             BuildInParallel="true"
+             SkipNonexistentTargets="true"
+             Projects="@(ProjectToBuild)"
+             Properties="DesignTimeBuild=true"
+             RebaseOutputs="True">
+      <Output TaskParameter="TargetOutputs" ItemName="_ReferenceProject" />
+    </MSBuild>
+    <RemoveDuplicates Inputs="@(_ReferenceProject->'%(FullPath)')">
+      <Output TaskParameter="Filtered" ItemName="ReferencedProjects" />
+    </RemoveDuplicates>
+    <Message Importance="High" Text="Projects referenced:" />
+    <Message Importance="High" Text=" - %(ReferencedProjects.Identity)" />
+
+    <WriteLinesToFile Lines="@(ReferencedProjects)" File="$(ProjectsReferencedOutFile)" Overwrite="true" Condition="'$(ProjectsReferencedOutFile)' != ''" />
+  </Target>
+
   <Target Name="GenerateProjectList" DependsOnTargets="ResolveProjects">
     <MSBuild Projects="@(ProjectToBuild)"
              Targets="GetReferencesProvided"

+ 4 - 1
docs/BuildFromSource.md

@@ -87,10 +87,13 @@ Opening solution files may produce an error code NU1105 with a message such
 
 This is a known issue in NuGet (<https://github.com/NuGet/Home/issues/5820>) and we are working with them for a solution. See also <https://github.com/aspnet/AspNetCore/issues/4183> to track progress on this.
 
-**The workaround** for now is to add all projects to the solution.
+**The workaround** for now is to add all projects to the solution. You can either do this one by one using `dotnet sln`
 
     dotnet sln add C:\src\AspNetCore\src\Hosting\Abstractions\src\Microsoft.AspNetCore.Hosting.Abstractions.csproj
 
+Or you can use this script to automatically traverse the project reference graph, which then invokes `dotnet sln` for you: [eng/scripts/AddAllProjectRefsToSolution.ps1](/eng/scripts/AddAllProjectRefsToSolution.ps1).
+
+    ./eng/scripts/AddAllProjectRefsToSolution.ps1 -WorkingDir src/Mvc/
 
 #### PATH
 

+ 60 - 0
eng/scripts/AddAllProjectRefsToSolution.ps1

@@ -0,0 +1,60 @@
+<#
+.SYNOPSIS
+This adds the complete closure of project references to a .sln file
+
+.EXAMPLE
+Let's say you have a folder of projects in src/Banana/, and a file src/Banana/Banana.sln.
+To traverse the ProjectReference graph to add all dependency projects, run this script:
+
+    ./eng/scripts/AddAllProjectRefsToSolution.ps1 -WorkingDir ./src/Banana/
+
+.EXAMPLE
+If src/Banana/ has multiple .sln files, use the -sln parameter.
+
+    ./eng/scripts/AddAllProjectRefsToSolution.ps1 -WorkingDir ./src/Banana/ -SolutionFile src/Banana/Solution1.sln
+#>
+[CmdletBinding(PositionalBinding = $false)]
+param(
+    [string]$WorkingDir,
+    [Alias('sln')]
+    [string]$SolutionFile
+)
+
+$ErrorActionPreference = 'Stop'
+$repoRoot = Resolve-Path "$PSScriptRoot/../../"
+$listFile = New-TemporaryFile
+
+if (-not $WorkingDir) {
+    $WorkingDir = Get-Location
+}
+
+Push-Location $WorkingDir
+try {
+    if (-not $SolutionFile) {
+
+        $slnCount = Get-ChildItem *.sln | Measure
+
+        if ($slnCount.count -eq 0) {
+            Write-Error "Could not find a solution in this directory. Specify one with -sln <PATH>"
+            exit 1
+        }
+        if ($slnCount.count -gt 1) {
+            Write-Error "Multiple solutions found in this directory. Specify which one to modify with -sln <PATH>"
+            exit 1
+        }
+        $SolutionFile = Get-ChildItem *.sln | select -first 1
+    }
+
+    & "$repoRoot\build.ps1" -projects "$(Get-Location)\**\*.*proj" /t:ShowProjectClosure "/p:ProjectsReferencedOutFile=$listFile"
+
+    foreach ($proj in (Get-Content $listFile)) {
+        & dotnet sln $SolutionFile add $proj
+        if ($lastexitcode -ne 0) {
+            Write-Warning "Failed to add $proj to $SolutionFile"
+        }
+    }
+}
+finally {
+    Pop-Location
+    rm $listFile -ea ignore
+}

+ 26 - 0
eng/targets/ResolveReferences.targets

@@ -169,4 +169,30 @@
       </ProvidesReference>
     </ItemGroup>
   </Target>
+
+  <!-- This is used by the eng/scripts/AddAllProjectRefsToSolution.ps1 script to traverse the ProjectRef graph -->
+  <PropertyGroup>
+    <_CustomCollectProjectReferenceDependsOn Condition="'$(TargetFramework)' != ''">ResolveProjectReferences</_CustomCollectProjectReferenceDependsOn>
+  </PropertyGroup>
+  <Target Name="_CustomCollectProjectReference" DependsOnTargets="$(_CustomCollectProjectReferenceDependsOn)" Returns="$(MSBuildProjectFullPath);@(_MSBuildProjectReferenceExistent)">
+    <ItemGroup>
+      <_TargetFrameworks Include="$(TargetFrameworks)" />
+    </ItemGroup>
+    <MSBuild Condition="'$(TargetFramework)' == ''"
+             Targets="_CustomCollectProjectReference"
+             BuildInParallel="true"
+             Projects="$(MSBuildProjectFullPath)"
+             Properties="TargetFramework=%(_TargetFrameworks.Identity)"
+             RebaseOutputs="True">
+      <Output TaskParameter="TargetOutputs" ItemName="_MSBuildProjectReferenceExistent" />
+    </MSBuild>
+    <MSBuild Condition="'$(TargetFramework)' != ''"
+             Targets="_CustomCollectProjectReference"
+             BuildInParallel="true"
+             SkipNonexistentTargets="true"
+             Projects="@(_MSBuildProjectReferenceExistent)"
+             RebaseOutputs="True">
+      <Output TaskParameter="TargetOutputs" ItemName="_MSBuildProjectReferenceExistent" />
+    </MSBuild>
+  </Target>
 </Project>