From d1cd9cce4d4d4cca4b40f4d77b86718aca9c71f4 Mon Sep 17 00:00:00 2001 From: Mikayla Hutchinson Date: Thu, 3 Dec 2020 21:55:14 -0500 Subject: [PATCH] Make runtime resolution more robust --- Directory.Build.props | 1 + .../RuntimeInfo.cs | 119 +++++++++--------- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 09d8a82..616cad7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,7 @@ https://github.com/mono/t4 git $(MSBuildThisFileDirectory)packages\$(Configuration) + 9.0 diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs index d64b5d6..a1360e5 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs @@ -27,6 +27,8 @@ using System; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; namespace Mono.TextTemplating.CodeCompilation { @@ -49,30 +51,28 @@ namespace Mono.TextTemplating.CodeCompilation public string CscPath { get; private set; } public bool IsValid => Error == null; + public string RefAssembliesDir { get; private set; } + public string RuntimeFacadesDir { get; internal set; } + public static RuntimeInfo GetRuntime () { - var monoFx = GetMonoRuntime (); - if (monoFx.IsValid) { - return monoFx; + if (Type.GetType ("Mono.Runtime") != null) + { + return GetMonoRuntime (); } - var netFx = GetNetFrameworkRuntime (); - if (netFx.IsValid) { - return netFx; + else if (RuntimeInformation.FrameworkDescription.StartsWith (".NET Framework")) + { + return GetNetFrameworkRuntime (); } - var coreFx = GetDotNetCoreRuntime (); - if (coreFx.IsValid) { - return coreFx; + else + { + return GetDotNetCoreSdk (); } - return FromError (RuntimeKind.Mono, "Could not find any valid runtime" ); } - public static RuntimeInfo GetMonoRuntime () + static RuntimeInfo GetMonoRuntime () { - if (Type.GetType ("Mono.Runtime") == null) { - return FromError (RuntimeKind.Mono, "Current runtime is not Mono" ); - } - - var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); + var runtimeDir = Path.GetDirectoryName (typeof (object).Assembly.Location); var csc = Path.Combine (runtimeDir, "csc.exe"); if (!File.Exists (csc)) { return FromError (RuntimeKind.Mono, "Could not find csc in host Mono installation" ); @@ -80,52 +80,70 @@ namespace Mono.TextTemplating.CodeCompilation return new RuntimeInfo (RuntimeKind.Mono) { CscPath = csc, - RuntimeDir = runtimeDir + RuntimeDir = runtimeDir, + RuntimeFacadesDir = Path.Combine (runtimeDir, "Facades"), }; } - public static RuntimeInfo GetNetFrameworkRuntime () + static RuntimeInfo GetNetFrameworkRuntime () { - var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); + var runtimeDir = Path.GetDirectoryName (typeof (object).Assembly.Location); var csc = Path.Combine (runtimeDir, "csc.exe"); if (!File.Exists (csc)) { return FromError (RuntimeKind.NetFramework, "Could not find csc in host .NET Framework installation"); } return new RuntimeInfo (RuntimeKind.NetFramework) { CscPath = csc, - RuntimeDir = runtimeDir + RuntimeDir = runtimeDir, + RuntimeFacadesDir = runtimeDir, }; } - static string FindDotNetRoot () + static bool TryParseVersionIgnoringSuffix(string versionString, out Version version) { - string dotnetRoot; - bool DotnetRootIsValid () => !string.IsNullOrEmpty (dotnetRoot) && (File.Exists (Path.Combine (dotnetRoot, "dotnet")) || File.Exists (Path.Combine (dotnetRoot, "dotnet.exe"))); + var dashIdx = versionString.IndexOf (';'); + if (dashIdx > -1) { + versionString = versionString.Substring (0, dashIdx); + } + return Version.TryParse (versionString, out version); + } - string FindInPath (string name) => (Environment.GetEnvironmentVariable ("PATH") ?? "") - .Split (new [] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries) - .Select (p => Path.Combine (p, name)) - .FirstOrDefault (File.Exists); + static RuntimeInfo GetDotNetCoreSdk () + { + static bool DotnetRootIsValid (string root) => !string.IsNullOrEmpty (root) && (File.Exists (Path.Combine (root, "dotnet")) || File.Exists (Path.Combine (root, "dotnet.exe"))); - dotnetRoot = Environment.GetEnvironmentVariable ("DOTNET_ROOT"); - if (DotnetRootIsValid ()) { - return dotnetRoot; + // this should get us something like /usr/local/share/dotnet/shared/Microsoft.NETCore.App/5.0.0 + var runtimeDir = Path.GetDirectoryName (typeof (object).Assembly.Location); + var dotnetRoot = Path.GetDirectoryName (Path.GetDirectoryName (Path.GetDirectoryName (runtimeDir))); + + if (!DotnetRootIsValid (dotnetRoot)) { + // this may happen on single file deployments + return FromError (RuntimeKind.NetCore, "Not a valid .NET Core host"); } - // this should get us something like /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.1.2/System.Runtime.dll - var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); - dotnetRoot = Path.GetDirectoryName (Path.GetDirectoryName (Path.GetDirectoryName (runtimeDir))); - - if (DotnetRootIsValid ()) { - return dotnetRoot; + var hostVersion = Environment.Version; + if (hostVersion.Major < 5) + { + var versionPathComponent = Path.GetFileName (runtimeDir); + if (!TryParseVersionIgnoringSuffix (versionPathComponent, out hostVersion)) + { + return FromError (RuntimeKind.NetCore, "Could not determine host runtime version"); + } } - dotnetRoot = Path.GetDirectoryName (FindInPath (Path.DirectorySeparatorChar == '\\' ? "dotnet.exe" : "dotnet")); - if (DotnetRootIsValid ()) { - return dotnetRoot; + string MakeCscPath (string d) => Path.Combine (d, "Roslyn", "bincore", "csc.dll"); + var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d))); + if (sdkDir == null) { + return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK"); } - return null; + // it's ok if this is null, we may be running on an older SDK that didn't support packs + var refAssembliesDir = FindHighestVersionedDirectory ( + Path.Combine (dotnetRoot, "packs", "Microsoft.NETCore.App.Ref"), + d => File.Exists (Path.Combine (d, $"net{hostVersion.Major}.{hostVersion.Minor}", "System.Runtime.dll")) + ); + + return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, RefAssembliesDir = refAssembliesDir, CscPath = MakeCscPath (sdkDir) }; } static string FindHighestVersionedDirectory (string parentFolder, Func validate) @@ -143,26 +161,5 @@ namespace Mono.TextTemplating.CodeCompilation } return bestMatch; } - - public static RuntimeInfo GetDotNetCoreRuntime () - { - var dotnetRoot = FindDotNetRoot (); - if (dotnetRoot == null) { - return FromError (RuntimeKind.NetCore, "Could not find .NET Core installation" ); - } - - string MakeCscPath (string d) => Path.Combine (d, "Roslyn", "bincore", "csc.dll"); - var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d))); - if (sdkDir == null) { - return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK" ); - } - - var runtimeDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "shared", "Microsoft.NETCore.App"), d => File.Exists (Path.Combine (d, "System.Runtime.dll"))); - if (runtimeDir == null) { - return FromError (RuntimeKind.NetCore, "Could not find System.Runtime.dll in any .NET shared runtime" ); - } - - return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, CscPath = MakeCscPath (sdkDir) }; - } } }