diff --git a/.gitignore b/.gitignore
index 847693d1d..397d2babe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,6 +127,9 @@ bin/
*.svclog
*.scc
+# BinLog artifacts
+msbuild.*.ProjectImports.zip
+
# Chutzpah Test files
_Chutzpah*
diff --git a/Documentation/general/signing-global-tool-packages.md b/Documentation/general/signing-global-tool-packages.md
new file mode 100644
index 000000000..5ecb910a1
--- /dev/null
+++ b/Documentation/general/signing-global-tool-packages.md
@@ -0,0 +1,60 @@
+Signing .NET Core Global Tool Packages
+===============================
+
+To create a signed package for your Dotnet Tool, you will need to create a signed shim. If a shim is found in the nupkg during `dotnet tool install`, it is used instead of creating one on consumer's machine.
+
+To create a signed shim, you need to add the following extra property in you project file:
+
+```
+ [list of RIDs]
+```
+
+When this property is set, `dotnet pack` will generate a shim in the package (nupkg). Assuming all other other content is signed, after you sign the shim you can sign the nupkg.
+
+Example:
+```xml
+
+
+
+ Exe
+ netcoreapp2.1
+ true
+ win-x64;win-x86;osx-x64
+
+
+```
+
+The result nupkg will have packaged shim included. Of course `dotnet pack` does not sign the shim or the package. The mechanism for that depends on your processes. The structure of the unzipped nupkg is:
+
+```
+│ shimexample.nuspec
+│ [Content_Types].xml
+│
+├───package
+│ └───services
+│ └───metadata
+│ └───core-properties
+│ 9c20d06e1d8b4a4ba3e126f30013ef32.psmdcp
+│
+├───tools
+│ └───netcoreapp2.1
+│ └───any
+│ │ DotnetToolSettings.xml
+│ │ shimexample.deps.json
+│ │ shimexample.dll
+│ │ shimexample.pdb
+│ │ shimexample.runtimeconfig.json
+│ │
+│ └───shims
+│ ├───osx-x64
+│ │ shimexample
+│ │
+│ ├───win-x64
+│ │ shimexample.exe
+│ │
+│ └───win-x86
+│ shimexample.exe
+│
+└───_rels
+ .rels
+```
diff --git a/Documentation/general/tool-nuget-package-format.md b/Documentation/general/tool-nuget-package-format.md
new file mode 100644
index 000000000..0fd0f39b6
--- /dev/null
+++ b/Documentation/general/tool-nuget-package-format.md
@@ -0,0 +1,29 @@
+Tool NuGet package format
+-------------------------------------------
+
+The most straightforward way to create a .NET tool package is to run `dotnet pack` with `PackAsTool` property set in the project file. However, if your build process is highly customized, `dotnet publish` may not create the right package for you. In this case, you can create a NuGet package for your tool using a *nuspec* file and explicitly placing assets into the NuGet package following these rules.
+
+- The NuGet package has only _/tools_ folder under the root and does **not** contain any other folders; do not include folders like _/lib_, _/content_, etc.
+- Under _/tools_ folder, the subfolders must be structured with pattern _target framework short version/RID_. For example, tool assets targeting .NET core framework V2.1 that are portable across platforms should be in the folder _tools/netcoreapp2.1/any_.
+
+Let's call assets under every _tools/target framework short version/RID_ combination "per TFM-RID assets" :
+- There is a DotnetToolSettings.xml for every "per TFM-RID assets".
+- The package type is DotnetTool.
+- Each set of TFM-RID assets should have all the dependencies the tool requires to run. The TFM-RID assets should work correctly after being copied via `xcopy` to another machine, assuming that machine has the correct runtime version and RID environment.
+- For portable app, there must be runtimeconfig.json for every "per TFM-RID assets".
+
+# Remark:
+- Currently, only portable apps are supported so the RID must be _any_.
+- Only one tool per tool package.
+
+DotnetToolSettings.xml:
+Example:
+```xml
+
+
+
+
+
+
+```
+Currently only configurable part is command name: _sayhello_ and entry point: _console.dll_. Command Name is what the user will type in their shell to invoke the command. Entry point is the relative path to the entry dll with main.
diff --git a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/dotnet-dependency-tool-invoker.csproj b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/dotnet-dependency-tool-invoker.csproj
index 8f6e579e7..0da9b9949 100644
--- a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/dotnet-dependency-tool-invoker.csproj
+++ b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/dotnet-dependency-tool-invoker.csproj
@@ -1,5 +1,9 @@
-
-
+
+
+
+
+
1.0.0-rc
@@ -16,4 +20,5 @@
+
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/MultitargetedCS.csproj b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/MultitargetedCS.csproj
new file mode 100644
index 000000000..988358c8a
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/MultitargetedCS.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/Program.cs b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/Program.cs
new file mode 100644
index 000000000..83d14f592
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedCS/Program.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace MultitargetedCS
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World!");
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/MultitargetedFS.fsproj b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/MultitargetedFS.fsproj
new file mode 100644
index 000000000..2d0082582
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/MultitargetedFS.fsproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
+
+
+
+
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/Program.fs b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/Program.fs
new file mode 100644
index 000000000..a7458f522
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedFS/Program.fs
@@ -0,0 +1,8 @@
+// Learn more about F# at http://fsharp.org
+
+open System
+
+[]
+let main argv =
+ printfn "Hello World from F#!"
+ 0 // return an integer exit code
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/MultitargetedVB.vbproj b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/MultitargetedVB.vbproj
new file mode 100644
index 000000000..da41d91f8
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/MultitargetedVB.vbproj
@@ -0,0 +1,9 @@
+
+
+
+ Exe
+ MultitargetedVB
+ netcoreapp2.2
+
+
+
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/Program.vb b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/Program.vb
new file mode 100644
index 000000000..46283ca23
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/MultitargetedVB/Program.vb
@@ -0,0 +1,7 @@
+Imports System
+
+Module Program
+ Sub Main(args As String())
+ Console.WriteLine("Hello World!")
+ End Sub
+End Module
diff --git a/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.sln b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.sln
new file mode 100644
index 000000000..2f92ebd9b
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.sln
@@ -0,0 +1,18 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/TestAssets/TestProjects/TestWebAppSimple/TestWebAppSimple.csproj b/TestAssets/TestProjects/TestWebAppSimple/TestWebAppSimple.csproj
index a6a28607a..a4ce1e1bc 100644
--- a/TestAssets/TestProjects/TestWebAppSimple/TestWebAppSimple.csproj
+++ b/TestAssets/TestProjects/TestWebAppSimple/TestWebAppSimple.csproj
@@ -13,11 +13,18 @@
-
+
+
+
+
+
-
+
diff --git a/build/BuildDefaults.props b/build/BuildDefaults.props
index 0a270a647..602b1970d 100644
--- a/build/BuildDefaults.props
+++ b/build/BuildDefaults.props
@@ -34,6 +34,7 @@
NU1701;NU5104
true
+ true
true
false
diff --git a/build/BundledTemplates.props b/build/BundledTemplates.props
index c86fe766b..e3e280bbf 100644
--- a/build/BundledTemplates.props
+++ b/build/BundledTemplates.props
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/build/DependencyVersions.props b/build/DependencyVersions.props
index ca660bc0d..4d014990b 100644
--- a/build/DependencyVersions.props
+++ b/build/DependencyVersions.props
@@ -18,13 +18,16 @@
3.0.0-preview1-26909-04
- $(MicrosoftNETCoreAppPackageVersion)
+
+
+ 3.0.0-preview1-26816-04
+
- 1.0.2-beta3
- $(MicrosoftDotNetCommonItemTemplatesPackageVersion)
- 1.0.2-beta3-20180716-1864993
+ 1.0.2-beta4-20180803-1918431
+ $(MicrosoftDotNetCommonItemTemplatesPackageVersion)
+ 1.0.2-beta4-20180821-1966911
0.2.0
1.5.1
@@ -48,7 +51,7 @@
2.1.0-prerelease-02430-04
$(BuildTasksFeedToolVersion)
- 2.0.0-preview2-25331-01
+ 2.0.0
diff --git a/build/NugetConfigFile.targets b/build/NugetConfigFile.targets
index ce1624044..8929e74dd 100644
--- a/build/NugetConfigFile.targets
+++ b/build/NugetConfigFile.targets
@@ -34,6 +34,7 @@
+
]]>
diff --git a/build/Test.targets b/build/Test.targets
index 9829573cd..a52cb1f48 100644
--- a/build/Test.targets
+++ b/build/Test.targets
@@ -10,6 +10,7 @@
$(TestOutputDir)/packages/
$(TestOutputDir)/artifacts/
$(TestOutputDir)/results/
+ $(TestArtifactsDir)/ExternalRestoreSourcesForTestsContainer.txt
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -184,8 +196,9 @@
-
-
+
+
+
diff --git a/build/package/Installer.RPM.targets b/build/package/Installer.RPM.targets
index dc8c27e2c..acb7531d6 100644
--- a/build/package/Installer.RPM.targets
+++ b/build/package/Installer.RPM.targets
@@ -197,7 +197,8 @@
-
+
+
diff --git a/build_projects/dotnet-cli-build/Crossgen.cs b/build_projects/dotnet-cli-build/Crossgen.cs
index 48ebdebfa..8c4d4954e 100644
--- a/build_projects/dotnet-cli-build/Crossgen.cs
+++ b/build_projects/dotnet-cli-build/Crossgen.cs
@@ -82,7 +82,38 @@ namespace Microsoft.DotNet.Build.Tasks
protected override MessageImportance StandardOutputLoggingImportance
{
- get { return MessageImportance.High; } // or else the output doesn't get logged by default
+ // Default is low, but we want to see output at normal verbosity.
+ get { return MessageImportance.Normal; }
+ }
+
+ protected override MessageImportance StandardErrorLoggingImportance
+ {
+ // This turns stderr messages into msbuild errors below.
+ get { return MessageImportance.High; }
+ }
+
+ protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
+ {
+ // Crossgen's error/warning formatting is inconsistent and so we do
+ // not use the "canonical error format" handling of base.
+ //
+ // Furthermore, we don't want to log crossgen warnings as msbuild
+ // warnings because we cannot prevent them and they are only
+ // occasionally formatted as something that base would recognize as
+ // a canonically formatted warning anyway.
+ //
+ // One thing that is consistent is that crossgne errors go to stderr
+ // and everything else goes to stdout. Above, we set stderr to high
+ // importance above, and stdout to normal. So we can use that here
+ // to distinguish between errors and messages.
+ if (messageImportance == MessageImportance.High)
+ {
+ Log.LogError(singleLine);
+ }
+ else
+ {
+ Log.LogMessage(messageImportance, singleLine);
+ }
}
protected override string GenerateFullPathToTool()
diff --git a/build_projects/update-dependencies/Program.cs b/build_projects/update-dependencies/Program.cs
index 26e353abb..8f3aa30da 100644
--- a/build_projects/update-dependencies/Program.cs
+++ b/build_projects/update-dependencies/Program.cs
@@ -87,7 +87,14 @@ namespace Microsoft.DotNet.Scripts
if (s_config.HasVersionFragment("aspnet"))
{
- yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftAspNetCoreAppPackageVersion", "Microsoft.AspNetCore.App");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftAspNetCoreAllPackageVersion", "Microsoft.AspNetCore.All");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "DotnetEfPackageVersion", "dotnet-ef");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftAspNetCoreDeveloperCertificatesXPlatPackageVersion", "Microsoft.AspNetCore.DeveloperCertificates.XPlat");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "MicrosoftAspNetCoreMvcPackageVersion", "Microsoft.AspNetCore.Mvc");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "DotnetDevCertsPackageVersion", "dotnet-dev-certs");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "DotnetSqlCachePackageVersion", "dotnet-sql-cache");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "DotnetUserSecretsPackageVersion", "dotnet-user-secrets");
+ yield return CreateRegexUpdater(dependencyVersionsPath, "DotnetWatchPackageVersion", "dotnet-watch");
}
if (s_config.HasVersionFragment("coresetup"))
{
diff --git a/packaging/windows/clisdk/bundle.wxl b/packaging/windows/clisdk/bundle.wxl
index 18fc7750c..dee03bb18 100644
--- a/packaging/windows/clisdk/bundle.wxl
+++ b/packaging/windows/clisdk/bundle.wxl
@@ -74,6 +74,6 @@ Resources
Installation note
A command will be run during the install process that will improve project restore speed and enable offline access. It will take up to a minute to complete.
- If you plan to use .NET Core 2.1 with Visual Studio, Visual Studio 2017 15.7 or newer is recommended. <A HREF="https://go.microsoft.com/fwlink/?linkid=866799">Learn More</A>.
+ If you plan to use .NET Core 2.2 with Visual Studio, Visual Studio 2017 15.9 or newer is recommended. <A HREF="https://go.microsoft.com/fwlink/?linkid=866799">Learn More</A>.
diff --git a/packaging/windows/clisdk/bundle.wxs b/packaging/windows/clisdk/bundle.wxs
index 2e9304ce5..af6482f3f 100644
--- a/packaging/windows/clisdk/bundle.wxs
+++ b/packaging/windows/clisdk/bundle.wxs
@@ -7,7 +7,7 @@
diff --git a/run-build.ps1 b/run-build.ps1
index 07fbb03f9..8e54ae652 100644
--- a/run-build.ps1
+++ b/run-build.ps1
@@ -76,6 +76,9 @@ $env:DOTNET_MULTILEVEL_LOOKUP=0
# Turn off MSBuild Node re-use
$env:MSBUILDDISABLENODEREUSE=1
+# Workaround for the sockets issue when restoring with many nuget feeds.
+$env:DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0
+
# Enable vs test console logging
$env:VSTEST_BUILD_TRACE=1
$env:VSTEST_TRACE_BUILD=1
@@ -109,7 +112,7 @@ if ($NoBuild)
}
else
{
- dotnet msbuild build.proj /p:Architecture=$Architecture /p:GeneratePropsFile=true /t:WriteDynamicPropsToStaticPropsFiles $ExtraParametersNoTargets
- dotnet msbuild build.proj /m /v:normal /fl /flp:v=diag /bl /p:Architecture=$Architecture $ExtraParameters
+ dotnet msbuild build.proj /bl:msbuild.generatepropsfile.binlog /p:Architecture=$Architecture /p:GeneratePropsFile=true /t:WriteDynamicPropsToStaticPropsFiles $ExtraParametersNoTargets
+ dotnet msbuild build.proj /bl:msbuild.generatepropsfile.binlog /m /v:normal /fl /flp:v=diag /bl /p:Architecture=$Architecture $ExtraParameters
if($LASTEXITCODE -ne 0) { throw "Failed to build" }
}
diff --git a/run-build.sh b/run-build.sh
index 756b46b87..b58ec14e9 100755
--- a/run-build.sh
+++ b/run-build.sh
@@ -156,6 +156,9 @@ export DOTNET_MULTILEVEL_LOOKUP=0
# Turn off MSBuild Node re-use
export MSBUILDDISABLENODEREUSE=1
+# Workaround for the sockets issue when restoring with many nuget feeds.
+export DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0
+
# Install a stage 0
INSTALL_ARCHITECTURE=$ARCHITECTURE
archlower="$(echo $ARCHITECTURE | awk '{print tolower($0)}')"
@@ -191,8 +194,8 @@ fi
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
if [ $BUILD -eq 1 ]; then
- dotnet msbuild build.proj /p:Architecture=$ARCHITECTURE $CUSTOM_BUILD_ARGS /p:GeneratePropsFile=true /t:WriteDynamicPropsToStaticPropsFiles ${argsnotargets[@]}
- dotnet msbuild build.proj /m /v:normal /fl /flp:v=diag /bl /p:Architecture=$ARCHITECTURE $CUSTOM_BUILD_ARGS $args
+ dotnet msbuild build.proj /bl:msbuild.generatepropsfile.binlog /p:Architecture=$ARCHITECTURE $CUSTOM_BUILD_ARGS /p:GeneratePropsFile=true /t:WriteDynamicPropsToStaticPropsFiles ${argsnotargets[@]}
+ dotnet msbuild build.proj /bl:msbuild.mainbuild.binlog /m /v:normal /fl /flp:v=diag /bl /p:Architecture=$ARCHITECTURE $CUSTOM_BUILD_ARGS $args
else
echo "Not building due to --nobuild"
echo "Command that would be run is: 'dotnet msbuild build.proj /m /p:Architecture=$ARCHITECTURE $CUSTOM_BUILD_ARGS $args'"
diff --git a/scripts/docker/debian/Dockerfile b/scripts/docker/debian/Dockerfile
index d54afeb0e..4b5515ec0 100644
--- a/scripts/docker/debian/Dockerfile
+++ b/scripts/docker/debian/Dockerfile
@@ -4,47 +4,16 @@
#
# Dockerfile that creates a container suitable to build dotnet-cli
-FROM debian:jessie
+FROM microsoft/dotnet-buildtools-prereqs:debian-8.2-debpkg-d770b8b-20180628122423
# Misc Dependencies for build
-RUN apt-get update && \
+RUN rm -rf /var/lib/apt/lists/* && \
+ apt-get update && \
apt-get -qqy install \
- curl \
- unzip \
- gettext \
sudo && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
-# This could become a "microsoft/coreclr" image, since it just installs the dependencies for CoreCLR (and stdlib)
-RUN apt-get update &&\
- apt-get -qqy install \
- libunwind8 \
- libkrb5-3 \
- libicu52 \
- liblttng-ust0 \
- libssl1.0.0 \
- zlib1g \
- libuuid1 && \
- apt-get clean && \
- rm -rf /var/lib/apt/lists/*
-
-# Install Build Prereqs
-RUN apt-get update && \
- apt-get -qqy install \
- debhelper \
- build-essential \
- devscripts \
- git \
- cmake \
- clang-3.5 && \
- apt-get clean && \
- rm -rf /var/lib/apt/lists/*
-
-# Use clang as c++ compiler
-RUN update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-3.5 100
-RUN update-alternatives --set c++ /usr/bin/clang++-3.5
-
# Setup User to match Host User, and give superuser permissions
ARG USER_ID=0
RUN useradd -m code_executor -u ${USER_ID} -g sudo
diff --git a/src/Microsoft.DotNet.MSBuildSdkResolver/Interop.cs b/src/Microsoft.DotNet.MSBuildSdkResolver/Interop.cs
new file mode 100644
index 000000000..cda6dd3d0
--- /dev/null
+++ b/src/Microsoft.DotNet.MSBuildSdkResolver/Interop.cs
@@ -0,0 +1,135 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Microsoft.DotNet.MSBuildSdkResolver
+{
+ internal static partial class Interop
+ {
+ internal static readonly bool RunningOnWindows =
+#if NET46
+ // Not using RuntimeInformation on NET46 to avoid non-in-box framework API,
+ // which create deployment problems for the resolver.
+ Path.DirectorySeparatorChar == '\\';
+#else
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+#endif
+
+ static Interop()
+ {
+ if (RunningOnWindows)
+ {
+ PreloadWindowsLibrary("hostfxr.dll");
+ }
+ }
+
+ // MSBuild SDK resolvers are required to be AnyCPU, but we have a native dependency and .NETFramework does not
+ // have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore
+ // preload the version with the correct architecture (from a corresponding sub-folder relative to us) on static
+ // construction so that subsequent P/Invokes can find it.
+ private static void PreloadWindowsLibrary(string dllFileName)
+ {
+ string basePath = Path.GetDirectoryName(typeof(Interop).Assembly.Location);
+ string architecture = IntPtr.Size == 8 ? "x64" : "x86";
+ string dllPath = Path.Combine(basePath, architecture, dllFileName);
+
+ // return value is intentially ignored as we let the subsequent P/Invokes fail naturally.
+ LoadLibraryExW(dllPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+
+ // lpFileName passed to LoadLibraryEx must be a full path.
+ private const int LOAD_WITH_ALTERED_SEARCH_PATH = 0x8;
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
+ private static extern IntPtr LoadLibraryExW(string lpFileName, IntPtr hFile, int dwFlags);
+
+
+ [Flags]
+ internal enum hostfxr_resolve_sdk2_flags_t : int
+ {
+ disallow_prerelease = 0x1,
+ }
+
+ internal enum hostfxr_resolve_sdk2_result_key_t : int
+ {
+ resolved_sdk_dir = 0,
+ global_json_path = 1,
+ }
+
+ internal static class Windows
+ {
+ private const CharSet UTF16 = CharSet.Unicode;
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF16)]
+ internal delegate void hostfxr_resolve_sdk2_result_fn(
+ hostfxr_resolve_sdk2_result_key_t key,
+ string value);
+
+ [DllImport("hostfxr", CharSet = UTF16, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int hostfxr_resolve_sdk2(
+ string exe_dir,
+ string working_dir,
+ hostfxr_resolve_sdk2_flags_t flags,
+ hostfxr_resolve_sdk2_result_fn result);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF16)]
+ internal delegate void hostfxr_get_available_sdks_result_fn(
+ int sdk_count,
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
+ string[] sdk_dirs);
+
+ [DllImport("hostfxr", CharSet = UTF16, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int hostfxr_get_available_sdks(
+ string exe_dir,
+ hostfxr_get_available_sdks_result_fn result);
+ }
+
+ internal static class Unix
+ {
+ // Ansi marhsaling on Unix is actually UTF8
+ private const CharSet UTF8 = CharSet.Ansi;
+ private static string PtrToStringUTF8(IntPtr ptr) => Marshal.PtrToStringAnsi(ptr);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF8)]
+ internal delegate void hostfxr_resolve_sdk2_result_fn(
+ hostfxr_resolve_sdk2_result_key_t key,
+ string value);
+
+ [DllImport("hostfxr", CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int hostfxr_resolve_sdk2(
+ string exe_dir,
+ string working_dir,
+ hostfxr_resolve_sdk2_flags_t flags,
+ hostfxr_resolve_sdk2_result_fn result);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF8)]
+ internal delegate void hostfxr_get_available_sdks_result_fn(
+ int sdk_count,
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
+ string[] sdk_dirs);
+
+ [DllImport("hostfxr", CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int hostfxr_get_available_sdks(
+ string exe_dir,
+ hostfxr_get_available_sdks_result_fn result);
+
+ [DllImport("libc", CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr realpath(string path, IntPtr buffer);
+
+ [DllImport("libc", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void free(IntPtr ptr);
+
+ internal static string realpath(string path)
+ {
+ var ptr = realpath(path, IntPtr.Zero);
+ var result = PtrToStringUTF8(ptr);
+ free(ptr);
+ return result;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.MSBuildSdkResolver/NETCoreSdkResolver.cs b/src/Microsoft.DotNet.MSBuildSdkResolver/NETCoreSdkResolver.cs
new file mode 100644
index 000000000..e00c618d9
--- /dev/null
+++ b/src/Microsoft.DotNet.MSBuildSdkResolver/NETCoreSdkResolver.cs
@@ -0,0 +1,76 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Diagnostics;
+
+namespace Microsoft.DotNet.MSBuildSdkResolver
+{
+ internal static class NETCoreSdkResolver
+ {
+ public sealed class Result
+ {
+ ///
+ /// Path to .NET Core SDK selected by hostfxr (e.g. C:\Program Files\dotnet\sdk\2.1.300).
+ ///
+ public string ResolvedSdkDirectory;
+
+ ///
+ /// Path to global.json file that impacted resolution.
+ ///
+ public string GlobalJsonPath;
+
+ public void Initialize(Interop.hostfxr_resolve_sdk2_result_key_t key, string value)
+ {
+ switch (key)
+ {
+ case Interop.hostfxr_resolve_sdk2_result_key_t.resolved_sdk_dir:
+ ResolvedSdkDirectory = value;
+ break;
+ case Interop.hostfxr_resolve_sdk2_result_key_t.global_json_path:
+ GlobalJsonPath = value;
+ break;
+ }
+ }
+ }
+
+ public static Result ResolveSdk(
+ string dotnetExeDirectory,
+ string globalJsonStartDirectory,
+ bool disallowPrerelease = false)
+ {
+ var result = new Result();
+ var flags = disallowPrerelease ? Interop.hostfxr_resolve_sdk2_flags_t.disallow_prerelease : 0;
+
+ int errorCode = Interop.RunningOnWindows
+ ? Interop.Windows.hostfxr_resolve_sdk2(dotnetExeDirectory, globalJsonStartDirectory, flags, result.Initialize)
+ : Interop.Unix.hostfxr_resolve_sdk2(dotnetExeDirectory, globalJsonStartDirectory, flags, result.Initialize);
+
+ Debug.Assert((errorCode == 0) == (result.ResolvedSdkDirectory != null));
+ return result;
+ }
+
+ private sealed class SdkList
+ {
+ public string[] Entries;
+
+ public void Initialize(int count, string[] entries)
+ {
+ entries = entries ?? Array.Empty();
+ Debug.Assert(count == entries.Length);
+ Entries = entries;
+ }
+ }
+
+ public static string[] GetAvailableSdks(string dotnetExeDirectory)
+ {
+ var list = new SdkList();
+
+ int errorCode = Interop.RunningOnWindows
+ ? Interop.Windows.hostfxr_get_available_sdks(dotnetExeDirectory, list.Initialize)
+ : Interop.Unix.hostfxr_get_available_sdks(dotnetExeDirectory, list.Initialize);
+
+ return list.Entries;
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.MSBuildSdkResolver/VSSettings.cs b/src/Microsoft.DotNet.MSBuildSdkResolver/VSSettings.cs
new file mode 100644
index 000000000..46dfda2e6
--- /dev/null
+++ b/src/Microsoft.DotNet.MSBuildSdkResolver/VSSettings.cs
@@ -0,0 +1,155 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+
+#if NET46
+using Microsoft.VisualStudio.Setup.Configuration;
+#endif
+
+namespace Microsoft.DotNet.MSBuildSdkResolver
+{
+ internal sealed class VSSettings
+ {
+ private readonly object _lock = new object();
+ private readonly string _settingsFilePath;
+ private readonly bool _disallowPrereleaseByDefault;
+ private FileInfo _settingsFile;
+ private bool _disallowPrerelease;
+
+ // In the product, this singleton is used. It must be safe to use in parallel on multiple threads.
+ // In tests, mock instances can be created with the test constructor below.
+ public static readonly VSSettings Ambient = new VSSettings();
+
+ private VSSettings()
+ {
+#if NET46
+ if (!Interop.RunningOnWindows)
+ {
+ return;
+ }
+
+ string instanceId;
+ string installationVersion;
+ bool isPrerelease;
+
+ try
+ {
+ var configuration = new SetupConfiguration();
+ var instance = configuration.GetInstanceForCurrentProcess();
+
+ instanceId = instance.GetInstanceId();
+ installationVersion = instance.GetInstallationVersion();
+ isPrerelease = ((ISetupInstanceCatalog)instance).IsPrerelease();
+ }
+ catch (COMException)
+ {
+ return;
+ }
+
+ var version = Version.Parse(installationVersion);
+
+ _settingsFilePath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Microsoft",
+ "VisualStudio",
+ version.Major + ".0_" + instanceId,
+ "sdk.txt");
+
+ _disallowPrereleaseByDefault = !isPrerelease;
+ _disallowPrerelease = _disallowPrereleaseByDefault;
+#endif
+ }
+
+ // Test constructor
+ public VSSettings(string settingsFilePath, bool disallowPrereleaseByDefault)
+ {
+ _settingsFilePath = settingsFilePath;
+ _disallowPrereleaseByDefault = disallowPrereleaseByDefault;
+ _disallowPrerelease = _disallowPrereleaseByDefault;
+ }
+
+ public bool DisallowPrerelease()
+ {
+ if (_settingsFilePath != null)
+ {
+ Refresh();
+ }
+
+ return _disallowPrerelease;
+ }
+
+ private void Refresh()
+ {
+ Debug.Assert(_settingsFilePath != null);
+
+ var file = new FileInfo(_settingsFilePath);
+
+ // NB: All calls to Exists and LastWriteTimeUtc below will not hit the disk
+ // They will return data obtained during Refresh() here.
+ file.Refresh();
+
+ lock (_lock)
+ {
+ // File does not exist -> use default.
+ if (!file.Exists)
+ {
+ _disallowPrerelease = _disallowPrereleaseByDefault;
+ _settingsFile = file;
+ return;
+ }
+
+ // File has not changed -> reuse prior read.
+ if (_settingsFile?.Exists == true && file.LastWriteTimeUtc <= _settingsFile.LastWriteTimeUtc)
+ {
+ return;
+ }
+
+ // File has changed -> read from disk
+ // If we encounter an I/O exception, assume writer is in the process of updating file,
+ // ignore the exception, and use stale settings until the next resolution.
+ try
+ {
+ ReadFromDisk();
+ _settingsFile = file;
+ return;
+ }
+ catch (IOException) { }
+ catch (UnauthorizedAccessException) { }
+ }
+ }
+
+ private void ReadFromDisk()
+ {
+ using (var reader = new StreamReader(_settingsFilePath))
+ {
+ string line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ int indexOfEquals = line.IndexOf('=');
+ if (indexOfEquals < 0 || indexOfEquals == (line.Length - 1))
+ {
+ continue;
+ }
+
+ string key = line.Substring(0, indexOfEquals).Trim();
+ string value = line.Substring(indexOfEquals + 1).Trim();
+
+ if (key.Equals("UsePreviews", StringComparison.OrdinalIgnoreCase)
+ && bool.TryParse(value, out bool usePreviews))
+ {
+ _disallowPrerelease = !usePreviews;
+ return;
+ }
+ }
+ }
+
+ // File does not have UsePreviews entry -> use default
+ _disallowPrerelease = _disallowPrereleaseByDefault;
+ }
+ }
+}
+
diff --git a/src/dotnet/ToolPackage/PackageLocation.cs b/src/dotnet/ToolPackage/PackageLocation.cs
new file mode 100644
index 000000000..c0838d1b5
--- /dev/null
+++ b/src/dotnet/ToolPackage/PackageLocation.cs
@@ -0,0 +1,23 @@
+
+using System;
+using Microsoft.Extensions.EnvironmentAbstractions;
+
+namespace Microsoft.DotNet.ToolPackage
+{
+ internal class PackageLocation
+ {
+ public PackageLocation(
+ FilePath? nugetConfig = null,
+ DirectoryPath? rootConfigDirectory = null,
+ string[] additionalFeeds = null)
+ {
+ NugetConfig = nugetConfig;
+ RootConfigDirectory = rootConfigDirectory;
+ AdditionalFeeds = additionalFeeds ?? Array.Empty();
+ }
+
+ public FilePath? NugetConfig { get; }
+ public DirectoryPath? RootConfigDirectory { get; }
+ public string[] AdditionalFeeds { get; }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-tool/ToolCommandRestorePassThroughOptions.cs b/src/dotnet/commands/dotnet-tool/ToolCommandRestorePassThroughOptions.cs
new file mode 100644
index 000000000..511f8b867
--- /dev/null
+++ b/src/dotnet/commands/dotnet-tool/ToolCommandRestorePassThroughOptions.cs
@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.DotNet.Cli.CommandLine;
+using LocalizableStrings = Microsoft.DotNet.Tools.Restore.LocalizableStrings;
+
+
+namespace Microsoft.DotNet.Cli
+{
+ internal static class ToolCommandRestorePassThroughOptions
+ {
+ public static Option DisableParallelOption()
+ {
+ return Create.Option(
+ "--disable-parallel",
+ LocalizableStrings.CmdDisableParallelOptionDescription,
+ Accept.NoArguments().ForwardAs("--disable-parallel"));
+ }
+
+ public static Option NoCacheOption()
+ {
+ return Create.Option(
+ "--no-cache",
+ LocalizableStrings.CmdNoCacheOptionDescription,
+ Accept.NoArguments().ForwardAs("--no-cache"));
+ }
+
+ public static Option IgnoreFailedSourcesOption()
+ {
+ return Create.Option(
+ "--ignore-failed-sources",
+ LocalizableStrings.CmdIgnoreFailedSourcesOptionDescription,
+ Accept.NoArguments().ForwardAs("--ignore-failed-sources"));
+ }
+ }
+}
diff --git a/test/EndToEnd/GivenAspNetAppsResolveImplicitVersions.cs b/test/EndToEnd/GivenAspNetAppsResolveImplicitVersions.cs
index 9e3850e74..f8b781be6 100644
--- a/test/EndToEnd/GivenAspNetAppsResolveImplicitVersions.cs
+++ b/test/EndToEnd/GivenAspNetAppsResolveImplicitVersions.cs
@@ -52,7 +52,7 @@ namespace EndToEnd
var bundledVersion = File.ReadAllText(bundledVersionPath).Trim();
restoredVersion.ToNormalizedString().Should().BeEquivalentTo(bundledVersion,
- "The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be idenitical to the versions set in DependencyVersions.props." +
+ "The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be identical to the versions generated." +
"Please update MSBuildExtensions.targets in this repo so these versions match.");
}
@@ -98,7 +98,7 @@ namespace EndToEnd
var bundledVersion = File.ReadAllText(bundledVersionPath).Trim();
restoredVersion.ToNormalizedString().Should().BeEquivalentTo(bundledVersion,
- "The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be idenitical to the versions set in DependencyVersions.props." +
+ "The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be identical to the versions set in DependencyVersions.props." +
"Please update MSBuildExtensions.targets in this repo so these versions match.");
}
diff --git a/test/EndToEnd/SupportedNetCoreAppVersions.cs b/test/EndToEnd/SupportedNetCoreAppVersions.cs
index fe1eb44e2..97e8262b9 100644
--- a/test/EndToEnd/SupportedNetCoreAppVersions.cs
+++ b/test/EndToEnd/SupportedNetCoreAppVersions.cs
@@ -18,7 +18,8 @@ namespace EndToEnd
"1.0",
"1.1",
"2.0",
- "2.1"
+ "2.1",
+ "2.2"
}.Select(version => new object[] { version });
}
}
diff --git a/test/Microsoft.DotNet.TestFramework/TestAssetInstance.cs b/test/Microsoft.DotNet.TestFramework/TestAssetInstance.cs
index 69a67a240..93509a21a 100644
--- a/test/Microsoft.DotNet.TestFramework/TestAssetInstance.cs
+++ b/test/Microsoft.DotNet.TestFramework/TestAssetInstance.cs
@@ -109,19 +109,23 @@ namespace Microsoft.DotNet.TestFramework
return this;
}
- public TestAssetInstance WithNuGetConfig(string nugetCache)
+ public TestAssetInstance WithNuGetConfig(string nugetCache, string externalRestoreSources = null)
{
var thisAssembly = typeof(TestAssetInstance).GetTypeInfo().Assembly;
var newNuGetConfig = Root.GetFile("NuGet.Config");
+ externalRestoreSources = externalRestoreSources ?? string.Empty;
var content = @"
+ $externalRestoreSources$
";
- content = content.Replace("$fullpath$", nugetCache);
+ content = content
+ .Replace("$fullpath$", nugetCache)
+ .Replace("$externalRestoreSources$", externalRestoreSources);
using (var newNuGetConfigStream =
new FileStream(newNuGetConfig.FullName, FileMode.Create, FileAccess.Write))
diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs
index 7de277852..de2af4896 100644
--- a/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs
+++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/RepoDirectoriesProvider.cs
@@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string _stage2WithBackwardsCompatibleRuntimesDirectory;
private string _testPackages;
private string _testWorkingFolder;
+ private string _testArtifactsFolder;
public static string RepoRoot
{
@@ -92,6 +93,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
public string Stage2WithBackwardsCompatibleRuntimesDirectory => _stage2WithBackwardsCompatibleRuntimesDirectory;
public string TestPackages => _testPackages;
public string TestWorkingFolder => _testWorkingFolder;
+ public string TestArtifactsFolder => _testArtifactsFolder;
public RepoDirectoriesProvider(
string artifacts = null,
@@ -123,6 +125,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_testPackages = Path.Combine(_artifacts, "test", "packages");
}
+ _testArtifactsFolder = Path.Combine(_artifacts, "test", "artifacts");
+
_testWorkingFolder = Path.Combine(RepoRoot,
"bin",
(previousStage + 1).ToString(),
diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestAssetInstanceExtensions.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestAssetInstanceExtensions.cs
new file mode 100644
index 000000000..a1cf95916
--- /dev/null
+++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestAssetInstanceExtensions.cs
@@ -0,0 +1,33 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.DotNet.TestFramework;
+using Microsoft.DotNet.Tools.Common;
+
+namespace Microsoft.DotNet.Tools.Test.Utilities
+{
+ public static class TestAssetInstanceExtensions
+ {
+ public static TestAssetInstance WithNuGetConfigAndExternalRestoreSources(
+ this TestAssetInstance testAssetInstance, string nugetCache)
+ {
+ var externalRestoreSourcesForTests = Path.Combine(
+ new RepoDirectoriesProvider().TestArtifactsFolder, "ExternalRestoreSourcesForTestsContainer.txt");
+ var externalRestoreSources = File.Exists(externalRestoreSourcesForTests) ?
+ File.ReadAllText(externalRestoreSourcesForTests) :
+ string.Empty;
+
+ return testAssetInstance.WithNuGetConfig(nugetCache, externalRestoreSources);
+ }
+ }
+}
\ No newline at end of file