diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8d72881706e91a..d18a21c3f054c4 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-reportgenerator-globaltool": { - "version": "4.3.0", + "version": "4.3.6", "commands": [ "reportgenerator" ] diff --git a/.gitignore b/.gitignore index f39c9433649aae..bf23e45830e084 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ cross/android-rootfs/ #NUNIT *.VisualState.xml TestResult.xml +testResults.xml # Build Results of an ATL Project [Dd]ebugPS/ diff --git a/Directory.Build.props b/Directory.Build.props index c9024609663cbd..d7e46d25026af0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,18 +11,23 @@ - - + + + $(MSBuildThisFileDirectory) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'eng')) + $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'bin')) + + $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'tools-local')) $([MSBuild]::NormalizeDirectory('$(RepoToolsLocalDir)', 'tasks')) - $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'installer.tasks', '$(Configuration)')) - $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'netstandard2.0', 'installer.tasks.dll')) - $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'net46', 'installer.tasks.dll')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'installer.tasks')) + $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'netstandard2.0', 'installer.tasks.dll')) + $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'net46', 'installer.tasks.dll')) $(ArtifactsObjDir)HostMachineInfo.props $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'libraries')) diff --git a/NuGet.config b/NuGet.config index 6b6e54b554f77f..b656e4d9162cef 100644 --- a/NuGet.config +++ b/NuGet.config @@ -12,6 +12,7 @@ --> + diff --git a/docs/libraries/building/code-coverage.md b/docs/libraries/building/code-coverage.md index f612695fcc31d1..76e7834dcb42b7 100644 --- a/docs/libraries/building/code-coverage.md +++ b/docs/libraries/building/code-coverage.md @@ -45,7 +45,7 @@ The results for this one library will then show up in the aforementioned index.h And then once the run completes: - $(TestPath)\report\index.htm + $(OutDir)\report\index.htm **Note:** If you only want to measure the coverage of your local changes (that haven't been pushed to git), run: diff --git a/docs/libraries/project-docs/developer-guide.md b/docs/libraries/project-docs/developer-guide.md index 4dd8b73fd4f7d6..8865259d23ab4e 100644 --- a/docs/libraries/project-docs/developer-guide.md +++ b/docs/libraries/project-docs/developer-guide.md @@ -423,7 +423,7 @@ cd src\System.Collections.Immutable\tests dotnet msbuild /t:BuildAndTest /p:Coverage=true ``` -If coverage succeeds, the individual report can be found at `$(TestPath)\report\index.htm`. +If coverage succeeds, the individual report can be found at `$(OutDir)\report\index.htm`. Code coverage reports from the continuous integration system are available from the links on the front page of the corefx repo. diff --git a/eng/Build.props b/eng/Build.props index 3f3624723e948f..e6bf9aa8cd981e 100644 --- a/eng/Build.props +++ b/eng/Build.props @@ -79,6 +79,7 @@ $(RepoTasksDir) - $(ArtifactsObjDir)runtime.tasks\$(Configuration)\build-semaphore.txt + $(ArtifactsObjDir)runtime.tasks\Debug\build-semaphore.txt diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a0cc6829edea9d..3e11596f70605f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -130,5 +130,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization d0bb63d2ec7060714e63ee4082fac48f2e57f3e2 + + https://github.com/Microsoft/vstest + ca987de449d17284f8c9806df36f42276f13962a + diff --git a/eng/Versions.props b/eng/Versions.props index c3887007e8240a..25eac8a779692d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -80,12 +80,12 @@ 4.9.4 4.4.0 - 4.4.0 - 16.3.0 + 16.4.0 2.4.1 2.0.5 - 12.0.1 + 12.0.3 + 2.1.26 1.0.16 1.0.4 diff --git a/eng/pipelines/libraries/corefx-base.yml b/eng/pipelines/libraries/corefx-base.yml index a8ad96ceb36838..aac9dbf563799f 100644 --- a/eng/pipelines/libraries/corefx-base.yml +++ b/eng/pipelines/libraries/corefx-base.yml @@ -84,7 +84,7 @@ jobs: - _msbuildCommonParameters: /p:OfficialBuildId=$(Build.BuildNumber) - ${{ if eq(job.submitToHelix, 'true') }}: - - _archiveTestsParameter: /p:ArchiveTests=Tests + - _archiveTestsParameter: /p:ArchiveTests=true - ${{ if eq(parameters.isOfficialBuild, 'true') }}: - group: DotNet-HelixApi-Access diff --git a/eng/pipelines/libraries/windows.yml b/eng/pipelines/libraries/windows.yml index 6fd05b3a5c0ead..c1825eaacad667 100644 --- a/eng/pipelines/libraries/windows.yml +++ b/eng/pipelines/libraries/windows.yml @@ -134,7 +134,7 @@ stages: -allconfigurations -arch $(_architecture) /p:RuntimeOS=win10 - /p:ArchiveTests=Packages + /p:ArchiveTests=true $(_msbuildCommonParameters) displayName: Build Packages and Tests diff --git a/eng/references.targets b/eng/references.targets index 3f9105695d8137..0c104db2bb27bc 100644 --- a/eng/references.targets +++ b/eng/references.targets @@ -17,8 +17,9 @@ true true + - + @@ -35,5 +36,32 @@ + + + + + + + + + + %(DefaultReferenceDirs.Identity) + + <_defaultReferenceExclusionsFullPath Include="%(DefaultReferenceExclusions.RefDir)%(DefaultReferenceExclusions.Identity).dll" /> + + + + + + + + + + + + \ No newline at end of file diff --git a/eng/testing/RunnerTemplate.Unix.txt b/eng/testing/RunnerTemplate.Unix.txt new file mode 100644 index 00000000000000..80b496efe82d7f --- /dev/null +++ b/eng/testing/RunnerTemplate.Unix.txt @@ -0,0 +1,200 @@ +#!/usr/bin/env bash + +usage() +{ + echo "Usage: RunTests.sh {-r|--runtime-path} [{--rsp-file} ]" + echo "" + echo "Parameters:" + echo "--runtime-path (Mandatory) Testhost containing the test runtime used during test execution (short: -r)" + echo "--rsp-file RSP file to pass in additional arguments" + echo "--help Print help and exit (short: -h)" +} + +EXECUTION_DIR=$(dirname "$0") +RUNTIME_PATH='' +RSP_FILE='' + +while [[ $# > 0 ]]; do + opt="$(echo "${1}" | awk '{print tolower($0)}')" + case "$opt" in + --help|-h) + usage + exit 0 + ;; + --runtime-path|-r) + RUNTIME_PATH=$2 + shift + ;; + --rsp-file) + RSP_FILE=\@$2 + shift + ;; + *) + echo "Invalid argument: $1" + usage + exit -1 + ;; + esac + + shift +done + +if [ "$RUNTIME_PATH" == "" ]; then + echo "error: -r|--runtime-path argument is required." + usage + exit -1 +fi + +# Don't use a globally installed SDK. +export DOTNET_MULTILEVEL_LOOKUP=0 + +exitcode_list[0]="Exited Successfully" +exitcode_list[130]="SIGINT Ctrl-C occurred. Likely tests timed out." +exitcode_list[131]="SIGQUIT Ctrl-\ occurred. Core dumped." +exitcode_list[132]="SIGILL Illegal Instruction. Core dumped. Likely codegen issue." +exitcode_list[133]="SIGTRAP Breakpoint hit. Core dumped." +exitcode_list[134]="SIGABRT Abort. Managed or native assert, or runtime check such as heap corruption, caused call to abort(). Core dumped." +exitcode_list[135]="IGBUS Unaligned memory access. Core dumped." +exitcode_list[136]="SIGFPE Bad floating point arguments. Core dumped." +exitcode_list[137]="SIGKILL Killed eg by kill" +exitcode_list[139]="SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped." +exitcode_list[143]="SIGTERM Terminated. Usually before SIGKILL." +exitcode_list[159]="SIGSYS Bad System Call." + +function print_info_from_core_file_using_lldb { + local core_file_name=$1 + local executable_name=$2 + local plugin_path_name="$RUNTIME_PATH/shared/Microsoft.NETCore.App/9.9.9/libsosplugin.so" + + # check for existence of lldb on the path + hash lldb 2>/dev/null || { echo >&2 "lldb was not found. Unable to print core file."; return; } + + # pe, clrstack, and dumpasync are defined in libsosplugin.so + if [ ! -f $plugin_path_name ]; then + echo $plugin_path_name cannot be found. + return + fi + + echo ----- start =============== lldb Output ===================================================== + echo Printing managed exceptions, managed call stacks, and async state machines. + lldb -O "settings set target.exec-search-paths $RUNTIME_PATH" -o "plugin load $plugin_path_name" -o "clrthreads -managedexception" -o "pe -nested" -o "clrstack -all -a -f" -o "dumpasync -fields -stacks -roots" -o "quit" --core $core_file_name $executable_name + echo ----- end =============== lldb Output ======================================================= +} + +function print_info_from_core_file_using_gdb { + local core_file_name=$1 + local executable_name=$2 + + # Check for the existence of GDB on the path + hash gdb 2>/dev/null || { echo >&2 "GDB was not found. Unable to print core file."; return; } + + echo ----- start =============== GDB Output ===================================================== + # Open the dump in GDB and print the stack from each thread. We can add more + # commands here if desired. + echo printing native stack. + gdb --batch -ex "thread apply all bt full" -ex "quit" $executable_name $core_file_name + echo ----- end =============== GDB Output ======================================================= +} + +function print_info_from_core_file { + local core_file_name=$1 + local executable_name=$RUNTIME_PATH/$2 + + if ! [ -e $executable_name ]; then + echo "Unable to find executable $executable_name" + return + elif ! [ -e $core_file_name ]; then + echo "Unable to find core file $core_file_name" + return + fi + echo "Printing info from core file $core_file_name" + print_info_from_core_file_using_gdb $core_file_name $executable_name + print_info_from_core_file_using_lldb $core_file_name $executable_name +} + +function copy_core_file_to_temp_location { + local core_file_name=$1 + + local storage_location="/tmp/coredumps" + + # Create the directory (this shouldn't fail even if it already exists). + mkdir -p $storage_location + + local new_location=$storage_location/core.$RANDOM + + echo "Copying core file $core_file_name to $new_location in case you need it." + cp $core_file_name $new_location +} + +# ========================= BEGIN Core File Setup ============================ +if [ "$(uname -s)" == "Darwin" ]; then + # On OS X, we will enable core dump generation only if there are no core + # files already in /cores/ at this point. This is being done to prevent + # inadvertently flooding the CI machines with dumps. + if [[ ! -d "/cores" || ! "$(ls -A /cores)" ]]; then + ulimit -c unlimited + fi +elif [ "$(uname -s)" == "Linux" ]; then + # On Linux, we'll enable core file generation unconditionally, and if a dump + # is generated, we will print some useful information from it and delete the + # dump immediately. + + if [ -e /proc/self/coredump_filter ]; then + # Include memory in private and shared file-backed mappings in the dump. + # This ensures that we can see disassembly from our shared libraries when + # inspecting the contents of the dump. See 'man core' for details. + echo -n 0x3F > /proc/self/coredump_filter + fi + + ulimit -c unlimited +fi +# ========================= END Core File Setup ============================== + +# ========================= BEGIN Test Execution ============================= +echo ----- start $(date) =============== To repro directly: ===================================================== +echo pushd $EXECUTION_DIR +[[RunCommandsEcho]] +echo popd +echo =========================================================================================================== +pushd $EXECUTION_DIR +[[RunCommands]] +test_exitcode=$? +popd +echo ----- end $(date) ----- exit code $test_exitcode ---------------------------------------------------------- + +if [ "${exitcode_list[$test_exitcode]}" != "" ]; then + echo exit code $test_exitcode means ${exitcode_list[$test_exitcode]} +fi +# ========================= END Test Execution =============================== + +# ======================= BEGIN Core File Inspection ========================= +pushd $EXECUTION_DIR >/dev/null +if [[ "$(uname -s)" == "Linux" && $test_exitcode -ne 0 ]]; then + echo Looking around for any Linux dump... + # Depending on distro/configuration, the core files may either be named "core" + # or "core." by default. We read /proc/sys/kernel/core_uses_pid to + # determine which it is. + core_name_uses_pid=0 + if [ -e /proc/sys/kernel/core_uses_pid ] && [ "1" == $(cat /proc/sys/kernel/core_uses_pid) ]; then + core_name_uses_pid=1 + fi + + if [ $core_name_uses_pid == "1" ]; then + # We don't know what the PID of the process was, so let's look at all core + # files whose name matches core.NUMBER + echo Looking for files matching core.* ... + for f in core.*; do + [[ $f =~ core.[0-9]+ ]] && print_info_from_core_file "$f" "dotnet" && copy_core_file_to_temp_location "$f" && rm "$f" + done + elif [ -f core ]; then + echo found a dump named core in $EXECUTION_DIR ! + print_info_from_core_file "core" "dotnet" + copy_core_file_to_temp_location "core" + rm "core" + else + echo ... found no dump in $PWD + fi +fi +popd >/dev/null +# ======================== END Core File Inspection ========================== +exit $test_exitcode diff --git a/eng/testing/RunnerTemplate.Windows.txt b/eng/testing/RunnerTemplate.Windows.txt new file mode 100644 index 00000000000000..6d956f5221e038 --- /dev/null +++ b/eng/testing/RunnerTemplate.Windows.txt @@ -0,0 +1,74 @@ +@echo off +setlocal enabledelayedexpansion + +set EXECUTION_DIR=%~dp0 + +:argparser_start + if "%~1" == "" goto argparser_end + set "argparser_currentarg=%~1" + shift + + set "argparser_help_specified_inloop=" + if /i "%argparser_currentarg%"=="-h" ( set "argparser_help_specified_inloop=1" ) + if /i "%argparser_currentarg%"=="--help" ( set "argparser_help_specified_inloop=1" ) + if defined argparser_help_specified_inloop ( + goto usage + ) + + set "argparser_runtime_path_specified_inloop=" + if /i "%argparser_currentarg%"=="-r" ( set "argparser_runtime_path_specified_inloop=1" ) + if /i "%argparser_currentarg%"=="--runtime-path" ( set "argparser_runtime_path_specified_inloop=1" ) + if defined argparser_runtime_path_specified_inloop ( + if "%~1" == "" ( goto argparser_invalid ) + set "RUNTIME_PATH=%~1" + goto argparser_break + ) + + if /i "%argparser_currentarg%"=="--rsp-file" ( + if "%~1" == "" ( goto argparser_invalid ) + set "RSP_FILE=@%~1" + goto argparser_break + ) + +:argparser_invalid + echo Invalid argument or value: %argparser_currentarg% + call :usage + exit /b -1 + +:argparser_break + shift + goto argparser_start + +:argparser_end + +if not defined RUNTIME_PATH ( + echo error: -r|--runtime-path argument is required. + call :usage + exit /b -1 +) + +:: Don't use a globally installed SDK. +set DOTNET_MULTILEVEL_LOOKUP=0 + +:: ========================= BEGIN Test Execution ============================= +echo ----- start %DATE% %TIME% =============== To repro directly: ===================================================== +echo pushd %EXECUTION_DIR% +[[RunCommandsEcho]] +echo popd +echo =========================================================================================================== +pushd %EXECUTION_DIR% +@echo on +[[RunCommands]] +@echo off +popd +echo ----- end %DATE% %TIME% ----- exit code %ERRORLEVEL% ---------------------------------------------------------- +exit /b %ERRORLEVEL% +:: ========================= END Test Execution ================================= + +:usage +echo Usage: RunTests.cmd {-r^|--runtime-path} ^ [{--rsp-file} ^] +echo. +echo Parameters: +echo --runtime-path (Mandatory) Testhost containing the test runtime used during test execution (short: -r)" +echo --rsp-file RSP file to pass in additional arguments +echo --help Print help and exit (short: -h) diff --git a/eng/testing/coverage.props b/eng/testing/coverage.props new file mode 100644 index 00000000000000..7af30267a5625a --- /dev/null +++ b/eng/testing/coverage.props @@ -0,0 +1,14 @@ + + + coverage.xml + 0 + line,branch,method + opencover + true + normal + + $(CoverageOutputPath) + Html + Info + + diff --git a/eng/testing/coverage.targets b/eng/testing/coverage.targets new file mode 100644 index 00000000000000..c2d9059eff3275 --- /dev/null +++ b/eng/testing/coverage.targets @@ -0,0 +1,62 @@ + + + + "$(TargetFileName)" --target "$(RunCommand)" --targetargs "$(RunArguments)" --format "$(CoverageFormat)" --output "$(CoverageOutputPath)" --threshold "$(CoverageThreshold)" --threshold-type "$(CoverageThresholdType)" --verbosity "$(CoverageVerbosity)" + $(RunArguments) --use-source-link + "$(DotNetTool)" tool run coverlet + + + + + $([MSBuild]::NormalizeDirectory('$(OutDir)', 'report')) + $([MSBuild]::NormalizePath('$(CoverageReportDir)', 'index.htm')) + "$(DotNetTool)" tool run reportgenerator "-reports:$(CoverageReportInputPath)" "-targetdir:$(CoverageReportDir.TrimEnd('\/'))" "-reporttypes:$(CoverageReportTypes)" "-verbosity:$(CoverageReportVerbosity)" + + + + + + + + + + --exclude-by-file @(CoverageExcludeFile -> '"%(Identity)"', ' --exclude-by-file ') + $(RunArguments) $(CoverageExcludeByFileFilter) + + + + --include-directory @(CoverageProbePath -> '"$(RunScriptHostDir)%(Identity)"', ' --include-directory ') + $(RunArguments) $(IncludeDirectoriesFilter) + + + + --exclude @(CoverageExclude -> '"%(Identity)"', ' --exclude ') + $(RunArguments) $(CoverageExcludeFilter) + + + + + <_ProjectDirectoryUnderSourceDir>$(MSBuildProjectDirectory.SubString($(LibrariesProjectRoot.Length))) + $(_ProjectDirectoryUnderSourceDir.SubString(0, $(_ProjectDirectoryUnderSourceDir.IndexOfAny("\\/")))) + + + + + <_CoverageAssemblies Include="$(AssemblyBeingTested)" /> + <_CoverageAssemblies Include="System.Private.CoreLib" Condition="'$(TestRuntime)' == 'true'" /> + <_CoverageAssemblies Include="@(AssembliesBeingTested)" /> + <_CoverageAssemblies Include="$(CoverageAssemblies)" Condition="'$(CoverageAssemblies)' != ''" /> + + + + --include @(_CoverageAssemblies -> '"[%(Identity)]*"', ' --include ') + $(RunArguments) $(CoverageFilter) + + + diff --git a/eng/testing/launchSettings.json b/eng/testing/launchSettings.json new file mode 100644 index 00000000000000..c215e10ba947f3 --- /dev/null +++ b/eng/testing/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + ".NET Core xUnit Console": { + "commandName": "Executable", + "executablePath": "$(TestHostRootPath)dotnet.exe", + "commandLineArgs": "$(RunArguments) -parallel none", + "workingDirectory": "$(RunWorkingDirectory)" + } + } +} diff --git a/eng/testing/launchSettings.targets b/eng/testing/launchSettings.targets new file mode 100644 index 00000000000000..6caf9475304570 --- /dev/null +++ b/eng/testing/launchSettings.targets @@ -0,0 +1,22 @@ + + + + $(MSBuildThisFileDirectory)launchSettings.json + $([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(AppDesignerFolder)', 'launchSettings.json')) + GenerateLaunchSettingsFile;$(PrepareForRunDependsOn); + + + + + + + \ No newline at end of file diff --git a/eng/testing/netfx.exe.config b/eng/testing/netfx.exe.config new file mode 100644 index 00000000000000..ed7d7d082438c8 --- /dev/null +++ b/eng/testing/netfx.exe.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/eng/testing/runtimeConfiguration.targets b/eng/testing/runtimeConfiguration.targets new file mode 100644 index 00000000000000..6b6c952cb79d05 --- /dev/null +++ b/eng/testing/runtimeConfiguration.targets @@ -0,0 +1,45 @@ + + + + $(MSBuildThisFileDirectory)netfx.exe.config + + + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eng/testing/tests.props b/eng/testing/tests.props new file mode 100644 index 00000000000000..1dc35ce2949ac1 --- /dev/null +++ b/eng/testing/tests.props @@ -0,0 +1,17 @@ + + + $(MSBuildProjectName) + xunit + + + + + + + + + + diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets new file mode 100644 index 00000000000000..527f418f9fd6fe --- /dev/null +++ b/eng/testing/tests.targets @@ -0,0 +1,127 @@ + + + $(DefaultOSGroup) + $(OutDir) + + RunnerTemplate.Windows.txt + RunnerTemplate.Unix.txt + $(MSBuildThisFileDirectory)$(RunScriptInputName) + + RunTests.cmd + RunTests.sh + $([MSBuild]::NormalizePath('$(OutDir)', '$(RunScriptOutputName)')) + + %RUNTIME_PATH%\ + $RUNTIME_PATH/ + + $(RunScriptHostDir)dotnet.exe + $(RunScriptHostDir)dotnet + + + + + + + + + + + + + + + $(RunArguments) %RSP_FILE% + $(RunArguments) $RSP_FILE + + + $([MSBuild]::Escape('$(RunArguments)')) + + $(RunCommand) $(RunArguments) + + + + + $(TestDebugger) $(RunScriptCommand) + $(TestDebugger) /debugexe $(RunScriptCommand) + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + "$(RunScriptOutputPath)" --runtime-path "$(TestHostRootPath.TrimEnd('\/'))" + $(RunTestsCommand) --rsp-file "$(TestRspFile)" + + + + + + + + + One or more tests failed while running tests from '$(TestProjectName)'. + $(TestRunErrorMessage) Please check $(TestResultsPath) for details! + + + + + + + + + + + + diff --git a/eng/testing/xunit/vstest.props b/eng/testing/xunit/vstest.props new file mode 100644 index 00000000000000..bcf5476a827173 --- /dev/null +++ b/eng/testing/xunit/vstest.props @@ -0,0 +1,20 @@ + + + + en + + + + + + + + + + + + + + diff --git a/eng/testing/xunit/vstest.targets b/eng/testing/xunit/vstest.targets new file mode 100644 index 00000000000000..9e1517a2bf648e --- /dev/null +++ b/eng/testing/xunit/vstest.targets @@ -0,0 +1,32 @@ + + + "$(RunScriptHost)" + test $(TargetFileName) + + + $(RunArguments) --logger "xunit;LogFilePath=$(TestResultsName)" + $(RunArguments) --framework $(TargetFramework) + $(RunArguments) --platform $(ArchGroup) + $(RunArguments) --parallel + $(RunArguments) --blame + + + <_testFilter Condition="'$(_withCategories)' != ''">$(_withCategories.Replace(';', '&category=')) + <_testFilter Condition="'$(_withoutCategories)' != ''">$(_testFilter)$(_withoutCategories.Replace(';', '&category!=')) + + <_testFilter Condition="'$(TargetOS)' == 'Windows_NT'">$(_testFilter.Replace('!=', '^!=')) + <_testFilter>$(_testFilter.Trim('&')) + + <_testFilter Condition="'$(TestFilter)' != ''">$(_testFilter)&$(TestFilter.Replace('!=', '^!=')) + + $(RunArguments) --filter "($(_testFilter))" + + + $(RunArguments) $(XUnitOptions) + + + $(RunSettingsOptions) RunConfiguration.DisableParallelization=true + $(RunSettingsOptions) RunConfiguration.DisableAppDomain=true + $(RunArguments) --(RunSettingsOptions) + + \ No newline at end of file diff --git a/eng/testing/xunit/xunit.console.props b/eng/testing/xunit/xunit.console.props new file mode 100644 index 00000000000000..48a3919fcb679f --- /dev/null +++ b/eng/testing/xunit/xunit.console.props @@ -0,0 +1,21 @@ + + + true + + + + + + + + + + + + + + diff --git a/eng/testing/xunit/xunit.console.targets b/eng/testing/xunit/xunit.console.targets new file mode 100644 index 00000000000000..c7f10a9041f9b6 --- /dev/null +++ b/eng/testing/xunit/xunit.console.targets @@ -0,0 +1,75 @@ + + + $(TargetFileName) + $(RunArguments) -xml $(TestResultsName) + $(RunArguments) -nologo + $(RunArguments) -nocolor + + + $(RunArguments) -maxthreads 1 + $(RunArguments) -method $(XUnitMethodName) + $(RunArguments) -class $(XUnitClassName) + $(RunArguments) -verbose + $(RunArguments) -noappdomain + + + $(RunArguments)$(_withCategories.Replace(';', ' -trait category=')) + $(RunArguments)$(_withoutCategories.Replace(';', ' -notrait category=')) + + + $(RunArguments) $(XUnitOptions) + + + + + + + <_testRunnerConfigSourceFile Include="$(TargetDir)$(TargetName).exe.config" /> + <_testRunnerConfigDestFile Include="$(TargetDir)$(_testRunnerName).config" /> + + + + + + + + + "$(RunScriptHost)" + <_depsFileRunArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json + exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileRunArgument) xunit.console.dll $(RunArguments) + + + + <_testRunnerName>xunit.console.exe + $(_testRunnerName) + + + + + + + + + + + + <_xunitConsoleNetCoreExclude Condition="'$(GenerateDependencyFile)' != 'true'" Include="$([System.IO.Path]::GetDirectoryName('$(XunitConsoleNetCore21AppPath)'))\xunit.console.deps.json" /> + + + + diff --git a/eng/testing/xunit/xunit.props b/eng/testing/xunit/xunit.props new file mode 100644 index 00000000000000..2282ba79caa905 --- /dev/null +++ b/eng/testing/xunit/xunit.props @@ -0,0 +1,18 @@ + + + xunit.console + $(MSBuildThisFileDirectory)xunit.runner.json + testResults.xml + + + + + + + + + + + + + diff --git a/eng/testing/xunit/xunit.runner.json b/eng/testing/xunit/xunit.runner.json new file mode 100644 index 00000000000000..5d2ac0433c91fe --- /dev/null +++ b/eng/testing/xunit/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "diagnosticMessages": true, + "longRunningTestSeconds": 120, + "shadowCopy": false +} \ No newline at end of file diff --git a/eng/testing/xunit/xunit.targets b/eng/testing/xunit/xunit.targets new file mode 100644 index 00000000000000..4ddddcce51cd6a --- /dev/null +++ b/eng/testing/xunit/xunit.targets @@ -0,0 +1,31 @@ + + + nonwindowstests + nonlinuxtests + nonosxtests + nonfreebsdtests + nonnetbsdtests + + + <_withCategories Condition="'$(WithCategories)' != ''">;$(WithCategories.Trim(';')) + <_withoutCategories Condition="'$(WithoutCategories)' != ''">;$(WithoutCategories.Trim(';')) + + all + <_withCategories Condition="'$(TestScope)' == 'outerloop'">$(_withCategories);OuterLoop + <_withoutCategories Condition="'$(ArchiveTest)' == 'true'">$(_withoutCategories);IgnoreForCI + <_withoutCategories Condition="'$(TestScope)' == '' or '$(TestScope)' == 'innerloop'">$(_withoutCategories);OuterLoop + <_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing + + <_withoutCategories>$(_withoutCategories);non$(_bc_TargetGroup)tests + <_withoutCategories Condition="'$(TargetOSCategory)' != ''">$(_withoutCategories);$(TargetOSCategory) + + + + + + + + + diff --git a/global.json b/global.json index 5cf141c8ca3b2f..bf792d35e80961 100644 --- a/global.json +++ b/global.json @@ -16,7 +16,6 @@ "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.19567.2", "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.19567.2", "Microsoft.DotNet.Build.Tasks.Configuration": "5.0.0-beta.19567.2", - "Microsoft.DotNet.CoreFxTesting": "5.0.0-beta.19567.2", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "5.0.0-alpha1.19563.3", "Microsoft.Build.NoTargets": "1.0.53", diff --git a/src/coreclr/tests/scripts/run-corefx-tests.py b/src/coreclr/tests/scripts/run-corefx-tests.py index b34609724d30cf..1dad96057c14e3 100644 --- a/src/coreclr/tests/scripts/run-corefx-tests.py +++ b/src/coreclr/tests/scripts/run-corefx-tests.py @@ -300,7 +300,7 @@ def main(args): common_config_args = '-configuration Release -framework netcoreapp -os %s -arch %s' % (clr_os, arch) build_args = '-build -restore' - build_test_args = '-buildtests /p:ArchiveTests=Tests' + build_test_args = '-buildtests /p:ArchiveTests=true' if not no_run_tests: build_test_args += ' -test' diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 84d0266966afd3..dd2bcf6b76f45d 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -86,7 +86,19 @@ - + + + + false + true + + false + true + true + + + false + true @@ -304,45 +316,25 @@ $(ArtifactsObjDir)version.txt - - - true - true - - $([MSBuild]::NormalizeDirectory('$(TestHostRootPath)', 'shared', 'Microsoft.NETCore.App', '$(ProductVersion)')) - - $(NETCoreAppTestSharedFrameworkPath) - $(TestHostRootPath) - - $(TestHostRuntimePath)PlatformManifest.txt - - - - - - - - - true - - - - - true - - - + + false + true + true + + + false + - $(OutputPath)$(MSBuildProjectName).xml - + $(OutputPath)$(MSBuildProjectName).xml + + $(LibrariesProjectRoot)CodeAnalysis.ruleset + false - - true @@ -356,22 +348,36 @@ false - - false - true - true + + + true + true - - false + $([MSBuild]::NormalizeDirectory('$(TestHostRootPath)', 'shared', 'Microsoft.NETCore.App', '$(ProductVersion)')) - $(LibrariesProjectRoot)CodeAnalysis.ruleset - false + $(NETCoreAppTestSharedFrameworkPath) + $(TestHostRootPath) + + $(TestHostRuntimePath)PlatformManifest.txt + + + + - + + + true + true + true + + + + + diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 41789089cd28d4..08426497067e93 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -115,9 +115,12 @@ + + + + - @@ -178,17 +181,6 @@ - - - - - - - - true - 1 + true + true true netcoreapp-Debug;netcoreapp-Release;netfx-Debug;netfx-Release - Common\System\IO\TempDirectory.cs diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs index 5232c1a2764001..31ecb26789250b 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs @@ -159,7 +159,7 @@ public void ValidateDeserializationOfObjectWithDifferentAssemblyVersion() // To generate this properly, change AssemblyVersion to a value which is unlikely to happen in production and generate base64(serialized-data) // For this test 9.98.7.987 is being used var obj = new SomeType() { SomeField = 7 }; - string serializedObj = @"AAEAAAD/////AQAAAAAAAAAMAgAAAHNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249OS45OC43Ljk4NywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA2U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNvbWVUeXBlAQAAAAlTb21lRmllbGQACAIAAAAHAAAACw=="; + string serializedObj = @"AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NS4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1jYzdiMTNmZmNkMmRkZDUxBQEAAAA2U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNvbWVUeXBlAQAAAAlTb21lRmllbGQACAIAAAAHAAAACw=="; var deserialized = (SomeType)BinaryFormatterHelpers.FromBase64String(serializedObj, FormatterAssemblyStyle.Simple); Assert.Equal(obj, deserialized); @@ -171,7 +171,7 @@ public void ValidateDeserializationOfObjectWithGenericTypeWhichGenericArgumentHa // To generate this properly, change AssemblyVersion to a value which is unlikely to happen in production and generate base64(serialized-data) // For this test 9.98.7.987 is being used var obj = new GenericTypeWithArg() { Test = new SomeType() { SomeField = 9 } }; - string serializedObj = @"AAEAAAD/////AQAAAAAAAAAMAgAAAHNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249OS45OC43Ljk4NywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADxAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HZW5lcmljVHlwZVdpdGhBcmdgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNvbWVUeXBlLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249OS45OC43Ljk4NywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABFRlc3QENlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Tb21lVHlwZQIAAAACAAAACQMAAAAFAwAAADZTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU29tZVR5cGUBAAAACVNvbWVGaWVsZAAIAgAAAAkAAAAL"; + string serializedObj = @"AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NS4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1jYzdiMTNmZmNkMmRkZDUxBQEAAADuAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HZW5lcmljVHlwZVdpdGhBcmdgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNvbWVUeXBlLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NS4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1jYzdiMTNmZmNkMmRkZDUxXV0BAAAABFRlc3QENlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Tb21lVHlwZQIAAAACAAAACQMAAAAFAwAAADZTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU29tZVR5cGUBAAAACVNvbWVGaWVsZAAIAgAAAAkAAAAL"; var deserialized = (GenericTypeWithArg)BinaryFormatterHelpers.FromBase64String(serializedObj, FormatterAssemblyStyle.Simple); Assert.Equal(obj, deserialized); diff --git a/src/libraries/pkg/test/testPackages.proj b/src/libraries/pkg/test/testPackages.proj index fd928d2b352ce9..6db7b5fbb7f241 100644 --- a/src/libraries/pkg/test/testPackages.proj +++ b/src/libraries/pkg/test/testPackages.proj @@ -155,7 +155,7 @@ + Condition="'$(ArchiveTests)' == 'true'"> + Condition="'$(ArchiveTests)' != 'true'"> $(TestDotNetPath) @@ -191,7 +191,7 @@ + Condition="'$(ArchiveTests)' != 'true'"> $(TestDotNetPath) diff --git a/src/libraries/pretest.proj b/src/libraries/pretest.proj index 25ed7f64c54f40..a86dfd053d6592 100644 --- a/src/libraries/pretest.proj +++ b/src/libraries/pretest.proj @@ -28,6 +28,28 @@ + + + + + + + + + + + diff --git a/src/libraries/restore/runtime/runtime.depproj b/src/libraries/restore/runtime/runtime.depproj index 397f7deaa848f2..bfb02bccfcd639 100644 --- a/src/libraries/restore/runtime/runtime.depproj +++ b/src/libraries/restore/runtime/runtime.depproj @@ -21,7 +21,6 @@ - - + @@ -57,7 +65,7 @@ ContinueOnError="ErrorAndContinue" /> - + diff --git a/tools-local/tasks/installer.tasks/GenerateFileVersionProps.cs b/tools-local/tasks/installer.tasks/GenerateFileVersionProps.cs index a8cfdb811004b7..9ded17981d4085 100644 --- a/tools-local/tasks/installer.tasks/GenerateFileVersionProps.cs +++ b/tools-local/tasks/installer.tasks/GenerateFileVersionProps.cs @@ -17,7 +17,6 @@ public partial class GenerateFileVersionProps : BuildTask private const string PreferredPackagesProperty = "PackageConflictPreferredPackages"; private static readonly Version ZeroVersion = new Version(0, 0, 0, 0); - [Required] public ITaskItem[] Files { get; set; } @@ -30,7 +29,6 @@ public partial class GenerateFileVersionProps : BuildTask [Required] public string PlatformManifestFile { get; set; } - [Required] public string PropsFile { get; set; } [Required] @@ -121,13 +119,19 @@ public override bool Execute() } } - var props = ProjectRootElement.Create(); - var itemGroup = props.AddItemGroup(); - // set the platform manifest when the platform is not being published as part of the app - itemGroup.Condition = "'$(RuntimeIdentifier)' == '' or '$(SelfContained)' != 'true'"; + bool generatePropsFile = !string.IsNullOrWhiteSpace(PropsFile); + ProjectRootElement props = null; - var manifestFileName = Path.GetFileName(PlatformManifestFile); - itemGroup.AddItem(PlatformManifestsItem, $"$(MSBuildThisFileDirectory){manifestFileName}"); + if (generatePropsFile) + { + props = ProjectRootElement.Create(); + var itemGroup = props.AddItemGroup(); + // set the platform manifest when the platform is not being published as part of the app + itemGroup.Condition = "'$(RuntimeIdentifier)' == '' or '$(SelfContained)' != 'true'"; + + var manifestFileName = Path.GetFileName(PlatformManifestFile); + itemGroup.AddItem(PlatformManifestsItem, $"$(MSBuildThisFileDirectory){manifestFileName}"); + } Directory.CreateDirectory(Path.GetDirectoryName(PlatformManifestFile)); using (var manifestWriter = File.CreateText(PlatformManifestFile)) @@ -143,13 +147,16 @@ public override bool Execute() } } - var propertyGroup = props.AddPropertyGroup(); - propertyGroup.AddProperty(PreferredPackagesProperty, PreferredPackages); + if (!string.IsNullOrWhiteSpace(PropsFile)) + { + var propertyGroup = props.AddPropertyGroup(); + propertyGroup.AddProperty(PreferredPackagesProperty, PreferredPackages); - var versionPropertyName = $"_{PackageId.Replace(".", "_")}_Version"; - propertyGroup.AddProperty(versionPropertyName, PackageVersion); + var versionPropertyName = $"_{PackageId.Replace(".", "_")}_Version"; + propertyGroup.AddProperty(versionPropertyName, PackageVersion); - props.Save(PropsFile); + props.Save(PropsFile); + } return !Log.HasLoggedErrors; } @@ -198,4 +205,4 @@ class FileVersionData public ITaskItem File { get; set; } } } -} +} \ No newline at end of file diff --git a/tools-local/tasks/installer.tasks/GenerateRunScript.cs b/tools-local/tasks/installer.tasks/GenerateRunScript.cs new file mode 100644 index 00000000000000..0dd240872a7e4c --- /dev/null +++ b/tools-local/tasks/installer.tasks/GenerateRunScript.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; +using System.IO; +using System.Text; + +namespace Microsoft.DotNet.Build.Tasks +{ + public class GenerateRunScript : Task + { + [Required] + public string[] RunCommands { get; set; } + + [Required] + public string TemplatePath { get; set; } + + [Required] + public string OutputPath { get; set; } + + public override bool Execute() + { + if (RunCommands.Length == 0) + { + Log.LogError("Please provide at least one test command to execute via the RunCommands property."); + return false; + } + + if (!File.Exists(TemplatePath)) + { + Log.LogError($"Runner script template {TemplatePath} was not found."); + return false; + } + + string templateContent = File.ReadAllText(TemplatePath); + Directory.CreateDirectory(Path.GetDirectoryName(OutputPath)); + + Log.LogMessage($"Run commands = {string.Join(Environment.NewLine, RunCommands)}"); + + string extension = Path.GetExtension(Path.GetFileName(OutputPath)).ToLowerInvariant(); + switch (extension) + { + case ".sh": + case ".cmd": + case ".bat": + WriteRunScript(templateContent, extension); + break; + default: + Log.LogError($"Generating runner scripts with extension '{extension}' is not supported."); + return false; + } + + return true; + } + + private void WriteRunScript(string templateContent, string extension) + { + bool isUnix = extension == ".sh"; + string lineFeed = isUnix ? "\n" : "\r\n"; + + var runCommandsBuilder = new StringBuilder(); + for (int i = 0; i < RunCommands.Length; i++) + { + runCommandsBuilder.Append(RunCommands[i]); + if (i < RunCommands.Length - 1) + { + runCommandsBuilder.Append(lineFeed); + } + } + templateContent = templateContent.Replace("[[RunCommands]]", runCommandsBuilder.ToString()); + + var runCommandEchoesBuilder = new StringBuilder(); + foreach (string runCommand in RunCommands) + { + // Escape backtick and question mark characters to avoid running commands instead of echo'ing them. + string sanitizedRunCommand = runCommand.Replace("`", "\\`") + .Replace("?", "\\") + .Replace("\r","") + .Replace("\n"," ") + .Replace("&", "^&") + .Replace(">", "^>"); + + if (isUnix) + { + // Remove parentheses and quotes from echo command before wrapping it in quotes to avoid errors on Linux. + sanitizedRunCommand = "\"" + sanitizedRunCommand.Replace("\"", "") + .Replace("(", "") + .Replace(")", "") + "\""; + } + + runCommandEchoesBuilder.Append($"echo {sanitizedRunCommand}{lineFeed}"); + } + templateContent = templateContent.Replace("[[RunCommandsEcho]]", runCommandEchoesBuilder.ToString()); + + if (isUnix) + { + // Just in case any Windows EOLs have made it in by here, clean any up. + templateContent = templateContent.Replace("\r\n", "\n"); + } + + using (StreamWriter sw = new StreamWriter(new FileStream(OutputPath, FileMode.Create))) + { + sw.NewLine = lineFeed; + sw.Write(templateContent); + sw.WriteLine(); + } + + Log.LogMessage($"Wrote {extension} run script to {OutputPath}"); + } + } +} \ No newline at end of file diff --git a/tools-local/tasks/installer.tasks/GenerateTestSharedFrameworkDepsFile.cs b/tools-local/tasks/installer.tasks/GenerateTestSharedFrameworkDepsFile.cs new file mode 100644 index 00000000000000..0048a463dc3f9a --- /dev/null +++ b/tools-local/tasks/installer.tasks/GenerateTestSharedFrameworkDepsFile.cs @@ -0,0 +1,132 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Build.Framework; +using System; +using System.IO; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using Microsoft.Extensions.DependencyModel; +using System.Collections.Generic; +using NuGet.RuntimeModel; + +namespace Microsoft.DotNet.Build.Tasks +{ + public partial class GenerateTestSharedFrameworkDepsFile : BuildTask + { + // we don't care about these values in the deps file + const string rid = "rid"; + const string tfm = "netcoreapp0.0"; + const string fullTfm = ".NETCoreApp,Version=v0.0"; + + [Required] + public string SharedFrameworkDirectory { get; set; } + + [Required] + public string[] RuntimeGraphFiles { get; set; } + + [Required] + public string TargetRuntimeIdentifier { get; set; } + + public override bool Execute() + { + var sharedFxDir = new DirectoryInfo(SharedFrameworkDirectory); + if (!sharedFxDir.Exists) + { + Log.LogError($"{nameof(SharedFrameworkDirectory)} '{SharedFrameworkDirectory}' does not exist."); + return false; + } + + // directory is the version folder, parent is the shared framework name. + string sharedFxVersion = sharedFxDir.Name; + string sharedFxName = sharedFxDir.Parent.Name; + + var ignoredExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) + { + ".pdb", + ".json", + ".config", + ".xml" + }; + + var isAssemblyTofileNames = Directory.EnumerateFiles(SharedFrameworkDirectory) + .Where(file => !ignoredExtensions.Contains(Path.GetExtension(file))) + .ToLookup(file => IsManagedAssembly(file), file => Path.GetFileName(file)); + + var managedFileNames = isAssemblyTofileNames[true]; + var nativeFileNames = isAssemblyTofileNames[false]; + + var runtimeLibraries = new[] + { + new RuntimeLibrary( + type:"package", + name: sharedFxName, + version: sharedFxVersion, + hash: "hash", + runtimeAssemblyGroups: new[] { new RuntimeAssetGroup(string.Empty, managedFileNames.Select(f => $"runtimes/{rid}/lib/{tfm}/{f}")) }, + nativeLibraryGroups: new[] { new RuntimeAssetGroup(string.Empty, nativeFileNames.Select(f => $"runtimes/{rid}/native/{f}")) }, + resourceAssemblies: Enumerable.Empty(), + dependencies: Enumerable.Empty(), + serviceable: true) + }; + + var targetInfo = new TargetInfo(fullTfm, rid, "runtimeSignature", isPortable: false); + + var runtimeFallbacks = GetRuntimeFallbacks(RuntimeGraphFiles, TargetRuntimeIdentifier); + + var dependencyContext = new DependencyContext( + targetInfo, + CompilationOptions.Default, + Enumerable.Empty(), + runtimeLibraries, + runtimeFallbacks); + + using (var depsFileStream = File.Create(Path.Combine(SharedFrameworkDirectory, $"{sharedFxName}.deps.json"))) + { + new DependencyContextWriter().Write(dependencyContext, depsFileStream); + } + + return !Log.HasLoggedErrors; + } + + private static bool IsManagedAssembly(string file) + { + bool result = false; + try + { + using (var peReader = new PEReader(File.OpenRead(file))) + { + result = peReader.HasMetadata && peReader.GetMetadataReader().IsAssembly; + } + } + catch (BadImageFormatException) + { } + + return result; + } + + private static IEnumerable GetRuntimeFallbacks(string[] runtimeGraphFiles, string runtime) + { + RuntimeGraph runtimeGraph = RuntimeGraph.Empty; + + foreach (string runtimeGraphFile in runtimeGraphFiles) + { + runtimeGraph = RuntimeGraph.Merge(runtimeGraph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeGraphFile)); + } + + foreach (string rid in runtimeGraph.Runtimes.Select(p => p.Key)) + { + IEnumerable ridFallback = runtimeGraph.ExpandRuntime(rid); + + if (ridFallback.Contains(runtime)) + { + // ExpandRuntime return runtime itself as first item so we are skiping it + yield return new RuntimeFallbacks(rid, ridFallback.Skip(1)); + } + } + } + + } +} diff --git a/tools-local/tasks/installer.tasks/installer.tasks.csproj b/tools-local/tasks/installer.tasks/installer.tasks.csproj index a955c7dc605c99..0c73fdc843a1f4 100644 --- a/tools-local/tasks/installer.tasks/installer.tasks.csproj +++ b/tools-local/tasks/installer.tasks/installer.tasks.csproj @@ -1,14 +1,12 @@ - + netstandard2.0 $(TargetFrameworks);net46 false - - $(IntermediateOutputPath)netstandard2.0\installer.tasks.dll - $(IntermediateOutputPath)net46\installer.tasks.dll AnyCPU + Debug @@ -17,30 +15,37 @@ - + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +