diff --git a/eng/Packages.props b/eng/Packages.props index b8ebc96c259..1a98130d455 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -18,6 +18,7 @@ + diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index bd80b78d7d3..01e62af024a 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -2800,34 +2800,23 @@ public void PropertyFunctionVersionComparisonsFailsWithInvalidArguments(string b var expander = new Expander(pg, FileSystems.Default); string expectedMessage = ResourceUtilities.GetResourceString("InvalidVersionFormat"); - AssertThrows($"$([MSBuild]::VersionGreaterThan('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionGreaterThan('1.0.0', '{badVersion}'))"); + AssertThrows(expander, $"$([MSBuild]::VersionGreaterThan('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionGreaterThan('1.0.0', '{badVersion}'))", expectedMessage); - AssertThrows($"$([MSBuild]::VersionGreaterThanOrEquals('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionGreaterThanOrEquals('1.0.0', '{badVersion}'))"); + AssertThrows(expander, $"$([MSBuild]::VersionGreaterThanOrEquals('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionGreaterThanOrEquals('1.0.0', '{badVersion}'))", expectedMessage); - AssertThrows($"$([MSBuild]::VersionLessThan('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionLessThan('1.0.0', '{badVersion}'))"); + AssertThrows(expander, $"$([MSBuild]::VersionLessThan('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionLessThan('1.0.0', '{badVersion}'))", expectedMessage); - AssertThrows($"$([MSBuild]::VersionLessThanOrEquals('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionLessThanOrEquals('1.0.0', '{badVersion}'))"); + AssertThrows(expander, $"$([MSBuild]::VersionLessThanOrEquals('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionLessThanOrEquals('1.0.0', '{badVersion}'))", expectedMessage); - AssertThrows($"$([MSBuild]::VersionEquals('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionEquals('1.0.0', '{badVersion}'))"); + AssertThrows(expander, $"$([MSBuild]::VersionEquals('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionEquals('1.0.0', '{badVersion}'))", expectedMessage); - AssertThrows($"$([MSBuild]::VersionNotEquals('{badVersion}', '1.0.0'))"); - AssertThrows($"$([MSBuild]::VersionNotEquals('1.0.0', '{badVersion}'))"); - - void AssertThrows(string expression) - { - var ex = Assert.Throws( - () => expander.ExpandPropertiesLeaveTypedAndEscaped( - expression, - ExpanderOptions.ExpandProperties, - MockElementLocation.Instance)); - - Assert.Contains(expectedMessage, ex.Message); - } + AssertThrows(expander, $"$([MSBuild]::VersionNotEquals('{badVersion}', '1.0.0'))", expectedMessage); + AssertThrows(expander, $"$([MSBuild]::VersionNotEquals('1.0.0', '{badVersion}'))", expectedMessage); } [Theory] @@ -2843,22 +2832,64 @@ public void PropertyFunctionVersionComparisons(string a, string b, int expectedS var pg = new PropertyDictionary(); var expander = new Expander(pg, FileSystems.Default); - AssertSuccess(expectedSign > 0, $"$([MSBuild]::VersionGreaterThan('{a}', '{b}'))"); - AssertSuccess(expectedSign >= 0, $"$([MSBuild]::VersionGreaterThanOrEquals('{a}', '{b}'))"); - AssertSuccess(expectedSign < 0, $"$([MSBuild]::VersionLessThan('{a}', '{b}'))"); - AssertSuccess(expectedSign <= 0, $"$([MSBuild]::VersionLessThanOrEquals('{a}', '{b}'))"); - AssertSuccess(expectedSign == 0, $"$([MSBuild]::VersionEquals('{a}', '{b}'))"); - AssertSuccess(expectedSign != 0, $"$([MSBuild]::VersionNotEquals('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign > 0, $"$([MSBuild]::VersionGreaterThan('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign >= 0, $"$([MSBuild]::VersionGreaterThanOrEquals('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign < 0, $"$([MSBuild]::VersionLessThan('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign <= 0, $"$([MSBuild]::VersionLessThanOrEquals('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign == 0, $"$([MSBuild]::VersionEquals('{a}', '{b}'))"); + AssertSuccess(expander, expectedSign != 0, $"$([MSBuild]::VersionNotEquals('{a}', '{b}'))"); + } - void AssertSuccess(bool expected, string expression) - { - bool actual = (bool)expander.ExpandPropertiesLeaveTypedAndEscaped( + [Theory] + [InlineData("net45", ".NETFramework", "4.5")] + [InlineData("netcoreapp3.1", ".NETCoreApp", "3.1")] + [InlineData("netstandard2.1", ".NETStandard", "2.1")] + [InlineData("foo", "Unsupported", "0.0")] + public void PropertyFunctionTargetFrameworkParsing(string tfm, string expectedIdentifier, string expectedVersion) + { + var pg = new PropertyDictionary(); + var expander = new Expander(pg, FileSystems.Default); + + AssertSuccess(expander, expectedIdentifier, $"$([MSBuild]::GetTargetFrameworkIdentifier('{tfm}'))"); + AssertSuccess(expander, expectedVersion, $"$([MSBuild]::GetTargetFrameworkVersion('{tfm}'))"); + } + + [Theory] + [InlineData("net5.0", "net5.0", true)] + [InlineData("net45", "net46", false)] + [InlineData("net46", "net45", true)] + [InlineData("netcoreapp3.1", "netcoreapp1.0", true)] + [InlineData("netstandard1.6", "netstandard2.1", false)] + [InlineData("netcoreapp3.0", "netstandard2.1", true)] + [InlineData("net461", "netstandard1.0", true)] + [InlineData("foo", "netstandard1.0", false)] + public void PropertyFunctionTargetFrameworkComparisons(string tfm1, string tfm2, bool expectedFrameworkCompatible) + { + var pg = new PropertyDictionary(); + var expander = new Expander(pg, FileSystems.Default); + + AssertSuccess(expander, expectedFrameworkCompatible, $"$([MSBuild]::IsTargetFrameworkCompatible('{tfm1}', '{tfm2}'))"); + } + + private void AssertThrows(Expander expander, string expression, string expectedMessage) + { + var ex = Assert.Throws( + () => expander.ExpandPropertiesLeaveTypedAndEscaped( expression, ExpanderOptions.ExpandProperties, - MockElementLocation.Instance); + MockElementLocation.Instance)); - Assert.Equal(expected, actual); - } + Assert.Contains(expectedMessage, ex.Message); + } + + private void AssertSuccess(Expander expander, object expected, string expression) + { + var actual = expander.ExpandPropertiesLeaveTypedAndEscaped( + expression, + ExpanderOptions.ExpandProperties, + MockElementLocation.Instance); + + Assert.Equal(expected, actual); } /// diff --git a/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj b/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj index 5806db2d3e6..c36a51b66b8 100644 --- a/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj +++ b/src/Build.UnitTests/Microsoft.Build.Engine.UnitTests.csproj @@ -11,12 +11,17 @@ $(DefineConstants);NO_MSBUILDTASKHOST + + true + + all + diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index 3242c693ab3..06b66765bd1 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -3916,6 +3916,30 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.GetTargetFrameworkIdentifier), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArg(args, out string arg0)) + { + returnVal = IntrinsicFunctions.GetTargetFrameworkIdentifier(arg0); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.GetTargetFrameworkVersion), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArg(args, out string arg0)) + { + returnVal = IntrinsicFunctions.GetTargetFrameworkVersion(arg0); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.IsTargetFrameworkCompatible), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out string arg0, out string arg1)) + { + returnVal = IntrinsicFunctions.IsTargetFrameworkCompatible(arg0, arg1); + return true; + } + } } else if (_receiverType == typeof(Path)) { diff --git a/src/Build/Evaluation/IntrinsicFunctions.cs b/src/Build/Evaluation/IntrinsicFunctions.cs index 5ab70bf0ddf..55f9e185226 100644 --- a/src/Build/Evaluation/IntrinsicFunctions.cs +++ b/src/Build/Evaluation/IntrinsicFunctions.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; using System.Text.RegularExpressions; @@ -32,6 +30,8 @@ internal static class IntrinsicFunctions private static readonly Lazy RegistrySdkRegex = new Lazy(() => new Regex(@"^HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Microsoft SDKs\\Windows\\v(\d+\.\d+)$", RegexOptions.IgnoreCase)); #endif // FEATURE_WIN32_REGISTRY + private static readonly Lazy NuGetFramework = new Lazy(() => new NuGetFrameworkWrapper()); + /// /// Add two doubles /// @@ -480,6 +480,21 @@ internal static bool VersionLessThanOrEquals(string a, string b) return SimpleVersion.Parse(a) <= SimpleVersion.Parse(b); } + internal static string GetTargetFrameworkIdentifier(string tfm) + { + return NuGetFramework.Value.GetTargetFrameworkIdentifier(tfm); + } + + internal static string GetTargetFrameworkVersion(string tfm) + { + return NuGetFramework.Value.GetTargetFrameworkVersion(tfm); + } + + internal static bool IsTargetFrameworkCompatible(string target, string candidate) + { + return NuGetFramework.Value.IsCompatible(target, candidate); + } + public static string GetCurrentToolsDirectory() { return BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory; diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index c70ad9fc654..f90572b462b 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -154,6 +154,7 @@ + diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index 010deec0fb0..846868e1a22 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -1825,4 +1825,7 @@ Utilization: {0} Average Utilization: {1:###.0} Property initial value: $({0})="{1}" Source: {2} + + A required NuGet assembly was not found. Expected Path: {0} + \ No newline at end of file diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index f8af843e339..245e60f730e 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -122,6 +122,11 @@ Operaci nelze dokončit, protože funkce BeginBuild ještě nebyla zavolána. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Uživatelem zadané zpětné volání ProjectInstanceFactoryFunc vrátilo odkaz null. To není přípustné. diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index ff9d8afd0de..ec4322d75e3 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -122,6 +122,11 @@ Der Vorgang kann nicht abgeschlossen werden, da BeginBuild noch nicht aufgerufen wurde. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Ein benutzerseitig angegebener ProjectInstanceFactoryFunc-Rückruf hat einen NULL-Verweis zurückgegeben. Dies ist nicht zulässig. diff --git a/src/Build/Resources/xlf/Strings.en.xlf b/src/Build/Resources/xlf/Strings.en.xlf index 141c71a1f04..ca1dd2da57a 100644 --- a/src/Build/Resources/xlf/Strings.en.xlf +++ b/src/Build/Resources/xlf/Strings.en.xlf @@ -122,6 +122,11 @@ The operation cannot be completed because BeginBuild has not yet been called. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index 51195540f5c..2c081aa56d0 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -122,6 +122,11 @@ La operación no se puede completar porque todavía no se llamó a BeginBuild. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Se devolvió una referencia nula de una devolución de llamada de ProjectInstanceFactoryFunc proporcionada por el usuario, y no se permite. diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 3d6c1cc1861..16a7024cede 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -122,6 +122,11 @@ Impossible d'effectuer l'opération car la méthode BeginBuild n'a pas encore été appelée. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Une référence null a été retournée à partir d'un rappel ProjectInstanceFactoryFunc fourni par l'utilisateur. Ceci n'est pas autorisé. diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 13e46cf8fba..7cf9c7da35c 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -122,6 +122,11 @@ Non è possibile completare l'operazione perché BeginBuild non è stato ancora chiamato. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: è stato restituito un riferimento Null da un callback ProjectInstanceFactoryFunc fornito dall'utente. Questa operazione non è consentita. diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 57b78eab025..269832f4806 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -122,6 +122,11 @@ BeginBuild がまだ呼び出されていないため、操作を完了できません。 + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: ユーザー提供の ProjectInstanceFactoryFunc コールバックから null 参照が返されました。これは許可されていません。 diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index 56f87996e63..d969c555020 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -122,6 +122,11 @@ BeginBuild가 아직 호출되지 않았으므로 작업을 완료할 수 없습니다. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: 사용자가 제공한 ProjectInstanceFactoryFunc 콜백에서 Null 참조가 반환되었습니다. 이는 허용되지 않습니다. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index f4d4a334239..01ed823e267 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -122,6 +122,11 @@ Nie można zakończyć operacji, ponieważ metoda BeginBuild nie została jeszcze wywołana. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Z podanego przez użytkownika wywołania zwrotnego ProjectInstanceFactoryFunc została zwrócona pusta referencja. Jest to niedozwolone. diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index d89955e9761..1ebadba8527 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -122,6 +122,11 @@ A operação não pode ser concluída porque BeginBuild ainda não foi chamado. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Uma referência nula foi devolvida de um retorno de chamada do ProjectInstanceFactoryFunc fornecido pelo usuário. Isso não é permitido. diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 8adb28739fd..0e8728ed6ca 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -122,6 +122,11 @@ Не удается завершить операцию, так как ещё не был вызван BeginBuild. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: ссылка со значением NULL была возвращена из предоставленного пользователем вызова ProjectInstanceFactoryFunc. Это недопустимо. diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index 32881e71a8e..19de9e7a29a 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -122,6 +122,11 @@ BeginBuild henüz çağrılmadığı için işlem tamamlanamıyor. + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: Kullanıcı tarafından sağlanan bir ProjectInstanceFactoryFunc geri aramasında null başvuru var. Buna izin verilmez. diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index a2dafa5caa3..3b1f23c2414 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -122,6 +122,11 @@ 无法完成该操作,因为尚未调用 BeginBuild。 + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: 从用户提供的 ProjectInstanceFactoryFunc 回调中返回了一个空引用。这是不允许的。 diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index 80a94bdb226..b8349400ff0 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -122,6 +122,11 @@ 無法完成作業,因為尚未呼叫 BeginBuild。 + + A required NuGet assembly was not found. Expected Path: {0} + A required NuGet assembly was not found. Expected Path: {0} + + MSB4253: A null reference was returned from a user-provided ProjectInstanceFactoryFunc callback. This is not allowed. MSB4253: 使用者提供的 ProjectInstanceFactoryFunc 回呼傳回了 null 參考。這是不允許的情況。 diff --git a/src/Build/Utilities/NuGetFrameworkWrapper.cs b/src/Build/Utilities/NuGetFrameworkWrapper.cs new file mode 100644 index 00000000000..117e85acd93 --- /dev/null +++ b/src/Build/Utilities/NuGetFrameworkWrapper.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft. 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.Reflection; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.Evaluation +{ + /// + /// Wraps the NuGet.Frameworks assembly, which is referenced by reflection. + /// + internal class NuGetFrameworkWrapper + { + /// + /// NuGet Types + /// + private static MethodInfo ParseMethod; + private static MethodInfo IsCompatibleMethod; + private static object DefaultCompatibilityProvider; + private static PropertyInfo FrameworkProperty; + private static PropertyInfo VersionProperty; + + public NuGetFrameworkWrapper() + { + /// Resolve the location of the NuGet.Frameworks assembly + var assemblyDirectory = BuildEnvironmentHelper.Instance.Mode == BuildEnvironmentMode.VisualStudio ? + Path.Combine(BuildEnvironmentHelper.Instance.VisualStudioInstallRootDirectory, "Common7", "IDE", "CommonExtensions", "Microsoft", "NuGet") : + BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory; + try + { + var NuGetAssembly = Assembly.LoadFile(Path.Combine(assemblyDirectory, "NuGet.Frameworks.dll")); + var NuGetFramework = NuGetAssembly.GetType("NuGet.Frameworks.NuGetFramework"); + var NuGetFrameworkCompatibilityProvider = NuGetAssembly.GetType("NuGet.Frameworks.CompatibilityProvider"); + var NuGetFrameworkDefaultCompatibilityProvider = NuGetAssembly.GetType("NuGet.Frameworks.DefaultCompatibilityProvider"); + ParseMethod = NuGetFramework.GetMethod("Parse", new Type[] { typeof(string) }); + IsCompatibleMethod = NuGetFrameworkCompatibilityProvider.GetMethod("IsCompatible"); + DefaultCompatibilityProvider = NuGetFrameworkDefaultCompatibilityProvider.GetMethod("get_Instance").Invoke(null, new object[] { }); + FrameworkProperty = NuGetFramework.GetProperty("Framework"); + VersionProperty = NuGetFramework.GetProperty("Version"); + } + catch + { + throw new InternalErrorException(string.Format(AssemblyResources.GetString("NuGetAssemblyNotFound"), assemblyDirectory)); + } + } + + private object Parse(string tfm) + { + return ParseMethod.Invoke(null, new object[] { tfm }); + } + + public string GetTargetFrameworkIdentifier(string tfm) + { + return FrameworkProperty.GetValue(Parse(tfm)) as string; + } + + public string GetTargetFrameworkVersion(string tfm) + { + return (VersionProperty.GetValue(Parse(tfm)) as Version).ToString(2); + } + + public bool IsCompatible(string target, string candidate) + { + return Convert.ToBoolean(IsCompatibleMethod.Invoke(DefaultCompatibilityProvider, new object[] { Parse(target), Parse(candidate) })); + } + } +}