Skip to content

Commit e16b20d

Browse files
committed
Remove need to workaround in corefx.
This change uses the new extension point in buildtools to extend the build to replace nuget package references with pseudo ProjectReferences.
1 parent 18a2541 commit e16b20d

12 files changed

+501
-61
lines changed

.editorconfig

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; EditorConfig helps developers define and maintain consistent
2+
; coding styles between different editors and IDEs.
3+
4+
; For more visit http://editorconfig.org.
5+
root = true
6+
7+
; Choose between lf or rf on "end_of_line" property
8+
[*]
9+
indent_style = space
10+
end_of_line = lf
11+
charset = utf-8
12+
trim_trailing_whitespace = true
13+
14+
[*.{*proj,targets,props}]
15+
indent_size = 2
16+
17+
[*.{cs,md}]
18+
indent_size = 4

build.proj

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<Import Project="src/index/index.proj"/>
3+
4+
<Target Name="BuildTasks">
5+
<MSBuild Projects="src/Microsoft.SourceIndexer.Tasks/Microsoft.SourceIndexer.Tasks.csproj" Targets="Build">
6+
<Output TaskParameter="TargetOutputs" PropertyName="SourceIndexerTasksAssembly"/>
7+
</MSBuild>
8+
</Target>
9+
10+
<Target Name="Rebuild" DependsOnTargets="BuildTasks">
11+
<MSBuild Projects="src/index/index.proj" Targets="Rebuild" Properties="SourceIndexerTasksAssembly=$(SourceIndexerTasksAssembly)"/>
12+
</Target>
13+
<Target Name="Clean" DependsOnTargets="BuildTasks">
14+
<MSBuild Projects="src/index/index.proj" Targets="Clean" Properties="SourceIndexerTasksAssembly=$(SourceIndexerTasksAssembly)"/>
15+
</Target>
16+
<Target Name="Build" DependsOnTargets="BuildTasks">
17+
<MSBuild Projects="src/index/index.proj" Targets="Build" Properties="SourceIndexerTasksAssembly=$(SourceIndexerTasksAssembly)"/>
18+
</Target>
19+
<Target Name="Clone" DependsOnTargets="BuildTasks">
20+
<MSBuild Projects="src/index/index.proj" Targets="Clone" Properties="SourceIndexerTasksAssembly=$(SourceIndexerTasksAssembly)"/>
21+
</Target>
22+
<Target Name="SelectProjects" DependsOnTargets="BuildTasks">
23+
<MSBuild Projects="src/index/index.proj" Targets="SelectProjects" Properties="SourceIndexerTasksAssembly=$(SourceIndexerTasksAssembly)"/>
24+
</Target>
425
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Microsoft.Build.Framework;
8+
9+
namespace Microsoft.SourceIndexer.Tasks
10+
{
11+
public static class Extensions
12+
{
13+
public static BuildEngineResult BuildProjectFilesInParallel(this IBuildEngine3 engine, string[] projectFileNames, string targetNames, IDictionary globalProperties, IList<string> removeGlobalProperties, string toolsVersion, bool returnTargetOutputs)
14+
{
15+
return engine.BuildProjectFilesInParallel(
16+
projectFileNames,
17+
CreateArray(targetNames, 1),
18+
CreateArray(globalProperties, projectFileNames.Length),
19+
CreateArray(removeGlobalProperties, projectFileNames.Length),
20+
CreateArray(toolsVersion, projectFileNames.Length),
21+
returnTargetOutputs
22+
);
23+
}
24+
25+
private static T[] CreateArray<T>(T value, int count)
26+
{
27+
return Enumerable.Repeat(value, count).ToArray();
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using Microsoft.Build.Framework;
7+
using Microsoft.Build.Utilities;
8+
using Newtonsoft.Json;
9+
10+
namespace Microsoft.SourceIndexer.Tasks
11+
{
12+
public class LiveReferenceData
13+
{
14+
public string Project { get; set; }
15+
public string TargetPath { get; set; }
16+
}
17+
18+
public class GenerateLiveReferenceCache : Task
19+
{
20+
[Required]
21+
public ITaskItem[] CandidateReferenceProjects { get; set; }
22+
23+
public string SetProperties { get; set; } = string.Empty;
24+
25+
public string UndefineProperties { get; set; } = string.Empty;
26+
27+
[Required]
28+
public string LiveReferenceCacheFile { get; set; }
29+
30+
public override bool Execute()
31+
{
32+
try
33+
{
34+
return ExecuteCore();
35+
}
36+
catch (Exception ex)
37+
{
38+
LogException(ex);
39+
return false;
40+
}
41+
}
42+
43+
private void LogException(Exception ex)
44+
{
45+
var agg = ex as AggregateException;
46+
if (agg != null)
47+
{
48+
foreach (var inner in agg.InnerExceptions)
49+
{
50+
LogException(inner);
51+
}
52+
}
53+
else
54+
{
55+
Log.LogErrorFromException(ex, true);
56+
}
57+
}
58+
59+
private bool ExecuteCore()
60+
{
61+
var properties = new Dictionary<string, string>();
62+
foreach (var prop in SetProperties.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
63+
{
64+
var key = prop.Substring(0, prop.IndexOf('=')).Trim();
65+
var value = prop.Substring(prop.IndexOf('=') + 1).Trim();
66+
if (!string.IsNullOrEmpty(key))
67+
{
68+
properties[key] = value;
69+
}
70+
}
71+
var projectFiles = CandidateReferenceProjects
72+
.Select(p => p.GetMetadata("FullPath"))
73+
.ToArray();
74+
var propertyArray = new IDictionary[projectFiles.Length];
75+
for (int i = 0; i < projectFiles.Length; i++)
76+
{
77+
propertyArray[i] = properties;
78+
}
79+
var removePropertiesArray = Enumerable.Repeat((IList<string>)UndefineProperties.Split(new[] { ';' }).Select(p => p.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToArray(), propertyArray.Length).ToArray();
80+
BuildEngineResult result = BuildEngine3.BuildProjectFilesInParallel(
81+
projectFiles,
82+
Enumerable.Repeat("GetTargetPath", projectFiles.Length).ToArray(),
83+
propertyArray,
84+
removePropertiesArray,
85+
new string[projectFiles.Length],
86+
true
87+
);
88+
if (!result.Result)
89+
{
90+
Log.LogError("Building 'GetTargetPath' Failed.");
91+
return false;
92+
}
93+
var assemblyNameToProject = new Dictionary<string, LiveReferenceData>();
94+
for (int i = 0; i < projectFiles.Length; i++)
95+
{
96+
string projectFile = projectFiles[i];
97+
IDictionary<string, ITaskItem[]> targetOutputs = result.TargetOutputsPerProject[i];
98+
ITaskItem targetPath = targetOutputs["GetTargetPath"].First();
99+
string assemblyName = targetPath.GetMetadata("FileName");
100+
assemblyNameToProject[assemblyName] = new LiveReferenceData
101+
{
102+
Project = projectFile,
103+
TargetPath = targetPath.GetMetadata("FullPath")
104+
};
105+
}
106+
File.WriteAllText(LiveReferenceCacheFile, JsonConvert.SerializeObject(assemblyNameToProject, Formatting.Indented));
107+
return true;
108+
}
109+
}
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
6+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
7+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
8+
<ProjectGuid>{5D86D28A-FEB9-4561-8EA8-D3C3BB409FB3}</ProjectGuid>
9+
<OutputType>Library</OutputType>
10+
<RootNamespace>Microsoft.SourceIndexer.Tasks</RootNamespace>
11+
<AssemblyName>Microsoft.SourceIndexer.Tasks</AssemblyName>
12+
<DefaultLanguage>en-US</DefaultLanguage>
13+
<FileAlignment>512</FileAlignment>
14+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
15+
<NuGetTargetMoniker>.NETFramework,Version=v4.5</NuGetTargetMoniker>
16+
</PropertyGroup>
17+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18+
<DebugSymbols>true</DebugSymbols>
19+
<DebugType>full</DebugType>
20+
<Optimize>false</Optimize>
21+
<OutputPath>bin\Debug\</OutputPath>
22+
<DefineConstants>DEBUG;TRACE</DefineConstants>
23+
<ErrorReport>prompt</ErrorReport>
24+
<WarningLevel>4</WarningLevel>
25+
</PropertyGroup>
26+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27+
<DebugType>pdbonly</DebugType>
28+
<Optimize>true</Optimize>
29+
<OutputPath>bin\Release\</OutputPath>
30+
<DefineConstants>TRACE</DefineConstants>
31+
<ErrorReport>prompt</ErrorReport>
32+
<WarningLevel>4</WarningLevel>
33+
</PropertyGroup>
34+
<ItemGroup>
35+
<None Include="project.json" />
36+
</ItemGroup>
37+
<ItemGroup>
38+
<Compile Include="Extensions.cs" />
39+
<Compile Include="GenerateLiveReferenceCache.cs" />
40+
<Compile Include="ResolveLivePackageReferences.cs" />
41+
<Compile Include="SelectProjects.cs" />
42+
</ItemGroup>
43+
<ItemGroup>
44+
<Reference Include="Microsoft.Build" />
45+
<Reference Include="Microsoft.Build.Conversion.v4.0" />
46+
<Reference Include="Microsoft.Build.Engine" />
47+
<Reference Include="Microsoft.Build.Framework" />
48+
<Reference Include="Microsoft.Build.Tasks.v4.0" />
49+
<Reference Include="Microsoft.Build.Utilities.v4.0" />
50+
<Reference Include="System" />
51+
<Reference Include="System.Core" />
52+
</ItemGroup>
53+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.Targets" />
54+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using Microsoft.Build.Framework;
6+
using Microsoft.Build.Utilities;
7+
using Newtonsoft.Json;
8+
9+
namespace Microsoft.SourceIndexer.Tasks
10+
{
11+
public class ResolveLivePackageReferences : Task
12+
{
13+
[Required]
14+
public ITaskItem[] References { get; set; }
15+
16+
public string AdditionalAssemblyReferences { get; set; } = string.Empty;
17+
18+
[Required]
19+
public string LiveReferenceCacheFile { get; set; }
20+
21+
[Output]
22+
public ITaskItem[] ReferencePaths { get; set; }
23+
24+
public override bool Execute()
25+
{
26+
try
27+
{
28+
return ExecuteCore();
29+
}
30+
catch (Exception ex)
31+
{
32+
LogException(ex);
33+
return false;
34+
}
35+
}
36+
37+
private void LogException(Exception ex)
38+
{
39+
var agg = ex as AggregateException;
40+
if (agg != null)
41+
{
42+
foreach (var inner in agg.InnerExceptions)
43+
{
44+
LogException(inner);
45+
}
46+
}
47+
else
48+
{
49+
Log.LogErrorFromException(ex, true);
50+
}
51+
}
52+
53+
private bool ExecuteCore()
54+
{
55+
var assemblyNameToProjectFile =
56+
JsonConvert.DeserializeObject<Dictionary<string, LiveReferenceData>>(File.ReadAllText(LiveReferenceCacheFile));
57+
var referencePaths = new List<ITaskItem>();
58+
var referencedProjects = new List<LiveReferenceData>();
59+
foreach (var reference in References)
60+
{
61+
var assemblyName = reference.GetMetadata("FileName");
62+
LiveReferenceData referenceData;
63+
if (assemblyNameToProjectFile.TryGetValue(assemblyName, out referenceData))
64+
{
65+
referencedProjects.Add(referenceData);
66+
}
67+
else
68+
{
69+
referencePaths.Add(reference);
70+
}
71+
}
72+
var additionalAssemblyReferences =
73+
AdditionalAssemblyReferences.Split(';').Where(s => !string.IsNullOrEmpty(s)).ToList();
74+
foreach (var assemblyName in additionalAssemblyReferences)
75+
{
76+
referencedProjects.Add(assemblyNameToProjectFile[assemblyName]);
77+
}
78+
var projectsToBuild = new List<string>();
79+
foreach (var liveReference in referencedProjects)
80+
{
81+
if (!File.Exists(liveReference.TargetPath))
82+
{
83+
Log.LogMessage(MessageImportance.Normal, "Reference '{0}' doesn't exist. It will be built.", liveReference.TargetPath);
84+
projectsToBuild.Add(liveReference.Project);
85+
}
86+
else
87+
{
88+
Log.LogMessage(MessageImportance.Normal, "Reference '{0}' exists", liveReference.TargetPath);
89+
}
90+
}
91+
BuildEngineResult result = BuildEngine3.BuildProjectFilesInParallel(
92+
projectsToBuild.ToArray(),
93+
"Build",
94+
new Dictionary<string, string>(),
95+
new[] {"CustomAfterBuildCommonTargets"},
96+
null,
97+
false
98+
);
99+
if (!result.Result)
100+
{
101+
Log.LogError("Failed to resolve references.");
102+
return false;
103+
}
104+
referencePaths.AddRange(referencedProjects.Select(p => new TaskItem(p.TargetPath)));
105+
ReferencePaths = referencePaths.ToArray();
106+
return true;
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)