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 @@
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+