From 853887b4e84df1965794802b7683f3a9aca3e930 Mon Sep 17 00:00:00 2001 From: Staffan Gustafsson Date: Wed, 30 Nov 2022 17:15:12 +0100 Subject: Adding support for DotNetCoreSdkSearch and DotNetCoreSdkCompatibilityCheck --- src/ext/NetFx/be/detectnetcore.cpp | 2 +- src/ext/NetFx/be/detectnetcoresdk.cpp | 122 +++++++++ src/ext/NetFx/be/detectnetcoresdk.h | 9 + src/ext/NetFx/be/netfxbe.vcxproj | 2 + src/ext/NetFx/be/netfxsearch.cpp | 25 +- src/ext/NetFx/be/netfxsearch.h | 6 + src/ext/NetFx/be/precomp.h | 1 + src/ext/NetFx/netcoresearch/netcoresearch.cpp | 216 ++++++++++++--- .../UsingDotNetCorePackages/NetCore3.1.12_x64.wxs | 19 ++ .../UsingDotNetCorePackages/NetCore3.1.12_x86.wxs | 19 ++ .../UsingDotNetCorePackages/NetCore3_Platform.wxi | 14 + src/ext/NetFx/wixext/NetFxCompiler.cs | 293 +++++++++++++++++---- src/ext/NetFx/wixext/NetfxTableDefinitions.cs | 2 +- .../Symbols/NetFxDotNetCompatibilityCheckSymbol.cs | 34 +-- .../wixext/Symbols/NetFxNetCoreSearchSdkSymbol.cs | 64 +++++ .../NetFx/wixext/Symbols/NetfxSymbolDefinitions.cs | 9 +- 16 files changed, 718 insertions(+), 119 deletions(-) create mode 100644 src/ext/NetFx/be/detectnetcoresdk.cpp create mode 100644 src/ext/NetFx/be/detectnetcoresdk.h create mode 100644 src/ext/NetFx/wixext/Symbols/NetFxNetCoreSearchSdkSymbol.cs (limited to 'src/ext') diff --git a/src/ext/NetFx/be/detectnetcore.cpp b/src/ext/NetFx/be/detectnetcore.cpp index 42156692..aeb04203 100644 --- a/src/ext/NetFx/be/detectnetcore.cpp +++ b/src/ext/NetFx/be/detectnetcore.cpp @@ -60,7 +60,7 @@ HRESULT DetectNetCore( hr = StrAllocFormatted(&sczExePath, L"%ls%ls\\netcoresearch.exe", wzBaseDirectory, wzPlatformName); BextExitOnFailure(hr, "Failed to build netcoresearch.exe path."); - hr = StrAllocFormatted(&sczCommandLine, L"\"%ls\" %ls %ls", sczExePath, wzMajorVersion, wzRuntimeType); + hr = StrAllocFormatted(&sczCommandLine, L"\"%ls\" runtime %ls %ls", sczExePath, wzMajorVersion, wzRuntimeType); BextExitOnFailure(hr, "Failed to build netcoresearch.exe command line."); hr = ProcExecute(sczExePath, sczCommandLine, &hProcess, NULL, &hStdOutErr); diff --git a/src/ext/NetFx/be/detectnetcoresdk.cpp b/src/ext/NetFx/be/detectnetcoresdk.cpp new file mode 100644 index 00000000..08b18334 --- /dev/null +++ b/src/ext/NetFx/be/detectnetcoresdk.cpp @@ -0,0 +1,122 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +HRESULT DetectNetCoreSdk( + __in NETFX_NET_CORE_PLATFORM platform, + __in LPCWSTR wzVersion, + __in LPCWSTR wzBaseDirectory, + __inout LPWSTR* psczLatestVersion + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzPlatformName = NULL; + LPWSTR sczExePath = NULL; + LPWSTR sczCommandLine = NULL; + HANDLE hProcess = NULL; + HANDLE hStdOutErr = INVALID_HANDLE_VALUE; + BYTE* rgbOutput = NULL; + DWORD cbOutput = 0; + DWORD cbTotalRead = 0; + DWORD cbRead = 0; + DWORD dwExitCode = 0; + + ReleaseNullStr(*psczLatestVersion); + + switch (platform) + { + case NETFX_NET_CORE_PLATFORM_ARM64: + wzPlatformName = L"arm64"; + break; + case NETFX_NET_CORE_PLATFORM_X64: + wzPlatformName = L"x64"; + break; + case NETFX_NET_CORE_PLATFORM_X86: + wzPlatformName = L"x86"; + break; + default: + BextExitWithRootFailure(hr, E_INVALIDARG, "Unknown platform: %u", platform); + break; + } + + hr = StrAllocFormatted(&sczExePath, L"%ls%ls\\netcoresearch.exe", wzBaseDirectory, wzPlatformName); + BextExitOnFailure(hr, "Failed to build netcoresearch.exe path."); + + hr = StrAllocFormatted(&sczCommandLine, L"\"%ls\" sdk %ls", sczExePath, wzVersion); + BextExitOnFailure(hr, "Failed to build netcoresearch.exe command line."); + + hr = ProcExecute(sczExePath, sczCommandLine, &hProcess, NULL, &hStdOutErr); + if (HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH) == hr) + { + ExitFunction1(hr = S_FALSE); + } + BextExitOnFailure(hr, "Failed to run: %ls", sczCommandLine); + + cbOutput = 64; + + rgbOutput = static_cast(MemAlloc(cbOutput, TRUE)); + BextExitOnNull(rgbOutput, hr, E_OUTOFMEMORY, "Failed to alloc output string."); + + while (::ReadFile(hStdOutErr, rgbOutput + cbTotalRead, cbOutput - cbTotalRead, &cbRead, NULL)) + { + cbTotalRead += cbRead; + + if (cbTotalRead == cbOutput) + { + cbOutput *= 2; + + const LPVOID pvNew = MemReAlloc(rgbOutput, cbOutput, TRUE); + BextExitOnNull(pvNew, hr, E_OUTOFMEMORY, "Failed to realloc output string."); + + rgbOutput = static_cast(pvNew); + } + } + + if (ERROR_BROKEN_PIPE != ::GetLastError()) + { + BextExitWithLastError(hr, "Failed to read netcoresearch.exe output."); + } + + hr = ProcWaitForCompletion(hProcess, INFINITE, &dwExitCode); + BextExitOnFailure(hr, "Failed to wait for netcoresearch.exe to exit."); + + if (0 != dwExitCode) + { + BextExitWithRootFailure(hr, E_UNEXPECTED, "netcoresearch.exe failed with exit code: 0x%x\r\nOutput:\r\n%hs", dwExitCode, rgbOutput); + } + + if (*rgbOutput) + { + hr = StrAllocStringAnsi(psczLatestVersion, reinterpret_cast(rgbOutput), 0, CP_UTF8); + BextExitOnFailure(hr, "Failed to widen output string: %hs", rgbOutput); + } + +LExit: + ReleaseFileHandle(hStdOutErr); + ReleaseHandle(hProcess); + ReleaseMem(rgbOutput); + ReleaseStr(sczCommandLine); + ReleaseStr(sczExePath); + + return hr; +} + +HRESULT NetfxPerformDetectNetCoreSdk( + __in LPCWSTR wzVariable, + __in NETFX_SEARCH* pSearch, + __in IBundleExtensionEngine* pEngine, + __in LPCWSTR wzBaseDirectory + ) +{ + HRESULT hr = S_OK; + LPWSTR sczLatestVersion = nullptr; + const auto& searchParams = pSearch->NetCoreSdkSearch; + hr = DetectNetCoreSdk(searchParams.platform, searchParams.sczVersion, wzBaseDirectory, &sczLatestVersion); + BextExitOnFailure(hr, "DetectNetCoreSdk failed."); + + hr = pEngine->SetVariableVersion(wzVariable, sczLatestVersion); + BextExitOnFailure(hr, "Failed to set variable '%ls' to '%ls'", wzVariable, sczLatestVersion); + +LExit: + return hr; +} diff --git a/src/ext/NetFx/be/detectnetcoresdk.h b/src/ext/NetFx/be/detectnetcoresdk.h new file mode 100644 index 00000000..025deaa2 --- /dev/null +++ b/src/ext/NetFx/be/detectnetcoresdk.h @@ -0,0 +1,9 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +HRESULT NetfxPerformDetectNetCoreSdk( + __in LPCWSTR wzVariable, + __in NETFX_SEARCH* pSearch, + __in IBundleExtensionEngine* pEngine, + __in LPCWSTR wzBaseDirectory + ); diff --git a/src/ext/NetFx/be/netfxbe.vcxproj b/src/ext/NetFx/be/netfxbe.vcxproj index d1084dd1..0408da72 100644 --- a/src/ext/NetFx/be/netfxbe.vcxproj +++ b/src/ext/NetFx/be/netfxbe.vcxproj @@ -47,6 +47,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/src/ext/NetFx/be/netfxsearch.cpp b/src/ext/NetFx/be/netfxsearch.cpp index 3c12161d..671e7546 100644 --- a/src/ext/NetFx/be/netfxsearch.cpp +++ b/src/ext/NetFx/be/netfxsearch.cpp @@ -15,7 +15,7 @@ STDMETHODIMP NetfxSearchParseFromXml( BSTR bstrNodeName = NULL; // Select Netfx search nodes. - hr = XmlSelectNodes(pixnBundleExtension, L"NetFxNetCoreSearch", &pixnNodes); + hr = XmlSelectNodes(pixnBundleExtension, L"NetFxNetCoreSearch|NetFxNetCoreSdkSearch", &pixnNodes); BextExitOnFailure(hr, "Failed to select Netfx search nodes."); // Get Netfx search node count. @@ -50,18 +50,32 @@ STDMETHODIMP NetfxSearchParseFromXml( { pSearch->Type = NETFX_SEARCH_TYPE_NET_CORE_SEARCH; + auto& netCoreSearch = pSearch->NetCoreSearch; // @RuntimeType - hr = XmlGetAttributeUInt32(pixnNode, L"RuntimeType", reinterpret_cast(&pSearch->NetCoreSearch.runtimeType)); + hr = XmlGetAttributeUInt32(pixnNode, L"RuntimeType", reinterpret_cast(&netCoreSearch.runtimeType)); BextExitOnFailure(hr, "Failed to get @RuntimeType."); // @Platform - hr = XmlGetAttributeUInt32(pixnNode, L"Platform", reinterpret_cast(&pSearch->NetCoreSearch.platform)); + hr = XmlGetAttributeUInt32(pixnNode, L"Platform", reinterpret_cast(&netCoreSearch.platform)); BextExitOnFailure(hr, "Failed to get @Platform."); // @MajorVersion - hr = XmlGetAttributeEx(pixnNode, L"MajorVersion", &pSearch->NetCoreSearch.sczMajorVersion); + hr = XmlGetAttributeEx(pixnNode, L"MajorVersion", &netCoreSearch.sczMajorVersion); BextExitOnFailure(hr, "Failed to get @MajorVersion."); } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"NetFxNetCoreSdkSearch", -1)) + { + pSearch->Type = NETFX_SEARCH_TYPE_NET_CORE_SDK_SEARCH; + + auto& netCoreSdkSearch = pSearch->NetCoreSdkSearch; + // @Platform + hr = XmlGetAttributeUInt32(pixnNode, L"Platform", reinterpret_cast(&netCoreSdkSearch.platform)); + BextExitOnFailure(hr, "Failed to get @Platform."); + + // @Version + hr = XmlGetAttributeEx(pixnNode, L"Version", &netCoreSdkSearch.sczVersion); + BextExitOnFailure(hr, "Failed to get @Version."); + } else { BextExitWithRootFailure(hr, E_UNEXPECTED, "Unexpected element name: %ls", bstrNodeName); @@ -115,6 +129,9 @@ STDMETHODIMP NetfxSearchExecute( case NETFX_SEARCH_TYPE_NET_CORE_SEARCH: hr = NetfxPerformDetectNetCore(wzVariable, pSearch, pEngine, wzBaseDirectory); break; + case NETFX_SEARCH_TYPE_NET_CORE_SDK_SEARCH: + hr = NetfxPerformDetectNetCoreSdk(wzVariable, pSearch, pEngine, wzBaseDirectory); + break; default: hr = E_UNEXPECTED; } diff --git a/src/ext/NetFx/be/netfxsearch.h b/src/ext/NetFx/be/netfxsearch.h index ae250690..f4e4db01 100644 --- a/src/ext/NetFx/be/netfxsearch.h +++ b/src/ext/NetFx/be/netfxsearch.h @@ -8,6 +8,7 @@ enum NETFX_SEARCH_TYPE { NETFX_SEARCH_TYPE_NONE, NETFX_SEARCH_TYPE_NET_CORE_SEARCH, + NETFX_SEARCH_TYPE_NET_CORE_SDK_SEARCH, }; enum NETFX_NET_CORE_RUNTIME_TYPE @@ -40,6 +41,11 @@ typedef struct _NETFX_SEARCH NETFX_NET_CORE_PLATFORM platform; LPWSTR sczMajorVersion; } NetCoreSearch; + struct + { + NETFX_NET_CORE_PLATFORM platform; + LPWSTR sczVersion; + } NetCoreSdkSearch; }; } NETFX_SEARCH; diff --git a/src/ext/NetFx/be/precomp.h b/src/ext/NetFx/be/precomp.h index 33aea9bc..4a774200 100644 --- a/src/ext/NetFx/be/precomp.h +++ b/src/ext/NetFx/be/precomp.h @@ -30,4 +30,5 @@ #include "..\..\beDecor.h" #include "netfxsearch.h" #include "detectnetcore.h" +#include "detectnetcoresdk.h" #include "NetfxBundleExtension.h" diff --git a/src/ext/NetFx/netcoresearch/netcoresearch.cpp b/src/ext/NetFx/netcoresearch/netcoresearch.cpp index 517f6ac4..5cf6d10b 100644 --- a/src/ext/NetFx/netcoresearch/netcoresearch.cpp +++ b/src/ext/NetFx/netcoresearch/netcoresearch.cpp @@ -2,16 +2,36 @@ #include "precomp.h" +enum class NETCORESEARCHKIND +{ + None, + Runtime, + Sdk, +}; + struct NETCORESEARCH_STATE { - LPCWSTR wzTargetName; - DWORD dwMajorVersion; + NETCORESEARCHKIND Kind = NETCORESEARCHKIND::None; + union + { + struct + { + LPCWSTR wzTargetName; + DWORD dwMajorVersion; + } Runtime; + struct + { + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwFeatureBand; + } + Sdk; + } Data; VERUTIL_VERSION* pVersion; }; static HRESULT GetDotnetEnvironmentInfo( - __in DWORD dwMajorVersion, - __in_z LPCWSTR wzTargetName, + __in NETCORESEARCH_STATE& pSearchState, __inout VERUTIL_VERSION** ppVersion ); static void HOSTFXR_CALLTYPE GetDotnetEnvironmentInfoResult( @@ -19,24 +39,28 @@ static void HOSTFXR_CALLTYPE GetDotnetEnvironmentInfoResult( __in LPVOID pvContext ); +bool string_equal_invariant(__in PCWSTR const x,__in PCWSTR const y) { return CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, x, -1, y, -1); } + +HRESULT get_search_state_from_arguments(__in int argc, __in LPWSTR argv[], __out NETCORESEARCH_STATE& searchState); + int __cdecl wmain(int argc, LPWSTR argv[]) { HRESULT hr = S_OK; - DWORD dwMajorVersion = 0; VERUTIL_VERSION* pVersion = NULL; + NETCORESEARCH_STATE searchState = {}; + + ::SetConsoleCP(CP_UTF8); ConsoleInitialize(); - if (argc != 3) + hr = get_search_state_from_arguments(argc, argv, OUT searchState); + if (FAILED(hr)) { - ExitFunction1(hr = E_INVALIDARG); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse arguments."); } - hr = StrStringToUInt32(argv[1], 0, reinterpret_cast(&dwMajorVersion)); - ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get target version from: %ls", argv[1]); + hr = GetDotnetEnvironmentInfo(searchState, &pVersion); - hr = GetDotnetEnvironmentInfo(dwMajorVersion, argv[2], &pVersion); - ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to search for .NET Core."); if (pVersion) { @@ -49,9 +73,65 @@ LExit: return hr; } +HRESULT get_search_state_from_arguments(int argc, LPWSTR argv[], __out NETCORESEARCH_STATE& searchState) +{ + HRESULT hr = S_OK; + searchState = {}; + const auto searchKind = argv[1]; + + if (argc < 3) + { + ExitFunction1(hr = E_INVALIDARG); + } + + + if (string_equal_invariant(searchKind, L"runtime")) + { + if (argc != 4) + { + ExitFunction1(hr = E_INVALIDARG); + } + searchState.Kind = NETCORESEARCHKIND::Runtime; + + const PCWSTR majorVersion = argv[2]; + const PCWSTR targetName = argv[3]; + + auto& data = searchState.Data.Runtime; + + data.wzTargetName = targetName; + hr = StrStringToUInt32(majorVersion, 0, reinterpret_cast(&data.dwMajorVersion)); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get target version from: %ls", majorVersion); + } + else if(string_equal_invariant(searchKind, L"sdk")) + { + searchState.Kind = NETCORESEARCHKIND::Sdk; + + const PCWSTR version = argv[2]; + + VERUTIL_VERSION* sdkVersion = nullptr; + hr = VerParseVersion(version, 0, FALSE, &sdkVersion); + if (FAILED(hr)) + { + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse version from: %ls", version); + } + + auto& data = searchState.Data.Sdk; + + data.dwMajorVersion = sdkVersion->dwMajor; + data.dwMinorVersion = sdkVersion->dwMinor; + data.dwFeatureBand = sdkVersion->dwPatch; + + VerFreeVersion(sdkVersion); + } + +LExit: + return hr; +} + + + static HRESULT GetDotnetEnvironmentInfo( - __in DWORD dwMajorVersion, - __in_z LPCWSTR wzTargetName, + __in NETCORESEARCH_STATE& state, __inout VERUTIL_VERSION** ppVersion ) { @@ -60,10 +140,6 @@ static HRESULT GetDotnetEnvironmentInfo( LPWSTR sczHostfxrPath = NULL; HMODULE hModule = NULL; hostfxr_get_dotnet_environment_info_fn pfnGetDotnetEnvironmentInfo = NULL; - NETCORESEARCH_STATE state = { }; - - state.dwMajorVersion = dwMajorVersion; - state.wzTargetName = wzTargetName; hr = PathForCurrentProcess(&sczProcessPath, NULL); ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to get process path."); @@ -102,50 +178,108 @@ LExit: return hr; } +bool matches_feature_band(const int requested, const int actual) +{ + // we have not requested a match on feature band, so skip the check + if (requested == 0) return true; + + const int requestedBand = requested / 100; + const int actualBand = actual / 100; + + if (actualBand != requestedBand) return false; + + return actual >= requested; +} + static void HOSTFXR_CALLTYPE GetDotnetEnvironmentInfoResult( __in const hostfxr_dotnet_environment_info* pInfo, __in LPVOID pvContext ) { - NETCORESEARCH_STATE* pState = reinterpret_cast(pvContext); + NETCORESEARCH_STATE* pState = static_cast(pvContext); HRESULT hr = S_OK; - VERUTIL_VERSION* pFrameworkVersion = NULL; + VERUTIL_VERSION* pDotnetVersion = nullptr; int nCompare = 0; - for (size_t i = 0; i < pInfo->framework_count; ++i) - { - const hostfxr_dotnet_environment_framework_info* pFrameworkInfo = pInfo->frameworks + i; - ReleaseVerutilVersion(pFrameworkVersion); - if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pState->wzTargetName, -1, pFrameworkInfo->name, -1)) + if (pState->Kind == NETCORESEARCHKIND::Sdk) + { + auto& sdkData = pState->Data.Sdk; + for (size_t i = 0; i < pInfo->sdk_count; ++i) { - continue; - } + const hostfxr_dotnet_environment_sdk_info* pSdkInfo = pInfo->sdks + i; + ReleaseVerutilVersion(pDotnetVersion); - hr = VerParseVersion(pFrameworkInfo->version, 0, FALSE, &pFrameworkVersion); - ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse framework version: %ls", pFrameworkInfo->version); + hr = VerParseVersion(pSdkInfo->version, 0, FALSE, &pDotnetVersion); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse sdk version: %ls", pSdkInfo->version); - if (pFrameworkVersion->dwMajor != pState->dwMajorVersion) - { - continue; - } + if (pDotnetVersion->dwMajor != sdkData.dwMajorVersion) + { + continue; + } + if (!matches_feature_band(sdkData.dwFeatureBand, pDotnetVersion->dwPatch)) + { + continue; + } - if (pState->pVersion) + if (pState->pVersion) + { + hr = VerCompareParsedVersions(pState->pVersion, pDotnetVersion, &nCompare); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to compare versions."); + + if (nCompare > -1) + { + continue; + } + } + + ReleaseVerutilVersion(pState->pVersion); + pState->pVersion = pDotnetVersion; + pDotnetVersion = nullptr; + } + } + else if(pState->Kind == NETCORESEARCHKIND::Runtime) + { + auto& runtimeData = pState->Data.Runtime; + for (size_t i = 0; i < pInfo->framework_count; ++i) { - hr = VerCompareParsedVersions(pState->pVersion, pFrameworkVersion, &nCompare); - ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to compare versions."); + const hostfxr_dotnet_environment_framework_info* pFrameworkInfo = pInfo->frameworks + i; + ReleaseVerutilVersion(pDotnetVersion); - if (nCompare > -1) + if (string_equal_invariant(runtimeData.wzTargetName, pFrameworkInfo->name)) { continue; } - } - ReleaseVerutilVersion(pState->pVersion); - pState->pVersion = pFrameworkVersion; - pFrameworkVersion = NULL; + hr = VerParseVersion(pFrameworkInfo->version, 0, FALSE, &pDotnetVersion); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to parse framework version: %ls", pFrameworkInfo->version); + + if (pDotnetVersion->dwMajor != runtimeData.dwMajorVersion) + { + continue; + } + + if (pState->pVersion) + { + hr = VerCompareParsedVersions(pState->pVersion, pDotnetVersion, &nCompare); + ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to compare versions."); + + if (nCompare > -1) + { + continue; + } + } + + ReleaseVerutilVersion(pState->pVersion); + pState->pVersion = pDotnetVersion; + pDotnetVersion = nullptr; + } + } + else + { + ConsoleWriteError(E_INVALIDARG, CONSOLE_COLOR_RED, "Invalid NETCORESEARCHKIND."); } LExit: - ReleaseVerutilVersion(pFrameworkVersion); + ReleaseVerutilVersion(pDotnetVersion); } diff --git a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x64.wxs b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x64.wxs index 20b266a5..74e82405 100644 --- a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x64.wxs +++ b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x64.wxs @@ -5,11 +5,15 @@ + + + + @@ -55,4 +59,19 @@ + + + + + + + + + + + + + + + diff --git a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x86.wxs b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x86.wxs index 4bd97492..9acc4dc5 100644 --- a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x86.wxs +++ b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3.1.12_x86.wxs @@ -5,11 +5,15 @@ + + + + @@ -55,4 +59,19 @@ + + + + + + + + + + + + + + + diff --git a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3_Platform.wxi b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3_Platform.wxi index f0b97d33..2933196d 100644 --- a/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3_Platform.wxi +++ b/src/ext/NetFx/test/WixToolsetTest.Netfx/TestData/UsingDotNetCorePackages/NetCore3_Platform.wxi @@ -21,6 +21,12 @@ + + + + + + @@ -46,4 +52,12 @@ + + + + + + + + diff --git a/src/ext/NetFx/wixext/NetFxCompiler.cs b/src/ext/NetFx/wixext/NetFxCompiler.cs index 563cd19d..7a37cf90 100644 --- a/src/ext/NetFx/wixext/NetFxCompiler.cs +++ b/src/ext/NetFx/wixext/NetFxCompiler.cs @@ -49,6 +49,12 @@ namespace WixToolset.Netfx case "DotNetCoreSearchRef": this.ParseDotNetCoreSearchRefElement(intermediate, section, element); break; + case "DotNetCoreSdkSearch": + this.ParseDotNetCoreSdkSearchElement(intermediate, section, element); + break; + case "DotNetCoreSdkSearchRef": + this.ParseDotNetCoreSdkSearchRefElement(intermediate, section, element); + break; case "DotNetCompatibilityCheck": this.ParseDotNetCompatibilityCheckElement(intermediate, section, element); break; @@ -69,6 +75,12 @@ namespace WixToolset.Netfx case "DotNetCoreSearchRef": this.ParseDotNetCoreSearchRefElement(intermediate, section, element); break; + case "DotNetCoreSdkSearch": + this.ParseDotNetCoreSdkSearchElement(intermediate, section, element); + break; + case "DotNetCoreSdkSearchRef": + this.ParseDotNetCoreSdkSearchRefElement(intermediate, section, element); + break; default: this.ParseHelper.UnexpectedElement(parentElement, element); break; @@ -248,6 +260,137 @@ namespace WixToolset.Netfx this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); } + private void ParseDotNetCoreSdkSearchElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + Identifier id = null; + string variable = null; + string condition = null; + string after = null; + NetCoreSdkSearchPlatform? platform = null; + string version = null; + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); + break; + case "Variable": + variable = this.ParseHelper.GetAttributeBundleVariableNameValue(sourceLineNumbers, attrib); + break; + case "Condition": + condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "After": + after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Platform": + var platformValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (platformValue) + { + case "arm64": + platform = NetCoreSdkSearchPlatform.Arm64; + break; + case "x64": + platform = NetCoreSdkSearchPlatform.X64; + break; + case "x86": + platform = NetCoreSdkSearchPlatform.X86; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Platform", platformValue, "arm64", "x64", "x86")); + break; + } + break; + case "Version": + // .NET Core had a different deployment strategy before .NET Core 3.0 which would require different detection logic. + version = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + if (id == null) + { + id = this.ParseHelper.CreateIdentifier("dncss", variable, condition, after); + } + + if (!platform.HasValue) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Platform")); + } + + + if (String.IsNullOrEmpty(version)) + { + this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Version")); + } + + var ver = Version.Parse(version); + if (ver.Major == 4) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Version", version, "3.*", "5+.*")); + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + + var bundleExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4NetfxBundleExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64); + if (bundleExtensionId == null) + { + this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName)); + } + + if (!this.Messaging.EncounteredError) + { + this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bundleExtensionId); + + section.AddSymbol(new NetFxNetCoreSdkSearchSymbol(sourceLineNumbers, id) + { + Platform = platform.Value, + Version = version, + }); + } + } + + private void ParseDotNetCoreSdkSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element) + { + var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); + + foreach (var attrib in element.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, NetfxSymbolDefinitions.NetFxNetCoreSdkSearch, refId); + break; + default: + this.ParseHelper.UnexpectedAttribute(element, attrib); + break; + } + } + else + { + this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib); + } + } + + this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); + } + /// /// Parses a NativeImage element. /// @@ -389,66 +532,19 @@ namespace WixToolset.Netfx property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "RuntimeType": - runtimeType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (runtimeType.ToLower()) - { - case "aspnet": - runtimeType = "Microsoft.AspNetCore.App"; - break; - case "desktop": - runtimeType = "Microsoft.WindowsDesktop.App"; - break; - case "core": - runtimeType = "Microsoft.NETCore.App"; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, runtimeType, "aspnet", "desktop", "core")); - break; - } + runtimeType = this.ParseRuntimeType(element, sourceLineNumbers, attrib); break; case "Platform": - platform = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (platform.ToLower()) - { - case "x86": - case "x64": - case "arm64": - platform = platform.ToLower(); - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, platform, "x86", "x64", "arm64")); - break; - } + platform = this.ParsePlatform(element, sourceLineNumbers, attrib); + break; + case "FeatureBand": + platform = this.ParseFeatureBand(element, sourceLineNumbers, attrib); break; case "Version": version = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib); break; case "RollForward": - rollForward = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); - switch (rollForward.ToLowerInvariant()) - { - case "latestmajor": - rollForward = "LatestMajor"; - break; - case "major": - rollForward = "Major"; - break; - case "latestminor": - rollForward = "LatestMinor"; - break; - case "minor": - rollForward = "Minor"; - break; - case "latestpatch": - rollForward = "LatestPatch"; - break; - case "disable": - rollForward = "Disable"; - break; - default: - this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, rollForward, "latestmajor", "major", "latestminor", "minor", "latestpatch", "disable")); - break; - } + rollForward = this.ParseRollForward(element, sourceLineNumbers, attrib); break; default: this.ParseHelper.UnexpectedAttribute(element, attrib); @@ -503,6 +599,97 @@ namespace WixToolset.Netfx } } + private string ParseRollForward(XElement element, SourceLineNumber sourceLineNumbers, XAttribute attrib) + { + string rollForward; + rollForward = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (rollForward.ToLowerInvariant()) + { + case "latestmajor": + rollForward = "LatestMajor"; + break; + case "major": + rollForward = "Major"; + break; + case "latestminor": + rollForward = "LatestMinor"; + break; + case "minor": + rollForward = "Minor"; + break; + case "latestpatch": + rollForward = "LatestPatch"; + break; + case "disable": + rollForward = "Disable"; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, + attrib.Name.LocalName, rollForward, "latestmajor", "major", "latestminor", "minor", "latestpatch", "disable")); + break; + } + + return rollForward; + } + + private string ParsePlatform(XElement element, SourceLineNumber sourceLineNumbers, XAttribute attrib) + { + string platform; + platform = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (platform.ToLower()) + { + case "x86": + case "x64": + case "arm64": + platform = platform.ToLower(); + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, + attrib.Name.LocalName, platform, "x86", "x64", "arm64")); + break; + } + + return platform; + } + + private string ParseFeatureBand(XElement element, SourceLineNumber sourceLineNumbers, XAttribute attrib) + { + string featureBand = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + + if (!Int32.TryParse(featureBand, out var intFeatureBand) || (100 > intFeatureBand) || (intFeatureBand > 999)) + { + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, + attrib.Name.LocalName, featureBand, "An integer in the range [100 - 999]")); + + } + + return featureBand; + } + + private string ParseRuntimeType(XElement element, SourceLineNumber sourceLineNumbers, XAttribute attrib) + { + var runtimeType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); + switch (runtimeType.ToLower()) + { + case "aspnet": + runtimeType = "Microsoft.AspNetCore.App"; + break; + case "desktop": + runtimeType = "Microsoft.WindowsDesktop.App"; + break; + case "core": + runtimeType = "Microsoft.NETCore.App"; + break; + default: + this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, + attrib.Name.LocalName, runtimeType, "aspnet", "desktop", "core")); + break; + } + + return runtimeType; + } + + /// /// Parses a DotNetCompatibilityCheckRef element. /// diff --git a/src/ext/NetFx/wixext/NetfxTableDefinitions.cs b/src/ext/NetFx/wixext/NetfxTableDefinitions.cs index 6be1abe7..114275c3 100644 --- a/src/ext/NetFx/wixext/NetfxTableDefinitions.cs +++ b/src/ext/NetFx/wixext/NetfxTableDefinitions.cs @@ -40,7 +40,7 @@ namespace WixToolset.Netfx public static readonly TableDefinition[] All = new[] { NetFxNativeImage, - NetFxDotNetCompatibilityCheck + NetFxDotNetCompatibilityCheck, }; } } diff --git a/src/ext/NetFx/wixext/Symbols/NetFxDotNetCompatibilityCheckSymbol.cs b/src/ext/NetFx/wixext/Symbols/NetFxDotNetCompatibilityCheckSymbol.cs index a46cf17f..ea1b16c5 100644 --- a/src/ext/NetFx/wixext/Symbols/NetFxDotNetCompatibilityCheckSymbol.cs +++ b/src/ext/NetFx/wixext/Symbols/NetFxDotNetCompatibilityCheckSymbol.cs @@ -11,11 +11,11 @@ namespace WixToolset.Netfx NetfxSymbolDefinitionType.NetFxDotNetCompatibilityCheck.ToString(), new[] { - new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbollFields.RuntimeType), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbollFields.Platform), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbollFields.Version), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbollFields.RollForward), IntermediateFieldType.String), - new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbollFields.Property), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbolFields.RuntimeType), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbolFields.Platform), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbolFields.Version), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbolFields.RollForward), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(NetFxDotNetCompatibilityCheckSymbolFields.Property), IntermediateFieldType.String), }, typeof(NetFxDotNetCompatibilityCheckSymbol)); } @@ -25,7 +25,7 @@ namespace WixToolset.Netfx.Symbols { using WixToolset.Data; - public enum NetFxDotNetCompatibilityCheckSymbollFields + public enum NetFxDotNetCompatibilityCheckSymbolFields { RuntimeType, Platform, @@ -44,36 +44,36 @@ namespace WixToolset.Netfx.Symbols { } - public IntermediateField this[NetFxDotNetCompatibilityCheckSymbollFields index] => this.Fields[(int)index]; + public IntermediateField this[NetFxDotNetCompatibilityCheckSymbolFields index] => this.Fields[(int)index]; public string RuntimeType { - get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbollFields.RuntimeType].AsString(); - set => this.Set((int)NetFxDotNetCompatibilityCheckSymbollFields.RuntimeType, value); + get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbolFields.RuntimeType].AsString(); + set => this.Set((int)NetFxDotNetCompatibilityCheckSymbolFields.RuntimeType, value); } public string Platform { - get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbollFields.Platform].AsString(); - set => this.Set((int)NetFxDotNetCompatibilityCheckSymbollFields.Platform, value); + get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbolFields.Platform].AsString(); + set => this.Set((int)NetFxDotNetCompatibilityCheckSymbolFields.Platform, value); } public string Version { - get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbollFields.Version].AsString(); - set => this.Set((int)NetFxDotNetCompatibilityCheckSymbollFields.Version, value); + get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbolFields.Version].AsString(); + set => this.Set((int)NetFxDotNetCompatibilityCheckSymbolFields.Version, value); } public string RollForward { - get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbollFields.RollForward].AsString(); - set => this.Set((int)NetFxDotNetCompatibilityCheckSymbollFields.RollForward, value); + get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbolFields.RollForward].AsString(); + set => this.Set((int)NetFxDotNetCompatibilityCheckSymbolFields.RollForward, value); } public string Property { - get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbollFields.Property].AsString(); - set => this.Set((int)NetFxDotNetCompatibilityCheckSymbollFields.Property, value); + get => this.Fields[(int)NetFxDotNetCompatibilityCheckSymbolFields.Property].AsString(); + set => this.Set((int)NetFxDotNetCompatibilityCheckSymbolFields.Property, value); } } } diff --git a/src/ext/NetFx/wixext/Symbols/NetFxNetCoreSearchSdkSymbol.cs b/src/ext/NetFx/wixext/Symbols/NetFxNetCoreSearchSdkSymbol.cs new file mode 100644 index 00000000..86b750ea --- /dev/null +++ b/src/ext/NetFx/wixext/Symbols/NetFxNetCoreSearchSdkSymbol.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Netfx +{ + using WixToolset.Data; + using WixToolset.Netfx.Symbols; + + public static partial class NetfxSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition NetFxNetCoreSdkSearch = new IntermediateSymbolDefinition( + NetfxSymbolDefinitionType.NetFxNetCoreSdkSearch.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(NetFxNetCoreSdkSearchSymbolFields.Platform), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(NetFxNetCoreSdkSearchSymbolFields.Version), IntermediateFieldType.String), + }, + typeof(NetFxNetCoreSearchSymbol)); + } +} + +namespace WixToolset.Netfx.Symbols +{ + using WixToolset.Data; + + + public enum NetCoreSdkSearchPlatform + { + X86, + X64, + Arm64, + } + + public enum NetFxNetCoreSdkSearchSymbolFields + { + Platform, + Version, + } + + + public class NetFxNetCoreSdkSearchSymbol : IntermediateSymbol + { + public NetFxNetCoreSdkSearchSymbol() : base(NetfxSymbolDefinitions.NetFxNetCoreSdkSearch, null, null) + { + } + + public NetFxNetCoreSdkSearchSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(NetfxSymbolDefinitions.NetFxNetCoreSdkSearch, sourceLineNumber, id) + { + } + + public IntermediateField this[NetFxNetCoreSdkSearchSymbolFields index] => this.Fields[(int)index]; + + public NetCoreSdkSearchPlatform Platform + { + get => (NetCoreSdkSearchPlatform)this.Fields[(int)NetFxNetCoreSdkSearchSymbolFields.Platform].AsNumber(); + set => this.Set((int)NetFxNetCoreSdkSearchSymbolFields.Platform, (int)value); + } + + public string Version + { + get => this.Fields[(int)NetFxNetCoreSdkSearchSymbolFields.Version].AsString(); + set => this.Set((int)NetFxNetCoreSdkSearchSymbolFields.Version, value); + } + } +} diff --git a/src/ext/NetFx/wixext/Symbols/NetfxSymbolDefinitions.cs b/src/ext/NetFx/wixext/Symbols/NetfxSymbolDefinitions.cs index ad729dd4..00c52f9e 100644 --- a/src/ext/NetFx/wixext/Symbols/NetfxSymbolDefinitions.cs +++ b/src/ext/NetFx/wixext/Symbols/NetfxSymbolDefinitions.cs @@ -10,7 +10,8 @@ namespace WixToolset.Netfx { NetFxNativeImage, NetFxNetCoreSearch, - NetFxDotNetCompatibilityCheck + NetFxNetCoreSdkSearch, + NetFxDotNetCompatibilityCheck, } public static partial class NetfxSymbolDefinitions @@ -36,7 +37,10 @@ namespace WixToolset.Netfx case NetfxSymbolDefinitionType.NetFxNetCoreSearch: return NetfxSymbolDefinitions.NetFxNetCoreSearch; - + + case NetfxSymbolDefinitionType.NetFxNetCoreSdkSearch: + return NetfxSymbolDefinitions.NetFxNetCoreSdkSearch; + case NetfxSymbolDefinitionType.NetFxDotNetCompatibilityCheck: return NetfxSymbolDefinitions.NetFxDotNetCompatibilityCheck; @@ -48,6 +52,7 @@ namespace WixToolset.Netfx static NetfxSymbolDefinitions() { NetFxNetCoreSearch.AddTag(BurnConstants.BundleExtensionSearchSymbolDefinitionTag); + NetFxNetCoreSdkSearch.AddTag(BurnConstants.BundleExtensionSearchSymbolDefinitionTag); } } } -- cgit v1.2.3-55-g6feb