Skip to content

Commit dc1fb80

Browse files
authored
Merge pull request #117 from AArnott/fix112
Add support for dotnet CLI on Linux
2 parents 2e974e5 + 7546986 commit dc1fb80

File tree

9 files changed

+213
-51
lines changed

9 files changed

+213
-51
lines changed

init.ps1

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<#
22
.SYNOPSIS
3-
Restores all NuGet, NPM and Typings packages necessary to build this repository.
3+
Restores all NuGet, NPM and Typings packages necessary to build this repository.
44
#>
55
[CmdletBinding(SupportsShouldProcess)]
66
Param(
@@ -18,12 +18,7 @@ try {
1818
& "$toolsPath\Restore-NuGetPackages.ps1" -Path $_ -Verbosity Quiet
1919
}
2020

21-
# Restore VS solution dependencies
22-
gci "$PSScriptRoot\src" -rec |? { $_.FullName.EndsWith('.sln') } |% {
23-
& "$toolsPath\Restore-NuGetPackages.ps1" -Path $_.FullName -Verbosity Quiet
24-
}
25-
26-
# Restore VS2017 style as well, since nuget 3.3 doesn't support it.
21+
# Restore VS2017 style to get the rest of the projects.
2722
msbuild "$PSScriptRoot\src\NerdBank.GitVersioning.Tests\NerdBank.GitVersioning.Tests.csproj" /t:restore /v:minimal /m /nologo
2823

2924
Write-Host "Restoring NPM packages..." -ForegroundColor Yellow
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
namespace MSBuildExtensionTask
2+
{
3+
using System;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
7+
#if NETCOREAPP1_0
8+
using System.Runtime.Loader;
9+
#endif
10+
using Microsoft.Build.Framework;
11+
using Microsoft.Build.Utilities;
12+
13+
public abstract class ContextAwareTask : Task
14+
{
15+
protected virtual string ManagedDllDirectory => Path.GetDirectoryName(new Uri(this.GetType().GetTypeInfo().Assembly.CodeBase).LocalPath);
16+
17+
protected virtual string UnmanagedDllDirectory => null;
18+
19+
public override bool Execute()
20+
{
21+
#if NETCOREAPP1_0
22+
string taskAssemblyPath = new Uri(this.GetType().GetTypeInfo().Assembly.CodeBase).LocalPath;
23+
var ctxt = new CustomAssemblyLoader(this);
24+
Assembly inContextAssembly = ctxt.LoadFromAssemblyPath(taskAssemblyPath);
25+
Type innerTaskType = inContextAssembly.GetType(this.GetType().FullName);
26+
object innerTask = Activator.CreateInstance(innerTaskType);
27+
28+
var outerProperties = this.GetType().GetRuntimeProperties().ToDictionary(i => i.Name);
29+
var innerProperties = innerTaskType.GetRuntimeProperties().ToDictionary(i => i.Name);
30+
var propertiesDiscovery = from outerProperty in outerProperties.Values
31+
where outerProperty.SetMethod != null && outerProperty.GetMethod != null
32+
let innerProperty = innerProperties[outerProperty.Name]
33+
select new { outerProperty, innerProperty };
34+
var propertiesMap = propertiesDiscovery.ToArray();
35+
var outputPropertiesMap = propertiesMap.Where(pair => pair.outerProperty.GetCustomAttribute<OutputAttribute>() != null).ToArray();
36+
37+
foreach (var propertyPair in propertiesMap)
38+
{
39+
object outerPropertyValue = propertyPair.outerProperty.GetValue(this);
40+
propertyPair.innerProperty.SetValue(innerTask, outerPropertyValue);
41+
}
42+
43+
var executeInnerMethod = innerTaskType.GetMethod(nameof(ExecuteInner), BindingFlags.Instance | BindingFlags.NonPublic);
44+
bool result = (bool)executeInnerMethod.Invoke(innerTask, new object[0]);
45+
46+
foreach (var propertyPair in outputPropertiesMap)
47+
{
48+
propertyPair.outerProperty.SetValue(this, propertyPair.innerProperty.GetValue(innerTask));
49+
}
50+
51+
return result;
52+
#else
53+
// On .NET Framework (on Windows), we find native binaries by adding them to our PATH.
54+
if (this.UnmanagedDllDirectory != null)
55+
{
56+
string pathEnvVar = Environment.GetEnvironmentVariable("PATH");
57+
string[] searchPaths = pathEnvVar.Split(Path.PathSeparator);
58+
if (!searchPaths.Contains(this.UnmanagedDllDirectory, StringComparer.OrdinalIgnoreCase))
59+
{
60+
pathEnvVar += Path.PathSeparator + this.UnmanagedDllDirectory;
61+
Environment.SetEnvironmentVariable("PATH", pathEnvVar);
62+
}
63+
}
64+
65+
return this.ExecuteInner();
66+
#endif
67+
}
68+
69+
protected abstract bool ExecuteInner();
70+
71+
#if NETCOREAPP1_0
72+
private class CustomAssemblyLoader : AssemblyLoadContext
73+
{
74+
private readonly ContextAwareTask loaderTask;
75+
76+
internal CustomAssemblyLoader(ContextAwareTask loaderTask)
77+
{
78+
this.loaderTask = loaderTask;
79+
}
80+
81+
protected override Assembly Load(AssemblyName assemblyName)
82+
{
83+
string assemblyPath = Path.Combine(this.loaderTask.ManagedDllDirectory, assemblyName.Name) + ".dll";
84+
if (File.Exists(assemblyPath))
85+
{
86+
return LoadFromAssemblyPath(assemblyPath);
87+
}
88+
89+
return Default.LoadFromAssemblyName(assemblyName);
90+
}
91+
92+
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
93+
{
94+
string unmanagedDllPath = Directory.EnumerateFiles(
95+
this.loaderTask.UnmanagedDllDirectory,
96+
$"{unmanagedDllName}.*").Concat(
97+
Directory.EnumerateFiles(
98+
this.loaderTask.UnmanagedDllDirectory,
99+
$"lib{unmanagedDllName}.*"))
100+
.FirstOrDefault();
101+
if (unmanagedDllPath != null)
102+
{
103+
return this.LoadUnmanagedDllFromPath(unmanagedDllPath);
104+
}
105+
106+
return base.LoadUnmanagedDll(unmanagedDllName);
107+
}
108+
}
109+
#endif
110+
}
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>netcoreapp1.0;net45</TargetFrameworks>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Nerdbank.GitVersioning.LKG" Version="1.6.20-beta-gfea83a8c9e" PrivateAssets="all" />
9+
<PackageReference Include="NuProj.Common" Version="0.11.14-beta" PrivateAssets="all" />
10+
</ItemGroup>
11+
<ItemGroup Condition="'$(TargetFramework)' == 'net45' ">
12+
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="14.3" />
13+
</ItemGroup>
14+
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.0'">
15+
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.1.548" />
16+
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
17+
</ItemGroup>
18+
</Project>

src/NerdBank.GitVersioning/GitExtensions.cs

+49-22
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
/// </summary>
1616
public static class GitExtensions
1717
{
18-
/// <summary>
19-
/// An AppDomain-wide variable used on
20-
/// </summary>
21-
private static bool libgit2PathInitialized;
22-
2318
/// <summary>
2419
/// The 0.0 version.
2520
/// </summary>
@@ -277,6 +272,7 @@ public static IEnumerable<Commit> GetCommitsFromVersion(this Repository repo, Ve
277272
return possibleCommits;
278273
}
279274

275+
#if NET45
280276
/// <summary>
281277
/// Assists the operating system in finding the appropriate native libgit2 module.
282278
/// </summary>
@@ -308,28 +304,59 @@ public static bool TryHelpFindLibGit2NativeBinaries(string basePath)
308304
/// <returns><c>true</c> if the libgit2 native binaries have been found; <c>false</c> otherwise.</returns>
309305
public static bool TryHelpFindLibGit2NativeBinaries(string basePath, out string attemptedDirectory)
310306
{
311-
attemptedDirectory = null;
312-
if (!libgit2PathInitialized)
307+
attemptedDirectory = FindLibGit2NativeBinaries(basePath);
308+
if (Directory.Exists(attemptedDirectory))
313309
{
314-
#if !NET45
315-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
310+
AddDirectoryToPath(attemptedDirectory);
311+
return true;
312+
}
313+
314+
return false;
315+
}
316+
317+
/// <summary>
318+
/// Add a directory to the PATH environment variable if it isn't already present.
319+
/// </summary>
320+
/// <param name="directory">The directory to be added.</param>
321+
public static void AddDirectoryToPath(string directory)
322+
{
323+
Requires.NotNullOrEmpty(directory, nameof(directory));
324+
325+
string pathEnvVar = Environment.GetEnvironmentVariable("PATH");
326+
string[] searchPaths = pathEnvVar.Split(Path.PathSeparator);
327+
if (!searchPaths.Contains(directory, StringComparer.OrdinalIgnoreCase))
328+
{
329+
pathEnvVar += Path.PathSeparator + directory;
330+
Environment.SetEnvironmentVariable("PATH", pathEnvVar);
331+
}
332+
}
316333
#endif
317-
{
318-
attemptedDirectory = Path.Combine(basePath, "lib", "win32", IntPtr.Size == 4 ? "x86" : "x64");
319-
if (Directory.Exists(attemptedDirectory))
320-
{
321-
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + Path.PathSeparator + attemptedDirectory);
322-
}
323-
else
324-
{
325-
return false;
326-
}
327-
}
328334

329-
libgit2PathInitialized = true;
335+
/// <summary>
336+
/// Finds the directory that contains the appropriate native libgit2 module.
337+
/// </summary>
338+
/// <param name="basePath">The path to the directory that contains the lib folder.</param>
339+
/// <returns>Receives the directory that native binaries are expected.</returns>
340+
public static string FindLibGit2NativeBinaries(string basePath)
341+
{
342+
#if !NET45
343+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
344+
#endif
345+
{
346+
return Path.Combine(basePath, "lib", "win32", IntPtr.Size == 4 ? "x86" : "x64");
347+
}
348+
#if !NET45
349+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
350+
{
351+
return Path.Combine(basePath, "lib", "linux", IntPtr.Size == 4 ? "x86" : "x86_64");
352+
}
353+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
354+
{
355+
return Path.Combine(basePath, "lib", "osx");
330356
}
331357

332-
return libgit2PathInitialized;
358+
return null;
359+
#endif
333360
}
334361

335362
/// <summary>

src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>netstandard1.3;net45</TargetFrameworks>
3+
<TargetFrameworks>netcoreapp1.0;net45</TargetFrameworks>
44
<GenerateDocumentationFile>true</GenerateDocumentationFile>
55
</PropertyGroup>
66
<ItemGroup>

src/Nerdbank.GitVersioning.NuGet/Nerdbank.GitVersioning.NuGet.nuproj

+4-3
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@
8787
<TargetSubdirectory>MSBuildFull</TargetSubdirectory>
8888
</CrossTargetProjects>
8989
<CrossTargetProjects Include="@(_MSBuildProjectReferenceExistent)">
90-
<SetPlatform>TargetFramework=netstandard1.3;%(_MSBuildProjectReferenceExistent.SetPlatform)</SetPlatform>
91-
<SetTargetFramework>TargetFramework=netstandard1.3;ProjectHasSingleTargetFramework=false</SetTargetFramework>
90+
<SetPlatform>TargetFramework=netcoreapp1.0;%(_MSBuildProjectReferenceExistent.SetPlatform)</SetPlatform>
91+
<SetTargetFramework>TargetFramework=netcoreapp1.0;ProjectHasSingleTargetFramework=false</SetTargetFramework>
9292
<TargetSubdirectory>MSBuildCore</TargetSubdirectory>
9393
</CrossTargetProjects>
9494
<_MSBuildProjectReferenceExistent Remove="@(CrossTargetProjects)" />
@@ -97,7 +97,7 @@
9797
<!-- Build the default target of our P2P ref to ensure it builds. Hacky workaround.-->
9898
<MSBuild Projects="@(CrossTargetProjects)"
9999
BuildInParallel="true"
100-
Properties="TargetFramework=netstandard1.3;ProjectHasSingleTargetFramework=false"
100+
Properties="TargetFramework=netcoreapp1.0;ProjectHasSingleTargetFramework=false"
101101
Condition=" '$(BuildingInsideVisualStudio)' != 'true' " />
102102
</Target>
103103
<Target Name="SkipFrameworkAssemblies" AfterTargets="GetPackageFiles">
@@ -107,6 +107,7 @@
107107
!$([System.String]::new('%(TargetPath)').StartsWith('build\lib\')) and
108108
'%(FileName)' != 'NerdBank.GitVersioning' and
109109
'%(FileName)' != 'NerdBank.GitVersioning.Tasks' and
110+
'%(FileName)' != 'MSBuildExtensionTask' and
110111
'%(FileName)' != 'LibGit2Sharp' and
111112
'%(FileName)' != 'Validation' and
112113
'%(FileName)' != 'Newtonsoft.Json' and

src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs

+7-12
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@
22
{
33
using System;
44
using System.Collections.Generic;
5-
using System.ComponentModel;
6-
using System.Diagnostics;
75
using System.IO;
86
using System.Linq;
9-
using System.Runtime.InteropServices;
10-
using System.Text;
11-
using System.Text.RegularExpressions;
127
using Microsoft.Build.Framework;
138
using Microsoft.Build.Utilities;
14-
using Nerdbank.GitVersioning;
9+
using MSBuildExtensionTask;
1510

16-
public class GetBuildVersion : Task
11+
public class GetBuildVersion : ContextAwareTask
1712
{
1813
/// <summary>
1914
/// Initializes a new instance of the <see cref="GetBuildVersion"/> class.
@@ -153,12 +148,12 @@ public GetBuildVersion()
153148
[Output]
154149
public ITaskItem[] CloudBuildVersionVars { get; private set; }
155150

156-
public override bool Execute()
151+
protected override string UnmanagedDllDirectory => GitExtensions.FindLibGit2NativeBinaries(this.TargetsPath);
152+
153+
protected override bool ExecuteInner()
157154
{
158155
try
159156
{
160-
GitExtensions.TryHelpFindLibGit2NativeBinaries(this.TargetsPath);
161-
162157
var cloudBuild = CloudBuild.Active;
163158
var oracle = VersionOracle.Create(Directory.GetCurrentDirectory(), this.GitRepoRoot, cloudBuild);
164159
if (!string.IsNullOrEmpty(this.DefaultPublicRelease))
@@ -194,14 +189,14 @@ public override bool Execute()
194189
.Select(item => new TaskItem(item.Key, new Dictionary<string, string> { { "Value", item.Value } }))
195190
.ToArray();
196191
}
192+
193+
return !this.Log.HasLoggedErrors;
197194
}
198195
catch (ArgumentOutOfRangeException ex)
199196
{
200197
Log.LogErrorFromException(ex);
201198
return false;
202199
}
203-
204-
return true;
205200
}
206201
}
207202
}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>netstandard1.3;net45</TargetFrameworks>
3+
<TargetFrameworks>netcoreapp1.0;net45</TargetFrameworks>
44
<IsTool>true</IsTool>
55
</PropertyGroup>
66
<ItemGroup>
7-
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.1.0-preview-000458-02" Condition=" '$(TargetFramework)' == 'netstandard1.3' " />
8-
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="14.3" Condition=" '$(TargetFramework)' == 'net45' " />
9-
<PackageReference Include="PInvoke.MSCorEE" Version="0.3.152" Condition=" '$(TargetFramework)' == 'net45' " />
107
<PackageReference Include="Nerdbank.GitVersioning.LKG" Version="1.6.20-beta-gfea83a8c9e" />
118
<PackageReference Include="NuProj.Common" Version="0.11.14-beta" />
129
</ItemGroup>
10+
<ItemGroup Condition="'$(TargetFramework)' == 'net45' ">
11+
<PackageReference Include="PInvoke.MSCorEE" Version="0.3.152" />
12+
</ItemGroup>
1313
<ItemGroup>
14+
<ProjectReference Include="..\MSBuildExtensionTask\MSBuildExtensionTask.csproj" />
1415
<ProjectReference Include="..\NerdBank.GitVersioning\NerdBank.GitVersioning.csproj" />
1516
</ItemGroup>
1617
</Project>

0 commit comments

Comments
 (0)