From a679f1dbb232ce31108cf7ef91e71b7654feedea Mon Sep 17 00:00:00 2001 From: Peter Schneider Date: Wed, 2 Mar 2016 22:13:00 +0100 Subject: [PATCH 01/99] Fix for issue #1656 --- scripts/Microsoft.DotNet.Cli.Build.Framework/AnsiConsole.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/AnsiConsole.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/AnsiConsole.cs index 7f3e26852..c66c8e5d5 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/AnsiConsole.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/AnsiConsole.cs @@ -38,8 +38,8 @@ namespace Microsoft.DotNet.Cli.Build.Framework Console.ForegroundColor = c < 0 ? color : // unknown, just use it - _boldRecursion > 0 ? (ConsoleColor)(c & ~Light) : // ensure color is dark - (ConsoleColor)(c | Light); // ensure color is light + _boldRecursion > 0 ? (ConsoleColor)(c | Light) : // ensure color is light + (ConsoleColor)(c & ~Light); // ensure color is dark } private void SetBold(bool bold) From 29bc612565e6c06f608a0113f8ff05de7ae7b6ff Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 13:39:41 -0800 Subject: [PATCH 02/99] Refactor SDK Build Steps Prefix the SDK build stuff with "Sdk" to make it easier to add other sorts of packages (e.g. the shared host and the shared framework). --- scripts/dotnet-cli-build/InstallerTargets.cs | 4 +- scripts/dotnet-cli-build/MsiTargets.cs | 22 ++++---- scripts/dotnet-cli-build/PackageTargets.cs | 4 +- scripts/dotnet-cli-build/PrepareTargets.cs | 55 +++++++++++--------- scripts/dotnet-cli-build/PublishTargets.cs | 12 ++--- scripts/dotnet-cli-build/Utils/Monikers.cs | 4 +- 6 files changed, 54 insertions(+), 47 deletions(-) diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index be1a4836a..b11039d7e 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -28,7 +28,7 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult GeneratePkg(BuildTargetContext c) { var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var pkg = c.BuildContext.Get("InstallerFile"); + var pkg = c.BuildContext.Get("SdkInstallerFile"); Cmd(Path.Combine(Dirs.RepoRoot, "packaging", "osx", "package-osx.sh"), "-v", version, "-i", Dirs.Stage2, "-o", pkg) .Execute() @@ -43,7 +43,7 @@ namespace Microsoft.DotNet.Cli.Build var channel = c.BuildContext.Get("Channel").ToLower(); var packageName = Monikers.GetDebianPackageName(c); var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var debFile = c.BuildContext.Get("InstallerFile"); + var debFile = c.BuildContext.Get("SdkInstallerFile"); var manPagesDir = Path.Combine(Dirs.RepoRoot, "Documentation", "manpages"); var previousVersionURL = $"https://dotnetcli.blob.core.windows.net/dotnet/{channel}/Installers/Latest/dotnet-ubuntu-x64.latest.deb"; diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index 6d83a8794..daf76a449 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -22,9 +22,9 @@ namespace Microsoft.DotNet.Cli.Build } } - private static string Msi { get; set; } + private static string SdkMsi { get; set; } - private static string Bundle { get; set; } + private static string SdkBundle { get; set; } private static string Engine { get; set; } @@ -60,9 +60,9 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult InitMsi(BuildTargetContext c) { - Bundle = c.BuildContext.Get("InstallerFile"); - Msi = Path.ChangeExtension(Bundle, "msi"); - Engine = Path.Combine(Path.GetDirectoryName(Bundle), ENGINE); + SdkBundle = c.BuildContext.Get("SdkInstallerFile"); + SdkMsi = Path.ChangeExtension(SdkBundle, "msi"); + Engine = Path.Combine(Path.GetDirectoryName(SdkBundle), ENGINE); var buildVersion = c.BuildContext.Get("BuildVersion"); MsiVersion = buildVersion.GenerateMsiVersion(); @@ -76,7 +76,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(MsiTargets.InitMsi), nameof(GenerateDotnetMuxerMsi), nameof(GenerateDotnetSharedFxMsi), - nameof(GenerateCLISDKMsi))] + nameof(GenerateCliSdkMsi))] [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateMsis(BuildTargetContext c) { @@ -85,11 +85,11 @@ namespace Microsoft.DotNet.Cli.Build [Target] [BuildPlatforms(BuildPlatform.Windows)] - public static BuildTargetResult GenerateCLISDKMsi(BuildTargetContext c) + public static BuildTargetResult GenerateCliSdkMsi(BuildTargetContext c) { Cmd("powershell", "-NoProfile", "-NoLogo", Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatemsi.ps1"), - Dirs.Stage2, Msi, WixRoot, MsiVersion, CliVersion, Arch, Channel) + Dirs.Stage2, SdkMsi, WixRoot, MsiVersion, CliVersion, Arch, Channel) .Execute() .EnsureSuccessful(); return c.Success(); @@ -116,7 +116,7 @@ namespace Microsoft.DotNet.Cli.Build { Cmd("powershell", "-NoProfile", "-NoLogo", Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatebundle.ps1"), - Msi, Bundle, WixRoot, MsiVersion, CliVersion, Arch, Channel) + SdkMsi, SdkBundle, WixRoot, MsiVersion, CliVersion, Arch, Channel) .EnvironmentVariable("Stage2Dir", Dirs.Stage2) .Execute() .EnsureSuccessful(); @@ -127,7 +127,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult ExtractEngineFromBundle(BuildTargetContext c) { - Cmd($"{WixRoot}\\insignia.exe", "-ib", Bundle, "-o", Engine) + Cmd($"{WixRoot}\\insignia.exe", "-ib", SdkBundle, "-o", Engine) .Execute() .EnsureSuccessful(); return c.Success(); @@ -137,7 +137,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult ReattachEngineToBundle(BuildTargetContext c) { - Cmd($"{WixRoot}\\insignia.exe", "-ab", Engine, Bundle, "-o", Bundle) + Cmd($"{WixRoot}\\insignia.exe", "-ab", Engine, SdkBundle, "-o", SdkBundle) .Execute() .EnsureSuccessful(); return c.Success(); diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index c43b201e1..af31bf688 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -55,7 +55,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateZip(BuildTargetContext c) { - var zipFile = c.BuildContext.Get("CompressedFile"); + var zipFile = c.BuildContext.Get("SdkCompressedFile"); if (File.Exists(zipFile)) { @@ -70,7 +70,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Unix)] public static BuildTargetResult GenerateTarBall(BuildTargetContext c) { - var tarFile = c.BuildContext.Get("CompressedFile"); + var tarFile = c.BuildContext.Get("SdkCompressedFile"); if (File.Exists(tarFile)) { diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 9a11d5b7e..1465d9d44 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -108,34 +108,11 @@ namespace Microsoft.DotNet.Cli.Build [Target] public static BuildTargetResult ExpectedBuildArtifacts(BuildTargetContext c) { - var productName = Monikers.GetProductMoniker(c); var config = Environment.GetEnvironmentVariable("CONFIGURATION"); var versionBadgeName = $"{CurrentPlatform.Current}_{CurrentArchitecture.Current}_{config}_version_badge.svg"; c.BuildContext["VersionBadge"] = Path.Combine(Dirs.Output, versionBadgeName); - var extension = CurrentPlatform.IsWindows ? ".zip" : ".tar.gz"; - c.BuildContext["CompressedFile"] = Path.Combine(Dirs.Packages, productName + extension); - - string installer = ""; - switch (CurrentPlatform.Current) - { - case BuildPlatform.Windows: - installer = productName + ".exe"; - break; - case BuildPlatform.OSX: - installer = productName + ".pkg"; - break; - case BuildPlatform.Ubuntu: - installer = productName + ".deb"; - break; - default: - break; - } - - if (!string.IsNullOrEmpty(installer)) - { - c.BuildContext["InstallerFile"] = Path.Combine(Dirs.Packages, installer); - } + AddInstallerArtifactToContext(c, "dotnet", "Sdk"); return c.Success(); } @@ -361,5 +338,35 @@ cmake is required to build the native host 'corehost'"; } return dict; } + + private static void AddInstallerArtifactToContext(BuildTargetContext c, string artifactPrefix, string contextPrefix) + { + var productName = Monikers.GetProductMoniker(c, artifactPrefix); + + var extension = CurrentPlatform.IsWindows ? ".zip" : ".tar.gz"; + c.BuildContext[contextPrefix + "CompressedFile"] = Path.Combine(Dirs.Packages, productName + extension); + + string installer = ""; + switch (CurrentPlatform.Current) + { + case BuildPlatform.Windows: + installer = productName + ".exe"; + break; + case BuildPlatform.OSX: + installer = productName + ".pkg"; + break; + case BuildPlatform.Ubuntu: + installer = productName + ".deb"; + break; + default: + break; + } + + if (!string.IsNullOrEmpty(installer)) + { + c.BuildContext[contextPrefix + "InstallerFile"] = Path.Combine(Dirs.Packages, installer); + } + + } } } diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 6a69fcd89..797f8a6a9 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -45,7 +45,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PublishTargets.PublishVersionBadge), nameof(PublishTargets.PublishCompressedFile), - nameof(PublishTargets.PublishInstallerFile), + nameof(PublishTargets.PublishSdkInstallerFile), nameof(PublishTargets.PublishLatestVersionTextFile))] public static BuildTargetResult PublishArtifacts(BuildTargetContext c) { @@ -67,7 +67,7 @@ namespace Microsoft.DotNet.Cli.Build [Target] public static BuildTargetResult PublishCompressedFile(BuildTargetContext c) { - var compressedFile = c.BuildContext.Get("CompressedFile"); + var compressedFile = c.BuildContext.Get("SdkCompressedFile"); var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; var latestCompressedFile = compressedFile.Replace(Version, "latest"); var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; @@ -79,9 +79,9 @@ namespace Microsoft.DotNet.Cli.Build [Target] [BuildPlatforms(BuildPlatform.Windows, BuildPlatform.OSX, BuildPlatform.Ubuntu)] - public static BuildTargetResult PublishInstallerFile(BuildTargetContext c) + public static BuildTargetResult PublishSdkInstallerFile(BuildTargetContext c) { - var installerFile = c.BuildContext.Get("InstallerFile"); + var installerFile = c.BuildContext.Get("SdkInstallerFile"); var installerFileBlob = $"{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; var latestInstallerFile = installerFile.Replace(Version, "latest"); var latestInstallerFileBlob = $"{Channel}/Installers/Latest/{Path.GetFileName(latestInstallerFile)}"; @@ -102,12 +102,12 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target(nameof(PublishInstallerFile))] + [Target(nameof(PublishSdkInstallerFile))] [BuildPlatforms(BuildPlatform.Ubuntu)] public static BuildTargetResult PublishDebFileToDebianRepo(BuildTargetContext c) { var packageName = Monikers.GetDebianPackageName(c); - var installerFile = c.BuildContext.Get("InstallerFile"); + var installerFile = c.BuildContext.Get("SdkInstallerFile"); var uploadUrl = $"https://dotnetcli.blob.core.windows.net/dotnet/{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; var uploadJson = GenerateUploadJsonFile(packageName, Version, uploadUrl); diff --git a/scripts/dotnet-cli-build/Utils/Monikers.cs b/scripts/dotnet-cli-build/Utils/Monikers.cs index ae8052636..56eac7ee1 100644 --- a/scripts/dotnet-cli-build/Utils/Monikers.cs +++ b/scripts/dotnet-cli-build/Utils/Monikers.cs @@ -8,12 +8,12 @@ namespace Microsoft.DotNet.Cli.Build { public class Monikers { - public static string GetProductMoniker(BuildTargetContext c) + public static string GetProductMoniker(BuildTargetContext c, string artifactPrefix) { string osname = GetOSShortName(); var arch = CurrentArchitecture.Current.ToString(); var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - return $"dotnet-{osname}-{arch}.{version}"; + return $"{artifactPrefix}-{osname}-{arch}.{version}"; } public static string GetDebianPackageName(BuildTargetContext c) From 04d21e6693a221f884294a15ee747498c50f69c6 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 15:22:33 -0800 Subject: [PATCH 03/99] Add Shared Host MSI Authoring Ideally in the project.json for the shared host we would just list the actual package that holds the shared host, instead of all of NetStandard.Library, but doing some leads to compliation errors, since publish wants to include a compile step that has a generated AssemblyAttributes file which references types like System.String. --- packaging/host/windows/generatemsi.ps1 | 109 ++++++++++++++++++ packaging/host/windows/host.wxs | 44 +++++++ packaging/host/windows/provider.wxs | 9 ++ packaging/host/windows/registrykeys.wxs | 28 +++++ packaging/host/windows/variables.wxi | 29 +++++ scripts/dotnet-cli-build/MsiTargets.cs | 25 +++- scripts/dotnet-cli-build/PrepareTargets.cs | 1 + .../SharedFrameworkTargets.cs | 46 ++++++++ src/sharedframework/host/project.json | 11 ++ 9 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 packaging/host/windows/generatemsi.ps1 create mode 100644 packaging/host/windows/host.wxs create mode 100644 packaging/host/windows/provider.wxs create mode 100644 packaging/host/windows/registrykeys.wxs create mode 100644 packaging/host/windows/variables.wxi create mode 100644 scripts/dotnet-cli-build/SharedFrameworkTargets.cs create mode 100644 src/sharedframework/host/project.json diff --git a/packaging/host/windows/generatemsi.ps1 b/packaging/host/windows/generatemsi.ps1 new file mode 100644 index 000000000..124a987e8 --- /dev/null +++ b/packaging/host/windows/generatemsi.ps1 @@ -0,0 +1,109 @@ +# 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. + +param( + [Parameter(Mandatory=$true)][string]$SharedHostPublishRoot, + [Parameter(Mandatory=$true)][string]$DotnetHostMSIOutput, + [Parameter(Mandatory=$true)][string]$WixRoot, + [Parameter(Mandatory=$true)][string]$DotnetMSIVersion, + [Parameter(Mandatory=$true)][string]$DotnetCLIVersion, + [Parameter(Mandatory=$true)][string]$Architecture, + [Parameter(Mandatory=$true)][string]$WixObjRoot +) + +. "$PSScriptRoot\..\..\..\scripts\common\_common.ps1" +$RepoRoot = Convert-Path "$PSScriptRoot\..\..\.." + +function RunCandle +{ + $result = $true + pushd "$WixRoot" + + Write-Host Running candle.. + $AuthWsxRoot = Join-Path $RepoRoot "packaging\host\windows" + + .\candle.exe -nologo ` + -out "$WixObjRoot\" ` + -ext WixDependencyExtension.dll ` + -dHostSrc="$SharedHostPublishRoot" ` + -dMicrosoftEula="$RepoRoot\packaging\osx\resources\en.lproj\eula.rtf" ` + -dBuildVersion="$DotnetMSIVersion" ` + -dDisplayVersion="$DotnetCLIVersion" ` + -arch $Architecture ` + "$AuthWsxRoot\host.wxs" ` + "$AuthWsxRoot\provider.wxs" ` + "$AuthWsxRoot\registrykeys.wxs" | Out-Host + + if($LastExitCode -ne 0) + { + $result = $false + Write-Host "Candle failed with exit code $LastExitCode." + } + + popd + return $result +} + +function RunLight +{ + $result = $true + pushd "$WixRoot" + + Write-Host Running light.. + + .\light.exe -nologo ` + -ext WixUIExtension.dll ` + -ext WixDependencyExtension.dll ` + -ext WixUtilExtension.dll ` + -cultures:en-us ` + "$WixObjRoot\host.wixobj" ` + "$WixObjRoot\provider.wixobj" ` + "$WixObjRoot\registrykeys.wixobj" ` + -out $DotnetHostMSIOutput | Out-Host + + if($LastExitCode -ne 0) + { + $result = $false + Write-Host "Light failed with exit code $LastExitCode." + } + + popd + return $result +} + +if(!(Test-Path $SharedHostPublishRoot)) +{ + throw "$SharedHostPublishRoot not found" +} + +if(!(Test-Path $WixObjRoot)) +{ + throw "$WixObjRoot not found" +} + +Write-Host "Creating shared host MSI at $DotnetHostMSIOutput" + +if([string]::IsNullOrEmpty($WixRoot)) +{ + Exit -1 +} + +if(-Not (RunCandle)) +{ + Exit -1 +} + +if(-Not (RunLight)) +{ + Exit -1 +} + +if(!(Test-Path $DotnetHostMSIOutput)) +{ + throw "Unable to create the shared host msi." + Exit -1 +} + +Write-Host -ForegroundColor Green "Successfully created shared host MSI - $DotnetHostMSIOutput" + +exit $LastExitCode \ No newline at end of file diff --git a/packaging/host/windows/host.wxs b/packaging/host/windows/host.wxs new file mode 100644 index 000000000..736beb665 --- /dev/null +++ b/packaging/host/windows/host.wxs @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/host/windows/provider.wxs b/packaging/host/windows/provider.wxs new file mode 100644 index 000000000..be191eb7e --- /dev/null +++ b/packaging/host/windows/provider.wxs @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packaging/host/windows/registrykeys.wxs b/packaging/host/windows/registrykeys.wxs new file mode 100644 index 000000000..6f5a3cad0 --- /dev/null +++ b/packaging/host/windows/registrykeys.wxs @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/host/windows/variables.wxi b/packaging/host/windows/variables.wxi new file mode 100644 index 000000000..71ea4a1d8 --- /dev/null +++ b/packaging/host/windows/variables.wxi @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index daf76a449..7cbb00ca5 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -26,6 +26,8 @@ namespace Microsoft.DotNet.Cli.Build private static string SdkBundle { get; set; } + private static string SharedHostMsi { get; set; } + private static string Engine { get; set; } private static string MsiVersion { get; set; } @@ -64,6 +66,8 @@ namespace Microsoft.DotNet.Cli.Build SdkMsi = Path.ChangeExtension(SdkBundle, "msi"); Engine = Path.Combine(Path.GetDirectoryName(SdkBundle), ENGINE); + SharedHostMsi = Path.ChangeExtension(c.BuildContext.Get("SharedHostInstallerFile"), "msi"); + var buildVersion = c.BuildContext.Get("BuildVersion"); MsiVersion = buildVersion.GenerateMsiVersion(); CliVersion = buildVersion.SimpleVersion; @@ -74,7 +78,7 @@ namespace Microsoft.DotNet.Cli.Build } [Target(nameof(MsiTargets.InitMsi), - nameof(GenerateDotnetMuxerMsi), + nameof(GenerateDotnetSharedHostMsi), nameof(GenerateDotnetSharedFxMsi), nameof(GenerateCliSdkMsi))] [BuildPlatforms(BuildPlatform.Windows)] @@ -95,10 +99,25 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target] + [Target(nameof(SharedFrameworkTargets.PublishSharedHost))] [BuildPlatforms(BuildPlatform.Windows)] - public static BuildTargetResult GenerateDotnetMuxerMsi(BuildTargetContext c) + public static BuildTargetResult GenerateDotnetSharedHostMsi(BuildTargetContext c) { + var inputDir = c.BuildContext.Get("SharedHostPublishRoot"); + var wixObjRoot = Path.Combine(Dirs.Output, "obj", "wix", "sharedhost"); + + if (Directory.Exists(wixObjRoot)) + { + Directory.Delete(wixObjRoot, true); + } + + Directory.CreateDirectory(wixObjRoot); + + Cmd("powershell", "-NoProfile", "-NoLogo", + Path.Combine(Dirs.RepoRoot, "packaging", "host", "windows", "generatemsi.ps1"), + inputDir, SharedHostMsi, WixRoot, MsiVersion, CliVersion, Arch, wixObjRoot) + .Execute() + .EnsureSuccessful(); return c.Success(); } diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 1465d9d44..69c957e91 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -113,6 +113,7 @@ namespace Microsoft.DotNet.Cli.Build c.BuildContext["VersionBadge"] = Path.Combine(Dirs.Output, versionBadgeName); AddInstallerArtifactToContext(c, "dotnet", "Sdk"); + AddInstallerArtifactToContext(c, "dotnet-host", "SharedHost"); return c.Success(); } diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs new file mode 100644 index 000000000..412b6ef1f --- /dev/null +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.Extensions.PlatformAbstractions; + +using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; + +namespace Microsoft.DotNet.Cli.Build +{ + public class SharedFrameworkTargets + { + private const string CoreHostBaseName = "corehost"; + + [Target] + public static BuildTargetResult PublishSharedHost(BuildTargetContext c) + { + string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); + + if (Directory.Exists(SharedHostPublishRoot)) + { + Directory.Delete(SharedHostPublishRoot, true); + } + + DotNetCli.Stage0.Publish("--output", SharedHostPublishRoot, Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "host")).Execute().EnsureSuccessful(); + + // For the shared host, we only want corerun and not any of the other artifacts in the package (like the hostpolicy) + foreach (var filePath in Directory.GetFiles(SharedHostPublishRoot)) + { + if (Path.GetFileName(filePath) != $"{CoreHostBaseName}{Constants.ExeSuffix}") + { + File.Delete(filePath); + } + } + + // corehost will be renamed to dotnet at some point and then this can be removed. + File.Move(Path.Combine(SharedHostPublishRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); + + c.BuildContext["SharedHostPublishRoot"] = SharedHostPublishRoot; + + return c.Success(); + } + } +} \ No newline at end of file diff --git a/src/sharedframework/host/project.json b/src/sharedframework/host/project.json new file mode 100644 index 000000000..30251684c --- /dev/null +++ b/src/sharedframework/host/project.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.0.0-rc2-23811" + }, + + "frameworks": { + "dnxcore50": { } + } +} \ No newline at end of file From e6bcfee4a4d73437c38bc55b4477afadc1181a31 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 19:32:31 -0800 Subject: [PATCH 04/99] Add SharedFramework MSI Authoring --- .../sharedframework/windows/generatemsi.ps1 | 151 ++++++++++++++++++ .../sharedframework/windows/provider.wxs | 9 ++ .../sharedframework/windows/registrykeys.wxs | 28 ++++ .../windows/sharedframework.wxs | 35 ++++ .../sharedframework/windows/variables.wxi | 31 ++++ scripts/dotnet-cli-build/MsiTargets.cs | 27 +++- scripts/dotnet-cli-build/PrepareTargets.cs | 1 + .../SharedFrameworkTargets.cs | 57 +++++++ scripts/dotnet-cli-build/Utils/Utils.cs | 51 ++++++ scripts/dotnet-cli-build/project.json | 1 + src/sharedframework/framework/Program.cs | 11 ++ src/sharedframework/framework/project.json | 14 ++ 12 files changed, 413 insertions(+), 3 deletions(-) create mode 100644 packaging/sharedframework/windows/generatemsi.ps1 create mode 100644 packaging/sharedframework/windows/provider.wxs create mode 100644 packaging/sharedframework/windows/registrykeys.wxs create mode 100644 packaging/sharedframework/windows/sharedframework.wxs create mode 100644 packaging/sharedframework/windows/variables.wxi create mode 100644 src/sharedframework/framework/Program.cs create mode 100644 src/sharedframework/framework/project.json diff --git a/packaging/sharedframework/windows/generatemsi.ps1 b/packaging/sharedframework/windows/generatemsi.ps1 new file mode 100644 index 000000000..ed78f847d --- /dev/null +++ b/packaging/sharedframework/windows/generatemsi.ps1 @@ -0,0 +1,151 @@ +# 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. + +param( + [Parameter(Mandatory=$true)][string]$SharedFrameworkPublishRoot, + [Parameter(Mandatory=$true)][string]$SharedFrameworkMSIOutput, + [Parameter(Mandatory=$true)][string]$WixRoot, + [Parameter(Mandatory=$true)][string]$DotnetMSIVersion, + [Parameter(Mandatory=$true)][string]$SharedFrameworkNugetName, + [Parameter(Mandatory=$true)][string]$SharedFrameworkNugetVersion, + [Parameter(Mandatory=$true)][string]$SharedFrameworkUpgradeCode, + [Parameter(Mandatory=$true)][string]$Architecture, + [Parameter(Mandatory=$true)][string]$WixObjRoot +) + +. "$PSScriptRoot\..\..\..\scripts\common\_common.ps1" +$RepoRoot = Convert-Path "$PSScriptRoot\..\..\.." + +$InstallFileswsx = "$WixObjRoot\install-files.wxs" +$InstallFilesWixobj = "$WixObjRoot\install-files.wixobj" + + +function RunHeat +{ + $result = $true + pushd "$WixRoot" + + Write-Host Running heat.. + + .\heat.exe dir `"$SharedFrameworkPublishRoot`" ` + -nologo ` + -template fragment ` + -sreg -gg ` + -var var.SharedFrameworkSource ` + -cg InstallFiles ` + -srd ` + -dr DOTNETHOME ` + -out $InstallFileswsx | Out-Host + + if($LastExitCode -ne 0) + { + $result = $false + Write-Host "Heat failed with exit code $LastExitCode." + } + + popd + return $result +} + +function RunCandle +{ + $result = $true + pushd "$WixRoot" + + Write-Host Running candle.. + $AuthWsxRoot = Join-Path $RepoRoot "packaging\sharedframework\windows" + $SharedFrameworkComponentVersion = $SharedFrameworkNugetVersion.Replace('-', '_'); + + .\candle.exe -nologo ` + -out "$WixObjRoot\" ` + -dSharedFrameworkSource="$SharedFrameworkPublishRoot" ` + -dMicrosoftEula="$RepoRoot\packaging\osx\resources\en.lproj\eula.rtf" ` + -dFrameworkName="$SharedFrameworkNugetName" ` + -dFrameworkDisplayVersion="$SharedFrameworkNugetVersion" ` + -dFrameworkComponentVersion="$SharedFrameworkComponentVersion" ` + -dFrameworkUpgradeCode="$SharedFrameworkUpgradeCode" ` + -dBuildVersion="$DotnetMSIVersion" ` + -arch $Architecture ` + -ext WixDependencyExtension.dll ` + "$AuthWsxRoot\sharedframework.wxs" ` + "$AuthWsxRoot\provider.wxs" ` + "$AuthWsxRoot\registrykeys.wxs" ` + $InstallFileswsx | Out-Host + + if($LastExitCode -ne 0) + { + $result = $false + Write-Host "Candle failed with exit code $LastExitCode." + } + + popd + return $result +} + +function RunLight +{ + $result = $true + pushd "$WixRoot" + + Write-Host Running light.. + $CabCache = Join-Path $WixRoot "cabcache" + + .\light.exe -nologo -ext WixUIExtension -ext WixDependencyExtension -ext WixUtilExtension ` + -cultures:en-us ` + "$WixObjRoot\sharedframework.wixobj" ` + "$WixObjRoot\provider.wixobj" ` + "$WixObjRoot\registrykeys.wixobj" ` + "$InstallFilesWixobj" ` + -out $SharedFrameworkMSIOutput | Out-Host + + if($LastExitCode -ne 0) + { + $result = $false + Write-Host "Light failed with exit code $LastExitCode." + } + + popd + return $result +} + +if(!(Test-Path $SharedFrameworkPublishRoot)) +{ + throw "$SharedHostPublishRoot not found" +} + +if(!(Test-Path $WixObjRoot)) +{ + throw "$WixObjRoot not found" +} + +Write-Host "Creating dotnet shared framework MSI at $SharedFrameworkMSIOutput" + +if([string]::IsNullOrEmpty($WixRoot)) +{ + Exit -1 +} + +if(-Not (RunHeat)) +{ + Exit -1 +} + +if(-Not (RunCandle)) +{ + Exit -1 +} + +if(-Not (RunLight)) +{ + Exit -1 +} + +if(!(Test-Path $SharedFrameworkMSIOutput)) +{ + throw "Unable to create the dotnet shared framework msi." + Exit -1 +} + +Write-Host -ForegroundColor Green "Successfully created shared framework MSI - $SharedFrameworkMSIOutput" + +exit $LastExitCode diff --git a/packaging/sharedframework/windows/provider.wxs b/packaging/sharedframework/windows/provider.wxs new file mode 100644 index 000000000..665d58c4a --- /dev/null +++ b/packaging/sharedframework/windows/provider.wxs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packaging/sharedframework/windows/registrykeys.wxs b/packaging/sharedframework/windows/registrykeys.wxs new file mode 100644 index 000000000..51d322da1 --- /dev/null +++ b/packaging/sharedframework/windows/registrykeys.wxs @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/sharedframework/windows/sharedframework.wxs b/packaging/sharedframework/windows/sharedframework.wxs new file mode 100644 index 000000000..88680f5f2 --- /dev/null +++ b/packaging/sharedframework/windows/sharedframework.wxs @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/sharedframework/windows/variables.wxi b/packaging/sharedframework/windows/variables.wxi new file mode 100644 index 000000000..ad175258f --- /dev/null +++ b/packaging/sharedframework/windows/variables.wxi @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index 7cbb00ca5..12c3f1f6c 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -28,6 +28,8 @@ namespace Microsoft.DotNet.Cli.Build private static string SharedHostMsi { get; set; } + private static string SharedFrameworkMsi { get; set; } + private static string Engine { get; set; } private static string MsiVersion { get; set; } @@ -67,6 +69,7 @@ namespace Microsoft.DotNet.Cli.Build Engine = Path.Combine(Path.GetDirectoryName(SdkBundle), ENGINE); SharedHostMsi = Path.ChangeExtension(c.BuildContext.Get("SharedHostInstallerFile"), "msi"); + SharedFrameworkMsi = Path.ChangeExtension(c.BuildContext.Get("SharedFrameworkInstallerFile"), "msi"); var buildVersion = c.BuildContext.Get("BuildVersion"); MsiVersion = buildVersion.GenerateMsiVersion(); @@ -79,7 +82,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(MsiTargets.InitMsi), nameof(GenerateDotnetSharedHostMsi), - nameof(GenerateDotnetSharedFxMsi), + nameof(GenerateDotnetSharedFrameworkMsi), nameof(GenerateCliSdkMsi))] [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateMsis(BuildTargetContext c) @@ -121,10 +124,28 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target] + [Target(nameof(SharedFrameworkTargets.PublishSharedFramework))] [BuildPlatforms(BuildPlatform.Windows)] - public static BuildTargetResult GenerateDotnetSharedFxMsi(BuildTargetContext c) + public static BuildTargetResult GenerateDotnetSharedFrameworkMsi(BuildTargetContext c) { + var inputDir = c.BuildContext.Get("SharedFrameworkPublishRoot"); + var sharedFrameworkNuGetName = SharedFrameworkTargets.SharedFrameworkName; + var sharedFrameworkNuGetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); + var upgradeCode = Utils.GenerateGuidFromName($"{sharedFrameworkNuGetName}-{sharedFrameworkNuGetVersion}-{Arch}").ToString().ToUpper(); + var wixObjRoot = Path.Combine(Dirs.Output, "obj", "wix", "sharedframework"); + + if (Directory.Exists(wixObjRoot)) + { + Directory.Delete(wixObjRoot, true); + } + + Directory.CreateDirectory(wixObjRoot); + + Cmd("powershell", "-NoProfile", "-NoLogo", + Path.Combine(Dirs.RepoRoot, "packaging", "sharedframework", "windows", "generatemsi.ps1"), + inputDir, SharedFrameworkMsi, WixRoot, MsiVersion, sharedFrameworkNuGetName, sharedFrameworkNuGetVersion, upgradeCode, Arch, wixObjRoot) + .Execute() + .EnsureSuccessful(); return c.Success(); } diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 69c957e91..08dca3e05 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -114,6 +114,7 @@ namespace Microsoft.DotNet.Cli.Build AddInstallerArtifactToContext(c, "dotnet", "Sdk"); AddInstallerArtifactToContext(c, "dotnet-host", "SharedHost"); + AddInstallerArtifactToContext(c, "dotnet-sharedframework", "SharedFramework"); return c.Success(); } diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index 412b6ef1f..760992734 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Text.RegularExpressions; using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.Extensions.PlatformAbstractions; @@ -12,8 +13,47 @@ namespace Microsoft.DotNet.Cli.Build { public class SharedFrameworkTargets { + public const string SharedFrameworkName = "NETStandard.Library"; + private const string CoreHostBaseName = "corehost"; + [Target] + public static BuildTargetResult PublishSharedFramework(BuildTargetContext c) + { + string SharedFrameworkPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedframework"); + string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"); + string SharedFrameworkNugetVersion = GetVersionFromProjectJson(Path.Combine(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"), "project.json")); + + if (Directory.Exists(SharedFrameworkPublishRoot)) + { + Directory.Delete(SharedFrameworkPublishRoot, true); + } + + // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. + string SharedFrameworkNameAndVersionRoot = Path.Combine(SharedFrameworkPublishRoot, "shared", SharedFrameworkName, SharedFrameworkNugetVersion); + + DotNetCli.Stage0.Publish("--output", SharedFrameworkNameAndVersionRoot, SharedFrameworkSourceRoot).Execute().EnsureSuccessful(); + + c.BuildContext["SharedFrameworkPublishRoot"] = SharedFrameworkPublishRoot; + c.BuildContext["SharedFrameworkNugetVersion"] = SharedFrameworkNugetVersion; + + // Clean up artifacts that dotnet-publish generates which we don't need + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb")); + + // Rename the .deps file + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); + + // corehost will be renamed to dotnet at some point and then this can be removed. + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); + + // hostpolicy will be renamed to dotnet at some point and then this can be removed. + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}dotnethostimpl{Constants.DynamicLibSuffix}")); + + return c.Success(); + } + [Target] public static BuildTargetResult PublishSharedHost(BuildTargetContext c) { @@ -42,5 +82,22 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + + private static string GetVersionFromProjectJson(string pathToProjectJson) + { + Regex r = new Regex($"\"{Regex.Escape(SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\""); + + foreach(var line in File.ReadAllLines(pathToProjectJson)) + { + var m = r.Match(line); + + if (m.Success) + { + return m.Groups["version"].Value; + } + } + + return null; + } } } \ No newline at end of file diff --git a/scripts/dotnet-cli-build/Utils/Utils.cs b/scripts/dotnet-cli-build/Utils/Utils.cs index edbee23d1..21512a08b 100644 --- a/scripts/dotnet-cli-build/Utils/Utils.cs +++ b/scripts/dotnet-cli-build/Utils/Utils.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Runtime.InteropServices; +using System.Security.Cryptography; namespace Microsoft.DotNet.Cli.Build { @@ -34,5 +35,55 @@ namespace Microsoft.DotNet.Cli.Build throw new PlatformNotSupportedException(); } } + + // Generate a Version 5 (SHA1 Name Based) Guid from a name. + public static Guid GenerateGuidFromName(string name) + { + // Any fixed GUID will do for a namespace. + Guid namespaceId = new Guid("28F1468D-672B-489A-8E0C-7C5B3030630C"); + + using (SHA1 hasher = SHA1.Create()) + { + var nameBytes = System.Text.Encoding.UTF8.GetBytes(name ?? string.Empty); + var namespaceBytes = namespaceId.ToByteArray(); + + SwapGuidByteOrder(namespaceBytes); + + var streamToHash = new byte[namespaceBytes.Length + nameBytes.Length]; + + Array.Copy(namespaceBytes, streamToHash, namespaceBytes.Length); + Array.Copy(nameBytes, 0, streamToHash, namespaceBytes.Length, nameBytes.Length); + + var hashResult = hasher.ComputeHash(streamToHash); + + var res = new byte[16]; + + Array.Copy(hashResult, res, res.Length); + + unchecked { res[6] = (byte)(0x50 | (res[6] & 0x0F)); } + unchecked { res[8] = (byte)(0x40 | (res[8] & 0x3F)); } + + SwapGuidByteOrder(res); + + return new Guid(res); + } + } + + // Do a byte order swap, .NET GUIDs store multi byte components in little + // endian. + private static void SwapGuidByteOrder(byte[] b) + { + Swap(b, 0, 3); + Swap(b, 1, 2); + Swap(b, 5, 6); + Swap(b, 7, 8); + } + + private static void Swap(byte[] b, int x, int y) + { + byte t = b[x]; + b[x] = b[y]; + b[y] = t; + } } } diff --git a/scripts/dotnet-cli-build/project.json b/scripts/dotnet-cli-build/project.json index e76a7a1c3..2be69c156 100755 --- a/scripts/dotnet-cli-build/project.json +++ b/scripts/dotnet-cli-build/project.json @@ -8,6 +8,7 @@ "dependencies": { "NETStandard.Library": "1.0.0-rc2-23901", "System.IO.Compression.ZipFile": "4.0.1-rc2-23901", + "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", "WindowsAzure.Storage" : "6.2.2-preview" diff --git a/src/sharedframework/framework/Program.cs b/src/sharedframework/framework/Program.cs new file mode 100644 index 000000000..4aa370b90 --- /dev/null +++ b/src/sharedframework/framework/Program.cs @@ -0,0 +1,11 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + } + } +} \ No newline at end of file diff --git a/src/sharedframework/framework/project.json b/src/sharedframework/framework/project.json new file mode 100644 index 000000000..5d904b02f --- /dev/null +++ b/src/sharedframework/framework/project.json @@ -0,0 +1,14 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "NETStandard.Library": "1.0.0-rc2-23811" + }, + + "frameworks": { + "dnxcore50": { } + } +} \ No newline at end of file From 92edb36e5b12bdbc063209b483b9146b5e55ccd5 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 21:52:34 -0800 Subject: [PATCH 05/99] Generate zips for SharedHost and SharedFramework --- scripts/dotnet-cli-build/MsiTargets.cs | 4 ++-- scripts/dotnet-cli-build/PackageTargets.cs | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index 12c3f1f6c..e0e3ecb37 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -102,7 +102,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target(nameof(SharedFrameworkTargets.PublishSharedHost))] + [Target] [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateDotnetSharedHostMsi(BuildTargetContext c) { @@ -124,7 +124,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target(nameof(SharedFrameworkTargets.PublishSharedFramework))] + [Target] [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateDotnetSharedFrameworkMsi(BuildTargetContext c) { diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index af31bf688..af17fe7b7 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -22,6 +22,8 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PrepareTargets.Init), nameof(PackageTargets.InitPackage), nameof(PackageTargets.GenerateVersionBadge), + nameof(SharedFrameworkTargets.PublishSharedHost), + nameof(SharedFrameworkTargets.PublishSharedFramework), nameof(PackageTargets.GenerateCompressedFile), nameof(InstallerTargets.GenerateInstaller), nameof(PackageTargets.GenerateNugetPackages))] @@ -55,14 +57,10 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateZip(BuildTargetContext c) { - var zipFile = c.BuildContext.Get("SdkCompressedFile"); + CreateZipFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); + CreateZipFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); + CreateZipFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile")); - if (File.Exists(zipFile)) - { - File.Delete(zipFile); - } - - ZipFile.CreateFromDirectory(Dirs.Stage2, zipFile, CompressionLevel.Optimal, false); return c.Success(); } @@ -134,5 +132,15 @@ namespace Microsoft.DotNet.Cli.Build return env; } + + private static void CreateZipFromDirectory(string directory, string artifactPath) + { + if (File.Exists(artifactPath)) + { + File.Delete(artifactPath); + } + + ZipFile.CreateFromDirectory(directory, artifactPath, CompressionLevel.Optimal, false); + } } } From 92e520bf7c9b12b03731bc49ab6052340d660db9 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 22:42:16 -0800 Subject: [PATCH 06/99] Generate tars for SharedHost and SharedFramework --- scripts/dotnet-cli-build/PackageTargets.cs | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index af17fe7b7..11ba01b43 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -68,16 +68,10 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Unix)] public static BuildTargetResult GenerateTarBall(BuildTargetContext c) { - var tarFile = c.BuildContext.Get("SdkCompressedFile"); + CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); + CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); + CreateTarBallFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile")); - if (File.Exists(tarFile)) - { - File.Delete(tarFile); - } - - Cmd("tar", "-czf", tarFile, "-C", Dirs.Stage2, ".") - .Execute() - .EnsureSuccessful(); return c.Success(); } @@ -142,5 +136,17 @@ namespace Microsoft.DotNet.Cli.Build ZipFile.CreateFromDirectory(directory, artifactPath, CompressionLevel.Optimal, false); } + + private static void CreateTarBallFromDirectory(string directory, string artifactPath) + { + if (File.Exists(artifactPath)) + { + File.Delete(artifactPath); + } + + Cmd("tar", "-czf", artifactPath, "-C", directory, ".") + .Execute() + .EnsureSuccessful(); + } } } From 7e7995274a7e80731ee3f56c53faf7cb1c829a5a Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 8 Mar 2016 23:23:15 -0800 Subject: [PATCH 07/99] Add stub targets for shared framework and host --- scripts/dotnet-cli-build/InstallerTargets.cs | 55 ++++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index b11039d7e..fb7f425db 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -14,18 +14,25 @@ namespace Microsoft.DotNet.Cli.Build { [Target(nameof(MsiTargets.GenerateMsis), nameof(MsiTargets.GenerateBundle), - nameof(InstallerTargets.GeneratePkg), - nameof(InstallerTargets.GenerateDeb))] + nameof(InstallerTargets.GeneratePkgs), + nameof(InstallerTargets.GenerateDebs))] public static BuildTargetResult GenerateInstaller(BuildTargetContext c) { return c.Success(); } - + [Target(nameof(InstallerTargets.GenerateSdkPkg), + nameof(InstallerTargets.GenerateSharedFrameworkPkg), + nameof(InstallerTargets.GenerateSharedHostPkg))] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GeneratePkgs(BuildTargetContext c) + { + return c.Success(); + } [Target] [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GeneratePkg(BuildTargetContext c) + public static BuildTargetResult GenerateSdkPkg(BuildTargetContext c) { var version = c.BuildContext.Get("BuildVersion").SimpleVersion; var pkg = c.BuildContext.Get("SdkInstallerFile"); @@ -37,8 +44,31 @@ namespace Microsoft.DotNet.Cli.Build } [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSharedFrameworkPkg(BuildTargetContext c) + { + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSharedHostPkg(BuildTargetContext c) + { + return c.Success(); + } + + [Target(nameof(InstallerTargets.GenerateSdkDeb), + nameof(InstallerTargets.GenerateSharedFrameworkDeb), + nameof(InstallerTargets.GenerateSharedHostDeb))] [BuildPlatforms(BuildPlatform.Ubuntu)] - public static BuildTargetResult GenerateDeb(BuildTargetContext c) + public static BuildTargetResult GenerateDebs(BuildTargetContext c) + { + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.Ubuntu)] + public static BuildTargetResult GenerateSdkDeb(BuildTargetContext c) { var channel = c.BuildContext.Get("Channel").ToLower(); var packageName = Monikers.GetDebianPackageName(c); @@ -53,5 +83,20 @@ namespace Microsoft.DotNet.Cli.Build .EnsureSuccessful(); return c.Success(); } + + [Target] + [BuildPlatforms(BuildPlatform.Ubuntu)] + public static BuildTargetResult GenerateSharedHostDeb(BuildTargetContext c) + { + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.Ubuntu)] + public static BuildTargetResult GenerateSharedFrameworkDeb(BuildTargetContext c) + { + return c.Success(); + } + } } From 5cf35e4f38a4dcb64c26f286cb61e72e689f3817 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 10 Mar 2016 00:21:09 -0800 Subject: [PATCH 08/99] Use explicit object directory for sdk deb pacakge As we add more deb packages, we should keep everything tidy by given each one it's on individual object root. --- scripts/dotnet-cli-build/InstallerTargets.cs | 11 ++++++++++- scripts/package/package-debian.sh | 11 ++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index fb7f425db..88b36c800 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -77,8 +77,17 @@ namespace Microsoft.DotNet.Cli.Build var manPagesDir = Path.Combine(Dirs.RepoRoot, "Documentation", "manpages"); var previousVersionURL = $"https://dotnetcli.blob.core.windows.net/dotnet/{channel}/Installers/Latest/dotnet-ubuntu-x64.latest.deb"; + var objRoot = Path.Combine(Dirs.Output, "obj", "debian", "sdk"); + + if (Directory.Exists(objRoot)) + { + Directory.Delete(objRoot, true); + } + + Directory.CreateDirectory(objRoot); + Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "package", "package-debian.sh"), - "-v", version, "-i", Dirs.Stage2, "-o", debFile, "-p", packageName, "-m", manPagesDir, "--previous-version-url", previousVersionURL) + "-v", version, "-i", Dirs.Stage2, "-o", debFile, "-p", packageName, "-m", manPagesDir, "--previous-version-url", previousVersionURL, "--obj-root", objRoot) .Execute() .EnsureSuccessful(); return c.Success(); diff --git a/scripts/package/package-debian.sh b/scripts/package/package-debian.sh index e06748739..1b54bfb02 100755 --- a/scripts/package/package-debian.sh +++ b/scripts/package/package-debian.sh @@ -29,6 +29,7 @@ help(){ echo " --output The full path to which the package will be written." echo " --package-name Package to identify during installation. Example - 'dotnet-nightly', 'dotnet'" echo " --previous-version-url Url to the previous version of the debian packge against which to run the upgrade tests." + echo " --obj-root Root folder for intermediate objects." exit 1 } @@ -61,6 +62,10 @@ parseargs(){ PREVIOUS_VERSION_URL=$2 shift ;; + --obj-root) + OBJECT_DIR=$2 + shift + ;; --help) help ;; @@ -103,9 +108,9 @@ parseargs $@ PACKAGING_ROOT="$REPOROOT/packaging/debian" PACKAGING_TOOL_DIR="$REPOROOT/tools/DebianPackageTool" -PACKAGE_OUTPUT_DIR=$(dirname "${OUTPUT_DEBIAN_FILE}") -PACKAGE_LAYOUT_DIR="$PACKAGE_OUTPUT_DIR/deb_intermediate" -TEST_STAGE_DIR="$PACKAGE_OUTPUT_DIR/debian_tests" +PACKAGE_OUTPUT_DIR="$OBJECT_DIR/deb_output" +PACKAGE_LAYOUT_DIR="$OBJECT_DIR/deb_intermediate" +TEST_STAGE_DIR="$OBJECT_DIR/debian_tests" # remove any residual deb files from earlier builds rm -f "$PACKAGE_OUTPUT_DIR/*.deb" From 9004e20cf4dd3ff838f8e8b90d42a3a0ecf4c234 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 10 Mar 2016 00:12:25 -0800 Subject: [PATCH 09/99] Allow optional install_root in package config The shared framework packages will want to install to the same root directory as the "dotnet" package itself. Augment the package_tool script to look for a json key named `install_root` and use that if specificed, falling back to `/usr/share/$PACKAGE_NAME` when it is not present. --- tools/DebianPackageTool/package_tool | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/DebianPackageTool/package_tool b/tools/DebianPackageTool/package_tool index c48da1755..3cc139878 100755 --- a/tools/DebianPackageTool/package_tool +++ b/tools/DebianPackageTool/package_tool @@ -132,7 +132,10 @@ parse_config_and_set_env_vars(){ DOCS_JSON_PATH="$INPUT_DIR/docs.json" PACKAGE_SOURCE_DIR="${OUTPUT_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}" - INSTALL_ROOT="/usr/share/${PACKAGE_NAME}" + + if ! INSTALL_ROOT="$($extract_base_cmd $CONFIG "install_root")"; then + INSTALL_ROOT="/usr/share/$PACKAGE_NAME" + fi DEBIAN_DIR="${PACKAGE_SOURCE_DIR}/debian" DOCS_DIR="${PACKAGE_SOURCE_DIR}/docs" From 696f4dc167a377b39539e49842a142929c034036 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 9 Mar 2016 17:33:05 -0800 Subject: [PATCH 10/99] Add Shared Framework debian packaging --- .../dotnet-sharedframework-debian_config.json | 35 +++++ scripts/dotnet-cli-build/InstallerTargets.cs | 20 +++ scripts/dotnet-cli-build/Utils/Monikers.cs | 7 + .../package/package-sharedframework-debian.sh | 132 ++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json create mode 100755 scripts/package/package-sharedframework-debian.sh diff --git a/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json b/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json new file mode 100644 index 000000000..866a67515 --- /dev/null +++ b/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json @@ -0,0 +1,35 @@ +{ + "maintainer_name":"Microsoft", + "maintainer_email": "dotnetcore@microsoft.com", + + "package_name": "%SHARED_FRAMEWORK_DEBIAN_PACKAGE_NAME%", + "install_root": "/usr/share/dotnet", + + "short_description": ".NET Core Shared Framework %SHARED_FRAMEWORK_NUGET_NAME% %SHARED_FRAMEWORK_NUGET_VERSION%", + "long_description": ".NET Core is a cross-platform implementation of .NET Framework, a modern, modular platform\n for building diverse kinds of applications, from command-line applications to microservices and \n modern websites.\n This package contains a runtime and framework which can be used by .NET Core applications.", + "homepage": "https://dotnet.github.io/core", + + "release":{ + "package_version":"1.0.0.0", + "package_revision":"1", + "urgency" : "low", + "changelog_message" : "Inital shared framework." + }, + + "control": { + "priority":"standard", + "section":"libs", + "architecture":"amd64" + }, + + "copyright": "2015 Microsoft", + "license": { + "type": "MIT", + "full_text": "Copyright (c) 2015 Microsoft\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." + }, + + "debian_dependencies":{ + "libssl-dev" : {}, + "libcurl3" : {} + } +} diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index 88b36c800..f822b4ad8 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -104,6 +104,26 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Ubuntu)] public static BuildTargetResult GenerateSharedFrameworkDeb(BuildTargetContext c) { + var packageName = Monikers.GetDebianSharedFrameworkPackageName(c); + var version = c.BuildContext.Get("BuildVersion").SimpleVersion; + var inputRoot = c.BuildContext.Get("SharedFrameworkPublishRoot"); + var debFile = c.BuildContext.Get("SharedFrameworkInstallerFile"); + var objRoot = Path.Combine(Dirs.Output, "obj", "debian", "sharedframework"); + + if (Directory.Exists(objRoot)) + { + Directory.Delete(objRoot, true); + } + + Directory.CreateDirectory(objRoot); + + Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "package", "package-sharedframework-debian.sh"), + "--input", inputRoot, "--output", debFile, "--package-name", packageName, + "--framework-nuget-name", SharedFrameworkTargets.SharedFrameworkName, + "--framework-nuget-version", c.BuildContext.Get("SharedFrameworkNugetVersion"), + "--obj-root", objRoot, "--version", version) + .Execute() + .EnsureSuccessful(); return c.Success(); } diff --git a/scripts/dotnet-cli-build/Utils/Monikers.cs b/scripts/dotnet-cli-build/Utils/Monikers.cs index 56eac7ee1..b69c0d05b 100644 --- a/scripts/dotnet-cli-build/Utils/Monikers.cs +++ b/scripts/dotnet-cli-build/Utils/Monikers.cs @@ -38,6 +38,13 @@ namespace Microsoft.DotNet.Cli.Build return packageName; } + public static string GetDebianSharedFrameworkPackageName(BuildTargetContext c) + { + var sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); + + return $"dotnet-sharedframework-{SharedFrameworkTargets.SharedFrameworkName}-{sharedFrameworkNugetVersion}".ToLower(); + } + public static string GetOSShortName() { string osname = ""; diff --git a/scripts/package/package-sharedframework-debian.sh b/scripts/package/package-sharedframework-debian.sh new file mode 100755 index 000000000..f4d993c98 --- /dev/null +++ b/scripts/package/package-sharedframework-debian.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# +# 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. + +# Debian Packaging Script +# Currently Intended to build on ubuntu14.04 + +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +source "$DIR/../common/_common.sh" +REPOROOT="$DIR/../.." + +help(){ + echo "Usage: $0" + echo "" + echo "Options:" + echo " --input Package the entire contents of the directory tree." + echo " --output The full path to which the package will be written." + echo " --package-name Package to identify during installation. Example - 'dotnet-sharedframework'" + echo " --framework-nuget-name The name of the nuget package that produced this shared framework." + echo " --framework-nuget-version The versionf of the nuget package that produced this shared framework." + echo " --obj-root Root folder for intermediate objects." + echo " --version Version for the debain package." + exit 1 +} + +while [[ $# > 0 ]]; do + lowerI="$(echo $1 | awk '{print tolower($0)}')" + case $lowerI in + -o|--output) + OUTPUT_DEBIAN_FILE=$2 + shift + ;; + -i|--input) + REPO_BINARIES_DIR=$2 + shift + ;; + -p|--package-name) + SHARED_FRAMEWORK_DEBIAN_PACKAGE_NAME=$2 + shift + ;; + --framework-nuget-name) + SHARED_FRAMEWORK_NUGET_NAME=$2 + shift + ;; + --framework-nuget-version) + SHARED_FRAMEWORK_NUGET_VERSION=$2 + shift + ;; + --obj-root) + OBJECT_DIR=$2 + shift + ;; + --version) + SHARED_FRAMEWORK_DEBIAN_VERSION=$2 + shift + ;; + --help) + help + ;; + *) + break + ;; + esac + shift +done + +PACKAGING_ROOT="$REPOROOT/packaging/sharedframework/debian" +PACKAGING_TOOL_DIR="$REPOROOT/tools/DebianPackageTool" + +PACKAGE_OUTPUT_DIR="$OBJECT_DIR/deb_output" +PACKAGE_LAYOUT_DIR="$OBJECT_DIR/deb_intermediate" + +execute_build(){ + create_empty_debian_layout + copy_files_to_debian_layout + update_debian_json + create_debian_package +} + +create_empty_debian_layout(){ + header "Creating empty debian package layout" + + rm -rf "$PACKAGE_LAYOUT_DIR" + mkdir -p "$PACKAGE_LAYOUT_DIR" + + mkdir "$PACKAGE_LAYOUT_DIR/\$" + mkdir "$PACKAGE_LAYOUT_DIR/package_root" + mkdir "$PACKAGE_LAYOUT_DIR/samples" + mkdir "$PACKAGE_LAYOUT_DIR/docs" +} + +copy_files_to_debian_layout(){ + header "Copying files to debian layout" + + # Copy Built Binaries + cp -a "$REPO_BINARIES_DIR/." "$PACKAGE_LAYOUT_DIR/package_root" + + # Copy config file + cp "$PACKAGING_ROOT/dotnet-sharedframework-debian_config.json" "$PACKAGE_LAYOUT_DIR/debian_config.json" +} + +create_debian_package(){ + header "Packing .deb" + + mkdir -p "$PACKAGE_OUTPUT_DIR" + + "$PACKAGING_TOOL_DIR/package_tool" -i "$PACKAGE_LAYOUT_DIR" -o "$PACKAGE_OUTPUT_DIR" -n "$SHARED_FRAMEWORK_DEBIAN_PACKAGE_NAME" -v "$SHARED_FRAMEWORK_DEBIAN_VERSION" +} + +update_debian_json() +{ + header "Updating debian.json file" + sed -i "s/%SHARED_FRAMEWORK_DEBIAN_PACKAGE_NAME%/$SHARED_FRAMEWORK_DEBIAN_PACKAGE_NAME/g" "$PACKAGE_LAYOUT_DIR"/debian_config.json + sed -i "s/%SHARED_FRAMEWORK_NUGET_NAME%/$SHARED_FRAMEWORK_NUGET_NAME/g" "$PACKAGE_LAYOUT_DIR"/debian_config.json + sed -i "s/%SHARED_FRAMEWORK_NUGET_VERSION%/$SHARED_FRAMEWORK_NUGET_VERSION/g" "$PACKAGE_LAYOUT_DIR"/debian_config.json +} + +execute_build + +DEBIAN_FILE=$(find $PACKAGE_OUTPUT_DIR -iname "*.deb") + +mv -f "$DEBIAN_FILE" "$OUTPUT_DEBIAN_FILE" From 56e5a99c5402badcc4133d8bb63fabfa8dfb1c7b Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 9 Mar 2016 17:53:08 -0800 Subject: [PATCH 11/99] Add Shared Host Debian Package --- .../dotnet-sharedhost-debian_config.json | 35 ++++++ scripts/dotnet-cli-build/InstallerTargets.cs | 17 ++- scripts/package/package-sharedhost-debian.sh | 108 ++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 packaging/host/debian/dotnet-sharedhost-debian_config.json create mode 100755 scripts/package/package-sharedhost-debian.sh diff --git a/packaging/host/debian/dotnet-sharedhost-debian_config.json b/packaging/host/debian/dotnet-sharedhost-debian_config.json new file mode 100644 index 000000000..840e5945f --- /dev/null +++ b/packaging/host/debian/dotnet-sharedhost-debian_config.json @@ -0,0 +1,35 @@ +{ + "maintainer_name":"Microsoft", + "maintainer_email": "dotnetcore@microsoft.com", + + "package_name": "dotnet-host", + "install_root": "/usr/share/dotnet", + + "short_description": ".NET Core Shared Host", + "long_description": ".NET Core is a cross-platform implementation of .NET Framework, a modern, modular platform\n for building diverse kinds of applications, from command-line applications to microservices and \n modern websites.\n This package contains the host that launches a .NET Core application.", + "homepage": "https://dotnet.github.io/core", + + "release":{ + "package_version":"1.0.0.0", + "package_revision":"1", + "urgency" : "low", + "changelog_message" : "Inital shared host." + }, + + "control": { + "priority":"standard", + "section":"libs", + "architecture":"amd64" + }, + + "copyright": "2015 Microsoft", + "license": { + "type": "MIT", + "full_text": "Copyright (c) 2015 Microsoft\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE." + }, + + "debian_dependencies":{ + "libssl-dev" : {}, + "libcurl3" : {} + } +} diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index f822b4ad8..e8e5d910b 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -97,6 +97,22 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Ubuntu)] public static BuildTargetResult GenerateSharedHostDeb(BuildTargetContext c) { + var version = c.BuildContext.Get("BuildVersion").SimpleVersion; + var inputRoot = c.BuildContext.Get("SharedHostPublishRoot"); + var debFile = c.BuildContext.Get("SharedHostInstallerFile"); + var objRoot = Path.Combine(Dirs.Output, "obj", "debian", "sharedhost"); + + if (Directory.Exists(objRoot)) + { + Directory.Delete(objRoot, true); + } + + Directory.CreateDirectory(objRoot); + + Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "package", "package-sharedhost-debian.sh"), + "--input", inputRoot, "--output", debFile, "--obj-root", objRoot, "--version", version) + .Execute() + .EnsureSuccessful(); return c.Success(); } @@ -126,6 +142,5 @@ namespace Microsoft.DotNet.Cli.Build .EnsureSuccessful(); return c.Success(); } - } } diff --git a/scripts/package/package-sharedhost-debian.sh b/scripts/package/package-sharedhost-debian.sh new file mode 100755 index 000000000..6ab255dc9 --- /dev/null +++ b/scripts/package/package-sharedhost-debian.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# +# 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. + +# Debian Packaging Script +# Currently Intended to build on ubuntu14.04 + +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +source "$DIR/../common/_common.sh" +REPOROOT="$DIR/../.." + +help(){ + echo "Usage: $0" + echo "" + echo "Options:" + echo " --input Package the entire contents of the directory tree." + echo " --output The full path to which the package will be written." + echo " --obj-root Root folder for intermediate objects." + echo " --version Version for the debain package." + exit 1 +} + +while [[ $# > 0 ]]; do + lowerI="$(echo $1 | awk '{print tolower($0)}')" + case $lowerI in + -o|--output) + OUTPUT_DEBIAN_FILE=$2 + shift + ;; + -i|--input) + REPO_BINARIES_DIR=$2 + shift + ;; + --obj-root) + OBJECT_DIR=$2 + shift + ;; + --version) + SHARED_HOST_DEBIAN_VERSION=$2 + shift + ;; + --help) + help + ;; + *) + break + ;; + esac + shift +done + +PACKAGING_ROOT="$REPOROOT/packaging/host/debian" +PACKAGING_TOOL_DIR="$REPOROOT/tools/DebianPackageTool" + +PACKAGE_OUTPUT_DIR="$OBJECT_DIR/deb_output" +PACKAGE_LAYOUT_DIR="$OBJECT_DIR/deb_intermediate" + +execute_build(){ + create_empty_debian_layout + copy_files_to_debian_layout + create_debian_package +} + +create_empty_debian_layout(){ + header "Creating empty debian package layout" + + rm -rf "$PACKAGE_LAYOUT_DIR" + mkdir -p "$PACKAGE_LAYOUT_DIR" + + mkdir "$PACKAGE_LAYOUT_DIR/\$" + mkdir "$PACKAGE_LAYOUT_DIR/package_root" + mkdir "$PACKAGE_LAYOUT_DIR/samples" + mkdir "$PACKAGE_LAYOUT_DIR/docs" +} + +copy_files_to_debian_layout(){ + header "Copying files to debian layout" + + # Copy Built Binaries + cp -a "$REPO_BINARIES_DIR/." "$PACKAGE_LAYOUT_DIR/package_root" + + # Copy config file + cp "$PACKAGING_ROOT/dotnet-sharedhost-debian_config.json" "$PACKAGE_LAYOUT_DIR/debian_config.json" +} + +create_debian_package(){ + header "Packing .deb" + + mkdir -p "$PACKAGE_OUTPUT_DIR" + + "$PACKAGING_TOOL_DIR/package_tool" -i "$PACKAGE_LAYOUT_DIR" -o "$PACKAGE_OUTPUT_DIR" -v "$SHARED_HOST_DEBIAN_VERSION" +} + +execute_build + +DEBIAN_FILE=$(find $PACKAGE_OUTPUT_DIR -iname "*.deb") + +mv -f "$DEBIAN_FILE" "$OUTPUT_DEBIAN_FILE" From 4df5ed39d5f63e2074d8d0a3ad326c9528d1a0ce Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 10 Mar 2016 03:19:00 -0800 Subject: [PATCH 12/99] Crossgen Shared Framework managed assemblies - Use Crossgen's Ready To Run mode on all of the managed assemblies that make up the shared framework. - Upgrade the version of the shared framework to match what is used in the rest of CLI (see the comment in SharedFrameworkTargets.cs to understand why this is needed). - Remove the IL mscorlib.dll image, since the Crossgen'd image is already published. Fixes dotnet/corefx#6753 --- scripts/dotnet-cli-build/CompileTargets.cs | 34 ++---------- .../SharedFrameworkTargets.cs | 54 ++++++++++++++++++- scripts/dotnet-cli-build/Utils/Crossgen.cs | 50 +++++++++++++++++ scripts/dotnet-cli-build/project.json | 3 +- src/sharedframework/framework/project.json | 2 +- src/sharedframework/host/project.json | 2 +- 6 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 scripts/dotnet-cli-build/Utils/Crossgen.cs diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 1fc300ce0..9cecf95de 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -293,41 +293,13 @@ namespace Microsoft.DotNet.Cli.Build } // Find crossgen - string arch = PlatformServices.Default.Runtime.RuntimeArchitecture; - string packageId; - if (CurrentPlatform.IsWindows) - { - packageId = $"runtime.win7-{arch}.Microsoft.NETCore.Runtime.CoreCLR"; - } - else if (CurrentPlatform.IsUbuntu) - { - packageId = "runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR"; - } - else if (CurrentPlatform.IsCentOS || CurrentPlatform.IsRHEL) - { - // CentOS runtime is in the runtime.rhel.7-x64... package. - packageId = "runtime.rhel.7-x64.Microsoft.NETCore.Runtime.CoreCLR"; - } - else if (CurrentPlatform.IsDebian) - { - packageId = "runtime.debian.8.2-x64.Microsoft.NETCore.Runtime.CoreCLR"; - } - else if (CurrentPlatform.IsOSX) - { - packageId = "runtime.osx.10.10-x64.Microsoft.NETCore.Runtime.CoreCLR"; - } - else + var crossGenExePath = Microsoft.DotNet.Cli.Build.Crossgen.GetCrossgenPathForVersion(CoreCLRVersion); + + if (string.IsNullOrEmpty(crossGenExePath)) { return c.Failed("Unsupported OS Platform"); } - var crossGenExePath = Path.Combine( - Dirs.NuGetPackages, - packageId, - CoreCLRVersion, - "tools", - $"crossgen{Constants.ExeSuffix}"); - // We have to copy crossgen next to mscorlib var crossgen = Path.Combine(outputDir, $"crossgen{Constants.ExeSuffix}"); File.Copy(crossGenExePath, crossgen, overwrite: true); diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index 760992734..e3b1d316f 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Text.RegularExpressions; +using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.Extensions.PlatformAbstractions; @@ -51,6 +52,15 @@ namespace Microsoft.DotNet.Cli.Build // hostpolicy will be renamed to dotnet at some point and then this can be removed. File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}dotnethostimpl{Constants.DynamicLibSuffix}")); + if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll"))) + { + // Publish already places the crossgen'd version of mscorlib into the output, so we can + // remove the IL version + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll")); + + CrossGenAllManagedAssemblies(SharedFrameworkNameAndVersionRoot); + } + return c.Success(); } @@ -99,5 +109,47 @@ namespace Microsoft.DotNet.Cli.Build return null; } + + private static void CrossGenAllManagedAssemblies(string pathToAssemblies) + { + foreach (var file in Directory.GetFiles(pathToAssemblies)) + { + string fileName = Path.GetFileName(file); + + if (fileName == "mscorlib.dll" || fileName == "mscorlib.ni.dll" || !HasMetadata(file)) + { + continue; + } + + string tempPathName = Path.ChangeExtension(file, "readytorun"); + + // This is not always correct. The version of crossgen we need to pick up is whatever one was restored as part + // of the Microsoft.NETCore.Runtime.CoreCLR package that is part of the shared library. For now, the version hardcoded + // in CompileTargets and the one in the shared library project.json match and are updated in lock step, but long term + // we need to be able to look at the project.lock.json file and figure out what version of Microsoft.NETCore.Runtime.CoreCLR + // was used, and then select that version. + ExecSilent(Crossgen.GetCrossgenPathForVersion(CompileTargets.CoreCLRVersion), + "-readytorun", "-in", file, "-out", tempPathName, "-platform_assemblies_paths", pathToAssemblies); + + File.Delete(file); + File.Move(tempPathName, file); + } + } + + private static bool HasMetadata(string pathToFile) + { + try + { + using (var inStream = File.OpenRead(pathToFile)) + { + using (var peReader = new PEReader(inStream)) + { + return peReader.HasMetadata; + } + } + } catch (BadImageFormatException) { } + + return false; + } } -} \ No newline at end of file +} diff --git a/scripts/dotnet-cli-build/Utils/Crossgen.cs b/scripts/dotnet-cli-build/Utils/Crossgen.cs new file mode 100644 index 000000000..37cf836aa --- /dev/null +++ b/scripts/dotnet-cli-build/Utils/Crossgen.cs @@ -0,0 +1,50 @@ +using System.IO; +using System.Linq; +using System; +using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.DotNet.Cli.Build +{ + internal static class Crossgen + { + public static string GetCrossgenPathForVersion(string coreClrVersion) + { + string arch = PlatformServices.Default.Runtime.RuntimeArchitecture; + string packageId; + if (CurrentPlatform.IsWindows) + { + packageId = $"runtime.win7-{arch}.Microsoft.NETCore.Runtime.CoreCLR"; + } + else if (CurrentPlatform.IsUbuntu) + { + packageId = "runtime.ubuntu.14.04-x64.Microsoft.NETCore.Runtime.CoreCLR"; + } + else if (CurrentPlatform.IsCentOS || CurrentPlatform.IsRHEL) + { + // CentOS runtime is in the runtime.rhel.7-x64... package. + packageId = "runtime.rhel.7-x64.Microsoft.NETCore.Runtime.CoreCLR"; + } + else if (CurrentPlatform.IsOSX) + { + packageId = "runtime.osx.10.10-x64.Microsoft.NETCore.Runtime.CoreCLR"; + } + else if (CurrentPlatform.IsDebian) + { + packageId = "runtime.debian.8.2-x64.Microsoft.NETCore.Runtime.CoreCLR"; + } + else + { + return null; + } + + return Path.Combine( + Dirs.NuGetPackages, + packageId, + coreClrVersion, + "tools", + $"crossgen{Constants.ExeSuffix}"); + } + } +} diff --git a/scripts/dotnet-cli-build/project.json b/scripts/dotnet-cli-build/project.json index 2be69c156..f66171d24 100755 --- a/scripts/dotnet-cli-build/project.json +++ b/scripts/dotnet-cli-build/project.json @@ -11,7 +11,8 @@ "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", - "WindowsAzure.Storage" : "6.2.2-preview" + "WindowsAzure.Storage" : "6.2.2-preview", + "System.Reflection.Metadata" : "1.2.0" }, "frameworks": { diff --git a/src/sharedframework/framework/project.json b/src/sharedframework/framework/project.json index 5d904b02f..48e835c95 100644 --- a/src/sharedframework/framework/project.json +++ b/src/sharedframework/framework/project.json @@ -5,7 +5,7 @@ }, "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23811" + "NETStandard.Library": "1.0.0-rc2-23901" }, "frameworks": { diff --git a/src/sharedframework/host/project.json b/src/sharedframework/host/project.json index 30251684c..80a3611f2 100644 --- a/src/sharedframework/host/project.json +++ b/src/sharedframework/host/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23811" + "NETStandard.Library": "1.0.0-rc2-23901" }, "frameworks": { From edbbc64b030b5a0b208c5294c9dda147e9352829 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Wed, 9 Mar 2016 13:26:37 -0800 Subject: [PATCH 13/99] Fill out pkg installer targets This causes three pkg files to be produced: * A component pkg for the shared framework. * A component pkg for the shared host. * A product archive which includes the above two components. The product archive also needs a distribution.xml file which contains metadata about the package (name, title, images, etc.). The installer for the "SDK" itself is still using logic implemented in package-osx.sh. We should move this logic into the build target as well, but we may want to wait until the CLI is using the shared framework to do so. --- .../osx/sharedframework/scripts/postinstall | 13 ++ ...shared-framework-distribution-template.xml | 24 ++++ packaging/osx/sharedhost/scripts/postinstall | 13 ++ scripts/dotnet-cli-build/InstallerTargets.cs | 38 +----- scripts/dotnet-cli-build/PkgTargets.cs | 123 ++++++++++++++++++ 5 files changed, 174 insertions(+), 37 deletions(-) create mode 100755 packaging/osx/sharedframework/scripts/postinstall create mode 100644 packaging/osx/sharedframework/shared-framework-distribution-template.xml create mode 100755 packaging/osx/sharedhost/scripts/postinstall create mode 100644 scripts/dotnet-cli-build/PkgTargets.cs diff --git a/packaging/osx/sharedframework/scripts/postinstall b/packaging/osx/sharedframework/scripts/postinstall new file mode 100755 index 000000000..50fd8f1b7 --- /dev/null +++ b/packaging/osx/sharedframework/scripts/postinstall @@ -0,0 +1,13 @@ +#!/bin/sh +# +# 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. +# + +PACKAGE=$1 +INSTALL_DESTINATION=$2 + +# A temporary fix for the permissions issue(s) +chmod -R 755 $INSTALL_DESTINATION/shared + +exit 0 diff --git a/packaging/osx/sharedframework/shared-framework-distribution-template.xml b/packaging/osx/sharedframework/shared-framework-distribution-template.xml new file mode 100644 index 000000000..a4c42cbc1 --- /dev/null +++ b/packaging/osx/sharedframework/shared-framework-distribution-template.xml @@ -0,0 +1,24 @@ + + + .NET Core Shared Framework ({SharedFrameworkNugetVersion}) + + + + + + + + + + + + + + + + + + + com.microsoft.dotnet.sharedframework.{SharedFrameworkNugetVersion}.component.osx.x64.pkg + com.microsoft.dotnet.sharedhost.osx.x64.pkg + diff --git a/packaging/osx/sharedhost/scripts/postinstall b/packaging/osx/sharedhost/scripts/postinstall new file mode 100755 index 000000000..bac3303f2 --- /dev/null +++ b/packaging/osx/sharedhost/scripts/postinstall @@ -0,0 +1,13 @@ +#!/bin/sh +# +# 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. +# + +PACKAGE=$1 +INSTALL_DESTINATION=$2 + +# A temporary fix for the permissions issue(s) +chmod 755 $INSTALL_DESTINATION/dotnet + +exit 0 diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index e8e5d910b..097d37f18 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -14,49 +14,13 @@ namespace Microsoft.DotNet.Cli.Build { [Target(nameof(MsiTargets.GenerateMsis), nameof(MsiTargets.GenerateBundle), - nameof(InstallerTargets.GeneratePkgs), + nameof(PkgTargets.GeneratePkgs), nameof(InstallerTargets.GenerateDebs))] public static BuildTargetResult GenerateInstaller(BuildTargetContext c) { return c.Success(); } - [Target(nameof(InstallerTargets.GenerateSdkPkg), - nameof(InstallerTargets.GenerateSharedFrameworkPkg), - nameof(InstallerTargets.GenerateSharedHostPkg))] - [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GeneratePkgs(BuildTargetContext c) - { - return c.Success(); - } - - [Target] - [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GenerateSdkPkg(BuildTargetContext c) - { - var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var pkg = c.BuildContext.Get("SdkInstallerFile"); - Cmd(Path.Combine(Dirs.RepoRoot, "packaging", "osx", "package-osx.sh"), - "-v", version, "-i", Dirs.Stage2, "-o", pkg) - .Execute() - .EnsureSuccessful(); - return c.Success(); - } - - [Target] - [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GenerateSharedFrameworkPkg(BuildTargetContext c) - { - return c.Success(); - } - - [Target] - [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GenerateSharedHostPkg(BuildTargetContext c) - { - return c.Success(); - } - [Target(nameof(InstallerTargets.GenerateSdkDeb), nameof(InstallerTargets.GenerateSharedFrameworkDeb), nameof(InstallerTargets.GenerateSharedHostDeb))] diff --git a/scripts/dotnet-cli-build/PkgTargets.cs b/scripts/dotnet-cli-build/PkgTargets.cs new file mode 100644 index 000000000..a60d32d21 --- /dev/null +++ b/scripts/dotnet-cli-build/PkgTargets.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.Extensions.PlatformAbstractions; + +using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; + +namespace Microsoft.DotNet.Cli.Build +{ + public class PkgTargets + { + [Target(nameof(GenerateSdkProductArchive), nameof(GenerateSharedFrameworkProductArchive))] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GeneratePkgs(BuildTargetContext c) + { + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSdkProductArchive(BuildTargetContext c) + { + var version = c.BuildContext.Get("BuildVersion").SimpleVersion; + var pkg = c.BuildContext.Get("SdkInstallerFile"); + + Cmd(Path.Combine(Dirs.RepoRoot, "packaging", "osx", "package-osx.sh"), + "-v", version, "-i", Dirs.Stage2, "-o", pkg) + .Execute() + .EnsureSuccessful(); + return c.Success(); + } + + [Target(nameof(GenerateSharedFrameworkPkg), nameof(GenerateSharedHostPkg))] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSharedFrameworkProductArchive(BuildTargetContext c) + { + string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); + string version = c.BuildContext.Get("BuildVersion").SimpleVersion; + string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetVersion}.osx.x64"; + string packageIntermediatesPath = Path.Combine(Dirs.Output, "obj", "pkg"); + string resourcePath = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "resources"); + string outFilePath = Path.Combine(packageIntermediatesPath, id + ".pkg"); + + string inputDistTemplatePath = Path.Combine( + Dirs.RepoRoot, + "packaging", + "osx", + "sharedframework", + "shared-framework-distribution-template.xml"); + string distTemplate = File.ReadAllText(inputDistTemplatePath); + string distributionPath = Path.Combine(packageIntermediatesPath, "shared-framework-formatted-distribution.xml"); + string formattedDistContents = + distTemplate.Replace("{SharedFrameworkNugetVersion}", sharedFrameworkNugetVersion) + .Replace("{VERSION}", version); + File.WriteAllText(distributionPath, formattedDistContents); + + Cmd("productbuild", + "--version", version, + "--identifier", id, + "--package-path", packageIntermediatesPath, + "--resources", resourcePath, + "--distribution", distributionPath, + outFilePath + ) + .Execute() + .EnsureSuccessful(); + + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSharedFrameworkPkg(BuildTargetContext c) + { + string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); + Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); + string version = c.BuildContext.Get("BuildVersion").SimpleVersion; + string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetVersion}.component.osx.x64"; + string outFilePath = Path.Combine(Dirs.Output, "obj", "pkg", id + ".pkg"); + string installLocation = "/usr/local/share/dotnet"; + string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "sharedframework", "scripts"); + + Cmd("pkgbuild", + "--root", c.BuildContext.Get("SharedFrameworkPublishRoot"), + "--identifier", id, + "--version", version, + "--install-location", installLocation, + "--scripts", scriptsLocation, + outFilePath) + .Execute() + .EnsureSuccessful(); + + return c.Success(); + } + + [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateSharedHostPkg(BuildTargetContext c) + { + Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); + string version = c.BuildContext.Get("BuildVersion").SimpleVersion; + string id = $"com.microsoft.dotnet.sharedhost.osx.x64"; + string outFilePath = Path.Combine(Dirs.Output, "obj", "pkg", id + ".pkg"); + string installLocation = "/usr/local/share/dotnet"; + string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "sharedhost", "scripts"); + + Cmd("pkgbuild", + "--root", c.BuildContext.Get("SharedHostPublishRoot"), + "--identifier", id, + "--version", version, + "--install-location", installLocation, + "--scripts", scriptsLocation, + outFilePath) + .Execute() + .EnsureSuccessful(); + + return c.Success(); + } + } +} \ No newline at end of file From d77fad4e684df505bae10dd40850b6e3ab462306 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Thu, 10 Mar 2016 15:19:54 -0800 Subject: [PATCH 14/99] Bring the OSX installer 'title' in line with Windows It now includes the shared framework 'name' (NuGet package name) in the installer. In this case, the installer is called '.NET Core Shared Framework (NETStandard.Library 1.0.0-*)' --- .../shared-framework-distribution-template.xml | 10 +++++----- scripts/dotnet-cli-build/PkgTargets.cs | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packaging/osx/sharedframework/shared-framework-distribution-template.xml b/packaging/osx/sharedframework/shared-framework-distribution-template.xml index a4c42cbc1..15ff9e92a 100644 --- a/packaging/osx/sharedframework/shared-framework-distribution-template.xml +++ b/packaging/osx/sharedframework/shared-framework-distribution-template.xml @@ -1,6 +1,6 @@ - .NET Core Shared Framework ({SharedFrameworkNugetVersion}) + .NET Core Shared Framework ({SharedFrameworkNugetName} {SharedFrameworkNugetVersion}) @@ -10,15 +10,15 @@ - + - - + + - com.microsoft.dotnet.sharedframework.{SharedFrameworkNugetVersion}.component.osx.x64.pkg + com.microsoft.dotnet.sharedframework.{SharedFrameworkNugetName}.{SharedFrameworkNugetVersion}.component.osx.x64.pkg com.microsoft.dotnet.sharedhost.osx.x64.pkg diff --git a/scripts/dotnet-cli-build/PkgTargets.cs b/scripts/dotnet-cli-build/PkgTargets.cs index a60d32d21..1f082b069 100644 --- a/scripts/dotnet-cli-build/PkgTargets.cs +++ b/scripts/dotnet-cli-build/PkgTargets.cs @@ -37,9 +37,10 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GenerateSharedFrameworkProductArchive(BuildTargetContext c) { + string sharedFrameworkNugetName = SharedFrameworkTargets.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; - string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetVersion}.osx.x64"; + string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.osx.x64"; string packageIntermediatesPath = Path.Combine(Dirs.Output, "obj", "pkg"); string resourcePath = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "resources"); string outFilePath = Path.Combine(packageIntermediatesPath, id + ".pkg"); @@ -54,6 +55,7 @@ namespace Microsoft.DotNet.Cli.Build string distributionPath = Path.Combine(packageIntermediatesPath, "shared-framework-formatted-distribution.xml"); string formattedDistContents = distTemplate.Replace("{SharedFrameworkNugetVersion}", sharedFrameworkNugetVersion) + .Replace("{SharedFrameworkNugetName}", SharedFrameworkTargets.SharedFrameworkName) .Replace("{VERSION}", version); File.WriteAllText(distributionPath, formattedDistContents); @@ -63,8 +65,7 @@ namespace Microsoft.DotNet.Cli.Build "--package-path", packageIntermediatesPath, "--resources", resourcePath, "--distribution", distributionPath, - outFilePath - ) + outFilePath) .Execute() .EnsureSuccessful(); @@ -75,10 +76,11 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GenerateSharedFrameworkPkg(BuildTargetContext c) { + string sharedFrameworkNugetName = SharedFrameworkTargets.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; - string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetVersion}.component.osx.x64"; + string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.component.osx.x64"; string outFilePath = Path.Combine(Dirs.Output, "obj", "pkg", id + ".pkg"); string installLocation = "/usr/local/share/dotnet"; string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "sharedframework", "scripts"); From ce118f9d079557b1e2ffab6a42362a0752e7612d Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Thu, 10 Mar 2016 15:20:29 -0800 Subject: [PATCH 15/99] Add warning if shared framework is not going to be crossgen'd because mscorlib.ni.dll does not exist --- scripts/dotnet-cli-build/SharedFrameworkTargets.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index e3b1d316f..e2bbd53f9 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -60,6 +60,10 @@ namespace Microsoft.DotNet.Cli.Build CrossGenAllManagedAssemblies(SharedFrameworkNameAndVersionRoot); } + else + { + c.Warn("Shared framework will not be crossgen'd because mscorlib.ni.dll does not exist."); + } return c.Success(); } From dc7bab9e28b44d08bf6136f1c5114bc06584cd47 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 10 Mar 2016 16:01:11 -0800 Subject: [PATCH 16/99] Probe for .NET reference assemblies path --- .../Resolution/FrameworkReferenceResolver.cs | 3 +- .../DotNetReferenceAssembliesPathResolver.cs | 59 +++++++++++++++++++ .../ReferenceAssemblyPathResolver.cs | 4 +- 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs diff --git a/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs b/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs index 17458d0eb..e279a695e 100644 --- a/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs +++ b/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.Versioning; using System.Xml.Linq; using Microsoft.DotNet.ProjectModel.Utilities; +using Microsoft.Extensions.DependencyModel.Resolution; using Microsoft.Extensions.PlatformAbstractions; using NuGet.Frameworks; @@ -53,7 +54,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution public static string GetDefaultReferenceAssembliesPath() { // Allow setting the reference assemblies path via an environment variable - var referenceAssembliesPath = Environment.GetEnvironmentVariable("DOTNET_REFERENCE_ASSEMBLIES_PATH"); + var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(); if (!string.IsNullOrEmpty(referenceAssembliesPath)) { diff --git a/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs new file mode 100644 index 000000000..5703b8d27 --- /dev/null +++ b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs @@ -0,0 +1,59 @@ +// 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 Microsoft.Extensions.EnvironmentAbstractions; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.Extensions.DependencyModel.Resolution +{ + public class DotNetReferenceAssembliesPathResolver + { + public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH"; + + internal static string Resolve(IEnvironment envirnment) + { + var path = envirnment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv); + if (!string.IsNullOrEmpty(path)) + { + return path; + } + + return GetDefaultDotNetReferenceAssembliesPath(); + } + + public static string Resolve() + { + return Resolve(EnvironmentWrapper.Default); + } + + private static string GetDefaultDotNetReferenceAssembliesPath() + { + var os = PlatformServices.Default.Runtime.OperatingSystemPlatform; + + if (os == Platform.Windows) + { + return null; + } + + if (os == Platform.Darwin && + Directory.Exists("/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks")) + { + return "/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks"; + } + + if (Directory.Exists("/usr/local/lib/mono/xbuild-frameworks")) + { + return "/usr/local/lib/mono/xbuild-frameworks"; + } + + if (Directory.Exists("/usr/lib/mono/xbuild-frameworks")) + { + return "/usr/lib/mono/xbuild-frameworks"; + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs b/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs index 523b20eca..ffc95ca0c 100644 --- a/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs +++ b/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs @@ -104,8 +104,7 @@ namespace Microsoft.Extensions.DependencyModel.Resolution internal static string GetDefaultReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment, IEnvironment environment) { // Allow setting the reference assemblies path via an environment variable - var referenceAssembliesPath = environment.GetEnvironmentVariable("DOTNET_REFERENCE_ASSEMBLIES_PATH"); - + var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(environment); if (!string.IsNullOrEmpty(referenceAssembliesPath)) { return referenceAssembliesPath; @@ -138,6 +137,5 @@ namespace Microsoft.Extensions.DependencyModel.Resolution programFiles, "Reference Assemblies", "Microsoft", "Framework"); } - } } \ No newline at end of file From 78257e738899431b1881d1709592af8c4e8204cf Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 10 Mar 2016 16:43:58 -0800 Subject: [PATCH 17/99] Update DotNEtReferenceAssembliesPathResolver --- .../Resolution/FrameworkReferenceResolver.cs | 4 +++- .../DotNetReferenceAssembliesPathResolver.cs | 16 ++++++++-------- .../Resolution/ReferenceAssemblyPathResolver.cs | 6 +++--- .../ReferenceAssemblyResolverTests.cs | 10 +++++----- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs b/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs index e279a695e..e75860ed1 100644 --- a/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs +++ b/src/Microsoft.DotNet.ProjectModel/Resolution/FrameworkReferenceResolver.cs @@ -208,7 +208,9 @@ namespace Microsoft.DotNet.ProjectModel.Resolution private static FrameworkInformation GetFrameworkInformation(NuGetFramework targetFramework, string referenceAssembliesPath) { // Check for legacy frameworks - if (targetFramework.IsDesktop() && targetFramework.Version <= new Version(3, 5)) + if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows && + targetFramework.IsDesktop() && + targetFramework.Version <= new Version(3, 5)) { return GetLegacyFrameworkInformation(targetFramework, referenceAssembliesPath); } diff --git a/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs index 5703b8d27..eee647c6a 100644 --- a/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs +++ b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.DependencyModel.Resolution { public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH"; - internal static string Resolve(IEnvironment envirnment) + internal static string Resolve(IEnvironment envirnment, IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment) { var path = envirnment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv); if (!string.IsNullOrEmpty(path)) @@ -20,17 +20,17 @@ namespace Microsoft.Extensions.DependencyModel.Resolution return path; } - return GetDefaultDotNetReferenceAssembliesPath(); + return GetDefaultDotNetReferenceAssembliesPath(fileSystem, runtimeEnvironment); } public static string Resolve() { - return Resolve(EnvironmentWrapper.Default); + return Resolve(EnvironmentWrapper.Default, FileSystemWrapper.Default, PlatformServices.Default.Runtime); } - private static string GetDefaultDotNetReferenceAssembliesPath() + private static string GetDefaultDotNetReferenceAssembliesPath(IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment) { - var os = PlatformServices.Default.Runtime.OperatingSystemPlatform; + var os = runtimeEnvironment.OperatingSystemPlatform; if (os == Platform.Windows) { @@ -38,17 +38,17 @@ namespace Microsoft.Extensions.DependencyModel.Resolution } if (os == Platform.Darwin && - Directory.Exists("/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks")) + fileSystem.Directory.Exists("/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks")) { return "/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks"; } - if (Directory.Exists("/usr/local/lib/mono/xbuild-frameworks")) + if (fileSystem.Directory.Exists("/usr/local/lib/mono/xbuild-frameworks")) { return "/usr/local/lib/mono/xbuild-frameworks"; } - if (Directory.Exists("/usr/lib/mono/xbuild-frameworks")) + if (fileSystem.Directory.Exists("/usr/lib/mono/xbuild-frameworks")) { return "/usr/lib/mono/xbuild-frameworks"; } diff --git a/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs b/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs index ffc95ca0c..55f212660 100644 --- a/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs +++ b/src/Microsoft.Extensions.DependencyModel/Resolution/ReferenceAssemblyPathResolver.cs @@ -27,7 +27,7 @@ namespace Microsoft.Extensions.DependencyModel.Resolution internal ReferenceAssemblyPathResolver(IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment, IEnvironment environment) : this(fileSystem, - GetDefaultReferenceAssembliesPath(runtimeEnvironment, environment), + GetDefaultReferenceAssembliesPath(runtimeEnvironment, fileSystem, environment), GetFallbackSearchPaths(fileSystem, runtimeEnvironment, environment)) { } @@ -101,10 +101,10 @@ namespace Microsoft.Extensions.DependencyModel.Resolution return new[] { net20Dir }; } - internal static string GetDefaultReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment, IEnvironment environment) + internal static string GetDefaultReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment, IFileSystem fileSystem, IEnvironment environment) { // Allow setting the reference assemblies path via an environment variable - var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(environment); + var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(environment, fileSystem, runtimeEnvironment); if (!string.IsNullOrEmpty(referenceAssembliesPath)) { return referenceAssembliesPath; diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/ReferenceAssemblyResolverTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/ReferenceAssemblyResolverTests.cs index 7561c77dc..dbaf6589d 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/ReferenceAssemblyResolverTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/ReferenceAssemblyResolverTests.cs @@ -36,12 +36,12 @@ namespace Microsoft.Extensions.DependencyModel.Tests { var runtime = new Mock(); runtime.SetupGet(r => r.OperatingSystemPlatform).Returns(Platform.Windows); - + var environment = EnvironmentMockBuilder.Create() .AddVariable("DOTNET_REFERENCE_ASSEMBLIES_PATH", ReferencePath) .Build(); - var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, environment); + var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, FileSystemMockBuilder.Empty, environment); result.Should().Be(ReferencePath); } @@ -51,7 +51,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests var runtime = new Mock(); runtime.SetupGet(r => r.OperatingSystemPlatform).Returns(Platform.Linux); - var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, EnvironmentMockBuilder.Empty); + var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, FileSystemMockBuilder.Empty, EnvironmentMockBuilder.Empty); result.Should().BeNull(); } @@ -66,7 +66,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests .AddVariable("ProgramFiles", "Program Files") .Build(); - var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, environment); + var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, FileSystemMockBuilder.Empty, environment); result.Should().Be(Path.Combine("Program Files (x86)", "Reference Assemblies", "Microsoft", "Framework")); } @@ -80,7 +80,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests .AddVariable("ProgramFiles", "Program Files") .Build(); - var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, environment); + var result = ReferenceAssemblyPathResolver.GetDefaultReferenceAssembliesPath(runtime.Object, FileSystemMockBuilder.Empty, environment); result.Should().Be(Path.Combine("Program Files", "Reference Assemblies", "Microsoft", "Framework")); } From e0f8ad04813a5d7a2e1fe618cefeb9afee1b1087 Mon Sep 17 00:00:00 2001 From: Senthil Date: Tue, 8 Mar 2016 20:43:06 -0800 Subject: [PATCH 18/99] Allow to pin a specific runtime version @anurse, @piotrpMSFT, @gkhanna79, @leecow, @richlander --- Documentation/specs/runtime-configuration-file.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/specs/runtime-configuration-file.md b/Documentation/specs/runtime-configuration-file.md index f35de1ec7..ff2df4c33 100644 --- a/Documentation/specs/runtime-configuration-file.md +++ b/Documentation/specs/runtime-configuration-file.md @@ -29,7 +29,8 @@ The files are both JSON files stored in UTF-8 encoding. Below are sample files. "gcConcurrent": false, "framework": { "name": "Microsoft.DotNetCore", - "version": "1.0.1" + "version": "1.0.1", + "rollForward": false, } } } @@ -118,7 +119,11 @@ This section is copied verbatim from an identical section in the input `project. * `gcServer` - Boolean indicating if the server GC should be used (Default: _TBD_). Note: This is designed to mirror the existing [app.config](https://msdn.microsoft.com/en-us/library/ms229357.aspx) setting) * `gcConcurrent` - Boolean indicating if background garbage collection should be used (Default: _TBD_). Note: This is designed to mirror the existing [app.config](https://msdn.microsoft.com/en-us/library/yhwwzef8.aspx) setting). -* `framework` - Indicates the name and version of the shared framework to use when activating the application. The presence of this section indicates that the application is a portable app designed to use a shared redistributable framework. +* `framework` - Indicates the `name`, `version`, and other properties of the shared framework to use when activating the application. The presence of this section indicates that the application is a portable app designed to use a shared redistributable framework. + * `rollForward` - When `false`, the framework version is strictly obeyed by the host. When `rollForward` is unspecified or specified as `true`, the framework from either the same or a higher version that differs only in the `SemVer` patch field will be used. + * For example, if `version=1.0.1` and `rollForward` is `true`, the host would load the shared framework from `1.0.{n}`, where `n >= 1`, but will not load from `1.1.0`, even if present. When `rollForward` is `false`, the shared framework will be loaded from `1.0.1` strictly. + * **Note:** This does not apply to `SemVer`'s `prerelease` versions, but only for `production` releases. + * **Note:** This section will not be present for standalone applications that do not rely upon a shared framework. * Others _TBD_ These settings are read by `corehost` to determine how to initialize the runtime. All versions of `corehost` **must ignore** settings in this section that they do not understand (thus allowing new settings to be added in later versions). From 72ad7aa4dbec9f981f9ad26579b9052376a31c00 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 11 Mar 2016 12:24:36 +0100 Subject: [PATCH 19/99] Fix pthread library option While building CoreRT on OSX, I have noticed a warning: clang: warning: argument unused during compilation: `-pthread` The issue is that the options should be `-lpthread` instead. --- .../IntermediateCompilation/Linux/LinuxCppCompileStep.cs | 2 +- .../IntermediateCompilation/Mac/MacCppCompileStep.cs | 2 +- .../IntermediateCompilation/Mac/MacRyuJitCompileStep.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Linux/LinuxCppCompileStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Linux/LinuxCppCompileStep.cs index 28e543de4..6197c0adc 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Linux/LinuxCppCompileStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Linux/LinuxCppCompileStep.cs @@ -12,7 +12,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native // TODO: debug/release support private readonly string [] _cLibsFlags = { "-lm", "-ldl"}; - private readonly string [] _cflags = { "-g", "-lstdc++", "-lrt", "-Wno-invalid-offsetof", "-pthread"}; + private readonly string [] _cflags = { "-g", "-lstdc++", "-lrt", "-Wno-invalid-offsetof", "-lpthread"}; public IEnumerable CompilerArgs { get; set; } diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs index 64fec18ef..a628535b6 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs @@ -16,7 +16,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native public const string InputExtension = ".cpp"; // TODO: debug/release support - private readonly string [] _cflags = { "-g", "-lstdc++", "-Wno-invalid-offsetof", "-pthread"}; + private readonly string [] _cflags = { "-g", "-lstdc++", "-Wno-invalid-offsetof", "-lpthread"}; // Link to iconv APIs private const string LibFlags = "-liconv"; diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacRyuJitCompileStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacRyuJitCompileStep.cs index 6a7ecb13c..4a44bd459 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacRyuJitCompileStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacRyuJitCompileStep.cs @@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native private IEnumerable CompilerArgs; // TODO: debug/release support - private readonly string [] _cflags = { "-g", "-lstdc++", "-Wno-invalid-offsetof", "-pthread", "-ldl", "-lm", "-liconv" }; + private readonly string [] _cflags = { "-g", "-lstdc++", "-Wno-invalid-offsetof", "-lpthread", "-ldl", "-lm", "-liconv" }; private readonly string[] _ilcSdkLibs = { From 9df3a986d8bbeaa74ae79b6dcc4b5ff22674eda8 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Fri, 11 Mar 2016 11:51:31 -0800 Subject: [PATCH 20/99] Fix incorrect reference assembly path --- .../Resolution/DotNetReferenceAssembliesPathResolver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs index eee647c6a..b44668ede 100644 --- a/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs +++ b/src/Microsoft.Extensions.DependencyModel/Resolution/DotNetReferenceAssembliesPathResolver.cs @@ -38,9 +38,9 @@ namespace Microsoft.Extensions.DependencyModel.Resolution } if (os == Platform.Darwin && - fileSystem.Directory.Exists("/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks")) + fileSystem.Directory.Exists("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks")) { - return "/Library/Framework/Mono.Framework/Versions/Current/lib/mono/xbuild-frameworks"; + return "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"; } if (fileSystem.Directory.Exists("/usr/local/lib/mono/xbuild-frameworks")) @@ -56,4 +56,4 @@ namespace Microsoft.Extensions.DependencyModel.Resolution return null; } } -} \ No newline at end of file +} From 94ca41874dea67005e59306a17998c7817d38b70 Mon Sep 17 00:00:00 2001 From: PiotrP Date: Fri, 11 Mar 2016 12:20:04 -0800 Subject: [PATCH 21/99] FragileNonVersionable --- scripts/dotnet-cli-build/CompileTargets.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 1fc300ce0..e7e29c510 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -342,7 +342,7 @@ namespace Microsoft.DotNet.Cli.Build foreach (var assemblyToCrossgen in AssembliesToCrossGen) { c.Info($"Crossgenning {assemblyToCrossgen}"); - ExecInSilent(outputDir, crossgen, "-nologo", "-platform_assemblies_paths", outputDir, assemblyToCrossgen); + ExecInSilent(outputDir, crossgen, "-FragileNonVersionable", "-nologo", "-platform_assemblies_paths", outputDir, assemblyToCrossgen); } c.Info("Crossgen complete"); From 5ae6dcbbdee110f6af227a492234cb376b40bd14 Mon Sep 17 00:00:00 2001 From: PiotrP Date: Fri, 11 Mar 2016 12:39:36 -0800 Subject: [PATCH 22/99] Hard-code stage0 on Mac, Linux to use 1.0.0.001665, which contained a NuGet believed not to contain current regressions. --- scripts/run-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-build.sh b/scripts/run-build.sh index 076abfdb2..c6f8f0961 100755 --- a/scripts/run-build.sh +++ b/scripts/run-build.sh @@ -85,7 +85,7 @@ done < "$DIR/../branchinfo.txt" # Ensure the latest stage0 is installed export CHANNEL=$RELEASE_SUFFIX -$DIR/obtain/install.sh --channel $CHANNEL +$DIR/obtain/install.sh --channel $CHANNEL --version 1.0.0.001665 # Put stage 0 on the PATH (for this shell only) PATH="$DOTNET_INSTALL_DIR/bin:$PATH" From b7392e65b66920774ae142ccc919b48fcee27089 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Fri, 11 Mar 2016 12:44:28 -0800 Subject: [PATCH 23/99] Modify version badge URL to invalidate the github image cache. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bc696ff8..8709b03b3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Installers | |Ubuntu 14.04 |Windows |Mac OS X |CentOS 7.1 | |---------|:------:|:------:|:------:|:------:| -|**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg?nocache)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg?nocache)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg?nocache)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg?nocache)| +|**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)| |**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A | |**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz) | From 9f3feda606197af37469a1781e6ae6477c1c567c Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Fri, 11 Mar 2016 14:24:09 -0800 Subject: [PATCH 24/99] Add sharedframework and sharedhost debian installer tests These are basic tests for now, which validate installation, upgrade, uninstall, etc. of the debian package itself. When the shared framework is fully functional, we will add more tests that cover real functionality. --- .../dotnet-sharedframework-debian_config.json | 2 +- .../package/package-sharedframework-debian.sh | 22 +++++++++++++++++++ scripts/package/package-sharedhost-debian.sh | 22 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json b/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json index 866a67515..93d32d198 100644 --- a/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json +++ b/packaging/sharedframework/debian/dotnet-sharedframework-debian_config.json @@ -29,7 +29,7 @@ }, "debian_dependencies":{ - "libssl-dev" : {}, + "libssl1.0.0" : {}, "libcurl3" : {} } } diff --git a/scripts/package/package-sharedframework-debian.sh b/scripts/package/package-sharedframework-debian.sh index f4d993c98..ef904c0ee 100755 --- a/scripts/package/package-sharedframework-debian.sh +++ b/scripts/package/package-sharedframework-debian.sh @@ -79,6 +79,7 @@ PACKAGING_TOOL_DIR="$REPOROOT/tools/DebianPackageTool" PACKAGE_OUTPUT_DIR="$OBJECT_DIR/deb_output" PACKAGE_LAYOUT_DIR="$OBJECT_DIR/deb_intermediate" +TEST_STAGE_DIR="$OBJECT_DIR/debian_tests" execute_build(){ create_empty_debian_layout @@ -125,8 +126,29 @@ update_debian_json() sed -i "s/%SHARED_FRAMEWORK_NUGET_VERSION%/$SHARED_FRAMEWORK_NUGET_VERSION/g" "$PACKAGE_LAYOUT_DIR"/debian_config.json } +test_debian_package(){ + header "Testing debian package" + + install_bats + run_package_integrity_tests +} + +install_bats() { + rm -rf $TEST_STAGE_DIR + git clone https://github.com/sstephenson/bats.git $TEST_STAGE_DIR +} + +run_package_integrity_tests() { + # Set LAST_VERSION_URL to enable upgrade tests + # export LAST_VERSION_URL="$PREVIOUS_VERSION_URL" + + $TEST_STAGE_DIR/bin/bats $PACKAGE_OUTPUT_DIR/test_package.bats +} + execute_build DEBIAN_FILE=$(find $PACKAGE_OUTPUT_DIR -iname "*.deb") +test_debian_package + mv -f "$DEBIAN_FILE" "$OUTPUT_DEBIAN_FILE" diff --git a/scripts/package/package-sharedhost-debian.sh b/scripts/package/package-sharedhost-debian.sh index 6ab255dc9..4c4ecb8db 100755 --- a/scripts/package/package-sharedhost-debian.sh +++ b/scripts/package/package-sharedhost-debian.sh @@ -64,6 +64,7 @@ PACKAGING_TOOL_DIR="$REPOROOT/tools/DebianPackageTool" PACKAGE_OUTPUT_DIR="$OBJECT_DIR/deb_output" PACKAGE_LAYOUT_DIR="$OBJECT_DIR/deb_intermediate" +TEST_STAGE_DIR="$OBJECT_DIR/debian_tests" execute_build(){ create_empty_debian_layout @@ -101,8 +102,29 @@ create_debian_package(){ "$PACKAGING_TOOL_DIR/package_tool" -i "$PACKAGE_LAYOUT_DIR" -o "$PACKAGE_OUTPUT_DIR" -v "$SHARED_HOST_DEBIAN_VERSION" } +test_debian_package(){ + header "Testing debian package" + + install_bats + run_package_integrity_tests +} + +install_bats() { + rm -rf $TEST_STAGE_DIR + git clone https://github.com/sstephenson/bats.git $TEST_STAGE_DIR +} + +run_package_integrity_tests() { + # Set LAST_VERSION_URL to enable upgrade tests + # export LAST_VERSION_URL="$PREVIOUS_VERSION_URL" + + $TEST_STAGE_DIR/bin/bats $PACKAGE_OUTPUT_DIR/test_package.bats +} + execute_build DEBIAN_FILE=$(find $PACKAGE_OUTPUT_DIR -iname "*.deb") +test_debian_package + mv -f "$DEBIAN_FILE" "$OUTPUT_DEBIAN_FILE" From 71d71b8ddcbdf0ae290ca5d73033baab8084e589 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Fri, 11 Mar 2016 14:32:36 -0800 Subject: [PATCH 25/99] Add RHEL and Windows x86 to CI. - Changes in netci.groovy to delete post-merge builds. We are suign VSO for that. - Also add RHEL and Windows x86 to PR CI jobs. Instead of doing 'debug' and 'release' for all platforms we are only selectively have a mixture of debug and release builds. (For ubuntu we are doing debug and release but that will change when we have 'Debian 8.2' support. Ubuntu:Debug will be replaced by Debian8.2:Debug) - Minor change in install.sh to maintain uniformity in OS names. --- README.md | 16 +++---- netci.groovy | 87 ++++++++++++++++++--------------------- scripts/obtain/install.sh | 2 +- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 8709b03b3..ad13d40ad 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,18 @@ If you don't find your issue, please file one! However, given that this is a ver Build Status ------------ -|Ubuntu 14.04 |Windows |Mac OS X |CentOS 7.1 | -|:------:|:------:|:------:|:------:| -|![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/601/badge)|![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/602/badge)|![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/600/badge) |![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/597/badge) | +|Ubuntu 14.04 |Windows x64 |Windows x86 |Mac OS X |CentOS 7.1 |RHEL 7.2 | +|:------:|:------:|:------:|:------:|:------:|:------:| +|![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/601/badge)|![](https://mseng.visualstudio.com/DefaultCollection/_apis/public/build/definitions/d09b7a4d-0a51-4c0e-a15a-07921d5b558f/3022/badge)|![](https://mseng.visualstudio.com/DefaultCollection/_apis/public/build/definitions/d09b7a4d-0a51-4c0e-a15a-07921d5b558f/3071/badge)|![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/600/badge) |![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/597/badge) |![](https://devdiv.visualstudio.com/DefaultCollection/_apis/public/build/definitions/0bdbc590-a062-4c3f-b0f6-9383f67865ee/897/badge) | Installers ---------- -| |Ubuntu 14.04 |Windows |Mac OS X |CentOS 7.1 | -|---------|:------:|:------:|:------:|:------:| -|**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)| -|**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A | -|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz) | +| |Ubuntu 14.04 |Windows x64 |Windows x86 |Mac OS X |CentOS 7.1 |RHEL 7.2 | +|---------|:------:|:------:|:------:|:------:|:------:|:------:| +|**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x86_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/RHEL_x64_Release_version_badge.svg)| +|**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x86.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A |N/A | +|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-rhel-x64.latest.tar.gz) | Interested in .NET Core + ASP.NET Core 1.0 RC1 bits? ---------------------------------------------------- diff --git a/netci.groovy b/netci.groovy index 0ff8b01e2..695a2c264 100644 --- a/netci.groovy +++ b/netci.groovy @@ -7,61 +7,56 @@ import jobs.generation.Utilities; def project = GithubProject def branch = GithubBranchName +def isPR = true -def osList = ['Ubuntu', 'OSX', 'Windows_NT', 'Windows_2016', 'CentOS7.1'] +def platformList = ['Ubuntu:x64:Debug', 'Ubuntu:x64:Release', 'OSX:x64:Release', 'Windows_NT:x64:Release', 'Windows_2016:x64:Release', 'Windows_2016:x86:Debug', 'RHEL7.2:x64:Release', 'CentOS7.1:x64:Debug'] -def static getBuildJobName(def configuration, def os) { - return configuration.toLowerCase() + '_' + os.toLowerCase() +def static getBuildJobName(def configuration, def os, def architecture) { + return configuration.toLowerCase() + '_' + os.toLowerCase() + '_' + architecture.toLowerCase() } -[true, false].each { isPR -> - ['Debug', 'Release'].each { configuration -> - osList.each { os -> - // Calculate names - def lowerConfiguration = configuration.toLowerCase() - // Calculate job name - def jobName = getBuildJobName(configuration, os) - def buildCommand = ''; +platformList.each { platform -> + // Calculate names + def (os, architecture, configuration) = platform.tokenize(':') - // Calculate the build command - if (os == 'Windows_NT') { - buildCommand = ".\\build.cmd -Configuration ${lowerConfiguration} -Targets Default" - } - else if (os == 'Windows_2016') { - buildCommand = ".\\build.cmd -Configuration ${lowerConfiguration} -RunInstallerTestsInDocker -Targets Default" - } - else if (os == 'Ubuntu') { - buildCommand = "./build.sh --skip-prereqs --configuration ${lowerConfiguration} --docker ubuntu --targets Default" + // Calculate job name + def jobName = getBuildJobName(configuration, os, architecture) + def buildCommand = ''; + + // Calculate the build command + if (os == 'Windows_NT') { + buildCommand = ".\\build.cmd -Configuration ${configuration} -Architecture ${architecture} -Targets Default" + } + else if (os == 'Windows_2016') { + buildCommand = ".\\build.cmd -Configuration ${configuration} -Architecture ${architecture} -RunInstallerTestsInDocker -Targets Default" + } + else if (os == 'Ubuntu') { + buildCommand = "./build.sh --skip-prereqs --configuration ${configuration} --docker ubuntu --targets Default" + } + else { + // Jenkins non-Ubuntu CI machines don't have docker + buildCommand = "./build.sh --skip-prereqs --configuration ${configuration} --targets Default" + } + + def newJob = job(Utilities.getFullJobName(project, jobName, isPR)) { + // Set the label. + steps { + if (os == 'Windows_NT' || os == 'Windows_2016') { + // Batch + batchFile(buildCommand) } else { - // Jenkins non-Ubuntu CI machines don't have docker - buildCommand = "./build.sh --skip-prereqs --configuration ${lowerConfiguration} --targets Default" - } - - def newJob = job(Utilities.getFullJobName(project, jobName, isPR)) { - // Set the label. - steps { - if (os == 'Windows_NT' || os == 'Windows_2016') { - // Batch - batchFile(buildCommand) - } - else { - // Shell - shell(buildCommand) - } - } - } - - Utilities.setMachineAffinity(newJob, os, 'latest-or-auto') - Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}") - Utilities.addXUnitDotNETResults(newJob, '**/*-testResults.xml') - if (isPR) { - Utilities.addGithubPRTriggerForBranch(newJob, branch, "${os} ${configuration} Build") - } - else { - Utilities.addGithubPushTrigger(newJob) + // Shell + shell(buildCommand) } } } + + Utilities.setMachineAffinity(newJob, os, 'latest-or-auto') + Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}") + Utilities.addXUnitDotNETResults(newJob, '**/*-testResults.xml') + Utilities.addGithubPRTriggerForBranch(newJob, branch, "${os} ${architecture} ${configuration} Build") } + + diff --git a/scripts/obtain/install.sh b/scripts/obtain/install.sh index c212eae44..198ed6041 100755 --- a/scripts/obtain/install.sh +++ b/scripts/obtain/install.sh @@ -84,7 +84,7 @@ current_os() elif [ "$(cat /etc/*-release | grep -cim1 centos)" -eq 1 ]; then echo "centos" elif [ "$(cat /etc/*-release | grep -cim1 rhel)" -eq 1 ]; then - echo "rhel.7" + echo "rhel" elif [ "$(cat /etc/*-release | grep -cim1 debian)" -eq 1 ]; then echo "debian" fi From d08e83d5db833181a0ceb3e690776741f28dbafa Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Wed, 9 Mar 2016 11:36:16 -0800 Subject: [PATCH 26/99] add support for portable application layout --- .../BuildTestPortableProject/Lib.cs | 3 - .../BuildTestStandaloneProject/Lib.cs | 3 - .../PortableTests/PortableApp/.noautobuild | 0 .../PortableTests/PortableApp/Program.cs | 12 ++ .../PortableApp}/project.json | 7 +- .../PortableAppWithNative/.noautobuild | 0 .../PortableAppWithNative/Program.cs | 12 ++ .../PortableAppWithNative/project.json | 14 +++ .../PortableTests/StandaloneApp/.noautobuild | 0 .../PortableTests/StandaloneApp/Program.cs | 12 ++ .../StandaloneApp}/project.json | 6 +- .../TestLibrary/README.md | 2 + .../Debug/dnxcore50/TestLibrary.dll | Bin .../Debug/dnxcore50/TestLibrary.pdb | Bin .../Debug/dnxcore50/TestLibrary.xml | 0 .../TestLibrary/project.json | 4 +- scripts/dotnet-cli-build/TestTargets.cs | 33 +++--- .../ProjectDependenciesCommandResolver.cs | 4 +- src/Microsoft.DotNet.Cli.Utils/CoreHost.cs | 3 + .../Executable.cs | 44 +++++++- .../Compilation/LibraryAsset.cs | 1 + .../FileNameSuffixes.cs | 1 + .../OutputPathsCalculator.cs | 6 +- .../ProjectContext.cs | 6 + .../RuntimeOutputFiles.cs | 45 ++++++-- ....DotNet.TestFramework.TestAssetsManager.cs | 2 +- .../commands/dotnet-build/CompileContext.cs | 45 ++++---- .../dotnet-compile/CompilerCommandApp.cs | 6 - .../dotnet-compile/ManagedCompiler.cs | 2 +- .../commands/dotnet-publish/PublishCommand.cs | 103 +++++++++++++----- .../Assertions/DirectoryInfoAssertions.cs | 4 +- .../Commands/BuildCommand.cs | 18 +-- .../Commands/PublishCommand.cs | 78 +++++-------- .../BuildInvalidArgumentsTests.cs | 12 +- test/dotnet-build.Tests/BuildOutputTests.cs | 4 +- test/dotnet-build.Tests/BuildPortableTests.cs | 17 ++- .../PublishPortableTests.cs | 54 +++++++++ ...Tools.Publish.Tests.cs => PublishTests.cs} | 0 38 files changed, 371 insertions(+), 192 deletions(-) delete mode 100644 TestAssets/TestProjects/BuildTestPortableProject/Lib.cs delete mode 100644 TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs create mode 100644 TestAssets/TestProjects/PortableTests/PortableApp/.noautobuild create mode 100644 TestAssets/TestProjects/PortableTests/PortableApp/Program.cs rename TestAssets/TestProjects/{BuildTestPortableProject => PortableTests/PortableApp}/project.json (58%) create mode 100644 TestAssets/TestProjects/PortableTests/PortableAppWithNative/.noautobuild create mode 100644 TestAssets/TestProjects/PortableTests/PortableAppWithNative/Program.cs create mode 100644 TestAssets/TestProjects/PortableTests/PortableAppWithNative/project.json create mode 100644 TestAssets/TestProjects/PortableTests/StandaloneApp/.noautobuild create mode 100644 TestAssets/TestProjects/PortableTests/StandaloneApp/Program.cs rename TestAssets/TestProjects/{BuildTestStandaloneProject => PortableTests/StandaloneApp}/project.json (78%) create mode 100644 TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/README.md rename TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/{bin => bin.keep}/Debug/dnxcore50/TestLibrary.dll (100%) rename TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/{bin => bin.keep}/Debug/dnxcore50/TestLibrary.pdb (100%) rename TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/{bin => bin.keep}/Debug/dnxcore50/TestLibrary.xml (100%) create mode 100644 test/dotnet-publish.Tests/PublishPortableTests.cs rename test/dotnet-publish.Tests/{Microsoft.DotNet.Tools.Publish.Tests.cs => PublishTests.cs} (100%) diff --git a/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs b/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs deleted file mode 100644 index 2ac94ca9d..000000000 --- a/TestAssets/TestProjects/BuildTestPortableProject/Lib.cs +++ /dev/null @@ -1,3 +0,0 @@ -public static class Thingy -{ -} diff --git a/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs b/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs deleted file mode 100644 index 2ac94ca9d..000000000 --- a/TestAssets/TestProjects/BuildTestStandaloneProject/Lib.cs +++ /dev/null @@ -1,3 +0,0 @@ -public static class Thingy -{ -} diff --git a/TestAssets/TestProjects/PortableTests/PortableApp/.noautobuild b/TestAssets/TestProjects/PortableTests/PortableApp/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/PortableTests/PortableApp/Program.cs b/TestAssets/TestProjects/PortableTests/PortableApp/Program.cs new file mode 100644 index 000000000..fbe8e9b0e --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/PortableApp/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace PortableApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/BuildTestPortableProject/project.json b/TestAssets/TestProjects/PortableTests/PortableApp/project.json similarity index 58% rename from TestAssets/TestProjects/BuildTestPortableProject/project.json rename to TestAssets/TestProjects/PortableTests/PortableApp/project.json index 841c77d4d..4386a64ac 100644 --- a/TestAssets/TestProjects/BuildTestPortableProject/project.json +++ b/TestAssets/TestProjects/PortableTests/PortableApp/project.json @@ -1,14 +1,17 @@ { + "compilationOptions": { + "emitEntryPoint": true + }, "dependencies": { }, "frameworks": { - "netstandardapp1.5": { + "netstandard1.5": { "imports": [ "dnxcore50", "portable-net45+win8" ], "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" } } } diff --git a/TestAssets/TestProjects/PortableTests/PortableAppWithNative/.noautobuild b/TestAssets/TestProjects/PortableTests/PortableAppWithNative/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/PortableTests/PortableAppWithNative/Program.cs b/TestAssets/TestProjects/PortableTests/PortableAppWithNative/Program.cs new file mode 100644 index 000000000..01b2c06d5 --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/PortableAppWithNative/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace PortableAppWithNative +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/PortableTests/PortableAppWithNative/project.json b/TestAssets/TestProjects/PortableTests/PortableAppWithNative/project.json new file mode 100644 index 000000000..b315d44e7 --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/PortableAppWithNative/project.json @@ -0,0 +1,14 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "netstandard1.5": { + "imports": [ "dnxcore50", "portable-net45+win8" ], + "dependencies": { + "Microsoft.NETCore.App": "1.0.0-rc2-23911", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*" + } + } + } +} diff --git a/TestAssets/TestProjects/PortableTests/StandaloneApp/.noautobuild b/TestAssets/TestProjects/PortableTests/StandaloneApp/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/PortableTests/StandaloneApp/Program.cs b/TestAssets/TestProjects/PortableTests/StandaloneApp/Program.cs new file mode 100644 index 000000000..529893b0e --- /dev/null +++ b/TestAssets/TestProjects/PortableTests/StandaloneApp/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace StandaloneApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/BuildTestStandaloneProject/project.json b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json similarity index 78% rename from TestAssets/TestProjects/BuildTestStandaloneProject/project.json rename to TestAssets/TestProjects/PortableTests/StandaloneApp/project.json index 5aff9ad77..eaae7c1cd 100644 --- a/TestAssets/TestProjects/BuildTestStandaloneProject/project.json +++ b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json @@ -1,5 +1,7 @@ { - "dependencies": { }, + "compilationOptions": { + "emitEntryPoint": true + }, "frameworks": { "netstandardapp1.5": { "imports": [ @@ -7,7 +9,7 @@ "portable-net45+win8" ], "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" } } }, diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/README.md b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/README.md new file mode 100644 index 000000000..add0a6729 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/README.md @@ -0,0 +1,2 @@ +# What is this? +This is a test wrapped project where we've checked in the binaries. To protect it from the build scripts cleaning the `bin` folder, we've renamed that folder to `bin.keep`. Please don't rename it! \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.dll b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.dll similarity index 100% rename from TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.dll rename to TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.dll diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.pdb b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.pdb similarity index 100% rename from TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.pdb rename to TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.pdb diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.xml b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.xml similarity index 100% rename from TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin/Debug/dnxcore50/TestLibrary.xml rename to TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/bin.keep/Debug/dnxcore50/TestLibrary.xml diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/project.json index 5fb2b0c73..44ae2133b 100644 --- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/project.json +++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestLibrary/project.json @@ -3,8 +3,8 @@ "netstandardapp1.5": { "imports": "dnxcore50", "bin": { - "assembly": "bin\\{configuration}\\dnxcore50\\TestLibrary.dll", - "pdb": "bin\\{configuration}\\dnxcore50\\TestLibrary.pdb" + "assembly": "bin.keep\\{configuration}\\dnxcore50\\TestLibrary.dll", + "pdb": "bin.keep\\{configuration}\\dnxcore50\\TestLibrary.pdb" } } } diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index b1a783be8..375a984be 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -44,7 +44,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(SetupTestPackages), nameof(SetupTestProjects))] public static BuildTargetResult SetupTests(BuildTargetContext c) => c.Success(); - + [Target(nameof(RestoreTestAssetPackages), nameof(BuildTestAssetPackages))] public static BuildTargetResult SetupTestPackages(BuildTargetContext c) => c.Success(); @@ -64,7 +64,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - + [Target] public static BuildTargetResult RestoreTestAssetProjects(BuildTargetContext c) { @@ -74,16 +74,16 @@ namespace Microsoft.DotNet.Cli.Build CleanNuGetTempCache(); var dotnet = DotNetCli.Stage2; - + dotnet.Restore("--fallbacksource", Dirs.TestPackages) .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestProjects")) .Execute().EnsureSuccessful(); - + // The 'ProjectModelServer' directory contains intentionally-unresolved dependencies, so don't check for success. Also, suppress the output dotnet.Restore() .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthTestProjects")) .Execute(); - + dotnet.Restore() .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthUpdateSearchPathSample")) .Execute(); @@ -94,6 +94,8 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(CleanTestPackages))] public static BuildTargetResult BuildTestAssetPackages(BuildTargetContext c) { + CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")); + var dotnet = DotNetCli.Stage2; Rmdir(Dirs.TestPackages); @@ -108,21 +110,23 @@ namespace Microsoft.DotNet.Cli.Build .Execute() .EnsureSuccessful(); } - + return c.Success(); } - + [Target] public static BuildTargetResult CleanTestPackages(BuildTargetContext c) { Rmdir(Path.Combine(Dirs.NuGetPackages, "dotnet-hello")); - + return c.Success(); } [Target] public static BuildTargetResult BuildTestAssetProjects(BuildTargetContext c) { + CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestProjects")); + var dotnet = DotNetCli.Stage2; var nobuildFileName = ".noautobuild"; string testProjectsRoot = Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestProjects"); @@ -137,7 +141,7 @@ namespace Microsoft.DotNet.Cli.Build .Execute() .EnsureSuccessful(); } - + return c.Success(); } @@ -246,7 +250,7 @@ namespace Microsoft.DotNet.Cli.Build { return new Dictionary(); } - + c.Verbose("Start Collecting Visual Studio Environment Variables"); var vsvarsPath = Path.GetFullPath(Path.Combine(Environment.GetEnvironmentVariable("VS140COMNTOOLS"), "..", "..", "VC")); @@ -273,14 +277,14 @@ set"); File.Delete(temp); } } - + result.EnsureSuccessful(); - + var vars = new Dictionary(); foreach (var line in result.StdOut.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) { var splat = line.Split(new[] { '=' }, 2); - + if (splat.Length == 2) { c.Verbose($"Adding variable '{line}'"); @@ -291,9 +295,8 @@ set"); c.Info($"Skipping VS Env Variable. Unknown format: '{line}'"); } } - + c.Verbose("Finish Collecting Visual Studio Environment Variables"); - return vars; } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs index f5436186c..bf314ee6a 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs @@ -25,12 +25,12 @@ namespace Microsoft.DotNet.Cli.Utils { if (environment == null) { - throw new ArgumentNullException("environment"); + throw new ArgumentNullException(nameof(environment)); } if (packagedCommandSpecFactory == null) { - throw new ArgumentNullException("packagedCommandSpecFactory"); + throw new ArgumentNullException(nameof(packagedCommandSpecFactory)); } _environment = environment; diff --git a/src/Microsoft.DotNet.Cli.Utils/CoreHost.cs b/src/Microsoft.DotNet.Cli.Utils/CoreHost.cs index 2dae756b0..5808c5140 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CoreHost.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CoreHost.cs @@ -49,6 +49,9 @@ namespace Microsoft.DotNet.Cli.Utils var outputBinaryPath = Path.Combine(destinationPath, outputBinaryName); var hostBinaryPath = Path.Combine(HostDir, binaryName); File.Copy(hostBinaryPath, outputBinaryPath, overwrite: true); + + // Update the last write time so this file can be treated as an output of a build + File.SetLastWriteTimeUtc(outputBinaryPath, DateTime.UtcNow); } } } diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs index 03c89273c..3fa63b148 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs +++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs @@ -14,11 +14,16 @@ using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Graph; using Microsoft.Extensions.DependencyModel; using NuGet.Frameworks; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; namespace Microsoft.Dotnet.Cli.Compiler.Common { public class Executable { + // GROOOOOSS + private static readonly string RedistPackageName = "Microsoft.NETCore.App"; + private readonly ProjectContext _context; private readonly LibraryExporter _exporter; @@ -71,7 +76,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common { WriteDepsFileAndCopyProjectDependencies(_exporter); - if (!string.IsNullOrEmpty(_context.RuntimeIdentifier)) + var emitEntryPoint = _context.ProjectFile.GetCompilerOptions(_context.TargetFramework, _configuration).EmitEntryPoint ?? false; + if (emitEntryPoint && !string.IsNullOrEmpty(_context.RuntimeIdentifier)) { // TODO: Pick a host based on the RID CoreHost.CopyTo(_runtimeOutputPath, _context.ProjectFile.Name + Constants.ExeSuffix); @@ -106,6 +112,7 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter) { WriteDeps(exporter); + WriteRuntimeConfig(exporter); var projectExports = exporter.GetDependencies(LibraryType.Project); CopyAssemblies(projectExports); @@ -115,6 +122,37 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common CopyAssets(packageExports); } + private void WriteRuntimeConfig(LibraryExporter exporter) + { + if (!_context.TargetFramework.IsDesktop()) + { + // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated + // in order to prevent breaking incremental compilation... + + var json = new JObject(); + var runtimeOptions = new JObject(); + json.Add("runtimeOptions", runtimeOptions); + + var redistExport = exporter + .GetAllExports() + .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); + if (redistExport != null) + { + var framework = new JObject( + new JProperty("name", redistExport.Library.Identity.Name), + new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); + runtimeOptions.Add("framework", framework); + } + + var runtimeConfigJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.RuntimeConfigJson); + using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) + { + writer.Formatting = Formatting.Indented; + json.WriteTo(writer); + } + } + } + public void WriteDeps(LibraryExporter exporter) { var path = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.Deps); @@ -128,7 +166,7 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common var exports = exporter.GetAllExports().ToArray(); var dependencyContext = new DependencyContextBuilder().Build( - compilerOptions: includeCompile? compilerOptions: null, + compilerOptions: includeCompile ? compilerOptions : null, compilationExports: includeCompile ? exports : null, runtimeExports: exports, portable: string.IsNullOrEmpty(_context.RuntimeIdentifier), @@ -141,10 +179,8 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common { writer.Write(dependencyContext, fileStream); } - } - public void GenerateBindingRedirects(LibraryExporter exporter) { var outputName = _outputPaths.RuntimeFiles.Assembly; diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs index 6186f26e5..b4565dd19 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryAsset.cs @@ -15,6 +15,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation public string Name { get; } public string RelativePath { get; } public string ResolvedPath { get; } + public string FileName => Path.GetFileName(RelativePath); public Action Transform { get; set; } public LibraryAsset(string name, string relativePath, string resolvedPath, Action transform = null) diff --git a/src/Microsoft.DotNet.ProjectModel/FileNameSuffixes.cs b/src/Microsoft.DotNet.ProjectModel/FileNameSuffixes.cs index 12bedfdb4..781e3cbed 100644 --- a/src/Microsoft.DotNet.ProjectModel/FileNameSuffixes.cs +++ b/src/Microsoft.DotNet.ProjectModel/FileNameSuffixes.cs @@ -7,6 +7,7 @@ namespace Microsoft.DotNet.ProjectModel { public const string Deps = ".deps"; public const string DepsJson = ".deps.json"; + public const string RuntimeConfigJson = ".runtimeconfig.json"; public static PlatformFileNameSuffixes CurrentPlatform { diff --git a/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs b/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs index fdaa7c5e3..f2a25bb45 100644 --- a/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs +++ b/src/Microsoft.DotNet.ProjectModel/OutputPathsCalculator.cs @@ -70,11 +70,7 @@ namespace Microsoft.DotNet.ProjectModel var compilationFiles = new CompilationOutputFiles(compilationOutputPath, project, configuration, framework); - RuntimeOutputFiles runtimeFiles = null; - if (runtimeOutputPath != null) - { - runtimeFiles = new RuntimeOutputFiles(runtimeOutputPath, project, configuration, framework); - } + RuntimeOutputFiles runtimeFiles = new RuntimeOutputFiles(runtimeOutputPath, project, configuration, framework, runtimeIdentifier); return new OutputPaths(intermediateOutputPath, compilationOutputPath, runtimeOutputPath, compilationFiles, runtimeFiles); } } diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index 99f869f36..c82e3927f 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -140,6 +140,12 @@ namespace Microsoft.DotNet.ProjectModel public ProjectContext CreateRuntimeContext(IEnumerable runtimeIdentifiers) { + // Temporary until we have removed RID inference from NuGet + if(TargetFramework.IsCompileOnly) + { + return this; + } + // Check if there are any runtime targets (i.e. are we portable) var standalone = LockFile.Targets .Where(t => t.TargetFramework.Equals(TargetFramework)) diff --git a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs index 7ade31bc1..8e9bdca3b 100644 --- a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs +++ b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs @@ -9,11 +9,15 @@ namespace Microsoft.DotNet.ProjectModel { public class RuntimeOutputFiles : CompilationOutputFiles { + private readonly string _runtimeIdentifier; + public RuntimeOutputFiles(string basePath, Project project, string configuration, - NuGetFramework framework) : base(basePath, project, configuration, framework) + NuGetFramework framework, + string runtimeIdentifier) : base(basePath, project, configuration, framework) { + _runtimeIdentifier = runtimeIdentifier; } public string Executable @@ -39,6 +43,7 @@ namespace Microsoft.DotNet.ProjectModel return Path.ChangeExtension(Assembly, FileNameSuffixes.Deps); } } + public string DepsJson { get @@ -47,6 +52,14 @@ namespace Microsoft.DotNet.ProjectModel } } + public string RuntimeConfigJson + { + get + { + return Path.ChangeExtension(Assembly, FileNameSuffixes.RuntimeConfigJson); + } + } + public string Config { get { return Assembly + ".config"; } @@ -59,20 +72,28 @@ namespace Microsoft.DotNet.ProjectModel yield return file; } + if (Project.HasRuntimeOutput(Config)) + { + if (!Framework.IsDesktop()) + { + yield return Deps; + yield return DepsJson; + yield return RuntimeConfigJson; + } + + // If the project actually has an entry point AND we're doing a standalone build + var hasEntryPoint = Project.GetCompilerOptions(targetFramework: null, configurationName: Configuration).EmitEntryPoint ?? false; + if (hasEntryPoint && !string.IsNullOrEmpty(_runtimeIdentifier)) + { + // Yield the executable + yield return Executable; + } + } + if (File.Exists(Config)) { yield return Config; } - - if (File.Exists(Deps)) - { - yield return Deps; - } - - if (File.Exists(DepsJson)) - { - yield return DepsJson; - } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestAssetsManager.cs b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestAssetsManager.cs index 9d4e59313..aa1e6ba56 100644 --- a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestAssetsManager.cs +++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestAssetsManager.cs @@ -92,7 +92,7 @@ namespace Microsoft.DotNet.TestFramework { throw new Exception($"Cannot find '{testProjectName}' at '{AssetsRoot}'"); } - + string testDestination = Path.Combine(AppContext.BaseDirectory, callingMethod + identifier, testProjectName); var testInstance = new TestInstance(testProjectDir, testDestination); return testInstance; diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs index 237fb744c..b6b5c2adb 100644 --- a/src/dotnet/commands/dotnet-build/CompileContext.cs +++ b/src/dotnet/commands/dotnet-build/CompileContext.cs @@ -33,7 +33,7 @@ namespace Microsoft.DotNet.Tools.Build { _rootProject = rootProject; - // Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args + // Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args // and then reasoning which ones to get from args and which ones from fields. _args = (BuilderCommandApp)args.ShallowCopy(); @@ -420,12 +420,6 @@ namespace Microsoft.DotNet.Tools.Build private void MakeRunnable() { var runtimeContext = _rootProject.CreateRuntimeContext(_args.GetRuntimes()); - if(_args.PortableMode) - { - // HACK: Force the use of the portable target - runtimeContext = _rootProject; - } - var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue); var libraryExporter = runtimeContext.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue); @@ -436,6 +430,7 @@ namespace Microsoft.DotNet.Tools.Build CopyCompilationOutput(outputPaths); } + var options = runtimeContext.ProjectFile.GetCompilerOptions(runtimeContext.TargetFramework, _args.ConfigValue); var executable = new Executable(runtimeContext, outputPaths, libraryExporter, _args.ConfigValue); executable.MakeCompilationOutputRunnable(); @@ -446,24 +441,22 @@ namespace Microsoft.DotNet.Tools.Build // time. See: https://github.com/dotnet/cli/issues/1374 private static void PatchMscorlibNextToCoreClr(ProjectContext context, string config) { + foreach (var exp in context.CreateExporter(config).GetAllExports()) { - foreach (var exp in context.CreateExporter(config).GetAllExports()) + var coreclrLib = exp.NativeLibraries.FirstOrDefault(nLib => + string.Equals(Constants.LibCoreClrFileName, nLib.Name)); + if (string.IsNullOrEmpty(coreclrLib.ResolvedPath)) { - var coreclrLib = exp.NativeLibraries.FirstOrDefault(nLib => - string.Equals(Constants.LibCoreClrFileName, nLib.Name)); - if (string.IsNullOrEmpty(coreclrLib.ResolvedPath)) - { - continue; - } - var coreclrDir = Path.GetDirectoryName(coreclrLib.ResolvedPath); - if (File.Exists(Path.Combine(coreclrDir, "mscorlib.dll")) || - File.Exists(Path.Combine(coreclrDir, "mscorlib.ni.dll"))) - { - continue; - } - var mscorlibFile = exp.RuntimeAssemblies.FirstOrDefault(r => r.Name.Equals("mscorlib") || r.Name.Equals("mscorlib.ni")).ResolvedPath; - File.Copy(mscorlibFile, Path.Combine(coreclrDir, Path.GetFileName(mscorlibFile)), overwrite: true); + continue; } + var coreclrDir = Path.GetDirectoryName(coreclrLib.ResolvedPath); + if (File.Exists(Path.Combine(coreclrDir, "mscorlib.dll")) || + File.Exists(Path.Combine(coreclrDir, "mscorlib.ni.dll"))) + { + continue; + } + var mscorlibFile = exp.RuntimeAssemblies.FirstOrDefault(r => r.Name.Equals("mscorlib") || r.Name.Equals("mscorlib.ni")).ResolvedPath; + File.Copy(mscorlibFile, Path.Combine(coreclrDir, Path.GetFileName(mscorlibFile)), overwrite: true); } } @@ -533,12 +526,16 @@ namespace Microsoft.DotNet.Tools.Build // input: dependencies AddDependencies(dependencies, compilerIO); - var allOutputPath = new List(calculator.CompilationFiles.All()); + var allOutputPath = new HashSet(calculator.CompilationFiles.All()); if (isRootProject && project.ProjectFile.HasRuntimeOutput(buildConfiguration)) { var runtimeContext = project.CreateRuntimeContext(_args.GetRuntimes()); - allOutputPath.AddRange(runtimeContext.GetOutputPaths(buildConfiguration, buildBasePath, outputPath).RuntimeFiles.All()); + foreach (var path in runtimeContext.GetOutputPaths(buildConfiguration, buildBasePath, outputPath).RuntimeFiles.All()) + { + allOutputPath.Add(path); + } } + // output: compiler outputs foreach (var path in allOutputPath) { diff --git a/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs b/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs index 9a66f1777..8da23d62e 100644 --- a/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs +++ b/src/dotnet/commands/dotnet-compile/CompilerCommandApp.cs @@ -29,7 +29,6 @@ namespace Microsoft.DotNet.Tools.Compiler private CommandOption _runtimeOption; private CommandOption _versionSuffixOption; private CommandOption _configurationOption; - private CommandOption _portableOption; private CommandArgument _projectArgument; private CommandOption _nativeOption; private CommandOption _archOption; @@ -55,7 +54,6 @@ namespace Microsoft.DotNet.Tools.Compiler public bool IsCppModeValue { get; set; } public string AppDepSdkPathValue { get; set; } public string CppCompilerFlagsValue { get; set; } - public bool PortableMode { get; set; } // workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params private readonly Dictionary baseClassOptions; @@ -86,9 +84,6 @@ namespace Microsoft.DotNet.Tools.Compiler _versionSuffixOption = _app.Option("--version-suffix ", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue); _projectArgument = _app.Argument("", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory"); - // HACK: Allow us to treat a project as though it was portable by ignoring the runtime-specific targets. This is temporary until RID inference is removed from NuGet - _portableOption = _app.Option("--portable", "TEMPORARY: Enforces portable build/publish mode", CommandOptionType.NoValue); - // Native Args _nativeOption = _app.Option("-n|--native", "Compiles source to native machine code.", CommandOptionType.NoValue); _archOption = _app.Option("-a|--arch ", "The architecture for which to compile. x64 only currently supported.", CommandOptionType.SingleValue); @@ -122,7 +117,6 @@ namespace Microsoft.DotNet.Tools.Compiler ConfigValue = _configurationOption.Value() ?? Constants.DefaultConfiguration; RuntimeValue = _runtimeOption.Value(); VersionSuffixValue = _versionSuffixOption.Value(); - PortableMode = _portableOption.HasValue(); IsNativeValue = _nativeOption.HasValue(); ArchValue = _archOption.Value(); diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs index d4f3dc4c3..2bff5ba89 100644 --- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs +++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs @@ -114,7 +114,7 @@ namespace Microsoft.DotNet.Tools.Compiler var dependencyContext = new DependencyContextBuilder().Build(compilationOptions, allExports, allExports, - args.PortableMode, + true, // For now, just assume portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty); diff --git a/src/dotnet/commands/dotnet-publish/PublishCommand.cs b/src/dotnet/commands/dotnet-publish/PublishCommand.cs index 802a1c963..2c5f3ef29 100644 --- a/src/dotnet/commands/dotnet-publish/PublishCommand.cs +++ b/src/dotnet/commands/dotnet-publish/PublishCommand.cs @@ -29,7 +29,7 @@ namespace Microsoft.DotNet.Tools.Publish public string Runtime { get; set; } public bool NativeSubdirectories { get; set; } public NuGetFramework NugetFramework { get; set; } - public IEnumerable ProjectContexts { get; set; } + public IList ProjectContexts { get; set; } public string VersionSuffix { get; set; } public int NumberOfProjects { get; private set; } public int NumberOfPublishedProjects { get; private set; } @@ -47,10 +47,10 @@ namespace Microsoft.DotNet.Tools.Publish } } - ProjectContexts = SelectContexts(ProjectPath, NugetFramework, Runtime); + ProjectContexts = SelectContexts(ProjectPath, NugetFramework, Runtime).ToList(); if (!ProjectContexts.Any()) { - string errMsg = $"'{ProjectPath}' cannot be published for '{Framework ?? ""}' '{Runtime ?? ""}'"; + string errMsg = $"'{ProjectPath}' cannot be published for '{Framework ?? ""}' '{Runtime ?? ""}'"; Reporter.Output.WriteLine(errMsg.Red()); return false; } @@ -84,7 +84,12 @@ namespace Microsoft.DotNet.Tools.Publish /// Return 0 if successful else return non-zero private bool PublishProjectContext(ProjectContext context, string buildBasePath, string outputPath, string configuration, bool nativeSubdirectories) { - Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}"); + var target = context.TargetFramework.DotNetFrameworkName; + if (!string.IsNullOrEmpty(context.RuntimeIdentifier)) + { + target = $"{target}/{context.RuntimeIdentifier}"; + } + Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {target.Yellow()}"); var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var outputPaths = context.GetOutputPaths(configuration, buildBasePath, outputPath); @@ -115,13 +120,17 @@ namespace Microsoft.DotNet.Tools.Publish var args = new List() { "--framework", $"{context.TargetFramework.DotNetFrameworkName}", - "--runtime", - context.RuntimeIdentifier, "--configuration", configuration, context.ProjectFile.ProjectDirectory }; + if (!string.IsNullOrEmpty(context.RuntimeIdentifier)) + { + args.Insert(0, context.RuntimeIdentifier); + args.Insert(0, "--runtime"); + } + if (!string.IsNullOrEmpty(VersionSuffix)) { args.Add("--version-suffix"); @@ -147,23 +156,43 @@ namespace Microsoft.DotNet.Tools.Publish { Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); - PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false); - PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories); + PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false, preserveRelativePath: false); + PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories, preserveRelativePath: false); export.RuntimeAssets.StructuredCopyTo(outputPath, outputPaths.IntermediateOutputDirectoryPath); + if (string.IsNullOrEmpty(context.RuntimeIdentifier)) + { + var assets = export.RuntimeTargets.SelectMany(t => Enumerable.Concat(t.NativeLibraries, t.RuntimeAssemblies)); + PublishFiles(assets, outputPath, nativeSubdirectories: false, preserveRelativePath: true); + } + if (options.PreserveCompilationContext.GetValueOrDefault()) { PublishRefs(export, outputPath); } } + if (context.ProjectFile.HasRuntimeOutput(configuration) && !context.TargetFramework.IsDesktop()) + { + // Get the output paths used by the call to `dotnet build` above (since we didn't pass `--output`, they will be different from + // our current output paths) + var buildOutputPaths = context.GetOutputPaths(configuration, buildBasePath); + PublishFiles( + new[] { + buildOutputPaths.RuntimeFiles.Deps, + buildOutputPaths.RuntimeFiles.DepsJson, + buildOutputPaths.RuntimeFiles.RuntimeConfigJson + }, + outputPath); + } + var contentFiles = new ContentFiles(context); contentFiles.StructuredCopyTo(outputPath); // Publish a host if this is an application - if (options.EmitEntryPoint.GetValueOrDefault()) + if (options.EmitEntryPoint.GetValueOrDefault() && !string.IsNullOrEmpty(context.RuntimeIdentifier)) { - Reporter.Verbose.WriteLine($"Making {context.ProjectFile.Name.Cyan()} runnable ..."); + Reporter.Verbose.WriteLine($"Copying native host to output to create fully standalone output."); PublishHost(context, outputPath); } @@ -228,18 +257,23 @@ namespace Microsoft.DotNet.Tools.Publish } } - private static void PublishFiles(IEnumerable files, string outputPath, bool nativeSubdirectories) + private static void PublishFiles(IEnumerable files, string outputPath, bool nativeSubdirectories, bool preserveRelativePath) { foreach (var file in files) { var destinationDirectory = DetermineFileDestinationDirectory(file, outputPath, nativeSubdirectories); + if (preserveRelativePath) + { + destinationDirectory = Path.Combine(destinationDirectory, Path.GetDirectoryName(file.RelativePath)); + } + if (!Directory.Exists(destinationDirectory)) { Directory.CreateDirectory(destinationDirectory); } - File.Copy(file.ResolvedPath, Path.Combine(destinationDirectory, Path.GetFileName(file.ResolvedPath)), overwrite: true); + File.Copy(file.ResolvedPath, Path.Combine(destinationDirectory, file.FileName), overwrite: true); } } @@ -272,29 +306,46 @@ namespace Microsoft.DotNet.Tools.Publish return candidate; } - private static IEnumerable SelectContexts(string projectPath, NuGetFramework framework, string runtime) + private IEnumerable SelectContexts(string projectPath, NuGetFramework framework, string runtime) { - var allContexts = ProjectContext.CreateContextForEachTarget(projectPath); + var allContexts = ProjectContext.CreateContextForEachTarget(projectPath).ToList(); + var frameworks = framework == null ? + allContexts.Select(c => c.TargetFramework).Distinct().ToArray() : + new[] { framework }; + if (string.IsNullOrEmpty(runtime)) { - // Nothing was specified, so figure out what the candidate runtime identifiers are and try each of them - // Temporary until #619 is resolved - foreach (var candidate in PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers()) - { - var contexts = GetMatchingProjectContexts(allContexts, framework, candidate); - if (contexts.Any()) - { - return contexts; - } - } - return Enumerable.Empty(); + // For each framework, find the best matching RID item + var candidates = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); + return frameworks.Select(f => FindBestTarget(f, allContexts, candidates)); } else { - return GetMatchingProjectContexts(allContexts, framework, runtime); + return frameworks.SelectMany(f => allContexts.Where(c => + Equals(c.TargetFramework, f) && + string.Equals(c.RuntimeIdentifier, runtime, StringComparison.Ordinal))); } } + private ProjectContext FindBestTarget(NuGetFramework f, List allContexts, IEnumerable candidates) + { + foreach (var candidate in candidates) + { + var target = allContexts.FirstOrDefault(c => + Equals(c.TargetFramework, f) && + string.Equals(c.RuntimeIdentifier, candidate, StringComparison.Ordinal)); + if (target != null) + { + return target; + } + } + + // No RID-specific target found, use the RID-less target and publish portable + return allContexts.FirstOrDefault(c => + Equals(c.TargetFramework, f) && + string.IsNullOrEmpty(c.RuntimeIdentifier)); + } + /// /// Return the matching framework/runtime ProjectContext. /// If 'framework' or 'runtimeIdentifier' is null or empty then it matches with any. diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/DirectoryInfoAssertions.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/DirectoryInfoAssertions.cs index 6d4aa575a..ad83606b7 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/DirectoryInfoAssertions.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/DirectoryInfoAssertions.cs @@ -47,7 +47,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities } public AndConstraint HaveFiles(IEnumerable expectedFiles) - { + { foreach (var expectedFile in expectedFiles) { HaveFile(expectedFile); @@ -61,7 +61,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities var dir = _dirInfo.EnumerateDirectories(expectedDir, SearchOption.TopDirectoryOnly).SingleOrDefault(); Execute.Assertion.ForCondition(dir != null) .FailWith("Expected directory {0} cannot be found inside directory {1}.", expectedDir, _dirInfo.FullName); - + return new AndConstraint(new DirectoryInfoAssertions(dir)); } } diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs index da059a1fe..4f36ac973 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs @@ -29,7 +29,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities private readonly bool _noIncremental; private readonly bool _noDependencies; private readonly string _runtime; - private readonly bool _forcePortable; private string OutputOption { @@ -41,16 +40,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities } } - private string ForcePortableOption - { - get - { - return _forcePortable ? - "--portable" : - string.Empty; - } - } - private string BuildBasePathOption { get @@ -228,9 +217,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities string cppCompilerFlags="", bool buildProfile=true, bool noIncremental=false, - bool noDependencies=false, - bool forcePortable=false - ) + bool noDependencies=false) : base("dotnet") { _projectPath = projectPath; @@ -253,7 +240,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities _buildProfile = buildProfile; _noIncremental = noIncremental; _noDependencies = noDependencies; - _forcePortable = forcePortable; } public override CommandResult Execute(string args = "") @@ -277,7 +263,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities private string BuildArgs() { - return $"{BuildProfile} {ForcePortableOption} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {RuntimeOption} {VersionSuffixOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}"; + return $"{BuildProfile} {NoDependencies} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {RuntimeOption} {VersionSuffixOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}"; } } } diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs index 154b1d6cd..ec24eb73a 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs @@ -1,16 +1,12 @@ // 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 Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.Extensions.PlatformAbstractions; using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Threading.Tasks; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.ProjectModel; -using Microsoft.DotNet.Tools.Test.Utilities; -using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.DotNet.Tools.Test.Utilities { @@ -18,14 +14,14 @@ namespace Microsoft.DotNet.Tools.Test.Utilities { private const string PublishSubfolderName = "publish"; - private Project _project; - private string _path; - private string _framework; - private string _runtime; - private string _config; - private string _output; + private readonly Project _project; + private readonly string _path; + private readonly string _framework; + private readonly string _runtime; + private readonly string _config; + private readonly string _output; - public PublishCommand(string projectPath, string framework="", string runtime="", string output="", string config="") + public PublishCommand(string projectPath, string framework = "", string runtime = "", string output = "", string config = "", bool forcePortable = false) : base("dotnet") { _path = projectPath; @@ -36,7 +32,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities _config = config; } - public override CommandResult Execute(string args="") + public override CommandResult Execute(string args = "") { args = $"publish {BuildArgs()} {args}"; return base.Execute(args); @@ -48,34 +44,33 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return base.ExecuteWithCapturedOutput(args); } - public string ProjectName - { - get - { - return _project.Name; - } - } + public string ProjectName => _project.Name; - private string BuildRelativeOutputPath() + private string BuildRelativeOutputPath(bool portable) { // lets try to build an approximate output path string config = string.IsNullOrEmpty(_config) ? "Debug" : _config; string framework = string.IsNullOrEmpty(_framework) ? _project.GetTargetFrameworks().First().FrameworkName.GetShortFolderName() : _framework; - string runtime = string.IsNullOrEmpty(_runtime) ? PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier() : _runtime; - string output = Path.Combine(config, framework, runtime, PublishSubfolderName); - - return output; + if (!portable) + { + var runtime = string.IsNullOrEmpty(_runtime) ? PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier() : _runtime; + return Path.Combine(config, framework, runtime, PublishSubfolderName); + } + else + { + return Path.Combine(config, framework, PublishSubfolderName); + } } - public DirectoryInfo GetOutputDirectory() + public DirectoryInfo GetOutputDirectory(bool portable = false) { if (!string.IsNullOrEmpty(_output)) { return new DirectoryInfo(_output); } - string output = Path.Combine(_project.ProjectDirectory, "bin", BuildRelativeOutputPath()); + string output = Path.Combine(_project.ProjectDirectory, "bin", BuildRelativeOutputPath(portable)); return new DirectoryInfo(output); } @@ -88,27 +83,12 @@ namespace Microsoft.DotNet.Tools.Test.Utilities private string BuildArgs() { - return $"{_path} {GetFrameworkOption()} {GetRuntimeOption()} {GetOutputOption()} {GetConfigOption()}"; + return $"{_path} {FrameworkOption} {RuntimeOption} {OutputOption} {ConfigOption}"; } - private string GetFrameworkOption() - { - return string.IsNullOrEmpty(_framework) ? "" : $"-f {_framework}"; - } - - private string GetRuntimeOption() - { - return string.IsNullOrEmpty(_runtime) ? "" : $"-r {_runtime}"; - } - - private string GetOutputOption() - { - return string.IsNullOrEmpty(_output) ? "" : $"-o \"{_output}\""; - } - - private string GetConfigOption() - { - return string.IsNullOrEmpty(_config) ? "" : $"-c {_output}"; - } + private string FrameworkOption => string.IsNullOrEmpty(_framework) ? "" : $"-f {_framework}"; + private string RuntimeOption => string.IsNullOrEmpty(_runtime) ? "" : $"-r {_runtime}"; + private string OutputOption => string.IsNullOrEmpty(_output) ? "" : $"-o \"{_output}\""; + private string ConfigOption => string.IsNullOrEmpty(_config) ? "" : $"-c {_output}"; } } diff --git a/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs b/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs index 15a38b24b..a90f634b1 100644 --- a/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs +++ b/test/dotnet-build.Tests/BuildInvalidArgumentsTests.cs @@ -9,11 +9,11 @@ namespace Microsoft.DotNet.Tools.Builder.Tests [Fact] public void ErrorOccursWhenBuildingPortableProjectToSpecificOutputPathWithoutSpecifyingFramework() { - var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject") + var testInstance = TestAssetsManager.CreateTestInstance("PortableTests") .WithLockFiles(); var result = new BuildCommand( - projectPath: testInstance.TestRoot, + projectPath: Path.Combine(testInstance.TestRoot, "PortableApp"), output: Path.Combine(testInstance.TestRoot, "out")) .ExecuteWithCapturedOutput(); @@ -24,11 +24,11 @@ namespace Microsoft.DotNet.Tools.Builder.Tests [Fact] public void ErrorOccursWhenBuildingPortableProjectAndSpecifyingFrameworkThatProjectDoesNotSupport() { - var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject") + var testInstance = TestAssetsManager.CreateTestInstance("PortableTests") .WithLockFiles(); var result = new BuildCommand( - projectPath: testInstance.TestRoot, + projectPath: Path.Combine(testInstance.TestRoot, "PortableApp"), output: Path.Combine(testInstance.TestRoot, "out"), framework: "sl40") .ExecuteWithCapturedOutput(); @@ -40,11 +40,11 @@ namespace Microsoft.DotNet.Tools.Builder.Tests [Fact] public void ErrorOccursWhenBuildingStandaloneProjectToSpecificOutputPathWithoutSpecifyingFramework() { - var testInstance = TestAssetsManager.CreateTestInstance("BuildTestStandaloneProject") + var testInstance = TestAssetsManager.CreateTestInstance("PortableTests") .WithLockFiles(); var result = new BuildCommand( - projectPath: testInstance.TestRoot, + projectPath: Path.Combine(testInstance.TestRoot, "StandaloneApp"), output: Path.Combine(testInstance.TestRoot, "out")) .ExecuteWithCapturedOutput(); diff --git a/test/dotnet-build.Tests/BuildOutputTests.cs b/test/dotnet-build.Tests/BuildOutputTests.cs index 8d8072456..dae4de553 100644 --- a/test/dotnet-build.Tests/BuildOutputTests.cs +++ b/test/dotnet-build.Tests/BuildOutputTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests private readonly string[] _libCompileFiles = { "TestLibrary" + FileNameSuffixes.DotNet.DynamicLib, - "TestLibrary" + FileNameSuffixes.DotNet.ProgramDatabase, + "TestLibrary" + FileNameSuffixes.DotNet.ProgramDatabase }; private void GetProjectInfo(string testRoot) @@ -114,7 +114,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests fileVersion.Should().NotBeNull(); fileVersion.Should().BeEquivalentTo("1.0.0.345"); } - + [Fact] public void SettingVersionSuffixFlag_ShouldStampAssemblyInfoInOutputAssembly() { diff --git a/test/dotnet-build.Tests/BuildPortableTests.cs b/test/dotnet-build.Tests/BuildPortableTests.cs index c9a0eebbd..5ea72db09 100644 --- a/test/dotnet-build.Tests/BuildPortableTests.cs +++ b/test/dotnet-build.Tests/BuildPortableTests.cs @@ -9,28 +9,27 @@ namespace Microsoft.DotNet.Tools.Builder.Tests [Fact] public void BuildingAPortableProjectProducesDepsFile() { - var testInstance = TestAssetsManager.CreateTestInstance("BuildTestPortableProject") + var testInstance = TestAssetsManager.CreateTestInstance("PortableTests") .WithLockFiles(); var result = new BuildCommand( - projectPath: testInstance.TestRoot, - forcePortable: true) + projectPath: Path.Combine(testInstance.TestRoot, "PortableApp")) .ExecuteWithCapturedOutput(); result.Should().Pass(); - var outputBase = new DirectoryInfo(Path.Combine(testInstance.TestRoot, "bin", "Debug")); + var outputBase = new DirectoryInfo(Path.Combine(testInstance.TestRoot, "PortableApp", "bin", "Debug")); - var netstandardappOutput = outputBase.Sub("netstandardapp1.5"); + var netstandardappOutput = outputBase.Sub("netstandard1.5"); netstandardappOutput.Should() .Exist().And .HaveFiles(new[] { - "BuildTestPortableProject.deps", - "BuildTestPortableProject.deps.json", - "BuildTestPortableProject.dll", - "BuildTestPortableProject.pdb" + "PortableApp.deps", + "PortableApp.deps.json", + "PortableApp.dll", + "PortableApp.pdb" }); } } diff --git a/test/dotnet-publish.Tests/PublishPortableTests.cs b/test/dotnet-publish.Tests/PublishPortableTests.cs new file mode 100644 index 000000000..bb2e82c80 --- /dev/null +++ b/test/dotnet-publish.Tests/PublishPortableTests.cs @@ -0,0 +1,54 @@ +using Microsoft.DotNet.Tools.Test.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using Xunit; + +namespace Microsoft.DotNet.Tools.Publish.Tests +{ + public class PublishPortableTests : TestBase + { + private static readonly IEnumerable> ExpectedRuntimeOutputs = new[] { + Tuple.Create("debian-x64", "libuv.so"), + Tuple.Create("rhel-x64", "libuv.so"), + Tuple.Create("osx", "libuv.dylib"), + Tuple.Create("win7-arm", "libuv.dll"), + Tuple.Create("win7-x86", "libuv.dll"), + Tuple.Create("win7-x64", "libuv.dll") + }; + + [Fact] + public void PortableAppWithRuntimeTargetsIsPublishedCorrectly() + { + var testInstance = TestAssetsManager.CreateTestInstance("PortableTests") + .WithLockFiles(); + + var publishCommand = new PublishCommand(Path.Combine(testInstance.TestRoot, "PortableAppWithNative")); + var publishResult = publishCommand.Execute(); + + publishResult.Should().Pass(); + + var publishDir = publishCommand.GetOutputDirectory(portable: true); + publishDir.Should().HaveFiles(new[] + { + "PortableAppWithNative.dll", + "PortableAppWithNative.deps", + "PortableAppWithNative.deps.json" + }); + + var runtimesOutput = publishDir.Sub("runtimes"); + + runtimesOutput.Should().Exist(); + + foreach (var output in ExpectedRuntimeOutputs) + { + var ridDir = runtimesOutput.Sub(output.Item1); + ridDir.Should().Exist(); + + var nativeDir = ridDir.Sub("native"); + nativeDir.Should().Exist(); + nativeDir.Should().HaveFile(output.Item2); + } + } + } +} diff --git a/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs b/test/dotnet-publish.Tests/PublishTests.cs similarity index 100% rename from test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs rename to test/dotnet-publish.Tests/PublishTests.cs From dc11ed2ba81f4994e8bef2785dd3da441c1355f0 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Mon, 14 Mar 2016 12:14:00 -0700 Subject: [PATCH 27/99] Remove the hack to download "1.0.0.001665" CLI. Revert to download the latest. --- scripts/run-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-build.sh b/scripts/run-build.sh index c6f8f0961..076abfdb2 100755 --- a/scripts/run-build.sh +++ b/scripts/run-build.sh @@ -85,7 +85,7 @@ done < "$DIR/../branchinfo.txt" # Ensure the latest stage0 is installed export CHANNEL=$RELEASE_SUFFIX -$DIR/obtain/install.sh --channel $CHANNEL --version 1.0.0.001665 +$DIR/obtain/install.sh --channel $CHANNEL # Put stage 0 on the PATH (for this shell only) PATH="$DOTNET_INSTALL_DIR/bin:$PATH" From 008a1ad0fa35fd662ece3a12addb7b7c8ca731a8 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Fri, 11 Mar 2016 14:49:23 -0800 Subject: [PATCH 28/99] put 'native' section in to runtime targets for deps file --- .../DependencyContextBuilder.cs | 1 + .../DependencyContextCsvReader.cs | 1 + .../DependencyContextJsonReader.cs | 9 ++++++--- .../DependencyContextStrings.cs | 2 ++ .../DependencyContextWriter.cs | 16 +++++++++++----- .../RuntimeLibrary.cs | 4 ++++ .../DependencyContextJsonWriterTests.cs | 13 +++++++++++++ 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs index 8b088e88c..fcfec2cc4 100644 --- a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs +++ b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs @@ -129,6 +129,7 @@ namespace Microsoft.Extensions.DependencyModel export.Library.Identity.Version.ToString(), export.Library.Hash, assemblies.Select(RuntimeAssembly.Create), + export.NativeLibraries.Select(l => l.RelativePath), export.ResourceAssemblies.Select(CreateResourceAssembly), export.RuntimeTargets.Select(CreateRuntimeTarget), libraryDependencies, diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs index 69c4b2bf2..ebab91f2e 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs @@ -47,6 +47,7 @@ namespace Microsoft.Extensions.DependencyModel version: identity.Item3, hash: identity.Item4, assemblies: packageGroup.Select(l => RuntimeAssembly.Create(l.AssetPath)), + nativeLibraries: Enumerable.Empty(), resourceAssemblies: Enumerable.Empty(), subTargets: Enumerable.Empty(), dependencies: Enumerable.Empty(), diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index 3dc15822f..ca0d90916 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -169,10 +169,12 @@ namespace Microsoft.Extensions.DependencyModel )); } - var assemblies = ReadAssemblies(libraryObject, DependencyContextStrings.RuntimeAssembliesKey) + var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.RuntimeAssembliesKey) .Select(RuntimeAssembly.Create) .ToArray(); + var nativeLibraries = ReadAssetList(libraryObject, DependencyContextStrings.NativeLibrariesKey); + var resourceAssemblies = ReadResourceAssemblies((JObject)libraryObject[DependencyContextStrings.ResourceAssembliesPropertyName]); return new RuntimeLibrary( @@ -181,6 +183,7 @@ namespace Microsoft.Extensions.DependencyModel version: version, hash: stub.Hash, assemblies: assemblies, + nativeLibraries: nativeLibraries, resourceAssemblies: resourceAssemblies, subTargets: runtimeTargets.ToArray(), dependencies: dependencies, @@ -188,7 +191,7 @@ namespace Microsoft.Extensions.DependencyModel } else { - var assemblies = ReadAssemblies(libraryObject, DependencyContextStrings.CompileTimeAssembliesKey); + var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.CompileTimeAssembliesKey); return new CompilationLibrary(stub.Type, name, version, stub.Hash, assemblies, dependencies, stub.Serviceable); } } @@ -226,7 +229,7 @@ namespace Microsoft.Extensions.DependencyModel } } - private static string[] ReadAssemblies(JObject libraryObject, string name) + private static string[] ReadAssetList(JObject libraryObject, string name) { var assembliesObject = (JObject) libraryObject[name]; diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs index 7f098877e..b5df3f7a3 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs @@ -11,6 +11,8 @@ namespace Microsoft.Extensions.DependencyModel internal const string RuntimeAssembliesKey = "runtime"; + internal const string NativeLibrariesKey = "native"; + internal const string RuntimeTargetPropertyName = "runtimeTarget"; internal const string LibrariesPropertyName = "libraries"; diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs index 2f26e8c49..1a6235345 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs @@ -147,7 +147,7 @@ namespace Microsoft.Extensions.DependencyModel return; } libraryObject.Add(new JProperty(DependencyContextStrings.CompileTimeAssembliesKey, - WriteAssemblies(compilationAssemblies)) + WriteAssetList(compilationAssemblies)) ); } @@ -158,7 +158,7 @@ namespace Microsoft.Extensions.DependencyModel return; } libraryObject.Add(new JProperty(DependencyContextStrings.RuntimeAssembliesKey, - WriteAssemblies(runtimeAssemblies.Select(a => a.Path))) + WriteAssetList(runtimeAssemblies.Select(a => a.Path))) ); } @@ -197,6 +197,12 @@ namespace Microsoft.Extensions.DependencyModel AddDependencies(libraryObject, runtimeLibrary.Dependencies); AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies); AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies); + + if (runtimeLibrary.NativeLibraries.Any()) + { + libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries)); + } + return libraryObject; } @@ -213,7 +219,6 @@ namespace Microsoft.Extensions.DependencyModel private JObject WritePortableTargetLibrary(RuntimeLibrary runtimeLibrary, CompilationLibrary compilationLibrary) { - var libraryObject = new JObject(); var dependencies = new HashSet(); @@ -229,6 +234,7 @@ namespace Microsoft.Extensions.DependencyModel } AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies); AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies); + libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries)); dependencies.UnionWith(runtimeLibrary.Dependencies); } @@ -272,9 +278,9 @@ namespace Microsoft.Extensions.DependencyModel } } - private JObject WriteAssemblies(IEnumerable assemblies) + private JObject WriteAssetList(IEnumerable assetPaths) { - return new JObject(assemblies.Select(assembly => new JProperty(NormalizePath(assembly), new JObject()))); + return new JObject(assetPaths.Select(assembly => new JProperty(NormalizePath(assembly), new JObject()))); } private JObject WriteLibraries(DependencyContext context) diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs index a3ee2332f..c7858de26 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs @@ -14,6 +14,7 @@ namespace Microsoft.Extensions.DependencyModel string version, string hash, IEnumerable assemblies, + IEnumerable nativeLibraries, IEnumerable resourceAssemblies, IEnumerable subTargets, IEnumerable dependencies, @@ -23,9 +24,12 @@ namespace Microsoft.Extensions.DependencyModel Assemblies = assemblies.ToArray(); ResourceAssemblies = resourceAssemblies.ToArray(); RuntimeTargets = subTargets.ToArray(); + NativeLibraries = nativeLibraries.ToArray(); } public IReadOnlyList Assemblies { get; } + + public IReadOnlyList NativeLibraries { get; } public IReadOnlyList ResourceAssemblies { get; } diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs index cafc90bf2..2091b157b 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs @@ -151,6 +151,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests "1.2.3", "HASH", new [] { RuntimeAssembly.Create("Banana.dll")}, + new [] { "runtimes\\linux\\native\\native.so" }, new [] { new ResourceAssembly("en-US\\Banana.Resource.dll", "en-US")}, new [] { @@ -172,8 +173,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests var library = target.Should().HavePropertyAsObject("PackageName/1.2.3").Subject; var dependencies = library.Should().HavePropertyAsObject("dependencies").Subject; dependencies.Should().HavePropertyValue("Fruits.Abstract.dll", "2.0.0"); + library.Should().HavePropertyAsObject("runtime") .Subject.Should().HaveProperty("Banana.dll"); + library.Should().HavePropertyAsObject("native") + .Subject.Should().HaveProperty("runtimes/linux/native/native.so"); var runtimeTargets = library.Should().HavePropertyAsObject("runtimeTargets").Subject; @@ -226,6 +230,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests "1.2.3", "HASH", new [] { RuntimeAssembly.Create("Banana.dll")}, + new [] { "native.dll" }, new ResourceAssembly[] {}, new [] { @@ -247,8 +252,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests var library = target.Should().HavePropertyAsObject("PackageName/1.2.3").Subject; var dependencies = library.Should().HavePropertyAsObject("dependencies").Subject; dependencies.Should().HavePropertyValue("Fruits.Abstract.dll", "2.0.0"); + library.Should().HavePropertyAsObject("runtime") .Subject.Should().HaveProperty("Banana.dll"); + library.Should().HavePropertyAsObject("native") + .Subject.Should().HaveProperty("native.dll"); library.Should().HavePropertyAsObject("compile") .Subject.Should().HaveProperty("ref/Banana.dll"); @@ -286,6 +294,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests "1.2.3", "HASH", new [] { RuntimeAssembly.Create("Banana.dll")}, + new [] { "runtimes\\osx\\native\\native.dylib" }, new ResourceAssembly[] {}, new RuntimeTarget[] {}, new [] { @@ -303,6 +312,8 @@ namespace Microsoft.Extensions.DependencyModel.Tests dependencies.Should().HavePropertyValue("Fruits.Abstract.dll", "2.0.0"); library.Should().HavePropertyAsObject("runtime") .Subject.Should().HaveProperty("Banana.dll"); + library.Should().HavePropertyAsObject("native") + .Subject.Should().HaveProperty("runtimes/osx/native/native.dylib"); //libraries var libraries = result.Should().HavePropertyAsObject("libraries").Subject; @@ -327,6 +338,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests "1.2.3", "HASH", new RuntimeAssembly[] { }, + new string[] { }, new [] { new ResourceAssembly("en-US/Fruits.resources.dll", "en-US") @@ -361,6 +373,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests "1.2.3", "HASH", new RuntimeAssembly[] { }, + new string[] { }, new [] { new ResourceAssembly("en-US/Fruits.resources.dll", "en-US") From 9a4936ae0dd0b38aa738e5a0c8a34ad96e5d6267 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 14 Mar 2016 15:20:35 -0500 Subject: [PATCH 29/99] When a failed command is executed in "silent" mode, it is not easy to figure out why it failed in the build logs. Fix: Add Standard Output and Error to the BuildFailureException message thrown by CommandResult.EnsureSuccessful. --- .../CommandResult.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs index 6630a857b..d6e657e2f 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Text; using System.Diagnostics; namespace Microsoft.DotNet.Cli.Build.Framework @@ -27,7 +28,19 @@ namespace Microsoft.DotNet.Cli.Build.Framework { if(ExitCode != 0) { - throw new BuildFailureException($"Command failed with exit code {ExitCode}: {StartInfo.FileName} {StartInfo.Arguments}"); + StringBuilder message = new StringBuilder($"Command failed with exit code {ExitCode}: {StartInfo.FileName} {StartInfo.Arguments}"); + + if (!string.IsNullOrEmpty(StdOut)) + { + message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{StdOut}"); + } + + if (!string.IsNullOrEmpty(StdErr)) + { + message.AppendLine($"{Environment.NewLine}Standard Error:{Environment.NewLine}{StdErr}"); + } + + throw new BuildFailureException(message.ToString()); } } } From 657efa23395f80b437fd24abfcf8314788ed98f6 Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Tue, 8 Mar 2016 10:54:44 -0800 Subject: [PATCH 30/99] Adding Files and Compiler.Common to projects to be packaged. --- scripts/package/projectsToPack.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/package/projectsToPack.ps1 b/scripts/package/projectsToPack.ps1 index 1b8cbe54f..5c08c9573 100644 --- a/scripts/package/projectsToPack.ps1 +++ b/scripts/package/projectsToPack.ps1 @@ -3,10 +3,13 @@ $ProjectsToPack = @( "Microsoft.DotNet.Cli.Utils", + "Microsoft.DotNet.Compiler.Common", + "Microsoft.DotNet.Files", + "Microsoft.DotNet.InternalAbstractions", "Microsoft.DotNet.ProjectModel", "Microsoft.DotNet.ProjectModel.Loader", "Microsoft.DotNet.ProjectModel.Workspaces", - "Microsoft.DotNet.InternalAbstractions", + "Microsoft.DotNet.TestFramework", "Microsoft.Extensions.DependencyModel", "Microsoft.Extensions.Testing.Abstractions" ) \ No newline at end of file From 09c8e298ed3a8873960578d6ea0b7a4af41cda06 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Mon, 14 Mar 2016 12:17:15 -0700 Subject: [PATCH 31/99] Switch sharedframework project.json to Microsoft.NETCore.App Use local-build corehost.exe This is staying in the repo, so we can copy the local-built version. Copy deps and deps.json, make sure corehost temp dir exists Add additional runtimes to the sharedframework's project.json Delete an unused file, modify crossgen target condition * sharedhost\project.json is unused. It is copied from the local build. * the crossgen target was conditioned on an environment variable, but the variable could be set to anything. Instead, make sure it is either "true" or "1". Use stage2 instead of stage0 for shared framework restore --- .../BuildContext.cs | 12 +++- .../SharedFrameworkTargets.cs | 61 +++++++++++-------- src/sharedframework/framework/project.json | 17 +++++- src/sharedframework/host/project.json | 11 ---- 4 files changed, 62 insertions(+), 39 deletions(-) delete mode 100644 src/sharedframework/host/project.json diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/BuildContext.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/BuildContext.cs index e4d8846f4..acd500f51 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/BuildContext.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/BuildContext.cs @@ -22,7 +22,17 @@ namespace Microsoft.DotNet.Cli.Build.Framework public object this[string name] { - get { return Properties.ContainsKey(name) ? Properties[name] : null; } + get + { + if (Properties.ContainsKey(name)) + { + return Properties[name]; + } + else + { + throw new KeyNotFoundException("No property with key " + name + " was found."); + } + } set { Properties[name] = value; } } diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index e2bbd53f9..a2ff2e67c 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -14,12 +14,18 @@ namespace Microsoft.DotNet.Cli.Build { public class SharedFrameworkTargets { - public const string SharedFrameworkName = "NETStandard.Library"; + public const string SharedFrameworkName = "Microsoft.NETCore.App"; private const string CoreHostBaseName = "corehost"; - [Target] + [Target(nameof(PackageSharedFramework), nameof(CrossGenAllManagedAssemblies))] public static BuildTargetResult PublishSharedFramework(BuildTargetContext c) + { + return c.Success(); + } + + [Target] + public static BuildTargetResult PackageSharedFramework(BuildTargetContext c) { string SharedFrameworkPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedframework"); string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"); @@ -33,7 +39,22 @@ namespace Microsoft.DotNet.Cli.Build // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. string SharedFrameworkNameAndVersionRoot = Path.Combine(SharedFrameworkPublishRoot, "shared", SharedFrameworkName, SharedFrameworkNugetVersion); - DotNetCli.Stage0.Publish("--output", SharedFrameworkNameAndVersionRoot, SharedFrameworkSourceRoot).Execute().EnsureSuccessful(); + string publishFramework = "dnxcore50"; // Temporary, use "netcoreapp" when we update nuget. + string publishRuntime; + if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows) + { + publishRuntime = $"win7-{PlatformServices.Default.Runtime.RuntimeArchitecture}"; + } + else + { + publishRuntime = PlatformServices.Default.Runtime.GetRuntimeIdentifier(); + } + + DotNetCli.Stage2.Publish( + "--output", SharedFrameworkNameAndVersionRoot, + "-r", publishRuntime, + "-f", publishFramework, + SharedFrameworkSourceRoot).Execute().EnsureSuccessful(); c.BuildContext["SharedFrameworkPublishRoot"] = SharedFrameworkPublishRoot; c.BuildContext["SharedFrameworkNugetVersion"] = SharedFrameworkNugetVersion; @@ -45,6 +66,7 @@ namespace Microsoft.DotNet.Cli.Build // Rename the .deps file File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json")); // corehost will be renamed to dotnet at some point and then this can be removed. File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); @@ -57,8 +79,7 @@ namespace Microsoft.DotNet.Cli.Build // Publish already places the crossgen'd version of mscorlib into the output, so we can // remove the IL version File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll")); - - CrossGenAllManagedAssemblies(SharedFrameworkNameAndVersionRoot); + c.BuildContext["SharedFrameworkNameAndVersionRoot"] = SharedFrameworkNameAndVersionRoot; } else { @@ -72,25 +93,9 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult PublishSharedHost(BuildTargetContext c) { string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); - - if (Directory.Exists(SharedHostPublishRoot)) - { - Directory.Delete(SharedHostPublishRoot, true); - } - - DotNetCli.Stage0.Publish("--output", SharedHostPublishRoot, Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "host")).Execute().EnsureSuccessful(); - - // For the shared host, we only want corerun and not any of the other artifacts in the package (like the hostpolicy) - foreach (var filePath in Directory.GetFiles(SharedHostPublishRoot)) - { - if (Path.GetFileName(filePath) != $"{CoreHostBaseName}{Constants.ExeSuffix}") - { - File.Delete(filePath); - } - } - + Directory.CreateDirectory(SharedHostPublishRoot); // corehost will be renamed to dotnet at some point and then this can be removed. - File.Move(Path.Combine(SharedHostPublishRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); + File.Copy(Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); c.BuildContext["SharedHostPublishRoot"] = SharedHostPublishRoot; @@ -111,11 +116,15 @@ namespace Microsoft.DotNet.Cli.Build } } - return null; + throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); } - private static void CrossGenAllManagedAssemblies(string pathToAssemblies) + [Target] + [Environment("CROSSGEN_SHAREDFRAMEWORK", "1", "true")] + public static BuildTargetResult CrossGenAllManagedAssemblies(BuildTargetContext c) { + string pathToAssemblies = c.BuildContext.Get("SharedFrameworkNameAndVersionRoot"); + foreach (var file in Directory.GetFiles(pathToAssemblies)) { string fileName = Path.GetFileName(file); @@ -138,6 +147,8 @@ namespace Microsoft.DotNet.Cli.Build File.Delete(file); File.Move(tempPathName, file); } + + return c.Success(); } private static bool HasMetadata(string pathToFile) diff --git a/src/sharedframework/framework/project.json b/src/sharedframework/framework/project.json index 48e835c95..b10880254 100644 --- a/src/sharedframework/framework/project.json +++ b/src/sharedframework/framework/project.json @@ -5,10 +5,23 @@ }, "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" + }, + + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8.2-x64": {} }, "frameworks": { - "dnxcore50": { } + "dnxcore50": { + "imports": [ "portable-net45+win8"] + } } } \ No newline at end of file diff --git a/src/sharedframework/host/project.json b/src/sharedframework/host/project.json deleted file mode 100644 index 80a3611f2..000000000 --- a/src/sharedframework/host/project.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "dnxcore50": { } - } -} \ No newline at end of file From 05ebf6f842d1d891d56a989d7fe5b881cf2d860c Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Mon, 14 Mar 2016 14:41:30 -0700 Subject: [PATCH 32/99] Update files copied into shared framework staging directory We need additional files from the corehost directory --- .../SharedFrameworkTargets.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index a2ff2e67c..fdeb5e17d 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -17,6 +17,8 @@ namespace Microsoft.DotNet.Cli.Build public const string SharedFrameworkName = "Microsoft.NETCore.App"; private const string CoreHostBaseName = "corehost"; + private const string DotnetHostFxrBaseName = "hostfxr"; + private const string HostPolicyBaseName = "hostpolicy"; [Target(nameof(PackageSharedFramework), nameof(CrossGenAllManagedAssemblies))] public static BuildTargetResult PublishSharedFramework(BuildTargetContext c) @@ -68,11 +70,13 @@ namespace Microsoft.DotNet.Cli.Build File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json")); - // corehost will be renamed to dotnet at some point and then this can be removed. - File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); - - // hostpolicy will be renamed to dotnet at some point and then this can be removed. - File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}dotnethostimpl{Constants.DynamicLibSuffix}")); + // corehost will be renamed to dotnet at some point and then we will not need to rename it here. + File.Copy( + Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), + Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); + File.Copy( + Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), + Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}")); if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll"))) { @@ -81,10 +85,6 @@ namespace Microsoft.DotNet.Cli.Build File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll")); c.BuildContext["SharedFrameworkNameAndVersionRoot"] = SharedFrameworkNameAndVersionRoot; } - else - { - c.Warn("Shared framework will not be crossgen'd because mscorlib.ni.dll does not exist."); - } return c.Success(); } @@ -94,8 +94,14 @@ namespace Microsoft.DotNet.Cli.Build { string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); Directory.CreateDirectory(SharedHostPublishRoot); + // corehost will be renamed to dotnet at some point and then this can be removed. - File.Copy(Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); + File.Copy( + Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), + Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); + File.Copy( + Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}"), + Path.Combine(SharedHostPublishRoot, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}")); c.BuildContext["SharedHostPublishRoot"] = SharedHostPublishRoot; From ee5d5ef6f1daa3f4735f0b120271f28aeffd0603 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Mon, 14 Mar 2016 15:40:19 -0700 Subject: [PATCH 33/99] Overwrite hostpolicy file from nuget with local-built one --- scripts/dotnet-cli-build/SharedFrameworkTargets.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index fdeb5e17d..e6bd47a78 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -76,7 +76,7 @@ namespace Microsoft.DotNet.Cli.Build Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); File.Copy( Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), - Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}")); + Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), true); if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll"))) { @@ -93,6 +93,11 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult PublishSharedHost(BuildTargetContext c) { string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); + if (Directory.Exists(SharedHostPublishRoot)) + { + Directory.Delete(SharedHostPublishRoot); + } + Directory.CreateDirectory(SharedHostPublishRoot); // corehost will be renamed to dotnet at some point and then this can be removed. From 8953400eee6367e2b3c21bd35ce1e56e9780ae09 Mon Sep 17 00:00:00 2001 From: eerhardt Date: Sat, 12 Mar 2016 05:28:08 +0000 Subject: [PATCH 34/99] Updating dependencies from last known good builds --- .../CompileFail/project.json | 33 +++-- .../FSharpTestProjects/TestApp/project.json | 35 +++-- .../TestAppWithArgs/project.json | 33 +++-- .../TestLibrary/project.json | 28 ++-- .../src/BrokenProjectPathSample/project.json | 16 +-- .../src/EmptyConsoleApp/project.json | 6 +- .../src/EmptyLibrary/project.json | 4 +- .../src/FailReleaseProject/project.json | 4 +- .../IncompatiblePackageSample/project.json | 16 +-- .../src/Project1/project.json | 22 ++- .../dotnet-hello/v1/dotnet-hello/project.json | 24 ++-- .../dotnet-hello/v2/dotnet-hello/project.json | 24 ++-- .../project.json | 42 +++--- .../AppWithDirectDependency/project.json | 32 ++--- .../AppWithToolDependency/project.json | 34 ++--- .../TestProjects/CompileFail/project.json | 24 ++-- .../DependencyContextValidator/project.json | 25 ++-- .../TestApp/project.json | 30 ++-- .../TestAppDeps/project.json | 28 ++-- .../OutputStandardOutputAndError/project.json | 24 ++-- .../PortableTests/PortableApp/project.json | 29 ++-- .../PortableTests/StandaloneApp/project.json | 46 +++--- .../TestAppMultiTarget/project.json | 25 ++-- .../TestApp/project.json | 31 ++-- .../TestLibrary/project.json | 31 ++-- .../TestProjects/TestAppWithArgs/project.json | 24 ++-- .../TestAppWithContentPackage/project.json | 7 +- .../TestAppWithContents/project.json | 27 ++-- .../TestAppWithLibrary/TestApp/project.json | 30 ++-- .../TestLibrary/project.json | 31 ++-- .../TestAppWithScripts/project.json | 39 +++-- .../TestApp/project.json | 43 +++--- .../TestLibrary/project.json | 31 ++-- .../TestLibrary2/project.json | 28 ++-- .../TestLibraryWithAppDependency/project.json | 21 +-- .../TestApp/project.json | 30 ++-- .../TestLibraryGreater/project.json | 35 +++-- .../TestLibraryLesser/project.json | 37 ++--- .../TestLibraryWithAnalyzer/project.json | 29 ++-- .../TestLibraryWithConfiguration/project.json | 38 ++--- .../project.json | 34 +++-- .../TestMicrosoftCSharpReference/project.json | 30 ++-- .../src/L0/project.json | 29 ++-- .../src/L11/project.json | 23 ++- .../src/L12/project.json | 21 ++- .../src/L21/project.json | 18 ++- .../src/L22/project.json | 18 ++- .../project.json | 24 ++-- .../TestProjectWithResource/project.json | 24 ++-- .../TestSimpleIncrementalApp/project.json | 26 ++-- .../project.json | 22 ++- scripts/dotnet-cli-build/CompileTargets.cs | 2 +- scripts/dotnet-cli-build/project.json | 38 +++-- src/Microsoft.DotNet.Cli.Utils/project.json | 46 +++--- .../project.json | 44 +++--- src/Microsoft.DotNet.Files/project.json | 38 ++--- .../project.json | 7 +- .../project.json | 28 ++-- .../project.json | 36 ++--- .../project.json | 80 +++++------ .../project.json | 4 +- .../project.json | 71 +++++---- .../project.json | 56 ++++---- .../dotnet-compile-native/appdep/project.json | 24 ++-- .../CSharp_Console/project.json.template | 24 ++-- .../FSharp_Console/project.json.template | 35 +++-- src/dotnet/project.json | 136 +++++++++--------- test/ArgumentForwardingTests/project.json | 54 +++---- test/ArgumentsReflector/project.json | 31 ++-- test/EndToEnd/project.json | 21 +-- .../project.json | 67 +++++---- .../project.json | 45 +++--- .../project.json | 12 +- .../project.json | 58 ++++---- .../project.json | 13 +- test/ScriptExecutorTests/project.json | 20 +-- test/dotnet-build.Tests/project.json | 13 +- test/dotnet-compile.Tests/project.json | 14 +- test/dotnet-compile.UnitTests/project.json | 19 ++- test/dotnet-pack.Tests/project.json | 14 +- .../project.json | 33 +++-- test/dotnet-publish.Tests/project.json | 13 +- test/dotnet-resgen.Tests/project.json | 14 +- test/dotnet-run.Tests/project.json | 13 +- test/dotnet-test.UnitTests/project.json | 11 +- test/dotnet.Tests/project.json | 20 ++- tools/MultiProjectValidator/project.json | 34 +++-- 87 files changed, 1238 insertions(+), 1315 deletions(-) diff --git a/TestAssets/FSharpTestProjects/CompileFail/project.json b/TestAssets/FSharpTestProjects/CompileFail/project.json index 40621376b..84d87f6df 100644 --- a/TestAssets/FSharpTestProjects/CompileFail/project.json +++ b/TestAssets/FSharpTestProjects/CompileFail/project.json @@ -1,20 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - "compilerName": "fsc", - "compileFiles": [ - "Program.fs" - ], - "dependencies": { - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "compilerName": "fsc", + "compileFiles": [ + "Program.fs" + ], + "dependencies": { + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/FSharpTestProjects/TestApp/project.json b/TestAssets/FSharpTestProjects/TestApp/project.json index 141270ca8..90fcb92b9 100644 --- a/TestAssets/FSharpTestProjects/TestApp/project.json +++ b/TestAssets/FSharpTestProjects/TestApp/project.json @@ -1,21 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - "compilerName": "fsc", - "compileFiles": [ - "Program.fs" - ], - "dependencies": { - "TestLibrary": "1.0.0-*", - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "compilerName": "fsc", + "compileFiles": [ + "Program.fs" + ], + "dependencies": { + "TestLibrary": "1.0.0-*", + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json b/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json index 40621376b..84d87f6df 100644 --- a/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json +++ b/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json @@ -1,20 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - "compilerName": "fsc", - "compileFiles": [ - "Program.fs" - ], - "dependencies": { - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "compilerName": "fsc", + "compileFiles": [ + "Program.fs" + ], + "dependencies": { + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/FSharpTestProjects/TestLibrary/project.json b/TestAssets/FSharpTestProjects/TestLibrary/project.json index 61961870b..0b29b1792 100644 --- a/TestAssets/FSharpTestProjects/TestLibrary/project.json +++ b/TestAssets/FSharpTestProjects/TestLibrary/project.json @@ -1,17 +1,17 @@ { - "version": "1.0.0-*", - "dependencies": { - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.0.0-rc2-23901" - }, - "compilerName": "fsc", - "compileFiles": [ - "Helper2.fs", - "Helper.fs" - ], - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "compilerName": "fsc", + "compileFiles": [ + "Helper2.fs", + "Helper.fs" + ], + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json index d183d244f..7ce8666ac 100644 --- a/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json @@ -1,11 +1,11 @@ { - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "EmptyLibrary": "1.0.0-*" - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "EmptyLibrary": "1.0.0-*" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json index 38a3ba296..a81519a70 100644 --- a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json @@ -1,12 +1,12 @@ { - "dependencies": { }, + "dependencies": {}, "frameworks": { "netstandardapp1.5": { "imports": "dnxcore50", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "NETStandard.Library": "1.5.0-rc2-23911" } }, - "dnx451": { } + "dnx451": {} } } diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json index 667685804..17c4e9e46 100644 --- a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json @@ -1,11 +1,11 @@ { "version": "1.0.0-*", - "dependencies": { }, + "dependencies": {}, "frameworks": { "netstandard1.3": { "imports": "dnxcore50", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "NETStandard.Library": "1.5.0-rc2-23911" } } } diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json index 505047ad2..83b5d4335 100644 --- a/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json @@ -3,9 +3,9 @@ "netstandardapp1.5": { "imports": "dnxcore50", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "NETStandard.Library": "1.5.0-rc2-23911" } } }, - "dependencies": { } + "dependencies": {} } diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json index 58af503dc..37a82e632 100644 --- a/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json +++ b/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json @@ -1,11 +1,11 @@ { - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.Web.Administration": "7.0.0" - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.Web.Administration": "7.0.0" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json b/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json index 8c87d36c9..bb3a9cebf 100755 --- a/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json +++ b/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json @@ -1,14 +1,12 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23811" - }, - - "frameworks": { - "dnxcore50": { } - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "dnxcore50": {} + } } diff --git a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json index ea118a24d..cafaf976b 100644 --- a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json +++ b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json index 464f94681..c1bd9c205 100644 --- a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json +++ b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json @@ -1,16 +1,14 @@ { - "version": "2.0.0", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "2.0.0", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json index 679acc364..7bcb08e63 100644 --- a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json +++ b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json @@ -1,23 +1,25 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "dotnet-hello": { "version": "1.0.0", "target": "package" } - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - }, - - "testRunner": "must-be-specified-to-generate-deps", - - "tools": { - "dotnet-hello": { "version": "2.0.0", "target": "package" } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "dotnet-hello": { + "version": "1.0.0", + "target": "package" } + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + }, + "testRunner": "must-be-specified-to-generate-deps", + "tools": { + "dotnet-hello": { + "version": "2.0.0", + "target": "package" + } + } } diff --git a/TestAssets/TestProjects/AppWithDirectDependency/project.json b/TestAssets/TestProjects/AppWithDirectDependency/project.json index 2ce5cf482..14cc1022a 100644 --- a/TestAssets/TestProjects/AppWithDirectDependency/project.json +++ b/TestAssets/TestProjects/AppWithDirectDependency/project.json @@ -1,19 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "testRunner": "must-be-specified-to-generate-deps", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "dotnet-hello": {"version": "1.0.0", "target": "package"} - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "testRunner": "must-be-specified-to-generate-deps", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "dotnet-hello": { + "version": "1.0.0", + "target": "package" } + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } } diff --git a/TestAssets/TestProjects/AppWithToolDependency/project.json b/TestAssets/TestProjects/AppWithToolDependency/project.json index 9537feb8f..4628c7718 100644 --- a/TestAssets/TestProjects/AppWithToolDependency/project.json +++ b/TestAssets/TestProjects/AppWithToolDependency/project.json @@ -1,20 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - }, - - "tools": { - "dotnet-hello": { "version": "2.0.0", "target": "package" } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + }, + "tools": { + "dotnet-hello": { + "version": "2.0.0", + "target": "package" + } + } } diff --git a/TestAssets/TestProjects/CompileFail/project.json b/TestAssets/TestProjects/CompileFail/project.json index c02d0dffe..2e5ebbe30 100644 --- a/TestAssets/TestProjects/CompileFail/project.json +++ b/TestAssets/TestProjects/CompileFail/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json index 90a5334e8..00cd67349 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json +++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json @@ -1,16 +1,15 @@ { - "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.Extensions.DependencyModel": { - "target": "project", - "version": "1.0.0-*" - } - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.Extensions.DependencyModel": { + "target": "project", + "version": "1.0.0-*" } + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } } diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json index 4c2908690..965a3f06e 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json +++ b/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json @@ -1,18 +1,16 @@ -{ - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "DependencyContextValidator": "1.0.0-*" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "DependencyContextValidator": "1.0.0-*" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json index 9f1f402f6..f41c7127f 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json +++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json @@ -1,17 +1,15 @@ -{ - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "DependencyContextValidator": "1.0.0-*" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "DependencyContextValidator": "1.0.0-*" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/OutputStandardOutputAndError/project.json b/TestAssets/TestProjects/OutputStandardOutputAndError/project.json index c02d0dffe..2e5ebbe30 100644 --- a/TestAssets/TestProjects/OutputStandardOutputAndError/project.json +++ b/TestAssets/TestProjects/OutputStandardOutputAndError/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/PortableTests/PortableApp/project.json b/TestAssets/TestProjects/PortableTests/PortableApp/project.json index 4386a64ac..3111191ad 100644 --- a/TestAssets/TestProjects/PortableTests/PortableApp/project.json +++ b/TestAssets/TestProjects/PortableTests/PortableApp/project.json @@ -1,18 +1,17 @@ { - "compilationOptions": { - "emitEntryPoint": true - }, - "dependencies": { - }, - "frameworks": { - "netstandard1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ], - "dependencies": { - "Microsoft.NETCore.App": "1.0.0-rc2-23911" - } - } + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": {}, + "frameworks": { + "netstandard1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ], + "dependencies": { + "Microsoft.NETCore.App": "1.0.0-rc2-23911" + } } + } } diff --git a/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json index eaae7c1cd..2cf04776c 100644 --- a/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json +++ b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json @@ -1,26 +1,26 @@ { - "compilationOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ], - "dependencies": { - "Microsoft.NETCore.App": "1.0.0-rc2-23911" - } - } - }, - "runtimes": { - "win7-x64": {}, - "win7-x86": {}, - "osx.10.10-x64": {}, - "osx.10.11-x64": {}, - "ubuntu.14.04-x64": {}, - "centos.7-x64": {}, - "rhel.7.2-x64": {}, - "debian.8.2-x64": {} + "compilationOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ], + "dependencies": { + "Microsoft.NETCore.App": "1.0.0-rc2-23911" + } } + }, + "runtimes": { + "win7-x64": { }, + "win7-x86": { }, + "osx.10.10-x64": { }, + "osx.10.11-x64": { }, + "ubuntu.14.04-x64": { }, + "centos.7-x64": { }, + "rhel.7.2-x64": { }, + "debian.8.2-x64": { } + } } diff --git a/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json b/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json index 5ed30dfa4..a081d6a7d 100644 --- a/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json +++ b/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json @@ -1,16 +1,15 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + } }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - } - }, - "net451": { } - } + "net451": {} + } } diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json index ded1b2439..6df0b0c6d 100644 --- a/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json +++ b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json @@ -1,19 +1,16 @@ -{ - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true - }, - - "dependencies": { - "TestLibrary": "1.0.0-*", - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": "1.0.0-*", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json index dce6a0dad..f0b60ee88 100644 --- a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json +++ b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json @@ -1,17 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "nowarn": [ "CS1591" ], - "xmlDoc": true, - "additionalArguments": [ "-highentropyva+" ] - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithArgs/project.json b/TestAssets/TestProjects/TestAppWithArgs/project.json index c02d0dffe..2e5ebbe30 100644 --- a/TestAssets/TestProjects/TestAppWithArgs/project.json +++ b/TestAssets/TestProjects/TestAppWithArgs/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/project.json b/TestAssets/TestProjects/TestAppWithContentPackage/project.json index 43575128d..6e9d2a179 100644 --- a/TestAssets/TestProjects/TestAppWithContentPackage/project.json +++ b/TestAssets/TestProjects/TestAppWithContentPackage/project.json @@ -1,11 +1,10 @@ -{ +{ "version": "1.0.0-*", "compilationOptions": { "emitEntryPoint": true }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", + "NETStandard.Library": "1.5.0-rc2-23911", "SharedContentA": "1.0.0-*" }, "frameworks": { @@ -13,4 +12,4 @@ "imports": "dnxcore50" } } -} \ No newline at end of file +} diff --git a/TestAssets/TestProjects/TestAppWithContents/project.json b/TestAssets/TestProjects/TestAppWithContents/project.json index c149fddc2..e5f81bb6f 100644 --- a/TestAssets/TestProjects/TestAppWithContents/project.json +++ b/TestAssets/TestProjects/TestAppWithContents/project.json @@ -1,18 +1,15 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "content": "testcontentfile.txt", - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "content": "testcontentfile.txt", + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json index f9f77f358..88dd7cbee 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json @@ -1,19 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": { + "target": "project", + "version": "1.0.0-*" }, - - "dependencies": { - "TestLibrary": { "target":"project", "version":"1.0.0-*" }, - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json index 8e8b984b1..f0b60ee88 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json @@ -1,17 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "nowarn": [ "CS1591" ], - "xmlDoc": true, - "additionalArguments": [ "-highentropyva+" ] - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23811" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithScripts/project.json b/TestAssets/TestProjects/TestAppWithScripts/project.json index 8de4803d7..11692199c 100644 --- a/TestAssets/TestProjects/TestAppWithScripts/project.json +++ b/TestAssets/TestProjects/TestAppWithScripts/project.json @@ -1,24 +1,21 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - }, - - "scripts": { - "prepublish" : ["echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"], - "postpublish" : ["echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"], - - "precompile" : ["echoscript precompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"], - "postcompile" : ["echoscript postcompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"] + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + }, + "scripts": { + "prepublish": [ "echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?" ], + "postpublish": [ "echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?" ], + + "precompile": [ "echoscript precompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?" ], + "postcompile": [ "echoscript postcompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?" ] + } } diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json index a1cb82f95..efafdef41 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json @@ -1,24 +1,27 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": { + "target": "project", + "version": "1.0.0-*" }, - - "dependencies": { - "TestLibrary": { "target":"project", "version":"1.0.0-*" }, - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - }, - - "scripts": { - "prepublish" : ["echo prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"], - "postpublish" : ["echo postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"] + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + }, + "scripts": { + "prepublish": [ + "echo prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?" + ], + "postpublish": [ + "echo postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?" + ] + } } diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json index dce6a0dad..f0b60ee88 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json @@ -1,17 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "nowarn": [ "CS1591" ], - "xmlDoc": true, - "additionalArguments": [ "-highentropyva+" ] - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json index 06a4d2157..bc94bb833 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json @@ -1,18 +1,18 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "TestLibraryWithAppDependency": { + "target": "project", + "version": "1.0.0-*" }, - - "dependencies": { - "TestLibraryWithAppDependency": { "target":"project", "version":"1.0.0-*" }, - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json index 42c1b5f55..9b7ae73b7 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json @@ -1,14 +1,15 @@ { - "version": "1.0.0-*", - "dependencies": { - "TestApp": { "target":"project", "version":"1.0.0-*" }, - - "NETStandard.Library": "1.0.0-rc2-23901" + "version": "1.0.0-*", + "dependencies": { + "TestApp": { + "target": "project", + "version": "1.0.0-*" }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json index f9f77f358..88dd7cbee 100644 --- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json +++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json @@ -1,19 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": { + "target": "project", + "version": "1.0.0-*" }, - - "dependencies": { - "TestLibrary": { "target":"project", "version":"1.0.0-*" }, - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json index 4b957d224..6254293c5 100644 --- a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json +++ b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json @@ -1,20 +1,19 @@ -{ - "version": "1.0.0-*", - "testRunner": "xunit", - "dependencies": { - "Newtonsoft.Json": "7.0.1" - }, - - "frameworks": { - "net451": { }, - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+wp80+win8" - ], - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - } - } +{ + "version": "1.0.0-*", + "testRunner": "xunit", + "dependencies": { + "Newtonsoft.Json": "7.0.1" + }, + "frameworks": { + "net451": {}, + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+wp80+win8" + ], + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + } } + } } diff --git a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json index 0cfc9606d..f1bb8120d 100644 --- a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json +++ b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json @@ -1,21 +1,22 @@ { - "version": "1.0.0-*", - "testRunner": "xunit", - "dependencies": { - "Newtonsoft.Json": "6.0.0", - "TestLibraryGreater": {"target":"project"} - }, - - "frameworks": { - "net451": { }, - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+wp80+win8" - ], - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - } - } + "version": "1.0.0-*", + "testRunner": "xunit", + "dependencies": { + "Newtonsoft.Json": "6.0.0", + "TestLibraryGreater": { + "target": "project" } + }, + "frameworks": { + "net451": {}, + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+wp80+win8" + ], + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + } + } + } } diff --git a/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json b/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json index 126757ed1..930858382 100644 --- a/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json +++ b/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json @@ -1,17 +1,18 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Runtime.Analyzers": { "version": "1.1.0", "type": "build" } - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Runtime.Analyzers": { + "version": "1.1.0", + "type": "build" } + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } } diff --git a/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json b/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json index 731ac1d10..a4c57dce6 100644 --- a/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json +++ b/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json @@ -1,21 +1,23 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "nowarn": [ "CS1591" ], - "xmlDoc": true, - "additionalArguments": [ "-highentropyva+" ] - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - "configurations": { - "Test": { - - } - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "configurations": { + "Test": {} + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json index 391a5fc11..f12c8dafa 100644 --- a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json +++ b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json @@ -1,21 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": false - }, - - "dependencies": { }, - - "frameworks": { - "net20": { }, - "net35": { }, - "net40": { }, - "net461": { }, - "netstandardapp1.5": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - } - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": false + }, + "dependencies": {}, + "frameworks": { + "net20": {}, + "net35": {}, + "net40": {}, + "net461": {}, + "netstandardapp1.5": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + } } + } } diff --git a/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json b/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json index 8f97305eb..8d78b8ecc 100644 --- a/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json +++ b/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json @@ -1,17 +1,17 @@ { - "version": "1.0.0", - "dependencies": { }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - } - }, - "dnx451": { - "dependencies": { - "Microsoft.CSharp": "4.0.1-*" - } - } + "version": "1.0.0", + "dependencies": {}, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + } + }, + "dnx451": { + "dependencies": { + "Microsoft.CSharp": "4.0.1-rc2-23911" + } } -} \ No newline at end of file + } +} diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json index ef971a748..06f18fa20 100644 --- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json +++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json @@ -1,19 +1,16 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "L11": "1.0.0-*", - "L12": "1.0.0-*", - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "L11": "1.0.0-*", + "L12": "1.0.0-*", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json index ed55b003b..ed65c4c04 100644 --- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json +++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json @@ -1,16 +1,13 @@ { - "version": "1.0.0-*", - - "dependencies": { - "L12": "1.0.0-*", - "L21": "1.0.0-*", - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "L12": "1.0.0-*", + "L21": "1.0.0-*", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json index ac03a9cf7..e9486914f 100644 --- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json +++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json @@ -1,15 +1,12 @@ { - "version": "1.0.0-*", - - "dependencies": { - "L22": "1.0.0-*", - - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "L22": "1.0.0-*", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json index 8af014e51..155cb2f02 100644 --- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json +++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json @@ -1,13 +1,11 @@ { - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json index 8af014e51..155cb2f02 100644 --- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json +++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json @@ -1,13 +1,11 @@ { - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json index c02d0dffe..2e5ebbe30 100644 --- a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json +++ b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestProjectWithResource/project.json b/TestAssets/TestProjects/TestProjectWithResource/project.json index c02d0dffe..2e5ebbe30 100644 --- a/TestAssets/TestProjects/TestProjectWithResource/project.json +++ b/TestAssets/TestProjects/TestProjectWithResource/project.json @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json b/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json index 3605210ec..7c888a5ad 100644 --- a/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json +++ b/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json @@ -1,17 +1,15 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true, - "xmlDoc": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true, + "xmlDoc": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json b/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json index 85a4e9c85..cb16f68b2 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json @@ -1,15 +1,13 @@ { - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Diagnostics.Process": "4.1.0-rc2-23901", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" - }, - - "frameworks": { - "netstandard1.3": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Diagnostics.Process": "4.1.0-rc2-23911", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" + }, + "frameworks": { + "netstandard1.3": { + "imports": "dnxcore50" } + } } diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 3391a649c..517a30ceb 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -12,7 +12,7 @@ namespace Microsoft.DotNet.Cli.Build { public class CompileTargets { - public static readonly string CoreCLRVersion = "1.0.2-rc2-23901"; + public static readonly string CoreCLRVersion = "1.0.2-rc2-23911"; public static readonly string AppDepSdkVersion = "1.0.6-prerelease-00003"; public static readonly bool IsWinx86 = CurrentPlatform.IsWindows && CurrentArchitecture.Isx86; diff --git a/scripts/dotnet-cli-build/project.json b/scripts/dotnet-cli-build/project.json index f66171d24..9d1ebb1d7 100755 --- a/scripts/dotnet-cli-build/project.json +++ b/scripts/dotnet-cli-build/project.json @@ -1,23 +1,21 @@ { - "version": "1.0.0-*", - "description": "Build scripts for dotnet-cli", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression.ZipFile": "4.0.1-rc2-23901", - "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", - "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", - "WindowsAzure.Storage" : "6.2.2-preview", - "System.Reflection.Metadata" : "1.2.0" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": ["dnxcore50", "portable-net45+win8"] - } + "version": "1.0.0-*", + "description": "Build scripts for dotnet-cli", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", + "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23911", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", + "WindowsAzure.Storage": "6.2.2-preview", + "System.Reflection.Metadata": "1.2.0" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ "dnxcore50", "portable-net45+win8" ] } + } } diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json index 625b48bf4..3e97e0621 100644 --- a/src/Microsoft.DotNet.Cli.Utils/project.json +++ b/src/Microsoft.DotNet.Cli.Utils/project.json @@ -1,27 +1,27 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk", - "warningsAsErrors": true - }, - "dependencies": { - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" - }, - "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build" - } - } - }, - "netstandard1.3": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Diagnostics.Process": "4.1.0-rc2-23901" - } + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk", + "warningsAsErrors": true + }, + "dependencies": { + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" + }, + "frameworks": { + "net451": { + "frameworkAssemblies": { + "System.Runtime": { + "type": "build" } + } + }, + "netstandard1.3": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Diagnostics.Process": "4.1.0-rc2-23911" + } } + } } diff --git a/src/Microsoft.DotNet.Compiler.Common/project.json b/src/Microsoft.DotNet.Compiler.Common/project.json index 0e15d8637..f0376403a 100644 --- a/src/Microsoft.DotNet.Compiler.Common/project.json +++ b/src/Microsoft.DotNet.Compiler.Common/project.json @@ -1,23 +1,23 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.CommandLine": "0.1.0-e160119-1", - "Microsoft.CodeAnalysis.CSharp": "1.2.0-beta1-20160202-02", - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.DotNet.Files": "1.0.0-*" - }, - "frameworks": { - "netstandard1.3": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } - }, - "scripts": {} -} \ No newline at end of file + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.CommandLine": "0.1.0-e160119-1", + "Microsoft.CodeAnalysis.CSharp": "1.2.0-beta1-20160202-02", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.DotNet.Files": "1.0.0-*" + }, + "frameworks": { + "netstandard1.3": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "scripts": {} +} diff --git a/src/Microsoft.DotNet.Files/project.json b/src/Microsoft.DotNet.Files/project.json index 82f1a2b51..1131165e9 100644 --- a/src/Microsoft.DotNet.Files/project.json +++ b/src/Microsoft.DotNet.Files/project.json @@ -1,20 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" - }, - "description": "Abstraction to interact with the file system and file paths.", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Linq.Expressions": "4.0.11-rc2-23901", - "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", - "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.DotNet.ProjectModel": "1.0.0-*" - }, - "frameworks": { - "netstandard1.3": { - "imports": "dnxcore50" - } - }, - "scripts": {} -} \ No newline at end of file + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "description": "Abstraction to interact with the file system and file paths.", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Linq.Expressions": "4.0.11-rc2-23911", + "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.DotNet.ProjectModel": "1.0.0-*" + }, + "frameworks": { + "netstandard1.3": { + "imports": "dnxcore50" + } + }, + "scripts": {} +} diff --git a/src/Microsoft.DotNet.InternalAbstractions/project.json b/src/Microsoft.DotNet.InternalAbstractions/project.json index 70b5e7221..3daa0c061 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/project.json +++ b/src/Microsoft.DotNet.InternalAbstractions/project.json @@ -13,14 +13,13 @@ "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" }, "frameworks": { - "net451": { }, + "net451": {}, "netstandard1.3": { "imports": "dnxcore50", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" + "NETStandard.Library": "1.5.0-rc2-23911" } } }, - "scripts": { - } + "scripts": {} } diff --git a/src/Microsoft.DotNet.ProjectModel.Loader/project.json b/src/Microsoft.DotNet.ProjectModel.Loader/project.json index efe082435..9d2eca854 100644 --- a/src/Microsoft.DotNet.ProjectModel.Loader/project.json +++ b/src/Microsoft.DotNet.ProjectModel.Loader/project.json @@ -1,16 +1,16 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "System.Runtime.Loader": "4.0.0-rc2-23901" - }, - "frameworks": { - "netstandard1.3": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "System.Runtime.Loader": "4.0.0-rc2-23911" + }, + "frameworks": { + "netstandard1.3": { + "imports": "dnxcore50" } -} \ No newline at end of file + } +} diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json b/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json index 83f7a2d6e..e14bbe01b 100644 --- a/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json +++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json @@ -1,20 +1,20 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.DotNet.Compiler.Common": "1.0.0-*", - "Microsoft.CodeAnalysis.CSharp.Workspaces": "1.2.0-beta1-20160202-02" - }, - "frameworks": { - "netstandard1.3": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Compiler.Common": "1.0.0-*", + "Microsoft.CodeAnalysis.CSharp.Workspaces": "1.2.0-beta1-20160202-02" + }, + "frameworks": { + "netstandard1.3": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] } -} \ No newline at end of file + } +} diff --git a/src/Microsoft.DotNet.ProjectModel/project.json b/src/Microsoft.DotNet.ProjectModel/project.json index 9479b166a..2cce12e3a 100644 --- a/src/Microsoft.DotNet.ProjectModel/project.json +++ b/src/Microsoft.DotNet.ProjectModel/project.json @@ -1,47 +1,47 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" + "version": "1.0.0-*", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "description": "Types to model a .NET Project", + "dependencies": { + "System.Reflection.Metadata": "1.2.0-rc2-23911", + "NuGet.Packaging": "3.4.0-rtm-0733", + "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", + "Microsoft.Extensions.JsonParser.Sources": { + "type": "build", + "version": "1.0.0-rc2-16453" }, - "description": "Types to model a .NET Project", - "dependencies": { - "System.Reflection.Metadata": "1.2.0-rc2-23901", - "NuGet.Packaging": "3.4.0-rtm-0733", - "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", - "Microsoft.Extensions.JsonParser.Sources": { - "type": "build", - "version": "1.0.0-rc2-16453" - }, - "Microsoft.Extensions.HashCodeCombiner.Sources": { - "type": "build", - "version": "1.0.0-rc2-16054" - }, - "Microsoft.Extensions.DependencyModel": "1.0.0-*" + "Microsoft.Extensions.HashCodeCombiner.Sources": { + "type": "build", + "version": "1.0.0-rc2-16054" }, - "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build" - }, - "System.Collections": { - "type": "build" - }, - "System.IO": { - "type": "build" - } - } + "Microsoft.Extensions.DependencyModel": "1.0.0-*" + }, + "frameworks": { + "net451": { + "frameworkAssemblies": { + "System.Runtime": { + "type": "build" }, - "netstandard1.3": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Dynamic.Runtime": "4.0.11-rc2-23901", - "System.Runtime.Loader": "4.0.0-rc2-23901", - "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901", - "Microsoft.CSharp": "4.0.1-rc2-23901", - "System.Xml.XDocument": "4.0.11-rc2-23901" - } + "System.Collections": { + "type": "build" + }, + "System.IO": { + "type": "build" } + } + }, + "netstandard1.3": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Dynamic.Runtime": "4.0.11-rc2-23911", + "System.Runtime.Loader": "4.0.0-rc2-23911", + "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23911", + "Microsoft.CSharp": "4.0.1-rc2-23911", + "System.Xml.XDocument": "4.0.11-rc2-23911" + } } + } } diff --git a/src/Microsoft.DotNet.TestFramework/project.json b/src/Microsoft.DotNet.TestFramework/project.json index e04e63cb5..2e096995e 100644 --- a/src/Microsoft.DotNet.TestFramework/project.json +++ b/src/Microsoft.DotNet.TestFramework/project.json @@ -1,4 +1,4 @@ -{ +{ "version": "1.0.0-*", "description": "Microsoft.DotNet.TestFramework Class Library", "authors": [ @@ -11,7 +11,7 @@ "licenseUrl": "", "dependencies": { "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "NETStandard.Library": "1.0.0-rc2-23901" + "NETStandard.Library": "1.5.0-rc2-23911" }, "frameworks": { "netstandard1.3": { diff --git a/src/Microsoft.Extensions.DependencyModel/project.json b/src/Microsoft.Extensions.DependencyModel/project.json index 1ad395b56..65fd21652 100644 --- a/src/Microsoft.Extensions.DependencyModel/project.json +++ b/src/Microsoft.Extensions.DependencyModel/project.json @@ -1,39 +1,38 @@ { - "description": "Abstractions for reading `.deps` files.", - "version": "1.0.0-*", - "repository": { - "type": "git", - "url": "git://github.com/dotnet/cli" + "description": "Abstractions for reading `.deps` files.", + "version": "1.0.0-*", + "repository": { + "type": "git", + "url": "git://github.com/dotnet/cli" + }, + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "Microsoft.Extensions.HashCodeCombiner.Sources": { + "type": "build", + "version": "1.0.0-rc2-16054" }, - "compilationOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" + "Microsoft.DotNet.InternalAbstractions": { + "target": "project", + "version": "1.0.0-*" }, - "dependencies": { - "Microsoft.Extensions.HashCodeCombiner.Sources": { - "type": "build", - "version": "1.0.0-rc2-16054" - }, - "Microsoft.DotNet.InternalAbstractions": { - "target": "project", - "version": "1.0.0-*" - }, - - "Newtonsoft.Json": "7.0.1", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "imports": "dnxcore50", - "dependencies": { - "System.IO.FileSystem": "4.0.1-rc2-23901", - "System.Linq": "4.0.1-rc2-23901", - "System.Runtime": "4.0.21-rc2-23901", - "System.Reflection": "4.1.0-rc2-23901", - "System.Dynamic.Runtime": "4.0.11-rc2-23901" - } - } - }, - "scripts": {} -} \ No newline at end of file + "Newtonsoft.Json": "7.0.1", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" + }, + "frameworks": { + "net451": {}, + "netstandard1.3": { + "imports": "dnxcore50", + "dependencies": { + "System.IO.FileSystem": "4.0.1-rc2-23911", + "System.Linq": "4.0.1-rc2-23911", + "System.Runtime": "4.0.21-rc2-23911", + "System.Reflection": "4.1.0-rc2-23911", + "System.Dynamic.Runtime": "4.0.11-rc2-23911" + } + } + }, + "scripts": {} +} diff --git a/src/Microsoft.Extensions.Testing.Abstractions/project.json b/src/Microsoft.Extensions.Testing.Abstractions/project.json index 7ecb6232e..4135cd377 100644 --- a/src/Microsoft.Extensions.Testing.Abstractions/project.json +++ b/src/Microsoft.Extensions.Testing.Abstractions/project.json @@ -1,29 +1,29 @@ { - "description": "Abstractions for test runners to communicate to a tool, such as Visual Studio.", - "version": "1.0.0-*", - "repository": { - "type": "git", - "url": "git://github.com/dotnet/cli" - }, - "compilationOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "Newtonsoft.Json": "7.0.1", - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-16040" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "imports": "dnxcore50", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Resources.ResourceManager": "4.0.1-rc2-23901", - "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23901" - } - } - }, - "scripts": {} -} \ No newline at end of file + "description": "Abstractions for test runners to communicate to a tool, such as Visual Studio.", + "version": "1.0.0-*", + "repository": { + "type": "git", + "url": "git://github.com/dotnet/cli" + }, + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "Newtonsoft.Json": "7.0.1", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-16040" + }, + "frameworks": { + "net451": {}, + "netstandard1.3": { + "imports": "dnxcore50", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Resources.ResourceManager": "4.0.1-rc2-23911", + "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911" + } + } + }, + "scripts": {} +} diff --git a/src/dotnet/commands/dotnet-compile-native/appdep/project.json b/src/dotnet/commands/dotnet-compile-native/appdep/project.json index 689ef478a..eaac3555d 100644 --- a/src/dotnet/commands/dotnet-compile-native/appdep/project.json +++ b/src/dotnet/commands/dotnet-compile-native/appdep/project.json @@ -1,15 +1,15 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.DotNet.AppDep":"1.0.6-prerelease-00003" - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.AppDep": "1.0.6-prerelease-00003" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template index c02d0dffe..2e5ebbe30 100644 --- a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template @@ -1,16 +1,14 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template index 60ba0af6e..84d87f6df 100644 --- a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template @@ -1,22 +1,19 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "compilerName": "fsc", - "compileFiles": [ - "Program.fs" - ], - - "dependencies": { - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "compilerName": "fsc", + "compileFiles": [ + "Program.fs" + ], + "dependencies": { + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" } + } } diff --git a/src/dotnet/project.json b/src/dotnet/project.json index b4a5354f1..ac77cac98 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -1,77 +1,71 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "compileExclude": [ + "commands/dotnet-new/CSharp_Console/**", + "commands/dotnet-new/FSharp_Console/**" + ], + "resource": [ + "commands/dotnet-new/CSharp_Console/NuGet.Config", + "commands/dotnet-new/CSharp_Console/Program.cs", + "commands/dotnet-new/CSharp_Console/project.json.template", + "commands/dotnet-new/FSharp_Console/NuGet.config", + "commands/dotnet-new/FSharp_Console/Program.fs", + "commands/dotnet-new/FSharp_Console/project.json.template" + ], + "dependencies": { + "Newtonsoft.Json": "7.0.1", + "Microsoft.Net.Compilers.netcore": "1.3.0-beta1-20160225-02", + "Microsoft.FSharp.Compiler.netcore": "1.0.0-alpha-151218", + "Microsoft.Net.CSharp.Interactive.netcore": "1.3.0-beta1-20160225-02", + "Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160225-02", + "Microsoft.DiaSymReader.Native": "1.3.3", + "NuGet.CommandLine.XPlat": "3.4.0-rtm-0733", + "System.CommandLine": "0.1.0-e160119-1", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Compiler.Common": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.DotNet.ILCompiler.SDK": "1.0.6-prerelease-00003", + "Microsoft.Extensions.Logging": "1.0.0-rc2-16040", + "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-16040", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "Microsoft.Extensions.CommandLineUtils.Sources": { + "type": "build", + "version": "1.0.0-rc2-16453" }, - "compileExclude": [ - "commands/dotnet-new/CSharp_Console/**", - "commands/dotnet-new/FSharp_Console/**" - ], - "resource": [ - "commands/dotnet-new/CSharp_Console/NuGet.Config", - "commands/dotnet-new/CSharp_Console/Program.cs", - "commands/dotnet-new/CSharp_Console/project.json.template", - "commands/dotnet-new/FSharp_Console/NuGet.config", - "commands/dotnet-new/FSharp_Console/Program.fs", - "commands/dotnet-new/FSharp_Console/project.json.template" - ], - "dependencies": { - "Newtonsoft.Json": "7.0.1", - - "Microsoft.Net.Compilers.netcore": "1.3.0-beta1-20160225-02", - "Microsoft.FSharp.Compiler.netcore": "1.0.0-alpha-151218", - "Microsoft.Net.CSharp.Interactive.netcore": "1.3.0-beta1-20160225-02", - "Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160225-02", - "Microsoft.DiaSymReader.Native": "1.3.3", - - "NuGet.CommandLine.XPlat": "3.4.0-rtm-0733", - "System.CommandLine": "0.1.0-e160119-1", - - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.DotNet.Compiler.Common": "1.0.0-*", - "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.DotNet.ILCompiler.SDK": "1.0.6-prerelease-00003", - - "Microsoft.Extensions.Logging": "1.0.0-rc2-16040", - "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-16040", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", - "Microsoft.Extensions.CommandLineUtils.Sources": { - "type": "build", - "version": "1.0.0-rc2-16453" - }, - "Microsoft.Dnx.Runtime.CommandParsing.Sources": { - "version": "1.0.0-rc2-16453", - "type": "build" - }, - "Microsoft.Dnx.Runtime.Sources": { - "version": "1.0.0-rc2-16453", - "type": "build" - }, - "Microsoft.Extensions.Testing.Abstractions": "1.0.0-*", - "Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-23901", - "Microsoft.NETCore.TestHost": "1.0.0-rc2-23901", - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Reflection.Metadata": "1.3.0-beta-23901", - "System.Diagnostics.TextWriterTraceListener": "4.0.0-rc2-23901", - "System.Diagnostics.TraceSource": "4.0.0-rc2-23901", - "System.Linq.Expressions": "4.0.11-rc2-23901", - "System.Xml.XDocument": "4.0.11-rc2-23901", - "System.Resources.ReaderWriter": "4.0.0-rc2-23901", - "System.Net.Sockets": "4.1.0-rc2-23901", - "System.IO.Compression.ZipFile": "4.0.1-rc2-23901", - "System.Threading.ThreadPool": "4.0.10-rc2-23901", - "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23901", - - "System.Private.DataContractSerialization": "4.1.0-rc2-23901" + "Microsoft.Dnx.Runtime.CommandParsing.Sources": { + "version": "1.0.0-rc2-16453", + "type": "build" }, - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } + "Microsoft.Dnx.Runtime.Sources": { + "version": "1.0.0-rc2-16453", + "type": "build" }, - "scripts": { + "Microsoft.Extensions.Testing.Abstractions": "1.0.0-*", + "Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-23911", + "Microsoft.NETCore.TestHost": "1.0.0-rc2-23911", + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Reflection.Metadata": "1.3.0-rc2-23911", + "System.Diagnostics.TextWriterTraceListener": "4.0.0-rc2-23911", + "System.Diagnostics.TraceSource": "4.0.0-rc2-23911", + "System.Linq.Expressions": "4.0.11-rc2-23911", + "System.Xml.XDocument": "4.0.11-rc2-23911", + "System.Resources.ReaderWriter": "4.0.0-rc2-23911", + "System.Net.Sockets": "4.1.0-rc2-23911", + "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", + "System.Threading.ThreadPool": "4.0.10-rc2-23911", + "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911", + "System.Private.DataContractSerialization": "4.1.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] } + }, + "scripts": {} } diff --git a/test/ArgumentForwardingTests/project.json b/test/ArgumentForwardingTests/project.json index 8b99a663f..ea8695288 100644 --- a/test/ArgumentForwardingTests/project.json +++ b/test/ArgumentForwardingTests/project.json @@ -1,31 +1,33 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": { + "target": "project" }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, - - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "Microsoft.DotNet.Cli.Utils": { + "target": "project" }, - - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" }, - - "testRunner": "xunit", - - "scripts": { "precompile": "dotnet build ../ArgumentsReflector/project.json --framework netstandardapp1.5 --runtime %compile:RuntimeIdentifier% --output %compile:RuntimeOutputDir%" } + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-79755-47" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "testRunner": "xunit", + "scripts": { + "precompile": "dotnet build ../ArgumentsReflector/project.json --framework netstandardapp1.5 --runtime %compile:RuntimeIdentifier% --output %compile:RuntimeOutputDir%" + } } diff --git a/test/ArgumentsReflector/project.json b/test/ArgumentsReflector/project.json index b78dfacbe..6869effa2 100644 --- a/test/ArgumentsReflector/project.json +++ b/test/ArgumentsReflector/project.json @@ -1,18 +1,17 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library" : "1.0.0-rc2-23901" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - }, - - "content": ["reflector_cmd.cmd"] + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + }, + "content": [ + "reflector_cmd.cmd" + ] } diff --git a/test/EndToEnd/project.json b/test/EndToEnd/project.json index 4bcbd9290..f712e1ce7 100644 --- a/test/EndToEnd/project.json +++ b/test/EndToEnd/project.json @@ -3,20 +3,22 @@ "compilationOptions": { "emitEntryPoint": true }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, - + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": { + "target": "project" + }, + "Microsoft.DotNet.Cli.Utils": { + "target": "project" + }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "xunit": "2.1.0", "xunit.netcore.extensions": "1.0.0-prerelease-*", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -25,6 +27,5 @@ ] } }, - "testRunner": "xunit" } diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json index 97536b3c7..1493122d8 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json @@ -1,39 +1,38 @@ { - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": { + "target": "project" }, - - "dependencies": { - "NETStandard.Library" : "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, - - "moq.netcore": "4.4.0-beta8", - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "Microsoft.DotNet.Cli.Utils": { + "target": "project" }, - - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" }, - - "content": [ - "../../TestAssets/TestProjects/OutputStandardOutputAndError/*", - "../../TestAssets/TestProjects/TestAppWithArgs/*", - "../../TestAssets/TestProjects/AppWithDirectAndToolDependency/**/*", - "../../TestAssets/TestProjects/AppWithDirectDependency/**/*", - "../../TestAssets/TestProjects/AppWithToolDependency/**/*" - ], - - "testRunner": "xunit" + "moq.netcore": "4.4.0-beta8", + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-79755-47" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "content": [ + "../../TestAssets/TestProjects/OutputStandardOutputAndError/*", + "../../TestAssets/TestProjects/TestAppWithArgs/*", + "../../TestAssets/TestProjects/AppWithDirectAndToolDependency/**/*", + "../../TestAssets/TestProjects/AppWithDirectDependency/**/*", + "../../TestAssets/TestProjects/AppWithToolDependency/**/*" + ], + "testRunner": "xunit" } diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json index 6b7d51697..e0e51113f 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json @@ -1,26 +1,27 @@ { - "version": "1.0.0-*", - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Compiler.Common": { "target": "project" }, - - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" }, - - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } + "Microsoft.DotNet.ProjectModel": { + "target": "project" }, - - "testRunner": "xunit" + "Microsoft.DotNet.Compiler.Common": { + "target": "project" + }, + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-79755-47" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "testRunner": "xunit" } diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/project.json b/test/Microsoft.DotNet.ProjectModel.Tests/project.json index edaaef649..79747421e 100644 --- a/test/Microsoft.DotNet.ProjectModel.Tests/project.json +++ b/test/Microsoft.DotNet.ProjectModel.Tests/project.json @@ -1,10 +1,14 @@ { "version": "1.0.0-*", "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": { + "target": "project" + }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json index cf42e619c..5df2c0e09 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json @@ -1,32 +1,30 @@ { - "version": "1.0.0-*", - "description": "Microsoft.DotNet.Tools.Tests.Utilities Class Library", - "compilationOptions": { - "keyFile": "../../tools/Key.snk" - }, - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.Collections.Immutable": "1.2.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - "FluentAssertions": "4.0.0", - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-91790-12", - - "Microsoft.DotNet.TestFramework": "1.0.0-*", - "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", - "Microsoft.DotNet.InternalAbstractions": { - "target": "project", - "version": "1.0.0-*" - } - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } - }, + "version": "1.0.0-*", + "description": "Microsoft.DotNet.Tools.Tests.Utilities Class Library", + "compilationOptions": { + "keyFile": "../../tools/Key.snk" + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "System.Collections.Immutable": "1.2.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "FluentAssertions": "4.0.0", + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-91790-12", + "Microsoft.DotNet.TestFramework": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "Microsoft.DotNet.InternalAbstractions": { + "target": "project", + "version": "1.0.0-*" + } + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + } } diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/project.json b/test/Microsoft.Extensions.DependencyModel.Tests/project.json index 18a43cf55..16e06287a 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/project.json +++ b/test/Microsoft.Extensions.DependencyModel.Tests/project.json @@ -5,16 +5,16 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "FluentAssertions": "4.0.0", "moq.netcore": "4.4.0-beta8", "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -23,6 +23,5 @@ ] } }, - "testRunner": "xunit" -} \ No newline at end of file +} diff --git a/test/ScriptExecutorTests/project.json b/test/ScriptExecutorTests/project.json index 0317d0a3b..158d402c7 100644 --- a/test/ScriptExecutorTests/project.json +++ b/test/ScriptExecutorTests/project.json @@ -1,17 +1,19 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, - + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": { + "target": "project" + }, + "Microsoft.DotNet.Cli.Utils": { + "target": "project" + }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-79755-47" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -20,10 +22,8 @@ ] } }, - "content": [ "../../TestAssets/TestProjects/TestApp/**/*" ], - "testRunner": "xunit" } diff --git a/test/dotnet-build.Tests/project.json b/test/dotnet-build.Tests/project.json index c158034ef..cb6194bc6 100644 --- a/test/dotnet-build.Tests/project.json +++ b/test/dotnet-build.Tests/project.json @@ -1,19 +1,17 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -22,6 +20,5 @@ ] } }, - "testRunner": "xunit" } diff --git a/test/dotnet-compile.Tests/project.json b/test/dotnet-compile.Tests/project.json index dd02d8697..99db1f04e 100644 --- a/test/dotnet-compile.Tests/project.json +++ b/test/dotnet-compile.Tests/project.json @@ -1,19 +1,17 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -22,7 +20,6 @@ ] } }, - "content": [ "../../TestAssets/TestProjects/DependencyContextValidator/**/*", "../../TestAssets/TestProjects/TestLibraryWithAnalyzer/*", @@ -31,6 +28,5 @@ "../../TestAssets/TestProjects/TestAppCompilationContext/**/*", "../../TestAssets/TestProjects/global.json" ], - "testRunner": "xunit" } diff --git a/test/dotnet-compile.UnitTests/project.json b/test/dotnet-compile.UnitTests/project.json index 9813a2d85..e3a0d8728 100644 --- a/test/dotnet-compile.UnitTests/project.json +++ b/test/dotnet-compile.UnitTests/project.json @@ -1,23 +1,22 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - - "dotnet": { "target": "project" }, - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - + "dotnet": { + "target": "project" + }, + "Microsoft.DotNet.ProjectModel": { + "target": "project" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12", "moq.netcore": "4.4.0-beta8", "FluentAssertions": "4.2.2" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -26,10 +25,8 @@ ] } }, - "content": [ "../../TestAssets/TestProjects/TestAppWithLibrary/**/*" ], - "testRunner": "xunit" } diff --git a/test/dotnet-pack.Tests/project.json b/test/dotnet-pack.Tests/project.json index 178d883d3..86c244272 100644 --- a/test/dotnet-pack.Tests/project.json +++ b/test/dotnet-pack.Tests/project.json @@ -1,19 +1,17 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression.ZipFile": "4.0.1-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-79755-47" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -22,10 +20,8 @@ ] } }, - "content": [ "../../TestAssets/TestProjects/TestLibraryWithConfiguration/*" ], - "testRunner": "xunit" } diff --git a/test/dotnet-projectmodel-server.Tests/project.json b/test/dotnet-projectmodel-server.Tests/project.json index 42d8fd6f6..0638878aa 100644 --- a/test/dotnet-projectmodel-server.Tests/project.json +++ b/test/dotnet-projectmodel-server.Tests/project.json @@ -1,20 +1,25 @@ { "dependencies": { - "dotnet": { "target": "project" }, - "Microsoft.DotNet.ProjectModel": { "target": "project" }, - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "dotnet": { + "target": "project" + }, + "Microsoft.DotNet.ProjectModel": { + "target": "project" + }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12", - - "System.Net.NameResolution": "4.0.0-rc2-23901" + "System.Net.NameResolution": "4.0.0-rc2-23911" }, - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - } - }, - "testRunner": "xunit" + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "testRunner": "xunit" } diff --git a/test/dotnet-publish.Tests/project.json b/test/dotnet-publish.Tests/project.json index 0064f9349..328333b55 100644 --- a/test/dotnet-publish.Tests/project.json +++ b/test/dotnet-publish.Tests/project.json @@ -1,21 +1,19 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.TestFramework": "1.0.0-*", - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "xunit.netcore.extensions": "1.0.0-prerelease-*", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -24,6 +22,5 @@ ] } }, - "testRunner": "xunit" } diff --git a/test/dotnet-resgen.Tests/project.json b/test/dotnet-resgen.Tests/project.json index fd3d26275..071591f36 100644 --- a/test/dotnet-resgen.Tests/project.json +++ b/test/dotnet-resgen.Tests/project.json @@ -1,20 +1,18 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "xunit.netcore.extensions": "1.0.0-prerelease-*", "dotnet-test-xunit": "1.0.0-dev-79755-47" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -23,10 +21,8 @@ ] } }, - "content": [ "../../TestAssets/TestProjects/TestProjectWithResource/**/*" ], - "testRunner": "xunit" } diff --git a/test/dotnet-run.Tests/project.json b/test/dotnet-run.Tests/project.json index ecbf0c5fc..1e30b0e77 100644 --- a/test/dotnet-run.Tests/project.json +++ b/test/dotnet-run.Tests/project.json @@ -1,19 +1,17 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project" }, - "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-79755-47" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -22,6 +20,5 @@ ] } }, - "testRunner": "xunit" } diff --git a/test/dotnet-test.UnitTests/project.json b/test/dotnet-test.UnitTests/project.json index eb23b1792..40707f654 100644 --- a/test/dotnet-test.UnitTests/project.json +++ b/test/dotnet-test.UnitTests/project.json @@ -1,18 +1,16 @@ { "version": "1.0.0-*", - "dependencies": { "Newtonsoft.Json": "7.0.1", - "NETStandard.Library": "1.0.0-rc2-23901", - - "dotnet": { "target": "project" }, - + "NETStandard.Library": "1.5.0-rc2-23911", + "dotnet": { + "target": "project" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12", "moq.netcore": "4.4.0-beta8", "FluentAssertions": "4.2.2" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -21,6 +19,5 @@ ] } }, - "testRunner": "xunit" } diff --git a/test/dotnet.Tests/project.json b/test/dotnet.Tests/project.json index 46da798d1..6ace6d28d 100644 --- a/test/dotnet.Tests/project.json +++ b/test/dotnet.Tests/project.json @@ -1,20 +1,18 @@ { "version": "1.0.0-*", - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "System.IO.Compression": "4.1.0-rc2-23901", - - "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "NETStandard.Library": "1.5.0-rc2-23911", + "System.IO.Compression": "4.1.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, "Microsoft.DotNet.Cli.Utils": { "target": "project", "type": "build" }, - "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12" }, - "frameworks": { "netstandardapp1.5": { "imports": [ @@ -23,12 +21,10 @@ ] } }, - "content": [ - "../../TestAssets/TestProjects/AppWithDirectAndToolDependency/**/*", - "../../TestAssets/TestProjects/AppWithDirectDependency/**/*", - "../../TestAssets/TestProjects/AppWithToolDependency/**/*" + "../../TestAssets/TestProjects/AppWithDirectAndToolDependency/**/*", + "../../TestAssets/TestProjects/AppWithDirectDependency/**/*", + "../../TestAssets/TestProjects/AppWithToolDependency/**/*" ], - "testRunner": "xunit" } diff --git a/tools/MultiProjectValidator/project.json b/tools/MultiProjectValidator/project.json index 59d9c5fb9..130929817 100644 --- a/tools/MultiProjectValidator/project.json +++ b/tools/MultiProjectValidator/project.json @@ -1,21 +1,19 @@ { - "version": "1.0.0-*", - "name": "pjvalidate", - "compilationOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "NETStandard.Library": "1.0.0-rc2-23901", - "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.DotNet.Cli.Utils": "1.0.0-*" - }, - - "frameworks": { - "netstandardapp1.5": { - "imports": [ - "dnxcore50" - ] - } + "version": "1.0.0-*", + "name": "pjvalidate", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50" + ] } + } } From 457e842c76ae94f67c1a3327654b1c10fc1e46a2 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Sat, 12 Mar 2016 00:32:02 -0600 Subject: [PATCH 35/99] Add workaround for System.Reflection.TypeExtensions. Roslyn is still referencing the old version, which is now incompatible with the latest System.Reflection nupkg. --- src/Microsoft.Extensions.Testing.Abstractions/project.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Extensions.Testing.Abstractions/project.json b/src/Microsoft.Extensions.Testing.Abstractions/project.json index 4135cd377..da1777c72 100644 --- a/src/Microsoft.Extensions.Testing.Abstractions/project.json +++ b/src/Microsoft.Extensions.Testing.Abstractions/project.json @@ -21,7 +21,8 @@ "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", "System.Resources.ResourceManager": "4.0.1-rc2-23911", - "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911" + "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911", + "System.Reflection.TypeExtensions": "4.1.0-rc2-23911" } } }, From 0de7a4c934cc820f5670d79ab22b61093077ddaa Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 14 Mar 2016 14:14:34 -0500 Subject: [PATCH 36/99] Workaround F# requiring Win32.Registry, which doesn't restore on Unix machines, by excluding it from compile. --- src/dotnet/project.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dotnet/project.json b/src/dotnet/project.json index ac77cac98..2333cf633 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -57,7 +57,11 @@ "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", "System.Threading.ThreadPool": "4.0.10-rc2-23911", "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911", - "System.Private.DataContractSerialization": "4.1.0-rc2-23911" + "System.Private.DataContractSerialization": "4.1.0-rc2-23911", + "Microsoft.Win32.Registry": { + "version": "4.0.0-rc2-23911", + "exclude": "Compile" + } }, "frameworks": { "netstandardapp1.5": { From 3bfd86b2542567e918175ac389590ace156f0ffd Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 14 Mar 2016 15:08:03 -0500 Subject: [PATCH 37/99] Remove crossgenning mscorlib on Unix platforms, since the CoreCLR nuget package now carries the crossgenned mscorlib on non-Windows platforms. --- scripts/dotnet-cli-build/CompileTargets.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 517a30ceb..060ead06c 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -335,7 +335,7 @@ namespace Microsoft.DotNet.Cli.Build private static List GetAssembliesToCrossGen() { - var list = new List + return new List { "System.Collections.Immutable.dll", "System.Reflection.Metadata.dll", @@ -345,15 +345,6 @@ namespace Microsoft.DotNet.Cli.Build "csc.dll", "vbc.dll" }; - - // mscorlib is already crossgenned on Windows - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // mscorlib has to be crossgenned first - list.Insert(0, "mscorlib.dll"); - } - - return list; } } } From 2378a34401b8dd9ce7a331593cf1fd6d77c01461 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 14 Mar 2016 16:54:26 -0500 Subject: [PATCH 38/99] Workaround Microsoft.Win32.Registry problem on unix in the tests that reference the dotnet project. --- test/dotnet-compile.UnitTests/project.json | 4 ++++ test/dotnet-projectmodel-server.Tests/project.json | 4 ++++ test/dotnet-test.UnitTests/project.json | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/test/dotnet-compile.UnitTests/project.json b/test/dotnet-compile.UnitTests/project.json index e3a0d8728..0fcb3236e 100644 --- a/test/dotnet-compile.UnitTests/project.json +++ b/test/dotnet-compile.UnitTests/project.json @@ -9,6 +9,10 @@ "dotnet": { "target": "project" }, + "Microsoft.Win32.Registry": { + "version": "4.0.0-rc2-23911", + "exclude": "Compile" + }, "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/dotnet-projectmodel-server.Tests/project.json b/test/dotnet-projectmodel-server.Tests/project.json index 0638878aa..2c6dd69cb 100644 --- a/test/dotnet-projectmodel-server.Tests/project.json +++ b/test/dotnet-projectmodel-server.Tests/project.json @@ -3,6 +3,10 @@ "dotnet": { "target": "project" }, + "Microsoft.Win32.Registry": { + "version": "4.0.0-rc2-23911", + "exclude": "Compile" + }, "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/dotnet-test.UnitTests/project.json b/test/dotnet-test.UnitTests/project.json index 40707f654..81e469a45 100644 --- a/test/dotnet-test.UnitTests/project.json +++ b/test/dotnet-test.UnitTests/project.json @@ -6,6 +6,10 @@ "dotnet": { "target": "project" }, + "Microsoft.Win32.Registry": { + "version": "4.0.0-rc2-23911", + "exclude": "Compile" + }, "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12", "moq.netcore": "4.4.0-beta8", From c8617c97e8e82b5b6a935d91704876ab2a751e6f Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 14 Mar 2016 16:49:38 -0700 Subject: [PATCH 39/99] remove resgen as a top level command --- src/dotnet/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index b858fc955..0f4e67d45 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -112,7 +112,6 @@ namespace Microsoft.DotNet.Cli ["publish"] = PublishCommand.Run, ["repl"] = ReplCommand.Run, ["restore"] = RestoreCommand.Run, - ["resgen"] = ResgenCommand.Run, ["run"] = RunCommand.Run, ["test"] = TestCommand.Run }; From 55db51a14b6b37bd9217e307f773d4cb1a08ba97 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Mon, 14 Mar 2016 16:44:52 -0700 Subject: [PATCH 40/99] Publish shared framework and host zips to azure --- scripts/dotnet-cli-build/PublishTargets.cs | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index b90e0c56c..23aa141f6 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -46,6 +46,8 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PublishTargets.PublishVersionBadge), nameof(PublishTargets.PublishCompressedFile), nameof(PublishTargets.PublishSdkInstallerFile), + nameof(PublishTargets.PublishSharedFrameworkCompressedFile), + nameof(PublishTargets.PublishSharedHostCompressedFile), nameof(PublishTargets.PublishLatestVersionTextFile))] public static BuildTargetResult PublishArtifacts(BuildTargetContext c) { @@ -140,6 +142,30 @@ namespace Microsoft.DotNet.Cli.Build return uploadJson; } + public static BuildTargetResult PublishSharedFrameworkCompressedFile(BuildTargetContext c) + { + var compressedFile = c.BuildContext.Get("SharedFrameworkCompressedFile"); + var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; + var latestCompressedFile = compressedFile.Replace(Version, "latest"); + var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; + + PublishFileAzure(compressedFileBlob, compressedFile); + PublishFileAzure(latestCompressedFileBlob, compressedFile); + return c.Success(); + } + + public static BuildTargetResult PublishSharedHostCompressedFile(BuildTargetContext c) + { + var compressedFile = c.BuildContext.Get("SharedHostCompressedFile"); + var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; + var latestCompressedFile = compressedFile.Replace(Version, "latest"); + var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; + + PublishFileAzure(compressedFileBlob, compressedFile); + PublishFileAzure(latestCompressedFileBlob, compressedFile); + return c.Success(); + } + private static BuildTargetResult PublishFile(BuildTargetContext c, string file) { var env = PackageTargets.GetCommonEnvVars(c); From 1c44d2566eb73d0a5ceba434a4e7dc873fac0d5e Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 14 Mar 2016 18:41:08 -0700 Subject: [PATCH 41/99] copy the deps json for packaged commands --- src/dotnet/commands/dotnet-restore/Program.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dotnet/commands/dotnet-restore/Program.cs b/src/dotnet/commands/dotnet-restore/Program.cs index 1b530edb0..806604cf6 100644 --- a/src/dotnet/commands/dotnet-restore/Program.cs +++ b/src/dotnet/commands/dotnet-restore/Program.cs @@ -162,14 +162,21 @@ namespace Microsoft.DotNet.Tools.Restore Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path), toolDescription.Identity.Name + FileNameSuffixes.Deps); + var depsJsonPath = Path.Combine( + toolDescription.Path, + Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path), + toolDescription.Identity.Name + FileNameSuffixes.DepsJson); + var calculator = context.GetOutputPaths(Constants.DefaultConfiguration, buidBasePath: null, outputPath: context.ProjectDirectory); var executable = new Executable(context, calculator, context.CreateExporter(Constants.DefaultConfiguration), null); executable.MakeCompilationOutputRunnable(); if (File.Exists(depsPath)) File.Delete(depsPath); + if (File.Exists(depsJsonPath)) File.Delete(depsJsonPath); File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.Deps), depsPath); + File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.DepsJson), depsJsonPath); } private static bool RestoreToolToPath(LibraryRange tooldep, IEnumerable args, string tempPath, bool quiet) From 6bd9d80fedd3db6f32ce94913d87dfa7ac892e9f Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Mon, 14 Mar 2016 18:46:56 -0700 Subject: [PATCH 42/99] Add the target attribute. --- scripts/dotnet-cli-build/PublishTargets.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 23aa141f6..b7308312e 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -142,6 +142,7 @@ namespace Microsoft.DotNet.Cli.Build return uploadJson; } + [Target] public static BuildTargetResult PublishSharedFrameworkCompressedFile(BuildTargetContext c) { var compressedFile = c.BuildContext.Get("SharedFrameworkCompressedFile"); @@ -154,6 +155,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] public static BuildTargetResult PublishSharedHostCompressedFile(BuildTargetContext c) { var compressedFile = c.BuildContext.Get("SharedHostCompressedFile"); From f615f74a398bf6cfce72a4be0e99a0ac098fea2e Mon Sep 17 00:00:00 2001 From: Senthil Date: Mon, 22 Feb 2016 01:41:25 -0800 Subject: [PATCH 43/99] Shared FX and Portable Support for Unified Host - Add Casablanca CPP Rest SDK to corehost - Correct understanding of portable runtimeTargets section - Fix minor issues and automation for RID - CLI Build Integration - Add API to consume deps files - Unix doesn't like major as a variable name - Define NOMINMAX for Windows.h - Support APP_CONTEXT_DEPS_FILES - mscorlib.ni can come from native - Append Dotnet.dll to sdk path - Muxer vs standalone distinction based on own name.dll --- scripts/dotnet-cli-build/CompileTargets.cs | 15 +- .../PackagedCommandSpecFactory.cs | 3 +- .../ProjectDependenciesCommandResolver.cs | 2 +- src/Microsoft.DotNet.Cli.Utils/Constants.cs | 3 +- src/corehost/build.sh | 42 +- src/corehost/cli/CMakeLists.txt | 19 +- src/corehost/cli/args.cpp | 51 +- src/corehost/cli/args.h | 7 +- src/corehost/cli/deps_entry.cpp | 144 + src/corehost/cli/deps_entry.h | 38 + src/corehost/cli/deps_format.cpp | 305 + src/corehost/cli/deps_format.h | 113 + src/corehost/cli/deps_resolver.cpp | 568 +- src/corehost/cli/deps_resolver.h | 102 +- src/corehost/cli/dll/CMakeLists.txt | 12 +- src/corehost/cli/fxr/CMakeLists.txt | 45 + src/corehost/cli/fxr/fx_muxer.cpp | 298 + src/corehost/cli/fxr/fx_muxer.h | 16 + src/corehost/cli/fxr/fx_ver.cpp | 168 + src/corehost/cli/fxr/fx_ver.h | 40 + src/corehost/cli/hostpolicy.cpp | 73 +- src/corehost/cli/json/casablanca/LICENSE.txt | 1 + .../include/cpprest/asyncrt_utils.h | 600 ++ .../include/cpprest/details/SafeInt3.hpp | 7048 +++++++++++++++++ .../include/cpprest/details/basic_types.h | 140 + .../include/cpprest/details/cpprest_compat.h | 97 + .../include/cpprest/details/nosal.h | 89 + .../json/casablanca/include/cpprest/json.h | 1936 +++++ .../cli/json/casablanca/include/stdafx.h | 109 + .../cli/json/casablanca/src/json/json.cpp | 495 ++ .../json/casablanca/src/json/json_parsing.cpp | 1312 +++ .../src/json/json_serialization.cpp | 274 + .../src/utilities/asyncrt_utils.cpp | 496 ++ src/corehost/cli/libhost.cpp | 61 + src/corehost/cli/libhost.h | 66 + src/corehost/cli/runtime_config.cpp | 114 + src/corehost/cli/runtime_config.h | 29 + src/corehost/cli/servicing_index.cpp | 34 +- src/corehost/cli/setup.cmake | 16 + src/corehost/common/pal.h | 17 +- src/corehost/common/pal.unix.cpp | 33 +- src/corehost/common/pal.windows.cpp | 41 + src/corehost/common/utils.cpp | 85 +- src/corehost/common/utils.h | 9 + src/corehost/corehost.cpp | 223 +- src/corehost/corehost.h | 36 + src/corehost/error_codes.h | 29 + src/corehost/policy_load.cpp | 79 + src/corehost/policy_load.h | 38 + 49 files changed, 14979 insertions(+), 592 deletions(-) create mode 100644 src/corehost/cli/deps_entry.cpp create mode 100644 src/corehost/cli/deps_entry.h create mode 100644 src/corehost/cli/deps_format.cpp create mode 100644 src/corehost/cli/deps_format.h create mode 100644 src/corehost/cli/fxr/CMakeLists.txt create mode 100644 src/corehost/cli/fxr/fx_muxer.cpp create mode 100644 src/corehost/cli/fxr/fx_muxer.h create mode 100644 src/corehost/cli/fxr/fx_ver.cpp create mode 100644 src/corehost/cli/fxr/fx_ver.h create mode 100644 src/corehost/cli/json/casablanca/LICENSE.txt create mode 100644 src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h create mode 100755 src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp create mode 100755 src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h create mode 100755 src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h create mode 100755 src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h create mode 100755 src/corehost/cli/json/casablanca/include/cpprest/json.h create mode 100644 src/corehost/cli/json/casablanca/include/stdafx.h create mode 100644 src/corehost/cli/json/casablanca/src/json/json.cpp create mode 100644 src/corehost/cli/json/casablanca/src/json/json_parsing.cpp create mode 100644 src/corehost/cli/json/casablanca/src/json/json_serialization.cpp create mode 100644 src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp create mode 100644 src/corehost/cli/libhost.cpp create mode 100644 src/corehost/cli/runtime_config.cpp create mode 100644 src/corehost/cli/runtime_config.h create mode 100644 src/corehost/corehost.h create mode 100644 src/corehost/error_codes.h create mode 100644 src/corehost/policy_load.cpp create mode 100644 src/corehost/policy_load.h diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 3391a649c..3ce42b820 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -70,15 +70,20 @@ namespace Microsoft.DotNet.Cli.Build var configuration = c.BuildContext.Get("Configuration"); // Run the build + string version = DotNetCli.Stage0.Exec("", "--version").CaptureStdOut().Execute().StdOut; + string rid = Array.Find(version.Split(Environment.NewLine.ToCharArray()), (e) => e.Contains("Runtime Id:")).Replace("Runtime Id:", "").Trim(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // Why does Windows directly call cmake but Linux/Mac calls "build.sh" in the corehost dir? // See the comment in "src/corehost/build.sh" for details. It doesn't work for some reason. var visualStudio = IsWinx86 ? "Visual Studio 14 2015" : "Visual Studio 14 2015 Win64"; var archMacro = IsWinx86 ? "-DCLI_CMAKE_PLATFORM_ARCH_I386=1" : "-DCLI_CMAKE_PLATFORM_ARCH_AMD64=1"; + var ridMacro = $"-DCLI_CMAKE_RUNTIME_ID:STRING={rid}"; + ExecIn(cmakeOut, "cmake", Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost"), archMacro, + ridMacro, "-G", visualStudio); @@ -101,14 +106,21 @@ namespace Microsoft.DotNet.Cli.Build File.Copy(Path.Combine(cmakeOut, "cli", configuration, "corehost.pdb"), Path.Combine(Dirs.Corehost, "corehost.pdb"), overwrite: true); File.Copy(Path.Combine(cmakeOut, "cli", "dll", configuration, "hostpolicy.dll"), Path.Combine(Dirs.Corehost, "hostpolicy.dll"), overwrite: true); File.Copy(Path.Combine(cmakeOut, "cli", "dll", configuration, "hostpolicy.pdb"), Path.Combine(Dirs.Corehost, "hostpolicy.pdb"), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "fxr", configuration, "hostfxr.dll"), Path.Combine(Dirs.Corehost, "hostfxr.dll"), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "fxr", configuration, "hostfxr.pdb"), Path.Combine(Dirs.Corehost, "hostfxr.pdb"), overwrite: true); } else { - ExecIn(cmakeOut, Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost", "build.sh")); + ExecIn(cmakeOut, Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost", "build.sh"), + "--arch", + "amd64", + "--rid", + rid); // Copy the output out File.Copy(Path.Combine(cmakeOut, "cli", "corehost"), Path.Combine(Dirs.Corehost, "corehost"), overwrite: true); File.Copy(Path.Combine(cmakeOut, "cli", "dll", $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "fxr", $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); } return c.Success(); @@ -193,6 +205,7 @@ namespace Microsoft.DotNet.Cli.Build // Copy corehost File.Copy(Path.Combine(Dirs.Corehost, $"corehost{Constants.ExeSuffix}"), Path.Combine(binDir, $"corehost{Constants.ExeSuffix}"), overwrite: true); File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); + File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); // Corehostify binaries foreach (var binaryToCorehostify in BinariesForCoreHost) diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index ee5bd7ecb..8129fa2e5 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -98,7 +98,8 @@ namespace Microsoft.DotNet.Cli.Utils if (depsFilePath != null) { - arguments.Add($"--depsfile:{depsFilePath}"); + arguments.Add("--depsfile"); + arguments.Add(depsFilePath); } arguments.AddRange(commandArguments); diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs index bf314ee6a..608beb231 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs @@ -75,7 +75,7 @@ namespace Microsoft.DotNet.Cli.Utils return null; } - var depsFilePath = projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.Deps; + var depsFilePath = projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.DepsJson; var dependencyLibraries = GetAllDependencyLibraries(projectContext); diff --git a/src/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Microsoft.DotNet.Cli.Utils/Constants.cs index 9bbb22325..13a349b13 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -37,7 +37,8 @@ namespace Microsoft.DotNet.Cli.Utils public static readonly string HostExecutableName = "corehost" + ExeSuffix; public static readonly string[] HostBinaryNames = new string[] { HostExecutableName, - (CurrentPlatform == Platform.Windows ? "hostpolicy" : "libhostpolicy") + DynamicLibSuffix + (CurrentPlatform == Platform.Windows ? "hostpolicy" : "libhostpolicy") + DynamicLibSuffix, + (CurrentPlatform == Platform.Windows ? "hostfxr" : "libhostfxr") + DynamicLibSuffix }; } diff --git a/src/corehost/build.sh b/src/corehost/build.sh index 339838348..7717bdc15 100755 --- a/src/corehost/build.sh +++ b/src/corehost/build.sh @@ -14,6 +14,46 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli done DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" +__build_arch= +__runtime_id= + +while [ "$1" != "" ]; do + lowerI="$(echo $1 | awk '{print tolower($0)}')" + case $lowerI in + -h|--help) + usage + exit 1 + ;; + --arch) + shift + __build_arch=$1 + ;; + --rid) + shift + __runtime_id=$1 + ;; + *) + echo "Unknown argument to build.sh $1"; exit 1 + esac + shift +done + +__cmake_defines= + +case $__build_arch in + amd64) + __define=-DCLI_CMAKE_PLATFORM_ARCH_AMD64=1 + ;; + x86) + __define=-DCLI_CMAKE_PLATFORM_ARCH_I386=1 + ;; + *) + echo "Unknown architecture $__build_arch"; exit 1 + ;; +esac +__cmake_defines="${__cmake_defines} ${__define}" + + echo "Building Corehost from $DIR to $(pwd)" -cmake "$DIR" -G "Unix Makefiles" +cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_RUNTIME_ID:STRING=$__runtime_id make diff --git a/src/corehost/cli/CMakeLists.txt b/src/corehost/cli/CMakeLists.txt index 9c22fc834..12636ae6b 100644 --- a/src/corehost/cli/CMakeLists.txt +++ b/src/corehost/cli/CMakeLists.txt @@ -14,13 +14,26 @@ include(setup.cmake) set (CMAKE_CXX_STANDARD 11) +include_directories(..) include_directories(../common) include_directories(.) +include_directories(./fxr) +include_directories(./json/casablanca/include) # CMake does not recommend using globbing since it messes with the freshness checks set(SOURCES - ../corehost.cpp + libhost.cpp + #deps_format.cpp + #./json/casablanca/src/json/json.cpp + #./json/casablanca/src/json/json_parsing.cpp + #./json/casablanca/src/json/json_serialization.cpp + #./json/casablanca/src/utilities/asyncrt_utils.cpp + + + ./fxr/fx_ver.cpp + ../corehost.cpp + ../policy_load.cpp ../common/trace.cpp ../common/utils.cpp) @@ -32,6 +45,9 @@ else() endif() add_executable(corehost ${SOURCES}) +install(TARGETS corehost DESTINATION bin) +add_definitions(-D_NO_ASYNCRTIMP) +add_definitions(-D_NO_PPLXIMP) # Older CMake doesn't support CMAKE_CXX_STANDARD and GCC/Clang need a switch to enable C++ 11 if(${CMAKE_CXX_COMPILER_ID} MATCHES "(Clang|GNU)") @@ -44,3 +60,4 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() add_subdirectory(dll) +add_subdirectory(fxr) diff --git a/src/corehost/cli/args.cpp b/src/corehost/cli/args.cpp index 086d05fab..569110857 100644 --- a/src/corehost/cli/args.cpp +++ b/src/corehost/cli/args.cpp @@ -4,6 +4,7 @@ #include "args.h" #include "utils.h" #include "coreclr.h" +#include "libhost.h" arguments_t::arguments_t() : managed_application(_X("")), @@ -11,11 +12,8 @@ arguments_t::arguments_t() : app_dir(_X("")), app_argc(0), app_argv(nullptr), - nuget_packages(_X("")), dotnet_packages_cache(_X("")), dotnet_servicing(_X("")), - dotnet_runtime_servicing(_X("")), - dotnet_home(_X("")), deps_path(_X("")) { } @@ -26,12 +24,13 @@ void display_help() _X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n") _X("Execute the specified managed assembly with the passed in arguments\n\n") _X("The Host's behavior can be altered using the following environment variables:\n") - _X(" DOTNET_HOME Set the dotnet home directory. The CLR is expected to be in the runtime subdirectory of this directory. Overrides all other values for CLR search paths\n") _X(" COREHOST_TRACE Set to affect trace levels (0 = Errors only (default), 1 = Warnings, 2 = Info, 3 = Verbose)\n"); } -bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args) +bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode, + const int argc, const pal::char_t* argv[], arguments_t* arg_out) { + arguments_t& args = *arg_out; // Get the full name of the application if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path)) { @@ -41,8 +40,8 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg auto own_name = get_filename(args.own_path); auto own_dir = get_directory(args.own_path); - - if (own_name.compare(HOST_EXE_NAME) == 0) + + if (mode != host_mode_t::standalone) { // corerun mode. First argument is managed app if (argc < 2) @@ -78,23 +77,26 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg args.app_argc = argc - 1; } - if (args.app_argc > 0) + std::unordered_map opts; + std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") }; + int num_args = 0; + if (!parse_known_args(args.app_argc, args.app_argv, known_opts, &opts, &num_args)) { - auto depsfile_candidate = pal::string_t(args.app_argv[0]); - - if (starts_with(depsfile_candidate, s_deps_arg_prefix, false)) - { - args.deps_path = depsfile_candidate.substr(s_deps_arg_prefix.length()); - if (!pal::realpath(&args.deps_path)) - { - trace::error(_X("Failed to locate deps file: %s"), args.deps_path.c_str()); - return false; - } - args.app_dir = get_directory(args.deps_path); - args.app_argc = args.app_argc - 1; - args.app_argv = &args.app_argv[1]; - } + return false; } + + args.app_argc -= num_args; + args.app_argv += num_args; + pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : deps_path; + pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : probe_dir; + + if (!deps_file.empty()) + { + args.deps_path = deps_file; + args.app_dir = get_directory(args.deps_path); + } + + args.probe_dir = probe_path; if (args.deps_path.empty()) { @@ -105,13 +107,10 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg args.deps_path.append(app_base); args.deps_path.push_back(DIR_SEPARATOR); args.deps_path.append(app_name, 0, app_name.find_last_of(_X("."))); - args.deps_path.append(_X(".deps")); + args.deps_path.append(_X(".deps.json")); } - pal::getenv(_X("NUGET_PACKAGES"), &args.nuget_packages); pal::getenv(_X("DOTNET_PACKAGES_CACHE"), &args.dotnet_packages_cache); pal::getenv(_X("DOTNET_SERVICING"), &args.dotnet_servicing); - pal::getenv(_X("DOTNET_RUNTIME_SERVICING"), &args.dotnet_runtime_servicing); - pal::getenv(_X("DOTNET_HOME"), &args.dotnet_home); return true; } diff --git a/src/corehost/cli/args.h b/src/corehost/cli/args.h index d510cd6e8..bec56128c 100644 --- a/src/corehost/cli/args.h +++ b/src/corehost/cli/args.h @@ -7,8 +7,7 @@ #include "utils.h" #include "pal.h" #include "trace.h" - -static const pal::string_t s_deps_arg_prefix = _X("--depsfile:"); +#include "libhost.h" struct arguments_t { @@ -18,7 +17,7 @@ struct arguments_t pal::string_t dotnet_servicing; pal::string_t dotnet_runtime_servicing; pal::string_t dotnet_home; - pal::string_t nuget_packages; + pal::string_t probe_dir; pal::string_t dotnet_packages_cache; pal::string_t managed_application; @@ -28,6 +27,6 @@ struct arguments_t arguments_t(); }; -bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args); +bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args); #endif // ARGS_H diff --git a/src/corehost/cli/deps_entry.cpp b/src/corehost/cli/deps_entry.cpp new file mode 100644 index 000000000..ff5ebbbe3 --- /dev/null +++ b/src/corehost/cli/deps_entry.cpp @@ -0,0 +1,144 @@ +// 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. + +#include "pal.h" +#include "utils.h" +#include "deps_entry.h" +#include "trace.h" + +// ----------------------------------------------------------------------------- +// Given a "base" directory, yield the relative path of this file in the package +// layout. +// +// Parameters: +// base - The base directory to look for the relative path of this entry +// str - If the method returns true, contains the file path for this deps +// entry relative to the "base" directory +// +// Returns: +// If the file exists in the path relative to the "base" directory. +// +bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) const +{ + pal::string_t& candidate = *str; + + candidate.clear(); + + // Base directory must be present to obtain full path + if (base.empty()) + { + return false; + } + + // Entry relative path contains '/' separator, sanitize it to use + // platform separator. Perf: avoid extra copy if it matters. + pal::string_t pal_relative_path = relative_path; + if (_X('/') != DIR_SEPARATOR) + { + replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR); + } + + // Reserve space for the path below + candidate.reserve(base.length() + + library_name.length() + + library_version.length() + + pal_relative_path.length() + 3); + + candidate.assign(base); + append_path(&candidate, library_name.c_str()); + append_path(&candidate, library_version.c_str()); + append_path(&candidate, pal_relative_path.c_str()); + + bool exists = pal::file_exists(candidate); + if (!exists) + { + candidate.clear(); + } + return exists; +} + +// ----------------------------------------------------------------------------- +// Given a "base" directory, yield the relative path of this file in the package +// layout if the entry hash matches the hash file in the "base" directory +// +// Parameters: +// base - The base directory to look for the relative path of this entry and +// the hash file. +// str - If the method returns true, contains the file path for this deps +// entry relative to the "base" directory +// +// Description: +// Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}" +// If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then +// yields the relative path of this entry in the "base" dir. +// +// Returns: +// If the file exists in the path relative to the "base" directory and there +// was hash file match with this deps entry. +// +// See: to_full_path(base, str) +// +bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const +{ + pal::string_t& candidate = *str; + + candidate.clear(); + + // Base directory must be present to perform hash lookup. + if (base.empty()) + { + return false; + } + + // First detect position of hyphen in [Algorithm]-[Hash] in the string. + size_t pos = library_hash.find(_X("-")); + if (pos == 0 || pos == pal::string_t::npos) + { + trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str()); + return false; + } + + // Build the nupkg file name. Just reserve approx 8 char_t's for the algorithm name. + pal::string_t nupkg_filename; + nupkg_filename.reserve(library_name.length() + 1 + library_version.length() + 16); + nupkg_filename.append(library_name); + nupkg_filename.append(_X(".")); + nupkg_filename.append(library_version); + nupkg_filename.append(_X(".nupkg.")); + nupkg_filename.append(library_hash.substr(0, pos)); + + // Build the hash file path str. + pal::string_t hash_file; + hash_file.reserve(base.length() + library_name.length() + library_version.length() + nupkg_filename.length() + 3); + hash_file.assign(base); + append_path(&hash_file, library_name.c_str()); + append_path(&hash_file, library_version.c_str()); + append_path(&hash_file, nupkg_filename.c_str()); + + // Read the contents of the hash file. + pal::ifstream_t fstream(hash_file); + if (!fstream.good()) + { + trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str()); + return false; + } + + // Obtain the hash from the file. + std::string hash; + hash.assign(pal::istreambuf_iterator_t(fstream), + pal::istreambuf_iterator_t()); + pal::string_t pal_hash; + pal::to_palstring(hash.c_str(), &pal_hash); + + // Check if contents match deps entry. + pal::string_t entry_hash = library_hash.substr(pos + 1); + if (entry_hash != pal_hash) + { + trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"), + pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length()); + return false; + } + + // All good, just append the relative dir to base. + return to_full_path(base, &candidate); +} diff --git a/src/corehost/cli/deps_entry.h b/src/corehost/cli/deps_entry.h new file mode 100644 index 000000000..81e30e541 --- /dev/null +++ b/src/corehost/cli/deps_entry.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef __DEPS_ENTRY_H_ +#define __DEPS_ENTRY_H_ + +#include +#include +#include "pal.h" + +struct deps_entry_t +{ + enum asset_types + { + runtime = 0, + resources, + native, + count + }; + + pal::string_t library_type; + pal::string_t library_name; + pal::string_t library_version; + pal::string_t library_hash; + pal::string_t asset_type; + pal::string_t asset_name; + pal::string_t relative_path; + bool is_serviceable; + + // Given a "base" dir, yield the relative path in the package layout. + bool to_full_path(const pal::string_t& root, pal::string_t* str) const; + + // Given a "base" dir, yield the relative path in the package layout only if + // the hash matches contents of the hash file. + bool to_hash_matched_path(const pal::string_t& root, pal::string_t* str) const; +}; + +#endif // __DEPS_ENTRY_H_ diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp new file mode 100644 index 000000000..c85db98b5 --- /dev/null +++ b/src/corehost/cli/deps_format.cpp @@ -0,0 +1,305 @@ +// 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. + +#include "deps_format.h" +#include "utils.h" +#include "trace.h" +#include +#include +#include +#include +#include +#include + +const std::array deps_json_t::s_known_asset_types = { + _X("runtime"), _X("resources"), _X("native") }; + +const deps_entry_t& deps_json_t::try_ni(const deps_entry_t& entry) const +{ + if (m_ni_entries.count(entry.asset_name)) + { + int index = m_ni_entries.at(entry.asset_name); + return m_deps_entries[deps_entry_t::asset_types::runtime][index]; + } + return entry; +} + +void deps_json_t::reconcile_libraries_with_targets( + const json_value& json, + const std::function& library_exists_fn, + const std::function&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn) +{ + const auto& libraries = json.at(_X("libraries")).as_object(); + for (const auto& library : libraries) + { + trace::info(_X("Reconciling library %s"), library.first.c_str()); + + if (pal::to_lower(library.second.at(_X("type")).as_string()) != _X("package")) + { + trace::info(_X("Library %s is not a package"), library.first.c_str()); + continue; + } + if (!library_exists_fn(library.first)) + { + trace::info(_X("Library %s does not exist"), library.first.c_str()); + continue; + } + + const auto& properties = library.second.as_object(); + + const pal::string_t& hash = properties.at(_X("sha512")).as_string(); + bool serviceable = properties.at(_X("serviceable")).as_bool(); + + for (int i = 0; i < s_known_asset_types.size(); ++i) + { + for (const auto& rel_path : get_rel_paths_by_asset_type_fn(library.first, i)) + { + bool ni_dll = false; + auto asset_name = get_filename_without_ext(rel_path); + if (ends_with(asset_name, _X(".ni"), false)) + { + ni_dll = true; + asset_name = strip_file_ext(asset_name); + } + + deps_entry_t entry; + size_t pos = library.first.find(_X("/")); + entry.library_name = library.first.substr(0, pos); + entry.library_version = library.first.substr(pos + 1); + entry.library_type = _X("package"); + entry.library_hash = hash; + entry.asset_name = asset_name; + entry.asset_type = s_known_asset_types[i]; + entry.relative_path = rel_path; + entry.is_serviceable = serviceable; + + // TODO: Deps file does not follow spec. It uses '\\', should use '/' + replace_char(&entry.relative_path, _X('\\'), _X('/')); + + m_deps_entries[i].push_back(entry); + + if (ni_dll) + { + m_ni_entries[entry.asset_name] = m_deps_entries + [deps_entry_t::asset_types::runtime].size() - 1; + } + + trace::info(_X("Added %s %s deps entry [%d] [%s, %s, %s]"), s_known_asset_types[i], entry.asset_name.c_str(), m_deps_entries[i].size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + + if (i == deps_entry_t::asset_types::native && + entry.asset_name == LIBCORECLR_FILENAME) + { + m_coreclr_index = m_deps_entries[i].size() - 1; + trace::verbose(_X("Found coreclr from deps %d [%s, %s, %s]"), + m_coreclr_index, + entry.library_name.c_str(), + entry.library_version.c_str(), + entry.relative_path.c_str()); + } + + } + } + } +} + +pal::string_t get_own_rid() +{ +#define _STRINGIFY(s) _X(s) +#if defined(TARGET_RUNTIME_ID) + return _STRINGIFY(TARGET_RUNTIME_ID); +#else +#error "Cannot build the host without knowing host's root RID" +#endif +} + +bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph) +{ + pal::string_t host_rid = get_own_rid(); + for (auto& package : *portable_assets) + { + pal::string_t matched_rid = package.second.count(host_rid) ? host_rid : _X(""); + if (matched_rid.empty()) + { + if (rid_fallback_graph.count(host_rid) == 0) + { + trace::error(_X("Did not find fallback rids for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str()); + return false; + } + const auto& fallback_rids = rid_fallback_graph.find(host_rid)->second; + auto iter = std::find_if(fallback_rids.begin(), fallback_rids.end(), [&package](const pal::string_t& rid) { + return package.second.count(rid); + }); + if (iter == fallback_rids.end() || (*iter).empty()) + { + trace::error(_X("Did not find a matching fallback rid for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str()); + return false; + } + matched_rid = *iter; + } + assert(!matched_rid.empty()); + for (auto iter = package.second.begin(); iter != package.second.end(); /* */) + { + iter = (iter->first != matched_rid) + ? package.second.erase(iter) + : iter++; + } + } + return true; +} + + +bool deps_json_t::process_runtime_targets(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph, rid_specific_assets_t* p_assets) +{ + rid_specific_assets_t& assets = *p_assets; + for (const auto& package : json.at(_X("targets")).at(target_name).as_object()) + { + const auto& targets = package.second.as_object(); + auto iter = targets.find(_X("runtimeTargets")); + if (iter == targets.end()) + { + continue; + } + + const auto& files = iter->second.as_object(); + for (const auto& file : files) + { + const auto& type = file.second.at(_X("assetType")).as_string(); + for (int i = 0; i < s_known_asset_types.size(); ++i) + { + if (pal::strcasecmp(type.c_str(), s_known_asset_types[i]) == 0) + { + const auto& rid = file.second.at(_X("rid")).as_string(); + assets[package.first][rid][i].push_back(file.first); + } + } + } + } + + if (!perform_rid_fallback(&assets, rid_fallback_graph)) + { + return false; + } + + return true; +} + +bool deps_json_t::process_targets(const json_value& json, const pal::string_t& target_name, deps_assets_t* p_assets) +{ + deps_assets_t& assets = *p_assets; + for (const auto& package : json.at(_X("targets")).at(target_name).as_object()) + { + // if (package.second.at(_X("type")).as_string() != _X("package")) continue; + + const auto& asset_types = package.second.as_object(); + for (int i = 0; i < s_known_asset_types.size(); ++i) + { + auto iter = asset_types.find(s_known_asset_types[i]); + if (iter != asset_types.end()) + { + for (const auto& file : iter->second.as_object()) + { + trace::info(_X("Adding %s asset %s from %s"), s_known_asset_types[i], file.first.c_str(), package.first.c_str()); + assets[package.first][i].push_back(file.first); + } + } + } + } + return true; +} + +bool deps_json_t::load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph) +{ + rid_specific_assets_t rid_assets; + if (!process_runtime_targets(json, target_name, rid_fallback_graph, &rid_assets)) + { + return false; + } + + deps_assets_t non_rid_assets; + if (!process_targets(json, target_name, &non_rid_assets)) + { + return false; + } + + auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool { + return rid_assets.count(package) || non_rid_assets.count(package); + }; + auto get_relpaths = [&rid_assets, &non_rid_assets](const pal::string_t& package, int type_index) -> const std::vector& { + return (rid_assets.count(package)) + ? rid_assets[package].begin()->second[type_index] + : non_rid_assets[package][type_index]; + }; + + reconcile_libraries_with_targets(json, package_exists, get_relpaths); + + return true; +} + +bool deps_json_t::load_standalone(const json_value& json, const pal::string_t& target_name) +{ + deps_assets_t assets; + + if (!process_targets(json, target_name, &assets)) + { + return false; + } + + auto package_exists = [&assets](const pal::string_t& package) -> bool { + return assets.count(package); + }; + + auto get_relpaths = [&assets](const pal::string_t& package, int type_index) -> const std::vector& { + return assets[package][type_index]; + }; + + reconcile_libraries_with_targets(json, package_exists, get_relpaths); + + const auto& json_object = json.as_object(); + const auto iter = json_object.find(_X("runtimes")); + if (iter != json_object.end()) + { + for (const auto& rid : iter->second.as_object()) + { + auto& vec = m_rid_fallback_graph[rid.first]; + for (const auto& fallback : rid.second.as_array()) + { + vec.push_back(fallback.as_string()); + } + } + } + return true; +} + +// ----------------------------------------------------------------------------- +// Load the deps file and parse its "entry" lines which contain the "fields" of +// the entry. Populate an array of these entries. +// +bool deps_json_t::load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph) +{ + // If file doesn't exist, then assume parsed. + if (!pal::file_exists(deps_path)) + { + return true; + } + + // Somehow the file stream could not be opened. This is an error. + pal::ifstream_t file(deps_path); + if (!file.good()) + { + return false; + } + + try + { + const auto json = json_value::parse(file); + + const auto& runtime_target = json.at(_X("runtimeTarget")); + const pal::string_t& name = runtime_target.as_string(); + + return (portable) ? load_portable(json, name, rid_fallback_graph) : load_standalone(json, name); + } + catch (...) + { + return false; + } +} diff --git a/src/corehost/cli/deps_format.h b/src/corehost/cli/deps_format.h new file mode 100644 index 000000000..e9c8a0cea --- /dev/null +++ b/src/corehost/cli/deps_format.h @@ -0,0 +1,113 @@ +// 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. + +#ifndef __DEPS_FORMAT_H_ +#define __DEPS_FORMAT_H_ + +#include +#include +#include +#include "pal.h" +#include "deps_entry.h" +#include "cpprest/json.h" + +class deps_json_t +{ + typedef web::json::value json_value; + typedef std::array, deps_entry_t::asset_types::count> vectors_t; + typedef std::unordered_map str_to_vectors_map_t; + typedef std::unordered_map> str_to_vector_map_t; + + typedef str_to_vector_map_t rid_fallback_graph_t; + typedef str_to_vectors_map_t deps_assets_t; + typedef std::unordered_map rid_specific_assets_t; + +public: + deps_json_t() + : m_valid(false) + , m_coreclr_index(-1) + { + } + + deps_json_t(bool portable, const pal::string_t& deps_path) + : deps_json_t(portable, deps_path, m_rid_fallback_graph /* dummy */) + { + } + + deps_json_t(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& graph) + : deps_json_t() + { + m_valid = load(portable, deps_path, graph); + } + + const std::vector& get_entries(deps_entry_t::asset_types type) + { + assert(type < deps_entry_t::asset_types::count); + return m_deps_entries[type]; + } + + bool has_coreclr_entry() + { + return m_coreclr_index >= 0; + } + + const deps_entry_t& get_coreclr_entry() + { + assert(has_coreclr_entry()); + return m_deps_entries[deps_entry_t::asset_types::native][m_coreclr_index]; + } + + bool is_valid() + { + return m_valid; + } + + const rid_fallback_graph_t& get_rid_fallback_graph() + { + return m_rid_fallback_graph; + } + + const deps_entry_t& try_ni(const deps_entry_t& entry) const; + +private: + bool load_standalone(const json_value& json, const pal::string_t& target_name); + bool load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph); + bool load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph); + bool process_runtime_targets(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph, rid_specific_assets_t* p_assets); + bool process_targets(const json_value& json, const pal::string_t& target_name, deps_assets_t* p_assets); + + void reconcile_libraries_with_targets( + const json_value& json, + const std::function& library_exists_fn, + const std::function&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn); + + bool perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph); + + static const std::array s_known_asset_types; + + std::vector m_deps_entries[deps_entry_t::asset_types::count]; + + std::unordered_map m_ni_entries; + rid_fallback_graph_t m_rid_fallback_graph; + int m_coreclr_index; + bool m_valid; +}; + +class deps_text_t +{ +public: + deps_text_t(const pal::string_t& deps_path) + : m_valid(load(deps_path)) + { + } + + bool load(const pal::string_t& deps_path); + bool is_valid() { return m_valid; } + const std::vector& get_entries() { return m_deps_entries; } + +private: + std::vector m_deps_entries; + bool m_valid; +}; + +#endif // __DEPS_FORMAT_H_ diff --git a/src/corehost/cli/deps_resolver.cpp b/src/corehost/cli/deps_resolver.cpp index a43fdab34..fd2901d8a 100644 --- a/src/corehost/cli/deps_resolver.cpp +++ b/src/corehost/cli/deps_resolver.cpp @@ -6,80 +6,12 @@ #include #include "trace.h" +#include "deps_format.h" #include "deps_resolver.h" #include "utils.h" namespace { -// ----------------------------------------------------------------------------- -// Read a single field from the deps entry -// -// Parameters: -// line - A deps file entry line -// buf - The temporary buffer to use while parsing (with size to contain "line") -// ofs - The offset that this method will read from "line" on invocation and -// the offset that has been consumed by this method upon successful exit -// field - The current field read from the line -// -// Assumption: -// The line should be in a CSV format, with commas separating the fields. -// The fields themselves will be quoted. The escape character is '\\' -// -// Returns: -// True if parsed successfully. Else, false -// -// Note: -// Callers cannot call with the same "line" upon an unsuccessful exit. -bool read_field(const pal::string_t& line, pal::char_t* buf, unsigned* ofs, pal::string_t* field) -{ - unsigned& offset = *ofs; - pal::string_t& value_recv = *field; - - // The first character should be a '"' - if (line[offset] != '"') - { - trace::error(_X("Error reading TPA file")); - return false; - } - offset++; - - auto buf_offset = 0; - - // Iterate through characters in the string - for (; offset < line.length(); offset++) - { - // Is this a '\'? - if (line[offset] == '\\') - { - // Skip this character and read the next character into the buffer - offset++; - buf[buf_offset] = line[offset]; - } - // Is this a '"'? - else if (line[offset] == '\"') - { - // Done! Advance to the pointer after the input - offset++; - break; - } - else - { - // Take the character - buf[buf_offset] = line[offset]; - } - buf_offset++; - } - buf[buf_offset] = '\0'; - value_recv.assign(buf); - - // Consume the ',' if we have one - if (line[offset] == ',') - { - offset++; - } - return true; -} - // ----------------------------------------------------------------------------- // A uniqifying append helper that doesn't let two entries with the same // "asset_name" be part of the "output" paths. @@ -106,28 +38,6 @@ void add_tpa_asset( items->insert(asset_name); } -// ----------------------------------------------------------------------------- -// Add mscorlib from the CLR directory. Even if CLR is serviced, we should pick -// mscorlib from the CLR directory. If mscorlib could not be found in the CLR -// location, then leave it to the CLR to pick the right mscorlib. -// -void add_mscorlib_to_tpa(const pal::string_t& clr_dir, std::set* items, pal::string_t* output) -{ - pal::string_t mscorlib_ni_path = clr_dir + DIR_SEPARATOR + _X("mscorlib.ni.dll"); - if (pal::file_exists(mscorlib_ni_path)) - { - add_tpa_asset(_X("mscorlib"), mscorlib_ni_path, items, output); - return; - } - - pal::string_t mscorlib_path = clr_dir + DIR_SEPARATOR + _X("mscorlib.dll"); - if (pal::file_exists(mscorlib_path)) - { - add_tpa_asset(_X("mscorlib"), mscorlib_path, items, output); - return; - } -} - // ----------------------------------------------------------------------------- // A uniqifying append helper that doesn't let two "paths" to be identical in // the "output" string. @@ -157,234 +67,16 @@ void add_unique_path( } // end of anonymous namespace -// ----------------------------------------------------------------------------- -// Given a "base" directory, yield the relative path of this file in the package -// layout. -// -// Parameters: -// base - The base directory to look for the relative path of this entry -// str - If the method returns true, contains the file path for this deps -// entry relative to the "base" directory -// -// Returns: -// If the file exists in the path relative to the "base" directory. -// -bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) const -{ - pal::string_t& candidate = *str; - - candidate.clear(); - - // Entry relative path contains '/' separator, sanitize it to use - // platform separator. Perf: avoid extra copy if it matters. - pal::string_t pal_relative_path = relative_path; - if (_X('/') != DIR_SEPARATOR) - { - replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR); - } - - // Reserve space for the path below - candidate.reserve(base.length() + - library_name.length() + - library_version.length() + - pal_relative_path.length() + 3); - - candidate.assign(base); - append_path(&candidate, library_name.c_str()); - append_path(&candidate, library_version.c_str()); - append_path(&candidate, pal_relative_path.c_str()); - - bool exists = pal::file_exists(candidate); - if (!exists) - { - candidate.clear(); - } - return exists; -} - -// ----------------------------------------------------------------------------- -// Given a "base" directory, yield the relative path of this file in the package -// layout if the entry hash matches the hash file in the "base" directory -// -// Parameters: -// base - The base directory to look for the relative path of this entry and -// the hash file. -// str - If the method returns true, contains the file path for this deps -// entry relative to the "base" directory -// -// Description: -// Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}" -// If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then -// yields the relative path of this entry in the "base" dir. -// -// Returns: -// If the file exists in the path relative to the "base" directory and there -// was hash file match with this deps entry. -// -// See: to_full_path(base, str) -// -bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const -{ - pal::string_t& candidate = *str; - - candidate.clear(); - - // Base directory must be present to perform hash lookup. - if (base.empty()) - { - return false; - } - - // First detect position of hyphen in [Algorithm]-[Hash] in the string. - size_t pos = library_hash.find(_X("-")); - if (pos == 0 || pos == pal::string_t::npos) - { - trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str()); - return false; - } - - // Build the nupkg file name. Just reserve approx 8 char_t's for the algorithm name. - pal::string_t nupkg_filename; - nupkg_filename.reserve(library_name.length() + 1 + library_version.length() + 16); - nupkg_filename.append(library_name); - nupkg_filename.append(_X(".")); - nupkg_filename.append(library_version); - nupkg_filename.append(_X(".nupkg.")); - nupkg_filename.append(library_hash.substr(0, pos)); - - // Build the hash file path str. - pal::string_t hash_file; - hash_file.reserve(base.length() + library_name.length() + library_version.length() + nupkg_filename.length() + 3); - hash_file.assign(base); - append_path(&hash_file, library_name.c_str()); - append_path(&hash_file, library_version.c_str()); - append_path(&hash_file, nupkg_filename.c_str()); - - // Read the contents of the hash file. - pal::ifstream_t fstream(hash_file); - if (!fstream.good()) - { - trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str()); - return false; - } - - // Obtain the hash from the file. - std::string hash; - hash.assign(pal::istreambuf_iterator_t(fstream), - pal::istreambuf_iterator_t()); - pal::string_t pal_hash; - pal::to_palstring(hash.c_str(), &pal_hash); - - // Check if contents match deps entry. - pal::string_t entry_hash = library_hash.substr(pos + 1); - if (entry_hash != pal_hash) - { - trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"), - pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length()); - return false; - } - - // All good, just append the relative dir to base. - return to_full_path(base, &candidate); -} - - -// ----------------------------------------------------------------------------- -// Load the deps file and parse its "entry" lines which contain the "fields" of -// the entry. Populate an array of these entries. -// -bool deps_resolver_t::load() -{ - // If file doesn't exist, then assume parsed. - if (!pal::file_exists(m_deps_path)) - { - return true; - } - - // Somehow the file stream could not be opened. This is an error. - pal::ifstream_t file(m_deps_path); - if (!file.good()) - { - return false; - } - - // Parse the "entry" lines of the deps file. - std::string stdline; - while (std::getline(file, stdline)) - { - pal::string_t line; - pal::to_palstring(stdline.c_str(), &line); - - deps_entry_t entry; - pal::string_t is_serviceable; - pal::string_t* fields[] = { - &entry.library_type, - &entry.library_name, - &entry.library_version, - &entry.library_hash, - &entry.asset_type, - &entry.asset_name, - &entry.relative_path, - // TODO: Add when the deps file support is enabled. - // &is_serviceable - }; - - std::vector buf(line.length()); - - for (unsigned i = 0, offset = 0; i < sizeof(fields) / sizeof(fields[0]); ++i) - { - if (!(read_field(line, buf.data(), &offset, fields[i]))) - { - return false; - } - } - - // Serviceable, if not false, default is true. - entry.is_serviceable = pal::strcasecmp(is_serviceable.c_str(), _X("false")) != 0; - - // TODO: Deps file does not follow spec. It uses '\\', should use '/' - replace_char(&entry.relative_path, _X('\\'), _X('/')); - - m_deps_entries.push_back(entry); - - trace::verbose(_X("Added deps entry [%d] [%s, %s, %s]"), m_deps_entries.size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); - - static_assert(std::is_same, decltype(m_deps_entries)>::value, "decltype(m_deps_entries) not a vector, took index based on size."); - if (entry.asset_type == _X("native") && - entry.asset_name == LIBCORECLR_FILENAME) - { - m_coreclr_index = m_deps_entries.size() - 1; - trace::verbose(_X("Found coreclr from deps entry [%d] [%s, %s, %s]"), - m_coreclr_index, - entry.library_name.c_str(), - entry.library_version.c_str(), - entry.relative_path.c_str()); - } - } - return true; -} - -// ----------------------------------------------------------------------------- -// Parse the deps file. -// -// Returns: -// True if the file parse is successful or if file doesn't exist. False, -// when there is an error parsing the file. -// -bool deps_resolver_t::parse_deps_file(const arguments_t& args) -{ - m_deps_path = args.deps_path; - - return load(); -} - // ----------------------------------------------------------------------------- // Load local assemblies by priority order of their file extensions and // unique-fied by their simple name. // -void deps_resolver_t::get_local_assemblies(const pal::string_t& dir) +void deps_resolver_t::get_dir_assemblies( + const pal::string_t& dir, + const pal::string_t& dir_name, + std::unordered_map* dir_assemblies) { - trace::verbose(_X("Adding files from dir %s"), dir.c_str()); + trace::verbose(_X("Adding files from %s dir %s"), dir_name.c_str(), dir.c_str()); // Managed extensions in priority order, pick DLL over EXE and NI over IL. const pal::string_t managed_ext[] = { _X(".ni.dll"), _X(".dll"), _X(".ni.exe"), _X(".exe") }; @@ -412,18 +104,17 @@ void deps_resolver_t::get_local_assemblies(const pal::string_t& dir) continue; } - // TODO: Do a case insensitive lookup. // Already added entry for this asset, by priority order skip this ext - if (m_local_assemblies.count(file_name)) + if (dir_assemblies->count(file_name)) { - trace::verbose(_X("Skipping %s because the %s already exists in local assemblies"), file.c_str(), m_local_assemblies.find(file_name)->second.c_str()); + trace::verbose(_X("Skipping %s because the %s already exists in %s assemblies"), file.c_str(), dir_assemblies->find(file_name)->second.c_str(), dir_name.c_str()); continue; } // Add entry for this asset pal::string_t file_path = dir + DIR_SEPARATOR + file; - trace::verbose(_X("Adding %s to local assembly set from %s"), file_name.c_str(), file_path.c_str()); - m_local_assemblies.emplace(file_name, file_path); + trace::verbose(_X("Adding %s to %s assembly set from %s"), file_name.c_str(), dir_name.c_str(), file_path.c_str()); + dir_assemblies->emplace(file_name, file_path); } } } @@ -440,43 +131,93 @@ pal::string_t deps_resolver_t::resolve_coreclr_dir( const pal::string_t& package_dir, const pal::string_t& package_cache_dir) { - // Runtime servicing - trace::verbose(_X("Probing for CoreCLR in servicing dir=[%s]"), m_runtime_svc.c_str()); - if (!m_runtime_svc.empty()) + auto process_coreclr = [&] + (bool is_portable, const pal::string_t& deps_dir, deps_json_t* deps) -> pal::string_t { - pal::string_t svc_clr = m_runtime_svc; - append_path(&svc_clr, _X("runtime")); - append_path(&svc_clr, _X("coreclr")); + pal::string_t candidate; - if (coreclr_exists_in_dir(svc_clr)) + // Servicing override. + if (deps->has_coreclr_entry()) { - return svc_clr; + const deps_entry_t& entry = deps->get_coreclr_entry(); + trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in servicing"), entry.library_name.c_str(), entry.library_version.c_str()); + if (entry.is_serviceable && m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &candidate)) + { + return get_directory(candidate); + } + } + else + { + trace::verbose(_X("Deps has no coreclr entry.")); } - } - // Package cache. - trace::verbose(_X("Probing for CoreCLR in package cache=[%s] deps index: [%d]"), package_cache_dir.c_str(), m_coreclr_index); - pal::string_t coreclr_cache; - if (m_coreclr_index >= 0 && !package_cache_dir.empty() && - m_deps_entries[m_coreclr_index].to_hash_matched_path(package_cache_dir, &coreclr_cache)) - { - return get_directory(coreclr_cache); - } + // Package cache. + pal::string_t coreclr_cache; + if (!package_cache_dir.empty()) + { + if (deps->has_coreclr_entry()) + { + const deps_entry_t& entry = deps->get_coreclr_entry(); + trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in package cache=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_cache_dir.c_str()); + if (entry.to_hash_matched_path(package_cache_dir, &coreclr_cache)) + { + return get_directory(coreclr_cache); + } + } + } - // App dir. - trace::verbose(_X("Probing for CoreCLR in app directory=[%s]"), app_dir.c_str()); - if (coreclr_exists_in_dir(app_dir)) - { - return app_dir; - } + // Deps directory: lookup relative path if portable, else look sxs. + if (is_portable) + { + pal::string_t coreclr_portable; + if (deps->has_coreclr_entry()) + { + const deps_entry_t& entry = deps->get_coreclr_entry(); + trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in portable app dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), deps_dir.c_str()); + if (entry.to_full_path(deps_dir, &coreclr_portable)) + { + return get_directory(coreclr_portable); + } + } + } + else + { + // App main dir or standalone app dir. + trace::verbose(_X("Probing for CoreCLR in deps directory=[%s]"), deps_dir.c_str()); + if (coreclr_exists_in_dir(deps_dir)) + { + return deps_dir; + } + } - // Packages dir - trace::verbose(_X("Probing for CoreCLR in packages=[%s] deps index: [%d]"), package_dir.c_str(), m_coreclr_index); - pal::string_t coreclr_package; - if (m_coreclr_index >= 0 && !package_dir.empty() && - m_deps_entries[m_coreclr_index].to_full_path(package_dir, &coreclr_package)) + // Packages dir. + pal::string_t coreclr_package; + if (!package_dir.empty()) + { + if (deps->has_coreclr_entry()) + { + const deps_entry_t& entry = deps->get_coreclr_entry(); + trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in packages dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_dir.c_str()); + if (entry.to_full_path(package_dir, &coreclr_package)) + { + return get_directory(coreclr_package); + } + } + } + + return pal::string_t(); + }; + + trace::info(_X("--- Starting CoreCLR Proble from app deps.json")); + pal::string_t clr_dir = process_coreclr(m_portable, app_dir, m_deps.get()); + if (clr_dir.empty() && m_portable) { - return get_directory(coreclr_package); + trace::info(_X("--- Starting CoreCLR Proble from FX deps.json")); + clr_dir = process_coreclr(false, m_fx_dir, m_fx_deps.get()); + } + if (!clr_dir.empty()) + { + return clr_dir; } // Use platform-specific search algorithm @@ -516,19 +257,33 @@ void deps_resolver_t::resolve_tpa_list( const pal::string_t& clr_dir, pal::string_t* output) { + std::vector empty(0); + + pal::string_t ni_package_cache_dir; + if (!package_cache_dir.empty()) + { + ni_package_cache_dir = package_cache_dir; + append_path(&ni_package_cache_dir, get_arch()); + } + // Obtain the local assemblies in the app dir. - get_local_assemblies(app_dir); + if (m_portable) + { + get_dir_assemblies(m_fx_dir, _X("fx"), &m_sxs_assemblies); + } + else + { + get_dir_assemblies(app_dir, _X("local"), &m_sxs_assemblies); + } std::set items; - add_mscorlib_to_tpa(clr_dir, &items, output); - - for (const deps_entry_t& entry : m_deps_entries) + auto process_entry = [&](bool is_portable, deps_json_t* deps, const deps_entry_t& entry) { // Is this asset a "runtime" type? - if (entry.asset_type != _X("runtime") || items.count(entry.asset_name)) + if (items.count(entry.asset_name)) { - continue; + return; } pal::string_t candidate; @@ -539,45 +294,63 @@ void deps_resolver_t::resolve_tpa_list( { add_tpa_asset(entry.asset_name, candidate, &items, output); } - // Is this entry present in the secondary package cache? + // Is an NI image for this entry present in the secondary package cache? + else if (entry.to_hash_matched_path(ni_package_cache_dir, &candidate)) + { + add_tpa_asset(entry.asset_name, candidate, &items, output); + } + // Is this entry present in the secondary package cache? (note: no .ni extension) else if (entry.to_hash_matched_path(package_cache_dir, &candidate)) { add_tpa_asset(entry.asset_name, candidate, &items, output); } // Is this entry present locally? - else if (m_local_assemblies.count(entry.asset_name)) + else if (!is_portable && m_sxs_assemblies.count(entry.asset_name)) { - // TODO: Case insensitive look up? - add_tpa_asset(entry.asset_name, m_local_assemblies.find(entry.asset_name)->second, &items, output); + add_tpa_asset(entry.asset_name, m_sxs_assemblies.find(entry.asset_name)->second, &items, output); } - // Is this entry present in the package restore dir? - else if (entry.to_full_path(package_dir, &candidate)) + // The app is portable so the asset should be picked up from relative subpath. + else if (is_portable && deps->try_ni(entry).to_full_path(app_dir, &candidate)) { add_tpa_asset(entry.asset_name, candidate, &items, output); } - } + // Is this entry present in the package restore dir? + else if (!package_dir.empty() && deps->try_ni(entry).to_full_path(package_dir, &candidate)) + { + add_tpa_asset(entry.asset_name, candidate, &items, output); + } + }; + + const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime); + std::for_each(deps_entries.begin(), deps_entries.end(), [&](const deps_entry_t& entry) { + process_entry(m_portable, m_deps.get(), entry); + }); + const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty; + std::for_each(fx_entries.begin(), fx_entries.end(), [&](const deps_entry_t& entry) { + process_entry(false, m_fx_deps.get(), entry); + }); // Finally, if the deps file wasn't present or has missing entries, then // add the app local assemblies to the TPA. - for (const auto& kv : m_local_assemblies) + for (const auto& kv : m_sxs_assemblies) { add_tpa_asset(kv.first, kv.second, &items, output); } } // ----------------------------------------------------------------------------- -// Resolve the directories order for culture/native lookup +// Resolve the directories order for resources/native lookup // // Description: // This general purpose function specifies priority order of directory lookup -// for both native images and culture specific resource images. Lookup for -// culture assemblies is done by looking up two levels above from the file +// for both native images and resources specific resource images. Lookup for +// resources assemblies is done by looking up two levels above from the file // path. Lookup for native images is done by looking up one level from the // file path. // // Parameters: // asset_type - The type of the asset that needs lookup, currently -// supports "culture" and "native" +// supports "resources" and "native" // app_dir - The application local directory // package_dir - The directory path to where packages are restored // package_cache_dir - The directory path to secondary cache for packages @@ -594,60 +367,89 @@ void deps_resolver_t::resolve_probe_dirs( const pal::string_t& clr_dir, pal::string_t* output) { - assert(asset_type == _X("culture") || asset_type == _X("native")); + assert(asset_type == _X("resources") || asset_type == _X("native")); - // For culture assemblies, we need to provide the base directory of the culture path. + // For resources assemblies, we need to provide the base directory of the resources path. // For example: .../Foo/en-US/Bar.dll, then, the resolved path is .../Foo - std::function culture = [] (const pal::string_t& str) { + std::function resources = [] (const pal::string_t& str) { return get_directory(get_directory(str)); }; // For native assemblies, obtain the directory path from the file path std::function native = [] (const pal::string_t& str) { return get_directory(str); }; - std::function& action = (asset_type == _X("culture")) ? culture : native; - + std::function& action = (asset_type == _X("resources")) ? resources : native; + deps_entry_t::asset_types entry_type = (asset_type == _X("resources")) ? deps_entry_t::asset_types::resources : deps_entry_t::asset_types::native; std::set items; + std::vector empty(0); + const auto& entries = m_deps->get_entries(entry_type); + const auto& fx_entries = m_portable ? m_fx_deps->get_entries(entry_type) : empty; + // Fill the "output" with serviced DLL directories if they are serviceable // and have an entry present. - for (const deps_entry_t& entry : m_deps_entries) + auto add_serviced_entry = [&](const deps_entry_t& entry) { pal::string_t redirection_path; - if (entry.is_serviceable && entry.asset_type == asset_type && entry.library_type == _X("Package") && + if (entry.is_serviceable && entry.library_type == _X("Package") && m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &redirection_path)) { add_unique_path(asset_type, action(redirection_path), &items, output); } - } + }; + + std::for_each(entries.begin(), entries.end(), add_serviced_entry); + std::for_each(fx_entries.begin(), fx_entries.end(), add_serviced_entry); pal::string_t candidate; // Take care of the secondary cache path if (!package_cache_dir.empty()) { - for (const deps_entry_t& entry : m_deps_entries) + auto add_package_cache_entry = [&](const deps_entry_t& entry) { - if (entry.asset_type == asset_type && entry.to_hash_matched_path(package_cache_dir, &candidate)) + if (entry.to_hash_matched_path(package_cache_dir, &candidate)) { add_unique_path(asset_type, action(candidate), &items, output); } - } + }; + std::for_each(entries.begin(), entries.end(), add_package_cache_entry); + std::for_each(fx_entries.begin(), fx_entries.end(), add_package_cache_entry); } // App local path add_unique_path(asset_type, app_dir, &items, output); - // Take care of the package restore path - if (!package_dir.empty()) + // For portable path, the app relative directory must be used. + if (m_portable) { - for (const deps_entry_t& entry : m_deps_entries) + std::for_each(entries.begin(), entries.end(), [&](const deps_entry_t& entry) { if (entry.asset_type == asset_type && entry.to_full_path(package_dir, &candidate)) { add_unique_path(asset_type, action(candidate), &items, output); } - } + }); + } + + // FX path if present + if (!m_fx_dir.empty()) + { + add_unique_path(asset_type, m_fx_dir, &items, output); + } + + // Take care of the package restore path + if (!package_dir.empty()) + { + auto add_packages_entry = [&](const deps_entry_t& entry) + { + if (entry.asset_type == asset_type && entry.to_full_path(package_dir, &candidate)) + { + add_unique_path(asset_type, action(candidate), &items, output); + } + }; + std::for_each(entries.begin(), entries.end(), add_packages_entry); + std::for_each(fx_entries.begin(), fx_entries.end(), add_packages_entry); } // CLR path @@ -656,7 +458,7 @@ void deps_resolver_t::resolve_probe_dirs( // ----------------------------------------------------------------------------- -// Entrypoint to resolve TPA, native and culture path ordering to pass to CoreCLR. +// Entrypoint to resolve TPA, native and resources path ordering to pass to CoreCLR. // // Parameters: // app_dir - The application local directory @@ -676,6 +478,6 @@ bool deps_resolver_t::resolve_probe_paths( { resolve_tpa_list(app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->tpa); resolve_probe_dirs(_X("native"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->native); - resolve_probe_dirs(_X("culture"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->culture); + resolve_probe_dirs(_X("resources"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->resources); return true; } diff --git a/src/corehost/cli/deps_resolver.h b/src/corehost/cli/deps_resolver.h index 309fce686..ce3d7c429 100644 --- a/src/corehost/cli/deps_resolver.h +++ b/src/corehost/cli/deps_resolver.h @@ -8,48 +8,45 @@ #include "pal.h" #include "trace.h" - +#include "deps_format.h" +#include "deps_entry.h" #include "servicing_index.h" - -struct deps_entry_t -{ - pal::string_t library_type; - pal::string_t library_name; - pal::string_t library_version; - pal::string_t library_hash; - pal::string_t asset_type; - pal::string_t asset_name; - pal::string_t relative_path; - bool is_serviceable; - - // Given a "base" dir, yield the relative path in the package layout. - bool to_full_path(const pal::string_t& root, pal::string_t* str) const; - - // Given a "base" dir, yield the relative path in the package layout only if - // the hash matches contents of the hash file. - bool to_hash_matched_path(const pal::string_t& root, pal::string_t* str) const; -}; +#include "runtime_config.h" // Probe paths to be resolved for ordering struct probe_paths_t { pal::string_t tpa; pal::string_t native; - pal::string_t culture; + pal::string_t resources; }; class deps_resolver_t { public: - deps_resolver_t(const arguments_t& args) + deps_resolver_t(const pal::string_t& fx_dir, const runtime_config_t* config, const arguments_t& args) : m_svc(args.dotnet_servicing) - , m_runtime_svc(args.dotnet_runtime_servicing) + , m_fx_dir(fx_dir) , m_coreclr_index(-1) + , m_portable(config->get_portable()) + , m_deps(nullptr) + , m_fx_deps(nullptr) { - m_deps_valid = parse_deps_file(args); + m_deps_file = args.deps_path; + if (m_portable) + { + m_fx_deps_file = get_fx_deps(fx_dir, config->get_fx_name()); + m_fx_deps = std::unique_ptr(new deps_json_t(false, m_fx_deps_file)); + m_deps = std::unique_ptr(new deps_json_t(true, m_deps_file, m_fx_deps->get_rid_fallback_graph())); + } + else + { + m_deps = std::unique_ptr(new deps_json_t(false, m_deps_file)); + } } - bool valid() { return m_deps_valid; } + + bool valid() { return m_deps->is_valid() && (!m_portable || m_fx_deps->is_valid()); } bool resolve_probe_paths( const pal::string_t& app_dir, @@ -63,11 +60,24 @@ public: const pal::string_t& package_dir, const pal::string_t& package_cache_dir); + const pal::string_t& get_fx_deps_file() const + { + return m_fx_deps_file; + } + + const pal::string_t& get_deps_file() const + { + return m_deps_file; + } private: - bool load(); - - bool parse_deps_file(const arguments_t& args); + static pal::string_t get_fx_deps(const pal::string_t& fx_dir, const pal::string_t& fx_name) + { + pal::string_t fx_deps = fx_dir; + pal::string_t fx_deps_name = pal::to_lower(fx_name) + _X(".deps.json"); + append_path(&fx_deps, fx_deps_name.c_str()); + return fx_deps; + } // Resolve order for TPA lookup. void resolve_tpa_list( @@ -86,30 +96,42 @@ private: const pal::string_t& clr_dir, pal::string_t* output); - // Populate local assemblies from app_dir listing. - void get_local_assemblies(const pal::string_t& dir); + // Populate assemblies from the directory. + void get_dir_assemblies( + const pal::string_t& dir, + const pal::string_t& dir_name, + std::unordered_map* dir_assemblies); // Servicing index to resolve serviced assembly paths. servicing_index_t m_svc; - // Runtime servicing directory. - pal::string_t m_runtime_svc; + // Framework deps file. + pal::string_t m_fx_dir; - // Map of simple name -> full path of local assemblies populated in priority - // order of their extensions. - std::unordered_map m_local_assemblies; - - // Entries in the dep file - std::vector m_deps_entries; + // Map of simple name -> full path of local/fx assemblies populated + // in priority order of their extensions. + std::unordered_map m_sxs_assemblies; // Special entry for coreclr in the deps entries int m_coreclr_index; - // The dep file path - pal::string_t m_deps_path; + // The filepath for the app deps + pal::string_t m_deps_file; + + // The filepath for the fx deps + pal::string_t m_fx_deps_file; + + // Deps files for the fx + std::unique_ptr m_fx_deps; + + // Deps files for the app + std::unique_ptr m_deps; // Is the deps file valid bool m_deps_valid; + + // Is the deps file portable app? + bool m_portable; }; #endif // DEPS_RESOLVER_H diff --git a/src/corehost/cli/dll/CMakeLists.txt b/src/corehost/cli/dll/CMakeLists.txt index 21248df7c..fd19ec602 100644 --- a/src/corehost/cli/dll/CMakeLists.txt +++ b/src/corehost/cli/dll/CMakeLists.txt @@ -13,16 +13,24 @@ endif() include(../setup.cmake) include_directories(../../common) +include_directories(../json/casablanca/include) # CMake does not recommend using globbing since it messes with the freshness checks set(SOURCES ../../common/trace.cpp ../../common/utils.cpp - + ../libhost.cpp + ../runtime_config.cpp + ../json/casablanca/src/json/json.cpp + ../json/casablanca/src/json/json_parsing.cpp + ../json/casablanca/src/json/json_serialization.cpp + ../json/casablanca/src/utilities/asyncrt_utils.cpp ../args.cpp ../hostpolicy.cpp ../coreclr.cpp ../deps_resolver.cpp + ../deps_format.cpp + ../deps_entry.cpp ../servicing_index.cpp) @@ -32,6 +40,8 @@ else() list(APPEND SOURCES ../../common/pal.unix.cpp) endif() +add_definitions(-D_NO_ASYNCRTIMP) +add_definitions(-D_NO_PPLXIMP) add_definitions(-DCOREHOST_MAKE_DLL=1) add_library(hostpolicy SHARED ${SOURCES}) diff --git a/src/corehost/cli/fxr/CMakeLists.txt b/src/corehost/cli/fxr/CMakeLists.txt new file mode 100644 index 000000000..43e0b54ca --- /dev/null +++ b/src/corehost/cli/fxr/CMakeLists.txt @@ -0,0 +1,45 @@ +# 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. + +cmake_minimum_required (VERSION 2.6) +project(hostpolicy) + +if(WIN32) + add_compile_options($<$:/MT>) + add_compile_options($<$:/MT>) + add_compile_options($<$:/MTd>) +endif() + +include(../setup.cmake) + +include_directories(../../common) +include_directories(../json/casablanca/include) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../../common/trace.cpp + ../../common/utils.cpp + ../../policy_load.cpp + ../libhost.cpp + ../runtime_config.cpp + ../json/casablanca/src/json/json.cpp + ../json/casablanca/src/json/json_parsing.cpp + ../json/casablanca/src/json/json_serialization.cpp + ../json/casablanca/src/utilities/asyncrt_utils.cpp + ./fx_ver.cpp + ./fx_muxer.cpp) + + +if(WIN32) + list(APPEND SOURCES ../../common/pal.windows.cpp) +else() + list(APPEND SOURCES ../../common/pal.unix.cpp) +endif() + +add_definitions(-D_NO_ASYNCRTIMP) +add_definitions(-D_NO_PPLXIMP) +add_definitions(-DCOREHOST_MAKE_DLL=1) + +add_library(hostfxr SHARED ${SOURCES}) + + diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp new file mode 100644 index 000000000..84ae55c1b --- /dev/null +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -0,0 +1,298 @@ +// 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. + +#include +#include "pal.h" +#include "utils.h" +#include "libhost.h" +#include "args.h" +#include "fx_ver.h" +#include "fx_muxer.h" +#include "trace.h" +#include "runtime_config.h" +#include "cpprest/json.h" +#include "corehost.h" +#include "policy_load.h" + +typedef web::json::value json_value; + +pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime, const pal::string_t& app_path) +{ + const auto fx_name = runtime->get_fx_name(); + const auto fx_ver = runtime->get_fx_version(); + const auto roll_fwd = runtime->get_fx_roll_fwd(); + + fx_ver_t specified(-1, -1, -1); + if (!fx_ver_t::parse(fx_ver, &specified, false)) + { + return pal::string_t(); + } + + auto fx_dir = muxer_dir; + append_path(&fx_dir, _X("Shared")); + append_path(&fx_dir, fx_name.c_str()); + + // If not roll forward or if pre-release, just return. + if (!roll_fwd || specified.is_prerelease()) + { + append_path(&fx_dir, fx_ver.c_str()); + } + else + { + std::vector list; + pal::readdir(fx_dir, &list); + fx_ver_t max_specified = specified; + for (const auto& version : list) + { + fx_ver_t ver(-1, -1, -1); + if (fx_ver_t::parse(version, &ver, true) && + ver.get_major() == max_specified.get_major() && + ver.get_minor() == max_specified.get_minor()) + { + max_specified.set_patch(std::max(ver.get_patch(), max_specified.get_patch())); + } + } + pal::string_t max_specified_str = max_specified.as_str(); + append_path(&fx_dir, max_specified_str.c_str()); + } + trace::verbose(_X("Found fx in: %s"), fx_dir.c_str()); + return pal::directory_exists(fx_dir) ? fx_dir : pal::string_t(); +} + +pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) +{ + pal::string_t retval; + if (!pal::file_exists(global_json)) + { + return retval; + } + + pal::ifstream_t file(global_json); + if (!file.good()) + { + return retval; + } + + try + { + const auto root = json_value::parse(file); + const auto& json = root.as_object(); + const auto sdk_iter = json.find(_X("sdk")); + if (sdk_iter == json.end() || sdk_iter->second.is_null()) + { + return retval; + } + + const auto& sdk_obj = sdk_iter->second.as_object(); + const auto ver_iter = sdk_obj.find(_X("version")); + if (ver_iter == sdk_obj.end() || ver_iter->second.is_null()) + { + return retval; + } + retval = ver_iter->second.as_string(); + } + catch (...) + { + } + trace::verbose(_X("Found cli in: %s"), retval.c_str()); + return retval; +} + +bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk) +{ + pal::string_t cwd; + pal::string_t global; + if (pal::getcwd(&cwd)) + { + for (pal::string_t parent_dir, cur_dir = cwd; true; cur_dir = parent_dir) + { + pal::string_t file = cur_dir; + append_path(&file, _X("global.json")); + if (pal::file_exists(file)) + { + global = file; + break; + } + parent_dir = get_directory(cur_dir); + if (parent_dir.empty() || parent_dir.size() == cur_dir.size()) + { + break; + } + } + } + pal::string_t retval; + if (!global.empty()) + { + pal::string_t cli_version = resolve_cli_version(global); + if (!cli_version.empty()) + { + pal::string_t sdk_path = own_dir; + append_path(&sdk_path, _X("sdk")); + append_path(&sdk_path, cli_version.c_str()); + if (pal::directory_exists(sdk_path)) + { + retval = sdk_path; + } + } + } + if (retval.empty()) + { + pal::string_t sdk_path = own_dir; + append_path(&sdk_path, _X("sdk")); + + std::vector versions; + pal::readdir(sdk_path, &versions); + fx_ver_t max_ver(-1, -1, -1); + for (const auto& version : versions) + { + fx_ver_t ver(-1, -1, -1); + if (fx_ver_t::parse(version, &ver, true)) + { + max_ver = std::max(ver, max_ver); + } + } + pal::string_t max_ver_str = max_ver.as_str(); + append_path(&sdk_path, max_ver_str.c_str()); + if (pal::directory_exists(sdk_path)) + { + retval = sdk_path; + } + } + cli_sdk->assign(retval); + trace::verbose(_X("Found cli sdk in: %s"), cli_sdk->c_str()); + return !retval.empty(); +} + +/* static */ +int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) +{ + pal::string_t own_path; + + // Get the full name of the application + if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path)) + { + trace::error(_X("Failed to locate current executable")); + return StatusCode::LibHostCurExeFindFailure; + } + + auto own_dir = get_directory(own_path); + + if (argc <= 1) + { + return StatusCode::InvalidArgFailure; + } + if (ends_with(argv[1], _X(".dll"), false)) + { + pal::string_t app_path = argv[1]; + + if (!pal::realpath(&app_path)) + { + return StatusCode::LibHostExecModeFailure; + } + + runtime_config_t config(get_runtime_config_json(app_path)); + if (!config.is_valid()) + { + trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); + return StatusCode::InvalidConfigFile; + } + if (config.get_portable()) + { + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config); + return policy_load_t::execute_app(fx_dir, &init, argc, argv); + } + else + { + corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config); + return policy_load_t::execute_app(get_directory(app_path), &init, argc, argv); + } + } + else + { + if (pal::strcasecmp(_X("exec"), argv[1]) == 0) + { + std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") }; + + int num_args = 0; + std::unordered_map opts; + if (!parse_known_args(argc - 2, &argv[2], known_opts, &opts, &num_args)) + { + return InvalidArgFailure; + } + int cur_i = 2 + num_args; + if (cur_i >= argc) + { + return InvalidArgFailure; + } + + // Transform dotnet exec [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args] + + std::vector new_argv(argc - cur_i + 1); // +1 for dotnet + memcpy(new_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*)); + new_argv[0] = argv[0]; + + pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : _X(""); + pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : _X(""); + + pal::string_t app_path = argv[cur_i]; + runtime_config_t config(get_runtime_config_json(app_path)); + if (!config.is_valid()) + { + trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); + return StatusCode::InvalidConfigFile; + } + if (config.get_portable()) + { + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + corehost_init_t init(deps_file, probe_path, fx_dir, host_mode_t::muxer, &config); + return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); + } + else + { + corehost_init_t init(deps_file, probe_path, _X(""), host_mode_t::muxer, &config); + pal::string_t impl_dir = get_directory(deps_file.empty() ? app_path : deps_file); + return policy_load_t::execute_app(impl_dir, &init, new_argv.size(), new_argv.data()); + } + } + else + { + pal::string_t sdk_dotnet; + if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet)) + { + return StatusCode::LibHostSdkFindFailure; + } + append_path(&sdk_dotnet, _X("dotnet.dll")); + // Transform dotnet [command] [args] -> dotnet [dotnet.dll] [command] [args] + + std::vector new_argv(argc + 1); + memcpy(&new_argv.data()[2], argv + 1, (argc - 1) * sizeof(pal::char_t*)); + new_argv[0] = argv[0]; + new_argv[1] = sdk_dotnet.c_str(); + + trace::verbose(_X("Using SDK dll=[%s]"), sdk_dotnet.c_str()); + + assert(ends_with(sdk_dotnet, _X(".dll"), false)); + + runtime_config_t config(get_runtime_config_json(sdk_dotnet)); + + if (config.get_portable()) + { + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, sdk_dotnet); + corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config); + return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); + } + else + { + corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config); + return policy_load_t::execute_app(get_directory(sdk_dotnet), &init, new_argv.size(), new_argv.data()); + } + } + } +} + +SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[]) +{ + trace::setup(); + return fx_muxer_t().execute(argc, argv); +} diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h new file mode 100644 index 000000000..de6518a4c --- /dev/null +++ b/src/corehost/cli/fxr/fx_muxer.h @@ -0,0 +1,16 @@ +// 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. + +class runtime_config_t; +struct fx_ver_t; + +class fx_muxer_t +{ +public: + static int execute(const int argc, const pal::char_t* argv[]); +private: + static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime, const pal::string_t& app_path); + static pal::string_t resolve_cli_version(const pal::string_t& global); + static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); +}; + diff --git a/src/corehost/cli/fxr/fx_ver.cpp b/src/corehost/cli/fxr/fx_ver.cpp new file mode 100644 index 000000000..7c81fb287 --- /dev/null +++ b/src/corehost/cli/fxr/fx_ver.cpp @@ -0,0 +1,168 @@ +// 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. + +#include +#include "pal.h" +#include "fx_ver.h" + +fx_ver_t::fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build) + : m_major(major) + , m_minor(minor) + , m_patch(patch) + , m_pre(pre) + , m_build(build) +{ +} + +fx_ver_t::fx_ver_t(int major, int minor, int patch, const pal::string_t& pre) + : fx_ver_t(major, minor, patch, pre, _X("")) +{ +} + +fx_ver_t::fx_ver_t(int major, int minor, int patch) + : fx_ver_t(major, minor, patch, _X(""), _X("")) +{ +} + +bool fx_ver_t::operator ==(const fx_ver_t& b) const +{ + return compare(*this, b) == 0; +} + +bool fx_ver_t::operator !=(const fx_ver_t& b) const +{ + return !operator ==(b); +} + +bool fx_ver_t::operator <(const fx_ver_t& b) const +{ + return compare(*this, b) < 0; +} + +bool fx_ver_t::operator >(const fx_ver_t& b) const +{ + return compare(*this, b) > 0; +} + +pal::string_t fx_ver_t::as_str() +{ + pal::stringstream_t stream; + stream << m_major << _X(".") << m_minor << _X(".") << m_patch; + if (!m_pre.empty()) + { + stream << m_pre; + } + if (!m_build.empty()) + { + stream << _X("+") << m_build; + } + return stream.str(); +} + +/* static */ +int fx_ver_t::compare(const fx_ver_t&a, const fx_ver_t& b, bool ignore_build) +{ + // compare(u.v.w-p+b, x.y.z-q+c) + return + (a.m_major == b.m_major) + ? ((a.m_minor == b.m_minor) + ? ((a.m_patch == b.m_patch) + ? ((a.m_pre.empty() == b.m_pre.empty()) + ? ((a.m_pre.empty()) + ? (ignore_build ? 0 : a.m_build.compare(b.m_build)) + : a.m_pre.compare(b.m_pre)) + : a.m_pre.empty() ? 1 : -1) + : (a.m_patch > b.m_patch ? 1 : -1)) + : (a.m_minor > b.m_minor ? 1 : -1)) + : ((a.m_major > b.m_major) ? 1 : -1) + ; +} + +bool try_stou(const pal::string_t& str, unsigned* num) +{ + if (str.empty()) + { + return false; + } + if (str.find_first_not_of(_X("0123456789")) != pal::string_t::npos) + { + return false; + } + *num = (unsigned) std::stoul(str); + return true; +} + +bool parse_internal(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production) +{ + size_t maj_start = 0; + size_t maj_sep = ver.find(_X('.')); + if (maj_sep == pal::string_t::npos) + { + return false; + } + unsigned major = 0; + if (!try_stou(ver.substr(maj_start, maj_sep), &major)) + { + return false; + } + + size_t min_start = maj_sep + 1; + size_t min_sep = ver.find(_X('.'), min_start); + if (min_sep == pal::string_t::npos) + { + return false; + } + + unsigned minor = 0; + if (!try_stou(ver.substr(min_start, min_sep - min_start), &minor)) + { + return false; + } + + unsigned patch = 0; + size_t pat_start = min_sep + 1; + size_t pat_sep = ver.find_first_not_of(_X("0123456789"), pat_start); + if (pat_sep == pal::string_t::npos) + { + if (!try_stou(ver.substr(pat_start), &patch)) + { + return false; + } + + *fx_ver = fx_ver_t(major, minor, patch); + return true; + } + + if (parse_only_production) + { + // This is a prerelease or has build suffix. + return false; + } + + if (!try_stou(ver.substr(pat_start, pat_sep - pat_start), &patch)) + { + return false; + } + + size_t pre_start = pat_sep; + size_t pre_sep = ver.find(_X('+'), pre_start); + if (pre_sep == pal::string_t::npos) + { + *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start)); + return true; + } + else + { + size_t build_start = pre_sep + 1; + *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start, pre_sep - pre_start), ver.substr(build_start)); + return true; + } +} + +/* static */ +bool fx_ver_t::parse(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production) +{ + bool valid = parse_internal(ver, fx_ver, parse_only_production); + assert(!valid || fx_ver->as_str() == ver); + return valid; +} diff --git a/src/corehost/cli/fxr/fx_ver.h b/src/corehost/cli/fxr/fx_ver.h new file mode 100644 index 000000000..180426737 --- /dev/null +++ b/src/corehost/cli/fxr/fx_ver.h @@ -0,0 +1,40 @@ +// 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. + +#include "pal.h" + +struct fx_ver_t +{ + fx_ver_t(int major, int minor, int patch); + fx_ver_t(int major, int minor, int patch, const pal::string_t& pre); + fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build); + + int get_major() { return m_major; } + int get_minor() { return m_minor; } + int get_patch() { return m_patch; } + + void set_major(int m) { m_major = m; } + void set_minor(int m) { m_minor = m; } + void set_patch(int p) { m_patch = p; } + + bool is_prerelease() { return !m_pre.empty(); } + + pal::string_t as_str(); + + bool operator ==(const fx_ver_t& b) const; + bool operator !=(const fx_ver_t& b) const; + bool operator <(const fx_ver_t& b) const; + bool operator >(const fx_ver_t& b) const; + + static bool parse(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production = false); + +private: + int m_major; + int m_minor; + int m_patch; + pal::string_t m_pre; + pal::string_t m_build; + + static int compare(const fx_ver_t&a, const fx_ver_t& b, bool ignore_build = false); +}; + diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index b087357c8..32bdb924d 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -5,25 +5,21 @@ #include "args.h" #include "trace.h" #include "deps_resolver.h" +#include "fx_muxer.h" #include "utils.h" #include "coreclr.h" +#include "cpprest/json.h" +#include "libhost.h" +#include "error_codes.h" -enum StatusCode -{ - // 0x80 prefix to distinguish from corehost main's error codes. - InvalidArgFailure = 0x81, - CoreClrResolveFailure = 0x82, - CoreClrBindFailure = 0x83, - CoreClrInitFailure = 0x84, - CoreClrExeFailure = 0x85, - ResolverInitFailure = 0x86, - ResolverResolveFailure = 0x87, -}; -int run(const arguments_t& args) +corehost_init_t* g_init = nullptr; + +int run(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args) { // Load the deps resolver - deps_resolver_t resolver(args); + deps_resolver_t resolver(init->fx_dir(), &config, args); + if (!resolver.valid()) { trace::error(_X("Invalid .deps file")); @@ -31,8 +27,8 @@ int run(const arguments_t& args) } // Add packages directory - pal::string_t packages_dir = args.nuget_packages; - if (!pal::directory_exists(packages_dir)) + pal::string_t packages_dir = init->probe_dir(); + if (packages_dir.empty() || !pal::directory_exists(packages_dir)) { (void)pal::get_default_packages_directory(&packages_dir); } @@ -55,6 +51,8 @@ int run(const arguments_t& args) return StatusCode::ResolverResolveFailure; } + // TODO: config.get_runtime_properties(); + // Build CoreCLR properties const char* property_keys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", @@ -63,20 +61,22 @@ int run(const arguments_t& args) "NATIVE_DLL_SEARCH_DIRECTORIES", "PLATFORM_RESOURCE_ROOTS", "AppDomainCompatSwitch", - // TODO: pipe this from corehost.json "SERVER_GC", // Workaround: mscorlib does not resolve symlinks for AppContext.BaseDirectory dotnet/coreclr/issues/2128 "APP_CONTEXT_BASE_DIRECTORY", + "APP_CONTEXT_DEPS_FILES" }; auto tpa_paths_cstr = pal::to_stdstring(probe_paths.tpa); auto app_base_cstr = pal::to_stdstring(args.app_dir); auto native_dirs_cstr = pal::to_stdstring(probe_paths.native); - auto culture_dirs_cstr = pal::to_stdstring(probe_paths.culture); + auto resources_dirs_cstr = pal::to_stdstring(probe_paths.resources); // Workaround for dotnet/cli Issue #488 and #652 pal::string_t server_gc; std::string server_gc_cstr = (pal::getenv(_X("COREHOST_SERVER_GC"), &server_gc) && !server_gc.empty()) ? pal::to_stdstring(server_gc) : "0"; + + std::string deps = pal::to_stdstring(resolver.get_deps_file() + _X(";") + resolver.get_fx_deps_file()); const char* property_values[] = { // TRUSTED_PLATFORM_ASSEMBLIES @@ -88,13 +88,15 @@ int run(const arguments_t& args) // NATIVE_DLL_SEARCH_DIRECTORIES native_dirs_cstr.c_str(), // PLATFORM_RESOURCE_ROOTS - culture_dirs_cstr.c_str(), + resources_dirs_cstr.c_str(), // AppDomainCompatSwitch "UseLatestBehaviorWhenTFMNotSpecified", // SERVER_GC server_gc_cstr.c_str(), // APP_CONTEXT_BASE_DIRECTORY - app_base_cstr.c_str() + app_base_cstr.c_str(), + // APP_CONTEXT_DEPS_FILES, + deps.c_str(), }; size_t property_size = sizeof(property_keys) / sizeof(property_keys[0]); @@ -188,16 +190,43 @@ int run(const arguments_t& args) return exit_code; } +SHARED_API int corehost_load(corehost_init_t* init) +{ + g_init = init; + return 0; +} + SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) { trace::setup(); + assert(g_init); + // Take care of arguments arguments_t args; - if (!parse_arguments(argc, argv, args)) + if (!parse_arguments(g_init->deps_file(), g_init->probe_dir(), g_init->host_mode(), argc, argv, &args)) { - return StatusCode::InvalidArgFailure; + return StatusCode::LibHostInvalidArgs; } - return run(args); + if (g_init->runtime_config()) + { + return run(g_init, *g_init->runtime_config(), args); + } + else + { + runtime_config_t config(get_runtime_config_json(args.managed_application)); + if (!config.is_valid()) + { + trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); + return StatusCode::InvalidConfigFile; + } + return run(g_init, config, args); + } +} + +SHARED_API int corehost_unload() +{ + g_init = nullptr; + return 0; } diff --git a/src/corehost/cli/json/casablanca/LICENSE.txt b/src/corehost/cli/json/casablanca/LICENSE.txt new file mode 100644 index 000000000..314f8097f --- /dev/null +++ b/src/corehost/cli/json/casablanca/LICENSE.txt @@ -0,0 +1 @@ +https://github.com/Microsoft/cpprestsdk diff --git a/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h b/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h new file mode 100644 index 000000000..c100ece52 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h @@ -0,0 +1,600 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Various common utilities. +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "cpprest/details/basic_types.h" + +#if !defined(_WIN32) || (_MSC_VER >= 1700) +#include +#endif + +#ifndef _WIN32 +//#include +#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 +#include +#endif +#endif + +/// Various utilities for string conversions and date and time manipulation. +namespace utility +{ + +// Left over from VS2010 support, remains to avoid breaking. +typedef std::chrono::seconds seconds; + +/// Functions for converting to/from std::chrono::seconds to xml string. +namespace timespan +{ + /// + /// Converts a timespan/interval in seconds to xml duration string as specified by + /// http://www.w3.org/TR/xmlschema-2/#duration + /// + _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs); + + /// + /// Converts an xml duration to timespan/interval in seconds + /// http://www.w3.org/TR/xmlschema-2/#duration + /// + _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t ×panString); +} + +/// Functions for Unicode string conversions. +namespace conversions +{ + /// + /// Converts a UTF-16 string to a UTF-8 string. + /// + /// A two byte character UTF-16 string. + /// A single byte character UTF-8 string. + _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w); + + /// + /// Converts a UTF-8 string to a UTF-16 + /// + /// A single byte character UTF-8 string. + /// A two byte character UTF-16 string. + _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s); + + /// + /// Converts a ASCII (us-ascii) string to a UTF-16 string. + /// + /// A single byte character us-ascii string. + /// A two byte character UTF-16 string. + _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s); + + /// + /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string. + /// + /// A single byte character UTF-8 string. + /// A two byte character UTF-16 string. + _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s); + + /// + /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string. + /// + /// A single byte character UTF-8 string. + /// A single byte character UTF-8 string. + _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s); + + /// + /// Converts to a platform dependent Unicode string type. + /// + /// A single byte character UTF-8 string. + /// A platform dependent string type. + _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s); + + /// + /// Converts to a platform dependent Unicode string type. + /// + /// A two byte character UTF-16 string. + /// A platform dependent string type. + _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s); + + /// + /// Converts to a platform dependent Unicode string type. + /// + /// A single byte character UTF-8 string. + /// A platform dependent string type. + _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s); + + /// + /// Converts to a platform dependent Unicode string type. + /// + /// A two byte character UTF-16 string. + /// A platform dependent string type. + _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s); + + /// + /// Converts to a UTF-16 from string. + /// + /// A single byte character UTF-8 string. + /// A two byte character UTF-16 string. + _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value); + + /// + /// Converts to a UTF-16 from string. + /// + /// A two byte character UTF-16 string. + /// A two byte character UTF-16 string. + _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value); + + /// + /// Converts to a UTF-8 string. + /// + /// A single byte character UTF-8 string. + /// A single byte character UTF-8 string. + _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value); + + /// + /// Converts to a UTF-8 string. + /// + /// A two byte character UTF-16 string. + /// A single byte character UTF-8 string. + _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value); + + /// + /// Encode the given byte array into a base64 string + /// + _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data); + + /// + /// Encode the given 8-byte integer into a base64 string + /// + _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data); + + /// + /// Decode the given base64 string to a byte array + /// + _ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); + + template + utility::string_t print_string(const Source &val, const std::locale &loc) + { + utility::ostringstream_t oss; + oss.imbue(loc); + oss << val; + if (oss.bad()) + { + throw std::bad_cast(); + } + return oss.str(); + } + + template + utility::string_t print_string(const Source &val) + { + return print_string(val, std::locale()); + } + + template + Target scan_string(const utility::string_t &str, const std::locale &loc) + { + Target t; + utility::istringstream_t iss(str); + iss.imbue(loc); + iss >> t; + if (iss.bad()) + { + throw std::bad_cast(); + } + return t; + } + + template + Target scan_string(const utility::string_t &str) + { + return scan_string(str, std::locale()); + } +} + +namespace details +{ + /// + /// Cross platform RAII container for setting thread local locale. + /// + class scoped_c_thread_locale + { + public: + _ASYNCRTIMP scoped_c_thread_locale(); + _ASYNCRTIMP ~scoped_c_thread_locale(); + +#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 +#ifdef _WIN32 + typedef _locale_t xplat_locale; +#else + typedef locale_t xplat_locale; +#endif + + static _ASYNCRTIMP xplat_locale __cdecl c_locale(); +#endif + private: +#ifdef _WIN32 + std::string m_prevLocale; + int m_prevThreadSetting; +#elif !(defined(ANDROID) || defined(__ANDROID__)) + locale_t m_prevLocale; +#endif + scoped_c_thread_locale(const scoped_c_thread_locale &); + scoped_c_thread_locale & operator=(const scoped_c_thread_locale &); + }; + + /// + /// Our own implementation of alpha numeric instead of std::isalnum to avoid + /// taking global lock for performance reasons. + /// + inline bool __cdecl is_alnum(char ch) + { + return (ch >= '0' && ch <= '9') + || (ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z'); + } + + /// + /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates + /// and therefore not be compatible with Dev10. + /// + template + std::unique_ptr<_Type> make_unique() { + return std::unique_ptr<_Type>(new _Type()); + } + + template + std::unique_ptr<_Type> make_unique(_Arg1&& arg1) { + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1))); + } + + template + std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) { + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2))); + } + + template + std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) { + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3))); + } + + template + std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) { + return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4))); + } + + /// + /// Cross platform utility function for performing case insensitive string comparision. + /// + /// First string to compare. + /// Second strong to compare. + /// true if the strings are equivalent, false otherwise +/* inline bool str_icmp(const utility::string_t &left, const utility::string_t &right) + { +#ifdef _WIN32 + return _wcsicmp(left.c_str(), right.c_str()) == 0; +#else + return boost::iequals(left, right); +#endif + } +*/ +#ifdef _WIN32 + +/// +/// Category error type for Windows OS errors. +/// +class windows_category_impl : public std::error_category +{ +public: + virtual const char *name() const CPPREST_NOEXCEPT { return "windows"; } + + _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; + + _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT; +}; + +/// +/// Gets the one global instance of the windows error category. +/// +/// An error category instance. +_ASYNCRTIMP const std::error_category & __cdecl windows_category(); + +#else + +/// +/// Gets the one global instance of the linux error category. +/// +/// An error category instance. +_ASYNCRTIMP const std::error_category & __cdecl linux_category(); + +#endif + +/// +/// Gets the one global instance of the current platform's error category. +/// +_ASYNCRTIMP const std::error_category & __cdecl platform_category(); + +/// +/// Creates an instance of std::system_error from a OS error code. +/// +inline std::system_error __cdecl create_system_error(unsigned long errorCode) +{ + std::error_code code((int)errorCode, platform_category()); + return std::system_error(code, code.message()); +} + +/// +/// Creates a std::error_code from a OS error code. +/// +inline std::error_code __cdecl create_error_code(unsigned long errorCode) +{ + return std::error_code((int)errorCode, platform_category()); +} + +/// +/// Creates the corresponding error message from a OS error code. +/// +inline utility::string_t __cdecl create_error_message(unsigned long errorCode) +{ + return utility::conversions::to_string_t(create_error_code(errorCode).message()); +} + +} + +class datetime +{ +public: + typedef uint64_t interval_type; + + /// + /// Defines the supported date and time string formats. + /// + enum date_format { RFC_1123, ISO_8601 }; + + /// + /// Returns the current UTC time. + /// + // static _ASYNCRTIMP datetime __cdecl utc_now(); + + /// + /// An invalid UTC timestamp value. + /// + enum:interval_type { utc_timestamp_invalid = static_cast(-1) }; + + /// + /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00. + /// If time is before epoch, utc_timestamp_invalid is returned. + /// + /* + static interval_type utc_timestamp() + { + const auto seconds = utc_now().to_interval() / _secondTicks; + if (seconds >= 11644473600LL) + { + return seconds - 11644473600LL; + } + else + { + return utc_timestamp_invalid; + } + } + */ + + datetime() : m_interval(0) + { + } + + /// + /// Creates datetime from a string representing time in UTC in RFC 1123 format. + /// + /// Returns a datetime of zero if not successful. + // static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123); + + /// + /// Returns a string representation of the datetime. + /// + _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const; + + /// + /// Returns the integral time value. + /// + interval_type to_interval() const + { + return m_interval; + } + + datetime operator- (interval_type value) const + { + return datetime(m_interval - value); + } + + datetime operator+ (interval_type value) const + { + return datetime(m_interval + value); + } + + bool operator== (datetime dt) const + { + return m_interval == dt.m_interval; + } + + bool operator!= (const datetime& dt) const + { + return !(*this == dt); + } + + static interval_type from_milliseconds(unsigned int milliseconds) + { + return milliseconds*_msTicks; + } + + static interval_type from_seconds(unsigned int seconds) + { + return seconds*_secondTicks; + } + + static interval_type from_minutes(unsigned int minutes) + { + return minutes*_minuteTicks; + } + + static interval_type from_hours(unsigned int hours) + { + return hours*_hourTicks; + } + + static interval_type from_days(unsigned int days) + { + return days*_dayTicks; + } + + bool is_initialized() const + { + return m_interval != 0; + } + +private: + + friend int operator- (datetime t1, datetime t2); + + static const interval_type _msTicks = static_cast(10000); + static const interval_type _secondTicks = 1000*_msTicks; + static const interval_type _minuteTicks = 60*_secondTicks; + static const interval_type _hourTicks = 60*60*_secondTicks; + static const interval_type _dayTicks = 24*60*60*_secondTicks; + + +#ifdef _WIN32 + // void* to avoid pulling in windows.h + static _ASYNCRTIMP bool __cdecl datetime::system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt); +#else + static datetime timeval_to_datetime(const timeval &time); +#endif + + // Private constructor. Use static methods to create an instance. + datetime(interval_type interval) : m_interval(interval) + { + } + + // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns. + interval_type m_interval; +}; + +#ifndef _WIN32 + +// temporary workaround for the fact that +// utf16char is not fully supported in GCC +class cmp +{ +public: + + static int icmp(std::string left, std::string right) + { + size_t i; + for (i = 0; i < left.size(); ++i) + { + if (i == right.size()) return 1; + + auto l = cmp::tolower(left[i]); + auto r = cmp::tolower(right[i]); + if (l > r) return 1; + if (l < r) return -1; + } + if (i < right.size()) return -1; + return 0; + } + +private: + static char tolower(char c) + { + if (c >= 'A' && c <= 'Z') + return static_cast(c - 'A' + 'a'); + return c; + } +}; + +#endif + +inline int operator- (datetime t1, datetime t2) +{ + auto diff = (t1.m_interval - t2.m_interval); + + // Round it down to seconds + diff /= 10 * 1000 * 1000; + + return static_cast(diff); +} + +/* +/// +/// Nonce string generator class. +/// +class nonce_generator +{ +public: + + /// + /// Define default nonce length. + /// + enum { default_length = 32 }; + + /// + /// Nonce generator constructor. + /// + /// Length of the generated nonce string. + nonce_generator(int length=default_length) : + m_random(static_cast(utility::datetime::utc_timestamp())), + m_length(length) + {} + + /// + /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9). + /// Length of the generated string is set by length(). + /// + /// The generated nonce string. + _ASYNCRTIMP utility::string_t generate(); + + /// + /// Get length of generated nonce string. + /// + /// Nonce string length. + int length() const { return m_length; } + + /// + /// Set length of the generated nonce string. + /// + /// Lenght of nonce string. + void set_length(int length) { m_length = length; } + +private: + static const utility::string_t c_allowed_chars; + std::mt19937 m_random; + int m_length; +}; +*/ +} // namespace utility; diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp b/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp new file mode 100755 index 000000000..798012bed --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp @@ -0,0 +1,7048 @@ +/*----------------------------------------------------------------------------------------------------------- +SafeInt.hpp +Version 3.0.18p + +This software is licensed under the Microsoft Public License (Ms-PL). +For more information about Microsoft open source licenses, refer to +http://www.microsoft.com/opensource/licenses.mspx + +This license governs use of the accompanying software. If you use the software, you accept this license. +If you do not accept the license, do not use the software. + +Definitions +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here +as under U.S. copyright law. A "contribution" is the original software, or any additions or changes to +the software. A "contributor" is any person that distributes its contribution under this license. +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +Grant of Rights +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations +in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to +reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution +or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in +section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed +patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution +in the software or derivative works of the contribution in the software. + +Conditions and Limitations +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, + or trademarks. +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the + software, your patent license from such contributor to the software ends automatically. +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and + attribution notices that are present in the software. +(D) If you distribute any portion of the software in source code form, you may do so only under this license + by including a complete copy of this license with your distribution. If you distribute any portion of the + software in compiled or object code form, you may only do so under a license that complies with this license. +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, + guarantees, or conditions. You may have additional consumer rights under your local laws which this license + cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties + of merchantability, fitness for a particular purpose and non-infringement. + + +Copyright (c) Microsoft Corporation. All rights reserved. + +This header implements an integer handling class designed to catch +unsafe integer operations + +This header compiles properly at Wall on Visual Studio, -Wall on gcc, and -Weverything on clang. + +Please read the leading comments before using the class. +---------------------------------------------------------------*/ +#pragma once + +// It is a bit tricky to sort out what compiler we are actually using, +// do this once here, and avoid cluttering the code +#define VISUAL_STUDIO_COMPILER 0 +#define CLANG_COMPILER 1 +#define GCC_COMPILER 2 +#define UNKNOWN_COMPILER -1 + +// Clang will sometimes pretend to be Visual Studio +// and does pretend to be gcc. Check it first, as nothing else pretends to be clang +#if defined __clang__ +#define SAFEINT_COMPILER CLANG_COMPILER +#elif defined __GNUC__ +#define SAFEINT_COMPILER GCC_COMPILER +#elif defined _MSC_VER +#define SAFEINT_COMPILER VISUAL_STUDIO_COMPILER +#else +#define SAFEINT_COMPILER UNKNOWN_COMPILER +#endif + +// Enable compiling with /Wall under VC +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning( push ) +// Disable warnings coming from headers +#pragma warning( disable:4987 4820 4987 4820 ) + +#endif + +// Need this for ptrdiff_t on some compilers +#include +#include + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64 + #include + #define SAFEINT_USE_INTRINSICS 1 +#else + #define SAFEINT_USE_INTRINSICS 0 +#endif + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning( pop ) +#endif + +// Various things needed for GCC +#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER + +#define NEEDS_INT_DEFINED + +#if !defined NULL +#define NULL 0 +#endif + +// GCC warning suppression +#if SAFEINT_COMPILER == GCC_COMPILER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif + +#include + +// clang only +#if SAFEINT_COMPILER == CLANG_COMPILER + +#if __has_feature(cxx_nullptr) + #define NEEDS_NULLPTR_DEFINED 0 +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif + +#endif + +// If the user made a choice, respect it #if !defined +#if !defined NEEDS_NULLPTR_DEFINED + // Visual Studio 2010 and higher support this + #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER + #if (_MSC_VER < 1600) + #define NEEDS_NULLPTR_DEFINED 1 + #else + #define NEEDS_NULLPTR_DEFINED 0 + #endif + #else + // Let everything else trigger based on whether we use c++11 or above + #if __cplusplus >= 201103L + #define NEEDS_NULLPTR_DEFINED 0 + #else + #define NEEDS_NULLPTR_DEFINED 1 + #endif + #endif +#endif + +#if NEEDS_NULLPTR_DEFINED +#define nullptr NULL +#endif + +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +// Let's test some assumptions +// We're assuming two's complement negative numbers +C_ASSERT( -1 == static_cast(0xffffffff) ); + +/************* Compiler Options ***************************************************************************************************** + +SafeInt supports several compile-time options that can change the behavior of the class. + +Compiler options: +SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this option is not + recommended. +NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16, __int32 and __int64, you can enable this. +SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert and figure out a problem than to try and figure out + how you landed in the catch block. +SafeIntDefaultExceptionHandler - if you'd like to replace the exception handlers SafeInt provides, define your replacement and + define this. Note - two built in (Windows-specific) options exist: + - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an exception + - SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught +SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to completely fail + to compile, define this. +ANSI_CONVERSIONS - This changes the class to use default comparison behavior, which may be unsafe. Enabling this + option is not recommended. +SAFEINT_DISABLE_BINARY_ASSERT - binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do + this, the default is to assert. Set this if you prefer not to assert under these conditions. +SIZE_T_CAST_NEEDED - some compilers complain if there is not a cast to size_t, others complain if there is one. + This lets you not have your compiler complain. +SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than the type has. Enabling + this option is not recommended. + +************************************************************************************************************************************/ + +/* +* The SafeInt class is designed to have as low an overhead as possible +* while still ensuring that all integer operations are conducted safely. +* Nearly every operator has been overloaded, with a very few exceptions. +* +* A usability-safety trade-off has been made to help ensure safety. This +* requires that every operation return either a SafeInt or a bool. If we +* allowed an operator to return a base integer type T, then the following +* can happen: +* +* char i = SafeInt(32) * 2 + SafeInt(16) * 4; +* +* The * operators take precedence, get overloaded, return a char, and then +* you have: +* +* char i = (char)64 + (char)64; //overflow! +* +* This situation would mean that safety would depend on usage, which isn't +* acceptable. +* +* One key operator that is missing is an implicit cast to type T. The reason for +* this is that if there is an implicit cast operator, then we end up with +* an ambiguous compile-time precedence. Because of this amiguity, there +* are two methods that are provided: +* +* Casting operators for every native integer type +* Version 3 note - it now compiles correctly for size_t without warnings +* +* SafeInt::Ptr() - returns the address of the internal integer +* Note - the '&' (address of) operator has been overloaded and returns +* the address of the internal integer. +* +* The SafeInt class should be used in any circumstances where ensuring +* integrity of the calculations is more important than performance. See Performance +* Notes below for additional information. +* +* Many of the conditionals will optimize out or be inlined for a release +* build (especially with /Ox), but it does have significantly more overhead, +* especially for signed numbers. If you do not _require_ negative numbers, use +* unsigned integer types - certain types of problems cannot occur, and this class +* performs most efficiently. +* +* Here's an example of when the class should ideally be used - +* +* void* AllocateMemForStructs(int StructSize, int HowMany) +* { +* SafeInt s(StructSize); +* +* s *= HowMany; +* +* return malloc(s); +* +* } +* +* Here's when it should NOT be used: +* +* void foo() +* { +* int i; +* +* for(i = 0; i < 0xffff; i++) +* .... +* } +* +* Error handling - a SafeInt class will throw exceptions if something +* objectionable happens. The exceptions are SafeIntException classes, +* which contain an enum as a code. +* +* Typical usage might be: +* +* bool foo() +* { +* SafeInt s; //note that s == 0 unless set +* +* try{ +* s *= 23; +* .... +* } +* catch(SafeIntException err) +* { +* //handle errors here +* } +* } +* +* Update for 3.0 - the exception class is now a template parameter. +* You can replace the exception class with any exception class you like. This is accomplished by: +* 1) Create a class that has the following interface: +* + template <> class YourSafeIntExceptionHandler < YourException > + { + public: + static __declspec(noreturn) void __stdcall SafeIntOnOverflow() + { + throw YourException( YourSafeIntArithmeticOverflowError ); + } + + static __declspec(noreturn) void __stdcall SafeIntOnDivZero() + { + throw YourException( YourSafeIntDivideByZeroError ); + } + }; +* +* Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do +* anything you like, just don't return from the call back into the code. +* +* 2) Either explicitly declare SafeInts like so: +* SafeInt< int, YourSafeIntExceptionHandler > si; +* or +* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler +* +* Performance: +* +* Due to the highly nested nature of this class, you can expect relatively poor +* performance in unoptimized code. In tests of optimized code vs. correct inline checks +* in native code, this class has been found to take approximately 8% more CPU time (this varies), +* most of which is due to exception handling. Solutions: +* +* 1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1 +* (optimize for size) does not work as well. +* 2) If that 8% hit is really a serious problem, walk through the code and inline the +* exact same checks as the class uses. +* 3) Some operations are more difficult than others - avoid using signed integers, and if +* possible keep them all the same size. 64-bit integers are also expensive. Mixing +* different integer sizes and types may prove expensive. Be aware that literals are +* actually ints. For best performance, cast literals to the type desired. +* +* +* Performance update +* The current version of SafeInt uses template specialization to force the compiler to invoke only the +* operator implementation needed for any given pair of types. This will dramatically improve the perf +* of debug builds. +* +* 3.0 update - not only have we maintained the specialization, there were some cases that were overly complex, +* and using some additional cases (e.g. signed __int64 and unsigned __int64) resulted in some simplification. +* Additionally, there was a lot of work done to better optimize the 64-bit multiplication. +* +* Binary Operators +* +* All of the binary operators have certain assumptions built into the class design. +* This is to ensure correctness. Notes on each class of operator follow: +* +* Arithmetic Operators (*,/,+,-,%) +* There are three possible variants: +* SafeInt< T, E > op SafeInt< T, E > +* SafeInt< T, E > op U +* U op SafeInt< T, E > +* +* The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do +* this the compiler with throw the following error: +* +* error C2593: 'operator *' is ambiguous +* +* This is because the arithmetic operators are required to return a SafeInt of some type. +* The compiler cannot know whether you'd prefer to get a type T or a type U returned. If +* you need to do this, you need to extract the value contained within one of the two using +* the casting operator. For example: +* +* SafeInt< T, E > t, result; +* SafeInt< U, E > u; +* +* result = t * (U)u; +* +* Comparison Operators +* Because each of these operators return type bool, mixing SafeInts of differing types is +* allowed. +* +* Shift Operators +* Shift operators always return the type on the left hand side of the operator. Mixed type +* operations are allowed because the return type is always known. +* +* Boolean Operators +* Like comparison operators, these overloads always return type bool, and mixed-type SafeInts +* are allowed. Additionally, specific overloads exist for type bool on both sides of the +* operator. +* +* Binary Operators +* Mixed-type operations are discouraged, however some provision has been made in order to +* enable things like: +* +* SafeInt c = 2; +* +* if(c & 0x02) +* ... +* +* The "0x02" is actually an int, and it needs to work. +* In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner +* cases do exist where you could get unexpected results. In any case where SafeInt returns a different +* result than the underlying operator, it will call assert(). You should examine your code and cast things +* properly so that you are not programming with side effects. +* +* Documented issues: +* +* This header compiles correctly at /W4 using VC++ 8 (Version 14.00.50727.42) and later. +* As of this writing, I believe it will also work for VC 7.1, but not for VC 7.0 or below. +* If you need a version that will work with lower level compilers, try version 1.0.7. None +* of them work with Visual C++ 6, and gcc didn't work very well, either, though this hasn't +* been tried recently. +* +* It is strongly recommended that any code doing integer manipulation be compiled at /W4 +* - there are a number of warnings which pertain to integer manipulation enabled that are +* not enabled at /W3 (default for VC++) +* +* Perf note - postfix operators are slightly more costly than prefix operators. +* Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++ +* +* The comparison operator behavior in this class varies from the ANSI definition, which is +* arguably broken. As an example, consider the following: +* +* unsigned int l = 0xffffffff; +* char c = -1; +* +* if(c == l) +* printf("Why is -1 equal to 4 billion???\n"); +* +* The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets +* cast again to an unsigned int, losing the true value. This behavior is despite the fact that +* an __int64 exists, and the following code will yield a different (and intuitively correct) +* answer: +* +* if((__int64)c == (__int64)l)) +* printf("Why is -1 equal to 4 billion???\n"); +* else +* printf("Why doesn't the compiler upcast to 64-bits when needed?\n"); +* +* Note that combinations with smaller integers won't display the problem - if you +* changed "unsigned int" above to "unsigned short", you'd get the right answer. +* +* If you prefer to retain the ANSI standard behavior insert +* #define ANSI_CONVERSIONS +* into your source. Behavior differences occur in the following cases: +* 8, 16, and 32-bit signed int, unsigned 32-bit int +* any signed int, unsigned 64-bit int +* Note - the signed int must be negative to show the problem +* +* +* Revision history: +* +* Oct 12, 2003 - Created +* Author - David LeBlanc - dleblanc@microsoft.com +* +* Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson +* Dec 28, 2003 - 1.0 +* added support for mixed-type operations +* thanks to vikramh +* also fixed broken __int64 multiplication section +* added extended support for mixed-type operations where possible +* Jan 28, 2004 - 1.0.1 +* changed WCHAR to wchar_t +* fixed a construct in two mixed-type assignment overloads that was +* not compiling on some compilers +* Also changed name of private method to comply with standards on +* reserved names +* Thanks to Niels Dekker for the input +* Feb 12, 2004 - 1.0.2 +* Minor changes to remove dependency on Windows headers +* Consistently used __int16, __int32 and __int64 to ensure +* portability +* May 10, 2004 - 1.0.3 +* Corrected bug in one case of GreaterThan +* July 22, 2004 - 1.0.4 +* Tightened logic in addition check (saving 2 instructions) +* Pulled error handler out into function to enable user-defined replacement +* Made internal type of SafeIntException an enum (as per Niels' suggestion) +* Added casts for base integer types (as per Scott Meyers' suggestion) +* Updated usage information - see important new perf notes. +* Cleaned up several const issues (more thanks to Niels) +* +* Oct 1, 2004 - 1.0.5 +* Added support for SEH exceptions instead of C++ exceptions - Win32 only +* Made handlers for DIV0 and overflows individually overridable +* Commented out the destructor - major perf gains here +* Added cast operator for type long, since long != __int32 +* Corrected a couple of missing const modifiers +* Fixed broken >= and <= operators for type U op SafeInt< T, E > +* Nov 5, 2004 - 1.0.6 +* Implemented new logic in binary operators to resolve issues with +* implicit casts +* Fixed casting operator because char != signed char +* Defined __int32 as int instead of long +* Removed unsafe SafeInt::Value method +* Re-implemented casting operator as a result of removing Value method +* Dec 1, 2004 - 1.0.7 +* Implemented specialized operators for pointer arithmetic +* Created overloads for cases of U op= SafeInt. What you do with U +* after that may be dangerous. +* Fixed bug in corner case of MixedSizeModulus +* Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0 +* Added throw() decorations +* +* Apr 12, 2005 - 2.0 +* Extensive revisions to leverage template specialization. +* April, 2007 Extensive revisions for version 3.0 +* Nov 22, 2009 Forked from MS internal code +* Changes needed to support gcc compiler - many thanks to Niels Dekker +* for determining not just the issues, but also suggesting fixes. +* Also updating some of the header internals to be the same as the upcoming Visual Studio version. +* +* Jan 16, 2010 64-bit gcc has long == __int64, which means that many of the existing 64-bit +* templates are over-specialized. This forces a redefinition of all the 64-bit +* multiplication routines to use pointers instead of references for return +* values. Also, let's use some intrinsics for x64 Microsoft compiler to +* reduce code size, and hopefully improve efficiency. +* +* June 21, 2014 Better support for clang, higher warning levels supported for all 3 primary supported + compilers (Visual Studio, clang, gcc). + Also started to converge the code base such that the public CodePlex version will + be a drop-in replacement for the Visual Studio version. + +* Note about code style - throughout this class, casts will be written using C-style (T), +* not C++ style static_cast< T >. This is because the class is nearly always dealing with integer +* types, and in this case static_cast and a C cast are equivalent. Given the large number of casts, +* the code is a little more readable this way. In the event a cast is needed where static_cast couldn't +* be substituted, we'll use the new templatized cast to make it explicit what the operation is doing. +* +************************************************************************************************************ +* Version 3.0 changes: +* +* 1) The exception type thrown is now replacable, and you can throw your own exception types. This should help +* those using well-developed exception classes. +* 2) The 64-bit multiplication code has had a lot of perf work done, and should be faster than 2.0. +* 3) There is now limited floating point support. You can initialize a SafeInt with a floating point type, +* and you can cast it out (or assign) to a float as well. +* 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one. +* +* Another major improvement is the addition of external functions - if you just want to check an operation, this can now happen: +* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially handy +* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for 64-bit. +* +* inline bool SafeCast( const T From, U& To ) throw() +* inline bool SafeEquals( const T t, const U u ) throw() +* inline bool SafeNotEquals( const T t, const U u ) throw() +* inline bool SafeGreaterThan( const T t, const U u ) throw() +* inline bool SafeGreaterThanEquals( const T t, const U u ) throw() +* inline bool SafeLessThan( const T t, const U u ) throw() +* inline bool SafeLessThanEquals( const T t, const U u ) throw() +* inline bool SafeModulus( const T& t, const U& u, T& result ) throw() +* inline bool SafeMultiply( T t, U u, T& result ) throw() +* inline bool SafeDivide( T t, U u, T& result ) throw() +* inline bool SafeAdd( T t, U u, T& result ) throw() +* inline bool SafeSubtract( T t, U u, T& result ) throw() +* +*/ + +//use these if the compiler does not support _intXX +#ifdef NEEDS_INT_DEFINED +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long +#endif + +namespace msl +{ + +namespace safeint3 +{ + +// catch these to handle errors +// Currently implemented code values: +// ERROR_ARITHMETIC_OVERFLOW +// EXCEPTION_INT_DIVIDE_BY_ZERO +enum SafeIntError +{ + SafeIntNoError = 0, + SafeIntArithmeticOverflow, + SafeIntDivideByZero +}; + +} // safeint3 +} // msl + + +/* +* Error handler classes +* Using classes to deal with exceptions is going to allow the most +* flexibility, and we can mix different error handlers in the same project +* or even the same file. It isn't advisable to do this in the same function +* because a SafeInt< int, MyExceptionHandler > isn't the same thing as +* SafeInt< int, YourExceptionHander >. +* If for some reason you have to translate between the two, cast one of them back to its +* native type. +* +* To use your own exception class with SafeInt, first create your exception class, +* which may look something like the SafeIntException class below. The second step is to +* create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero. +* For example: +* +* template <> class SafeIntExceptionHandler < YourExceptionClass > +* { +* static __declspec(noreturn) void __stdcall SafeIntOnOverflow() +* { +* throw YourExceptionClass( EXCEPTION_INT_OVERFLOW ); +* } +* +* static __declspec(noreturn) void __stdcall SafeIntOnDivZero() +* { +* throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO ); +* } +* }; +* +* typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler +* You'd then declare your SafeInt objects like this: +* SafeInt< int, YourSafeIntExceptionHandler > +* +* Unfortunately, there is no such thing as partial template specialization in typedef +* statements, so you have three options if you find this cumbersome: +* +* 1) Create a holder class: +* +* template < typename T > +* class MySafeInt +* { +* public: +* SafeInt< T, MyExceptionClass> si; +* }; +* +* You'd then declare an instance like so: +* MySafeInt< int > i; +* +* You'd lose handy things like initialization - it would have to be initialized as: +* +* i.si = 0; +* +* 2) You could create a typedef for every int type you deal with: +* +* typedef SafeInt< int, MyExceptionClass > MySafeInt; +* typedef SafeInt< char, MyExceptionClass > MySafeChar; +* +* and so on. The second approach is probably more usable, and will just drop into code +* better, which is the original intent of the SafeInt class. +* +* 3) If you're going to consistently use a different class to handle your exceptions, +* you can override the default typedef like so: +* +* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler +* +* Overall, this is probably the best approach. +* */ + +// On the Microsoft compiler, violating a throw() annotation is a silent error. +// Other compilers might turn these into exceptions, and some users may want to not have throw() enabled. +// In addition, some error handlers may not throw C++ exceptions, which makes everything no throw. +#if defined SAFEINT_REMOVE_NOTHROW +#define SAFEINT_NOTHROW +#else +#define SAFEINT_NOTHROW throw() +#endif + +namespace msl +{ + +namespace safeint3 +{ + +// If you would like to use your own custom assert +// Define SAFEINT_ASSERT +#if !defined SAFEINT_ASSERT +#include +#define SAFEINT_ASSERT(x) assert(x) +#endif + +#if defined SAFEINT_ASSERT_ON_EXCEPTION + inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); } +#else + inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {} +#endif + +#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER + #define SAFEINT_NORETURN __attribute__((noreturn)) + #define SAFEINT_STDCALL + #define SAFEINT_VISIBLE __attribute__ ((__visibility__("default"))) + #define SAFEINT_WEAK __attribute__ ((weak)) +#else + #define SAFEINT_NORETURN __declspec(noreturn) + #define SAFEINT_STDCALL __stdcall + #define SAFEINT_VISIBLE + #define SAFEINT_WEAK +#endif + +class SAFEINT_VISIBLE SafeIntException +{ +public: + SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; } + SafeIntException( SafeIntError code ) SAFEINT_NOTHROW + { + m_code = code; + } + SafeIntError m_code; +}; + +namespace SafeIntInternal +{ + // Visual Studio version of SafeInt provides for two possible error + // handlers: + // SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined + // SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers, + // exits the app with a crash + template < typename E > class SafeIntExceptionHandler; + + template <> class SafeIntExceptionHandler < SafeIntException > + { + public: + + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() + { + SafeIntExceptionAssert(); + throw SafeIntException( SafeIntArithmeticOverflow ); + } + + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() + { + SafeIntExceptionAssert(); + throw SafeIntException( SafeIntDivideByZero ); + } + }; + +#if !defined _CRT_SECURE_INVALID_PARAMETER + // Calling fail fast is somewhat more robust than calling abort, + // but abort is the closest we can manage without Visual Studio support + // Need the header for abort() + #include + #define _CRT_SECURE_INVALID_PARAMETER(msg) abort() +#endif + + class SafeInt_InvalidParameter + { + public: + static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow"); + } + + static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero"); + } + }; + +#if defined _WINDOWS_ + + class SafeIntWin32ExceptionHandler + { + public: + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + RaiseException( static_cast(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0); + } + + static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW + { + SafeIntExceptionAssert(); + RaiseException( static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0); + } + }; + +#endif + +} // namespace SafeIntInternal + +// both of these have cross-platform support +typedef SafeIntInternal::SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler; +typedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler; + +// This exception handler is no longer recommended, but is left here in order not to break existing users +#if defined _WINDOWS_ +typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler; +#endif + +// For Visual Studio compatibility +#if defined VISUAL_STUDIO_SAFEINT_COMPAT + typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException; + typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter; +#endif + +// If the user hasn't defined a default exception handler, +// define one now, depending on whether they would like Win32 or C++ exceptions + +// This library will use conditional noexcept soon, but not in this release +// Some users might mix exception handlers, which is not advised, but is supported +#if !defined SafeIntDefaultExceptionHandler + #if defined SAFEINT_RAISE_EXCEPTION + #if !defined _WINDOWS_ + #error Include windows.h in order to use Win32 exceptions + #endif + + #define SafeIntDefaultExceptionHandler Win32ExceptionHandler + #elif defined SAFEINT_FAILFAST + #define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler + #else + #define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler + #if !defined SAFEINT_EXCEPTION_HANDLER_CPP + #define SAFEINT_EXCEPTION_HANDLER_CPP 1 + #endif + #endif +#endif + +#if !defined SAFEINT_EXCEPTION_HANDLER_CPP +#define SAFEINT_EXCEPTION_HANDLER_CPP 0 +#endif + +// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast, +// or abort, then all methods become no throw. Some teams track throw() annotations closely, +// and the following option provides for this. +#if SAFEINT_EXCEPTION_HANDLER_CPP +#define SAFEINT_CPP_THROW +#else +#define SAFEINT_CPP_THROW SAFEINT_NOTHROW +#endif + +// Turns out we can fool the compiler into not seeing compile-time constants with +// a simple template specialization +template < int method > class CompileConst; +template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return true; } }; +template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return false; } }; + +// The following template magic is because we're now not allowed +// to cast a float to an enum. This means that if we happen to assign +// an enum to a SafeInt of some type, it won't compile, unless we prevent +// isFloat = ( (T)( (float)1.1 ) > (T)1 ) +// from compiling in the case of an enum, which is the point of the specialization +// that follows. + +// If we have support for std, then we can do this easily, and detect enums as well +template < typename T > class NumericType; + +#if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_ +// Continue to special case bool +template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; +template < typename T > class NumericType +{ + public: + enum + { + isBool = false, // We specialized out a bool + isFloat = std::is_floating_point::value, + // If it is an enum, then consider it an int type + // This does allow someone to make a SafeInt from an enum type, which is not recommended, + // but it also allows someone to add an enum value to a SafeInt, which is handy. + isInt = std::is_integral::value || std::is_enum::value + }; +}; + +#else + +template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +#endif +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; +template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; +// Catch-all for anything not supported +template < typename T > class NumericType +{ +public: + // We have some unknown type, which could be an enum. For parity with the code that uses , + // We can try a static_cast - it if compiles, then it might be an enum, and should work. + // If it is something else that just happens to have a constructor that takes an int, and a casting operator, + // then it is possible something will go wrong, and for best results, cast it directly to an int before letting it + // interact with a SafeInt + + enum + { + isBool = false, + isFloat = false, + isInt = static_cast( static_cast(0) ) == 0 + }; +}; +#endif // type traits + +// Use this to avoid compile-time const truncation warnings +template < int fSigned, int bits > class SafeIntMinMax; + +template <> class SafeIntMinMax< true, 8 > { public: const static signed __int8 min = (-0x7f - 1); + const static signed __int8 max = 0x7f; }; +template <> class SafeIntMinMax< true, 16 > { public: const static __int16 min = ( -0x7fff - 1 ); + const static __int16 max = 0x7fff; }; +template <> class SafeIntMinMax< true, 32 > { public: const static __int32 min = ( -0x7fffffff -1 ); + const static __int32 max = 0x7fffffff; }; +template <> class SafeIntMinMax< true, 64 > { public: const static __int64 min = static_cast<__int64>(0x8000000000000000LL); + const static __int64 max = 0x7fffffffffffffffLL; }; + +template <> class SafeIntMinMax< false, 8 > { public: const static unsigned __int8 min = 0; + const static unsigned __int8 max = 0xff; }; +template <> class SafeIntMinMax< false, 16 > { public: const static unsigned __int16 min = 0; + const static unsigned __int16 max = 0xffff; }; +template <> class SafeIntMinMax< false, 32 > { public: const static unsigned __int32 min = 0; + const static unsigned __int32 max = 0xffffffff; }; +template <> class SafeIntMinMax< false, 64 > { public: const static unsigned __int64 min = 0; + const static unsigned __int64 max = 0xffffffffffffffffULL; }; + +template < typename T > class IntTraits +{ +public: + C_ASSERT( NumericType::isInt ); + enum + { + isSigned = ( (T)(-1) < 0 ), + is64Bit = ( sizeof(T) == 8 ), + is32Bit = ( sizeof(T) == 4 ), + is16Bit = ( sizeof(T) == 2 ), + is8Bit = ( sizeof(T) == 1 ), + isLT32Bit = ( sizeof(T) < 4 ), + isLT64Bit = ( sizeof(T) < 8 ), + isInt8 = ( sizeof(T) == 1 && isSigned ), + isUint8 = ( sizeof(T) == 1 && !isSigned ), + isInt16 = ( sizeof(T) == 2 && isSigned ), + isUint16 = ( sizeof(T) == 2 && !isSigned ), + isInt32 = ( sizeof(T) == 4 && isSigned ), + isUint32 = ( sizeof(T) == 4 && !isSigned ), + isInt64 = ( sizeof(T) == 8 && isSigned ), + isUint64 = ( sizeof(T) == 8 && !isSigned ), + bitCount = ( sizeof(T)*8 ), + isBool = ( (T)2 == (T)1 ) + }; + + // On version 13.10 enums cannot define __int64 values + // so we'll use const statics instead! + // These must be cast to deal with the possibility of a SafeInt being given an enum as an argument + const static T maxInt = static_cast(SafeIntMinMax< isSigned, bitCount >::max); + const static T minInt = static_cast(SafeIntMinMax< isSigned, bitCount >::min); +}; + +template < typename T > +const T IntTraits< T >::maxInt; +template < typename T > +const T IntTraits< T >::minInt; + +template < typename T, typename U > class SafeIntCompare +{ +public: + enum + { + isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned), + isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned), + isLikeSigned = ((bool)(IntTraits< T >::isSigned) == (bool)(IntTraits< U >::isSigned)), + isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || + (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))), + isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit), + isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit) + }; +}; + +//all of the arithmetic operators can be solved by the same code within +//each of these regions without resorting to compile-time constant conditionals +//most operators collapse the problem into less than the 22 zones, but this is used +//as the first cut +//using this also helps ensure that we handle all of the possible cases correctly + +template < typename T, typename U > class IntRegion +{ +public: + enum + { + //unsigned-unsigned zone + IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit, + IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, + IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, + IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit, + IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, + //unsigned-signed + IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, + IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, + IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32, + IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, + IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64, + IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64, + //signed-signed + IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit, + IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, + IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, + IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64, + IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit, + IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, + //signed-unsigned + IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, + IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit, + IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32, + IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, + IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit, + IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64 + }; +}; + + +// In all of the following functions, we have two versions +// One for SafeInt, which throws C++ (or possibly SEH) exceptions +// The non-throwing versions are for use by the helper functions that return success and failure. +// Some of the non-throwing functions are not used, but are maintained for completeness. + +// There's no real alternative to duplicating logic, but keeping the two versions +// immediately next to one another will help reduce problems + + +// useful function to help with getting the magnitude of a negative number +enum AbsMethod +{ + AbsMethodInt, + AbsMethodInt64, + AbsMethodNoop +}; + +template < typename T > +class GetAbsMethod +{ +public: + enum + { + method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt : + IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop + }; +}; + +// let's go ahead and hard-code a dependency on the +// representation of negative numbers to keep compilers from getting overly +// happy with optimizing away things like -MIN_INT. +template < typename T, int > class AbsValueHelper; + +template < typename T > class AbsValueHelper < T, AbsMethodInt> +{ +public: + static unsigned __int32 Abs( T t ) SAFEINT_NOTHROW + { + SAFEINT_ASSERT( t < 0 ); + return ~(unsigned __int32)t + 1; + } +}; + +template < typename T > class AbsValueHelper < T, AbsMethodInt64 > +{ +public: + static unsigned __int64 Abs( T t ) SAFEINT_NOTHROW + { + SAFEINT_ASSERT( t < 0 ); + return ~(unsigned __int64)t + 1; + } +}; + +template < typename T > class AbsValueHelper < T, AbsMethodNoop > +{ +public: + static T Abs( T t ) SAFEINT_NOTHROW + { + // Why are you calling Abs on an unsigned number ??? + SAFEINT_ASSERT( false ); + return t; + } +}; + +template < typename T, bool > class NegationHelper; +// Previous versions had an assert that the type being negated was 32-bit or higher +// In retrospect, this seems like something to just document +// Negation will normally upcast to int +// For example -(unsigned short)0xffff == (int)0xffff0001 +// This class will retain the type, and will truncate, which may not be what +// you wanted +// If you want normal operator casting behavior, do this: +// SafeInt ss = 0xffff; +// then: +// -(SafeInt(ss)) +// will then emit a signed int with the correct value and bitfield + +template < typename T > class NegationHelper // Signed +{ +public: + template + static T NegativeThrow( T t ) SAFEINT_CPP_THROW + { + // corner case + if( t != IntTraits< T >::minInt ) + { + // cast prevents unneeded checks in the case of small ints + return -t; + } + E::SafeIntOnOverflow(); + } + + static bool Negative( T t, T& ret ) SAFEINT_NOTHROW + { + // corner case + if( t != IntTraits< T >::minInt ) + { + // cast prevents unneeded checks in the case of small ints + ret = -t; + return true; + } + return false; + } +}; + +// Helper classes to work keep compilers from +// optimizing away negation +template < typename T > class SignedNegation; + +template <> +class SignedNegation +{ +public: + static signed __int32 Value(unsigned __int64 in) SAFEINT_NOTHROW + { + return (signed __int32)(~(unsigned __int32)in + 1); + } + + static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW + { + return (signed __int32)(~in + 1); + } +}; + +template <> +class SignedNegation +{ +public: + static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW + { + return (signed __int64)(~in + 1); + } +}; + +template < typename T > class NegationHelper // unsigned +{ +public: + template + static T NegativeThrow( T t ) SAFEINT_CPP_THROW + { +#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION + C_ASSERT( sizeof(T) == 0 ); +#endif + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning(push) +//this avoids warnings from the unary '-' operator being applied to unsigned numbers +#pragma warning(disable:4146) +#endif + // Note - this could be quenched on gcc + // by doing something like: + // return (T)-((__int64)t); + // but it seems like you would want a warning when doing this. + return (T)-t; + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning(pop) +#endif + } + + static bool Negative( T t, T& ret ) SAFEINT_NOTHROW + { + if( IntTraits::isLT32Bit ) + { + // See above + SAFEINT_ASSERT( false ); + } +#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION + C_ASSERT( sizeof(T) == 0 ); +#endif + // Do it this way to avoid warning + ret = -t; + return true; + } +}; + +//core logic to determine casting behavior +enum CastMethod +{ + CastOK = 0, + CastCheckLTZero, + CastCheckGTMax, + CastCheckSafeIntMinMaxUnsigned, + CastCheckSafeIntMinMaxSigned, + CastToFloat, + CastFromFloat, + CastToBool, + CastFromBool +}; + + +template < typename ToType, typename FromType > +class GetCastMethod +{ +public: + enum + { + method = ( IntTraits< FromType >::isBool && + !IntTraits< ToType >::isBool ) ? CastFromBool : + + ( !IntTraits< FromType >::isBool && + IntTraits< ToType >::isBool ) ? CastToBool : + + ( SafeIntCompare< ToType, FromType >::isCastOK ) ? CastOK : + + ( ( IntTraits< ToType >::isSigned && + !IntTraits< FromType >::isSigned && + sizeof( FromType ) >= sizeof( ToType ) ) || + ( SafeIntCompare< ToType, FromType >::isBothUnsigned && + sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax : + + ( !IntTraits< ToType >::isSigned && + IntTraits< FromType >::isSigned && + sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero : + + ( !IntTraits< ToType >::isSigned ) ? CastCheckSafeIntMinMaxUnsigned + : CastCheckSafeIntMinMaxSigned + }; +}; + +template < typename FromType > class GetCastMethod < float, FromType > +{ +public: + enum{ method = CastOK }; +}; + +template < typename FromType > class GetCastMethod < double, FromType > +{ +public: + enum{ method = CastOK }; +}; + +template < typename FromType > class GetCastMethod < long double, FromType > +{ +public: + enum{ method = CastOK }; +}; + +template < typename ToType > class GetCastMethod < ToType, float > +{ +public: + enum{ method = CastFromFloat }; +}; + +template < typename ToType > class GetCastMethod < ToType, double > +{ +public: + enum{ method = CastFromFloat }; +}; + +template < typename ToType > class GetCastMethod < ToType, long double > +{ +public: + enum{ method = CastFromFloat }; +}; + +template < typename T, typename U, int > class SafeCastHelper; + +template < typename T, typename U > class SafeCastHelper < T, U, CastOK > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + t = (T)u; + return true; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + t = (T)u; + } +}; + +// special case floats and doubles +// tolerate loss of precision +template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + if( u <= (U)IntTraits< T >::maxInt && + u >= (U)IntTraits< T >::minInt ) + { + t = (T)u; + return true; + } + return false; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + if( u <= (U)IntTraits< T >::maxInt && + u >= (U)IntTraits< T >::minInt ) + { + t = (T)u; + return; + } + E::SafeIntOnOverflow(); + } +}; + +// Match on any method where a bool is cast to type T +template < typename T > class SafeCastHelper < T, bool, CastFromBool > +{ +public: + static bool Cast( bool b, T& t ) SAFEINT_NOTHROW + { + t = (T)( b ? 1 : 0 ); + return true; + } + + template < typename E > + static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW + { + t = (T)( b ? 1 : 0 ); + } +}; + +template < typename T > class SafeCastHelper < bool, T, CastToBool > +{ +public: + static bool Cast( T t, bool& b ) SAFEINT_NOTHROW + { + b = !!t; + return true; + } + + template < typename E > + static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW + { + b = !!t; + } +}; + +template < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + if( u < 0 ) + return false; + + t = (T)u; + return true; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + if( u < 0 ) + E::SafeIntOnOverflow(); + + t = (T)u; + } +}; + +template < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + if( u > (U)IntTraits< T >::maxInt ) + return false; + + t = (T)u; + return true; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + if( u > (U)IntTraits< T >::maxInt ) + E::SafeIntOnOverflow(); + + t = (T)u; + } +}; + +template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + // U is signed - T could be either signed or unsigned + if( u > IntTraits< T >::maxInt || u < 0 ) + return false; + + t = (T)u; + return true; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + // U is signed - T could be either signed or unsigned + if( u > IntTraits< T >::maxInt || u < 0 ) + E::SafeIntOnOverflow(); + + t = (T)u; + } +}; + +template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned > +{ +public: + static bool Cast( U u, T& t ) SAFEINT_NOTHROW + { + // T, U are signed + if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) + return false; + + t = (T)u; + return true; + } + + template < typename E > + static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW + { + //T, U are signed + if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) + E::SafeIntOnOverflow(); + + t = (T)u; + } +}; + +//core logic to determine whether a comparison is valid, or needs special treatment +enum ComparisonMethod +{ + ComparisonMethod_Ok = 0, + ComparisonMethod_CastInt, + ComparisonMethod_CastInt64, + ComparisonMethod_UnsignedT, + ComparisonMethod_UnsignedU +}; + + // Note - the standard is arguably broken in the case of some integer + // conversion operations + // For example, signed char a = -1 = 0xff + // unsigned int b = 0xffffffff + // If you then test if a < b, a value-preserving cast + // is made, and you're essentially testing + // (unsigned int)a < b == false + // + // I do not think this makes sense - if you perform + // a cast to an __int64, which can clearly preserve both value and signedness + // then you get a different and intuitively correct answer + // IMHO, -1 should be less than 4 billion + // If you prefer to retain the ANSI standard behavior + // insert #define ANSI_CONVERSIONS into your source + // Behavior differences occur in the following cases: + // 8, 16, and 32-bit signed int, unsigned 32-bit int + // any signed int, unsigned 64-bit int + // Note - the signed int must be negative to show the problem + +template < typename T, typename U > +class ValidComparison +{ +public: + enum + { +#ifdef ANSI_CONVERSIONS + method = ComparisonMethod_Ok +#else + method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok : + ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) || + ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt : + ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) || + ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 : + ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT : + ComparisonMethod_UnsignedU ) +#endif + }; +}; + +template class EqualityTest; + +template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok > +{ +public: + static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); } +}; + +template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt > +{ +public: + static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); } +}; + +template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 > +{ +public: + static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t == (__int64)u ); } +}; + +template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT > +{ +public: + static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW + { + //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if( u < 0 ) + return false; + + //else safe to cast to type T + return ( t == (T)u ); + } +}; + +template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU> +{ +public: + static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW + { + //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if( t < 0 ) + return false; + + //else safe to cast to type U + return ( (U)t == u ); + } +}; + +template class GreaterThanTest; + +template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok > +{ +public: + static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); } +}; + +template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt > +{ +public: + static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); } +}; + +template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 > +{ +public: + static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t > (__int64)u ); } +}; + +template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT > +{ +public: + static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW + { + // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if( u < 0 ) + return true; + + // else safe to cast to type T + return ( t > (T)u ); + } +}; + +template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU > +{ +public: + static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW + { + // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller + if( t < 0 ) + return false; + + // else safe to cast to type U + return ( (U)t > u ); + } +}; + +// Modulus is simpler than comparison, but follows much the same logic +// using this set of functions, it can't fail except in a div 0 situation +template class ModulusHelper; + +template class ModulusHelper +{ +public: + static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if(u == 0) + return SafeIntDivideByZero; + + //trap corner case + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + // Some compilers don't notice that this only compiles when u is signed + // Add cast to make them happy + if( u == (U)-1 ) + { + result = 0; + return SafeIntNoError; + } + } + + result = (T)(t % u); + return SafeIntNoError; + } + + template < typename E > + static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + E::SafeIntOnDivZero(); + + //trap corner case + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + if( u == (U)-1 ) + { + result = 0; + return; + } + } + + result = (T)(t % u); + } +}; + +template class ModulusHelper +{ +public: + static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if(u == 0) + return SafeIntDivideByZero; + + //trap corner case + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + if( u == (U)-1 ) + { + result = 0; + return SafeIntNoError; + } + } + + result = (T)(t % u); + return SafeIntNoError; + } + + template < typename E > + static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + E::SafeIntOnDivZero(); + + //trap corner case + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + if( u == (U)-1 ) + { + result = 0; + return; + } + } + + result = (T)(t % u); + } +}; + +template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_CastInt64> +{ +public: + static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if(u == 0) + return SafeIntDivideByZero; + + //trap corner case + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + if( u == (U)-1 ) + { + result = 0; + return SafeIntNoError; + } + } + + result = (T)((__int64)t % (__int64)u); + return SafeIntNoError; + } + + template < typename E > + static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + E::SafeIntOnDivZero(); + + if( CompileConst< IntTraits< U >::isSigned >::Value() ) + { + if( u == (U)-1 ) + { + result = 0; + return; + } + } + + result = (T)((__int64)t % (__int64)u); + } +}; + +// T is unsigned __int64, U is any signed int +template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT> +{ +public: + static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if(u == 0) + return SafeIntDivideByZero; + + // u could be negative - if so, need to convert to positive + // casts below are always safe due to the way modulus works + if(u < 0) + result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u)); + else + result = (T)(t % u); + + return SafeIntNoError; + } + + template < typename E > + static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + E::SafeIntOnDivZero(); + + // u could be negative - if so, need to convert to positive + if(u < 0) + result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u )); + else + result = (T)(t % u); + } +}; + +// U is unsigned __int64, T any signed int +template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU> +{ +public: + static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if(u == 0) + return SafeIntDivideByZero; + + //t could be negative - if so, need to convert to positive + if(t < 0) + result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 ); + else + result = (T)((T)t % u); + + return SafeIntNoError; + } + + template < typename E > + static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + E::SafeIntOnDivZero(); + + //t could be negative - if so, need to convert to positive + if(t < 0) + result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1); + else + result = (T)( (T)t % u ); + } +}; + +//core logic to determine method to check multiplication +enum MultiplicationState +{ + MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit + MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit + MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit + MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller + MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller + MultiplicationState_Uint64Uint64, // Both are unsigned int64 + MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32 + MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64 + MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit + MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64 + MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32 + MultiplicationState_Int64Int64, // lhs int64, rhs int64 + MultiplicationState_Int64Int, // lhs int64, rhs int32 + MultiplicationState_IntUint64, // lhs int, rhs unsigned int64 + MultiplicationState_IntInt64, // lhs int, rhs int64 + MultiplicationState_Int64Uint64, // lhs int64, rhs uint64 + MultiplicationState_Error +}; + +template < typename T, typename U > +class MultiplicationMethod +{ +public: + enum + { + // unsigned-unsigned + method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint : + (IntRegion< T,U >::IntZone_Uint32_UintLT64 || + IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 : + SafeIntCompare< T,U >::isBothUnsigned && + IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 : + (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint : + (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : + // unsigned-signed + (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt : + (IntRegion< T,U >::IntZone_Uint32_IntLT64 || + IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 : + (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int : + (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 : + (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 : + // signed-signed + (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt : + (IntRegion< T,U >::IntZone_Int32_IntLT64 || + IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 : + (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 : + (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int : + (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 : + // signed-unsigned + (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt : + (IntRegion< T,U >::IntZone_Int32_UintLT32 || + IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 : + (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint : + (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 : + (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 : + MultiplicationState_Error ) ) + }; +}; + +template class MultiplicationHelper; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt> +{ +public: + //accepts signed, both less than 32-bit + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + int tmp = t * u; + + if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) + return false; + + ret = (T)tmp; + return true; + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + int tmp = t * u; + + if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) + E::SafeIntOnOverflow(); + + ret = (T)tmp; + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint > +{ +public: + //accepts unsigned, both less than 32-bit + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + unsigned int tmp = (unsigned int)(t * u); + + if( tmp > IntTraits< T >::maxInt ) + return false; + + ret = (T)tmp; + return true; + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + unsigned int tmp = (unsigned int)( t * u ); + + if( tmp > IntTraits< T >::maxInt ) + E::SafeIntOnOverflow(); + + ret = (T)tmp; + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64> +{ +public: + //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + __int64 tmp = (__int64)t * (__int64)u; + + if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) + return false; + + ret = (T)tmp; + return true; + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + __int64 tmp = (__int64)t * (__int64)u; + + if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) + E::SafeIntOnOverflow(); + + ret = (T)tmp; + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64> +{ +public: + //both unsigned where at least one argument is 32-bit, and both are 32-bit or less + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; + + if(tmp > (unsigned __int64)IntTraits< T >::maxInt) + return false; + + ret = (T)tmp; + return true; + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; + + if(tmp > (unsigned __int64)IntTraits< T >::maxInt) + E::SafeIntOnOverflow(); + + ret = (T)tmp; + } +}; + +// T = left arg and return type +// U = right arg +template < typename T, typename U > class LargeIntRegMultiply; + +#if SAFEINT_USE_INTRINSICS +// As usual, unsigned is easy +inline bool IntrinsicMultiplyUint64( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW +{ + unsigned __int64 ulHigh = 0; + *pRet = _umul128(a , b, &ulHigh); + return ulHigh == 0; +} + +// Signed, is not so easy +inline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW +{ + __int64 llHigh = 0; + *pRet = _mul128(a , b, &llHigh); + + // Now we need to figure out what we expect + // If llHigh is 0, then treat *pRet as unsigned + // If llHigh is < 0, then treat *pRet as signed + + if( (a ^ b) < 0 ) + { + // Negative result expected + if( llHigh == -1 && *pRet < 0 || + llHigh == 0 && *pRet == 0 ) + { + // Everything is within range + return true; + } + } + else + { + // Result should be positive + // Check for overflow + if( llHigh == 0 && (unsigned __int64)*pRet <= IntTraits< signed __int64 >::maxInt ) + return true; + } + return false; +} + +#endif + +template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > +{ +public: + static bool RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyUint64( a, b, pRet ); +#else + unsigned __int32 aHigh, aLow, bHigh, bLow; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) + // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) + // Note - same approach applies for 128 bit math on a 64-bit system + + aHigh = (unsigned __int32)(a >> 32); + aLow = (unsigned __int32)a; + bHigh = (unsigned __int32)(b >> 32); + bLow = (unsigned __int32)b; + + *pRet = 0; + + if(aHigh == 0) + { + if(bHigh != 0) + { + *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; + } + } + else if(bHigh == 0) + { + if(aHigh != 0) + { + *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; + } + } + else + { + return false; + } + + if(*pRet != 0) + { + unsigned __int64 tmp; + + if((unsigned __int32)(*pRet >> 32) != 0) + return false; + + *pRet <<= 32; + tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; + *pRet += tmp; + + if(*pRet < tmp) + return false; + + return true; + } + + *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow; + return true; +#endif + } + + template < typename E > + static void RegMultiplyThrow( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyUint64( a, b, pRet ) ) + E::SafeIntOnOverflow(); +#else + unsigned __int32 aHigh, aLow, bHigh, bLow; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) + // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) + // Note - same approach applies for 128 bit math on a 64-bit system + + aHigh = (unsigned __int32)(a >> 32); + aLow = (unsigned __int32)a; + bHigh = (unsigned __int32)(b >> 32); + bLow = (unsigned __int32)b; + + *pRet = 0; + + if(aHigh == 0) + { + if(bHigh != 0) + { + *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; + } + } + else if(bHigh == 0) + { + if(aHigh != 0) + { + *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; + } + } + else + { + E::SafeIntOnOverflow(); + } + + if(*pRet != 0) + { + unsigned __int64 tmp; + + if((unsigned __int32)(*pRet >> 32) != 0) + E::SafeIntOnOverflow(); + + *pRet <<= 32; + tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; + *pRet += tmp; + + if(*pRet < tmp) + E::SafeIntOnOverflow(); + + return; + } + + *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow; +#endif + } +}; + +template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > +{ +public: + static bool RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); +#else + unsigned __int32 aHigh, aLow; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * b + // => (aHigh * b * 2^32) + (aLow * b) + + aHigh = (unsigned __int32)(a >> 32); + aLow = (unsigned __int32)a; + + *pRet = 0; + + if(aHigh != 0) + { + *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; + + unsigned __int64 tmp; + + if((unsigned __int32)(*pRet >> 32) != 0) + return false; + + *pRet <<= 32; + tmp = (unsigned __int64)aLow * (unsigned __int64)b; + *pRet += tmp; + + if(*pRet < tmp) + return false; + + return true; + } + + *pRet = (unsigned __int64)aLow * (unsigned __int64)b; + return true; +#endif + } + + template < typename E > + static void RegMultiplyThrow( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) + E::SafeIntOnOverflow(); +#else + unsigned __int32 aHigh, aLow; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * b + // => (aHigh * b * 2^32) + (aLow * b) + + aHigh = (unsigned __int32)(a >> 32); + aLow = (unsigned __int32)a; + + *pRet = 0; + + if(aHigh != 0) + { + *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; + + unsigned __int64 tmp; + + if((unsigned __int32)(*pRet >> 32) != 0) + E::SafeIntOnOverflow(); + + *pRet <<= 32; + tmp = (unsigned __int64)aLow * (unsigned __int64)b; + *pRet += tmp; + + if(*pRet < tmp) + E::SafeIntOnOverflow(); + + return; + } + + *pRet = (unsigned __int64)aLow * (unsigned __int64)b; + return; +#endif + } +}; + +template<> class LargeIntRegMultiply< unsigned __int64, signed __int32 > +{ +public: + // Intrinsic not needed + static bool RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + { + if( b < 0 && a != 0 ) + return false; + +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); +#else + return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply(a, (unsigned __int32)b, pRet); +#endif + } + + template < typename E > + static void RegMultiplyThrow( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + { + if( b < 0 && a != 0 ) + E::SafeIntOnOverflow(); + +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) + E::SafeIntOnOverflow(); +#else + LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( a, (unsigned __int32)b, pRet ); +#endif + } +}; + +template<> class LargeIntRegMultiply< unsigned __int64, signed __int64 > +{ +public: + static bool RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_NOTHROW + { + if( b < 0 && a != 0 ) + return false; + +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); +#else + return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply(a, (unsigned __int64)b, pRet); +#endif + } + + template < typename E > + static void RegMultiplyThrow( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW + { + if( b < 0 && a != 0 ) + E::SafeIntOnOverflow(); + +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) + E::SafeIntOnOverflow(); +#else + LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); +#endif + } +}; + +template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > +{ +public: + // Devolves into ordinary 64-bit calculation + static bool RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW + { + unsigned __int32 bHigh, bLow; + bool fIsNegative = false; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) + // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) + // aHigh == 0 implies: + // ( aLow * bHigh * 2^32 ) + ( aLow + bLow ) + // If the first part is != 0, fail + + bHigh = (unsigned __int32)(b >> 32); + bLow = (unsigned __int32)b; + + *pRet = 0; + + if(bHigh != 0 && a != 0) + return false; + + if( a < 0 ) + { + + a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + fIsNegative = true; + } + + unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; + + if( !fIsNegative ) + { + if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) + { + *pRet = (signed __int32)tmp; + return true; + } + } + else + { + if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) + { + *pRet = SignedNegation< signed __int32 >::Value( tmp ); + return true; + } + } + + return false; + } + + template < typename E > + static void RegMultiplyThrow( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW + { + unsigned __int32 bHigh, bLow; + bool fIsNegative = false; + + // Consider that a*b can be broken up into: + // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) + // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) + + bHigh = (unsigned __int32)(b >> 32); + bLow = (unsigned __int32)b; + + *pRet = 0; + + if(bHigh != 0 && a != 0) + E::SafeIntOnOverflow(); + + if( a < 0 ) + { + a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + fIsNegative = true; + } + + unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; + + if( !fIsNegative ) + { + if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) + { + *pRet = (signed __int32)tmp; + return; + } + } + else + { + if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) + { + *pRet = SignedNegation< signed __int32 >::Value( tmp ); + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 > +{ +public: + // Becomes ordinary 64-bit multiplication, intrinsic not needed + static bool RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW + { + // Consider that a*b can be broken up into: + // (bHigh * 2^32 + bLow) * a + // => (bHigh * a * 2^32) + (bLow * a) + // In this case, the result must fit into 32-bits + // If bHigh != 0 && a != 0, immediate error. + + if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) + return false; + + unsigned __int64 tmp = b * (unsigned __int64)a; + + if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow + return false; + + *pRet = (unsigned __int32)tmp; + return true; + } + + template < typename E > + static void RegMultiplyThrow( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW + { + if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) + E::SafeIntOnOverflow(); + + unsigned __int64 tmp = b * (unsigned __int64)a; + + if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow + E::SafeIntOnOverflow(); + + *pRet = (unsigned __int32)tmp; + } +}; + +template<> class LargeIntRegMultiply< unsigned __int32, signed __int64 > +{ +public: + static bool RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW + { + if( b < 0 && a != 0 ) + return false; + return LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( a, (unsigned __int64)b, pRet ); + } + + template < typename E > + static void RegMultiplyThrow( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW + { + if( b < 0 && a != 0 ) + E::SafeIntOnOverflow(); + + LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); + } +}; + +template<> class LargeIntRegMultiply< signed __int64, signed __int64 > +{ +public: + static bool RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyInt64( a, b, pRet ); +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int64 tmp; + __int64 a1 = a; + __int64 b1 = b; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( b1 < 0 ) + { + bNegative = true; + b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + } + + if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return true; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return true; + } + } + } + + return false; +#endif + } + + template < typename E > + static void RegMultiplyThrow( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyInt64( a, b, pRet ) ) + E::SafeIntOnOverflow(); +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int64 tmp; + __int64 a1 = a; + __int64 b1 = b; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( b1 < 0 ) + { + bNegative = true; + b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + } + + LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ); + + // The unsigned multiplication didn't overflow or we'd be in the exception handler + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return; + } + } + + E::SafeIntOnOverflow(); +#endif + } +}; + +template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 > +{ +public: + static bool RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); +#else + bool aNegative = false; + unsigned __int64 tmp; + __int64 a1 = a; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, b, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return true; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return true; + } + } + } + + return false; +#endif + } + + template < typename E > + static void RegMultiplyThrow( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) + E::SafeIntOnOverflow(); +#else + bool aNegative = false; + unsigned __int64 tmp; + __int64 a1 = a; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, b, &tmp ); + + // The unsigned multiplication didn't overflow + if( aNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return; + } + } + + E::SafeIntOnOverflow(); +#endif + } +}; + +template<> class LargeIntRegMultiply< signed __int64, signed __int32 > +{ +public: + static bool RegMultiply( const signed __int64& a, signed __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int64 tmp; + __int64 a1 = a; + __int64 b1 = b; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( b1 < 0 ) + { + bNegative = true; + b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + } + + if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return true; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return true; + } + } + } + + return false; +#endif + } + + template < typename E > + static void RegMultiplyThrow( signed __int64 a, signed __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) + E::SafeIntOnOverflow(); +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int64 tmp; + + if( a < 0 ) + { + aNegative = true; + a = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a); + } + + if( b < 0 ) + { + bNegative = true; + b = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(b); + } + + LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a, (unsigned __int32)b, &tmp ); + + // The unsigned multiplication didn't overflow + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return; + } + } + + E::SafeIntOnOverflow(); +#endif + } +}; + +template<> class LargeIntRegMultiply< signed __int32, signed __int64 > +{ +public: + static bool RegMultiply( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW + { +#if SAFEINT_USE_INTRINSICS + __int64 tmp; + + if( IntrinsicMultiplyInt64( a, b, &tmp ) ) + { + if( tmp > IntTraits< signed __int32 >::maxInt || + tmp < IntTraits< signed __int32 >::minInt ) + { + return false; + } + + *pRet = (__int32)tmp; + return true; + } + return false; +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int32 tmp; + __int64 b1 = b; + + if( a < 0 ) + { + aNegative = true; + a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + } + + if( b1 < 0 ) + { + bNegative = true; + b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); + } + + if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) + { + *pRet = SignedNegation< signed __int32 >::Value( tmp ); + return true; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) + { + *pRet = (signed __int32)tmp; + return true; + } + } + } + + return false; +#endif + } + + template < typename E > + static void RegMultiplyThrow( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW + { +#if SAFEINT_USE_INTRINSICS + __int64 tmp; + + if( IntrinsicMultiplyInt64( a, b, &tmp ) ) + { + if( tmp > IntTraits< signed __int32 >::maxInt || + tmp < IntTraits< signed __int32 >::minInt ) + { + E::SafeIntOnOverflow(); + } + + *pRet = (__int32)tmp; + return; + } + E::SafeIntOnOverflow(); +#else + bool aNegative = false; + bool bNegative = false; + + unsigned __int32 tmp; + signed __int64 b2 = b; + + if( a < 0 ) + { + aNegative = true; + a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); + } + + if( b < 0 ) + { + bNegative = true; + b2 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b2); + } + + LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)a, (unsigned __int64)b2, &tmp ); + + // The unsigned multiplication didn't overflow + if( aNegative ^ bNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) + { + *pRet = SignedNegation< signed __int32 >::Value( tmp ); + return; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) + { + *pRet = (signed __int32)tmp; + return; + } + } + + E::SafeIntOnOverflow(); +#endif + } +}; + +template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 > +{ +public: + // Leave this one as-is - will call unsigned intrinsic internally + static bool RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW + { + bool aNegative = false; + + unsigned __int64 tmp; + __int64 a1 = a; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return true; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return true; + } + } + } + + return false; + } + + template < typename E > + static void RegMultiplyThrow( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW + { + bool aNegative = false; + unsigned __int64 tmp; + __int64 a1 = a; + + if( a1 < 0 ) + { + aNegative = true; + a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); + } + + if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) + { + // The unsigned multiplication didn't overflow + if( aNegative ) + { + // Result must be negative + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) + { + *pRet = SignedNegation< signed __int64 >::Value( tmp ); + return; + } + } + else + { + // Result must be positive + if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) + { + *pRet = (signed __int64)tmp; + return; + } + } + } + + E::SafeIntOnOverflow(); + } +}; + +// In all of the following functions where LargeIntRegMultiply methods are called, +// we need to properly transition types. The methods need __int64, __int32, etc. +// but the variables being passed to us could be long long, long int, or long, depending on +// the compiler. Microsoft compiler knows that long long is the same type as __int64, but gcc doesn't + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 > +{ +public: + // T, U are unsigned __int64 + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); + unsigned __int64 t1 = t; + unsigned __int64 u1 = u; + return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast(&ret) ); + } + + template < typename E > + static void MultiplyThrow(const unsigned __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); + unsigned __int64 t1 = t; + unsigned __int64 u1 = u; + LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast(&ret) ); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint > +{ +public: + // T is unsigned __int64 + // U is any unsigned int 32-bit or less + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 t1 = t; + return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 t1 = t; + LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); + } +}; + +// converse of the previous function +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 > +{ +public: + // T is any unsigned int up to 32-bit + // U is unsigned __int64 + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 u1 = u; + unsigned __int32 tmp; + + if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( t, u1, &tmp ) && + SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) + { + return true; + } + + return false; + } + + template < typename E > + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 u1 = u; + unsigned __int32 tmp; + + LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( t, u1, &tmp ); + SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int > +{ +public: + // T is unsigned __int64 + // U is any signed int, up to 64-bit + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 t1 = t; + return LargeIntRegMultiply< unsigned __int64, signed __int32 >::RegMultiply(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); + } + + template < typename E > + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 t1 = t; + LargeIntRegMultiply< unsigned __int64, signed __int32 >::template RegMultiplyThrow< E >(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 > +{ +public: + // T is unsigned __int64 + // U is __int64 + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); + unsigned __int64 t1 = t; + __int64 u1 = u; + return LargeIntRegMultiply< unsigned __int64, __int64 >::RegMultiply(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); + } + + template < typename E > + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); + unsigned __int64 t1 = t; + __int64 u1 = u; + LargeIntRegMultiply< unsigned __int64, __int64 >::template RegMultiplyThrow< E >(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 > +{ +public: + // T is unsigned up to 32-bit + // U is __int64 + static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 u1 = u; + unsigned __int32 tmp; + + if( LargeIntRegMultiply< unsigned __int32, __int64 >::RegMultiply( (unsigned __int32)t, u1, &tmp ) && + SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) + { + return true; + } + + return false; + } + + template < typename E > + static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 u1 = u; + unsigned __int32 tmp; + + LargeIntRegMultiply< unsigned __int32, __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)t, u1, &tmp ); + SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint > +{ +public: + // T is __int64 + // U is unsigned up to 32-bit + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 t1 = t; + return LargeIntRegMultiply< __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 t1 = t; + LargeIntRegMultiply< __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 > +{ +public: + // T, U are __int64 + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); + __int64 t1 = t; + __int64 u1 = u; + return LargeIntRegMultiply< __int64, __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); + } + + template < typename E > + static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); + __int64 t1 = t; + __int64 u1 = u; + LargeIntRegMultiply< __int64, __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret)); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int > +{ +public: + // T is __int64 + // U is signed up to 32-bit + static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 t1 = t; + return LargeIntRegMultiply< __int64, __int32 >::RegMultiply( t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); + } + + template < typename E > + static void MultiplyThrow( const __int64& t, U u, T& ret ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 t1 = t; + LargeIntRegMultiply< __int64, __int32 >::template RegMultiplyThrow< E >(t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 > +{ +public: + // T is signed up to 32-bit + // U is unsigned __int64 + static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 u1 = u; + __int32 tmp; + + if( LargeIntRegMultiply< __int32, unsigned __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) + { + return true; + } + + return false; + } + + template < typename E > + static void MultiplyThrow(T t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isUint64 ); + unsigned __int64 u1 = u; + __int32 tmp; + + LargeIntRegMultiply< __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64> +{ +public: + // T is __int64 + // U is unsigned __int64 + static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); + __int64 t1 = t; + unsigned __int64 u1 = u; + return LargeIntRegMultiply< __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); + } + + template < typename E > + static void MultiplyThrow( const __int64& t, const unsigned __int64& u, T& ret ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); + __int64 t1 = t; + unsigned __int64 u1 = u; + LargeIntRegMultiply< __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret) ); + } +}; + +template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64> +{ +public: + // T is signed, up to 32-bit + // U is __int64 + static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 u1 = u; + __int32 tmp; + + if( LargeIntRegMultiply< __int32, __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) + { + return true; + } + + return false; + } + + template < typename E > + static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits::isInt64 ); + __int64 u1 = u; + __int32 tmp; + + LargeIntRegMultiply< __int32, __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); + } +}; + +enum DivisionState +{ + DivisionState_OK, + DivisionState_UnsignedSigned, + DivisionState_SignedUnsigned32, + DivisionState_SignedUnsigned64, + DivisionState_SignedUnsigned, + DivisionState_SignedSigned +}; + +template < typename T, typename U > class DivisionMethod +{ +public: + enum + { + method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK : + (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned : + (IntTraits< T >::isSigned && + IntTraits< U >::isUint32 && + IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 : + (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 : + (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned : + DivisionState_SignedSigned) + }; +}; + +template < typename T, typename U, int state > class DivisionHelper; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK > +{ +public: + static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if( u == 0 ) + return SafeIntDivideByZero; + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + result = (T)( t/u ); + return SafeIntNoError; + } + + template < typename E > + static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if( u == 0 ) + E::SafeIntOnDivZero(); + + if( t == 0 ) + { + result = 0; + return; + } + + result = (T)( t/u ); + } +}; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned> +{ +public: + static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + + if( u == 0 ) + return SafeIntDivideByZero; + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + if( u > 0 ) + { + result = (T)( t/u ); + return SafeIntNoError; + } + + // it is always an error to try and divide an unsigned number by a negative signed number + // unless u is bigger than t + if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) + { + result = 0; + return SafeIntNoError; + } + + return SafeIntArithmeticOverflow; + } + + template < typename E > + static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + + if( u == 0 ) + E::SafeIntOnDivZero(); + + if( t == 0 ) + { + result = 0; + return; + } + + if( u > 0 ) + { + result = (T)( t/u ); + return; + } + + // it is always an error to try and divide an unsigned number by a negative signed number + // unless u is bigger than t + if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) + { + result = 0; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 > +{ +public: + static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if( u == 0 ) + return SafeIntDivideByZero; + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + // Test for t > 0 + // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors + // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional + + if( t > 0 ) + result = (T)( t/u ); + else + result = (T)( (__int64)t/(__int64)u ); + + return SafeIntNoError; + } + + template < typename E > + static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if( u == 0 ) + { + E::SafeIntOnDivZero(); + } + + if( t == 0 ) + { + result = 0; + return; + } + + // Test for t > 0 + // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors + // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional + + if( t > 0 ) + result = (T)( t/u ); + else + result = (T)( (__int64)t/(__int64)u ); + } +}; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 > +{ +public: + static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits< U >::isUint64 ); + + if( u == 0 ) + { + return SafeIntDivideByZero; + } + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + if( u <= (unsigned __int64)IntTraits< T >::maxInt ) + { + // Else u can safely be cast to T + if( CompileConst< sizeof( T ) < sizeof( __int64 )>::Value() ) + result = (T)( (int)t/(int)u ); + else + result = (T)((__int64)t/(__int64)u); + } + else // Corner case + if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) + { + // Min int divided by it's own magnitude is -1 + result = -1; + } + else + { + result = 0; + } + return SafeIntNoError; + } + + template < typename E > + static void DivideThrow( const T& t, const unsigned __int64& u, T& result ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits< U >::isUint64 ); + + if( u == 0 ) + { + E::SafeIntOnDivZero(); + } + + if( t == 0 ) + { + result = 0; + return; + } + + if( u <= (unsigned __int64)IntTraits< T >::maxInt ) + { + // Else u can safely be cast to T + if( CompileConst< sizeof( T ) < sizeof( __int64 ) >::Value() ) + result = (T)( (int)t/(int)u ); + else + result = (T)((__int64)t/(__int64)u); + } + else // Corner case + if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) + { + // Min int divided by it's own magnitude is -1 + result = -1; + } + else + { + result = 0; + } + } +}; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned> +{ +public: + // T is any signed, U is unsigned and smaller than 32-bit + // In this case, standard operator casting is correct + static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if( u == 0 ) + { + return SafeIntDivideByZero; + } + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + result = (T)( t/u ); + return SafeIntNoError; + } + + template < typename E > + static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if( u == 0 ) + { + E::SafeIntOnDivZero(); + } + + if( t == 0 ) + { + result = 0; + return; + } + + result = (T)( t/u ); + } +}; + +template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned> +{ +public: + static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW + { + if( u == 0 ) + { + return SafeIntDivideByZero; + } + + if( t == 0 ) + { + result = 0; + return SafeIntNoError; + } + + // Must test for corner case + if( t == IntTraits< T >::minInt && u == (U)-1 ) + return SafeIntArithmeticOverflow; + + result = (T)( t/u ); + return SafeIntNoError; + } + + template < typename E > + static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW + { + if(u == 0) + { + E::SafeIntOnDivZero(); + } + + if( t == 0 ) + { + result = 0; + return; + } + + // Must test for corner case + if( t == IntTraits< T >::minInt && u == (U)-1 ) + E::SafeIntOnOverflow(); + + result = (T)( t/u ); + } +}; + +enum AdditionState +{ + AdditionState_CastIntCheckMax, + AdditionState_CastUintCheckOverflow, + AdditionState_CastUintCheckOverflowMax, + AdditionState_CastUint64CheckOverflow, + AdditionState_CastUint64CheckOverflowMax, + AdditionState_CastIntCheckSafeIntMinMax, + AdditionState_CastInt64CheckSafeIntMinMax, + AdditionState_CastInt64CheckMax, + AdditionState_CastUint64CheckSafeIntMinMax, + AdditionState_CastUint64CheckSafeIntMinMax2, + AdditionState_CastInt64CheckOverflow, + AdditionState_CastInt64CheckOverflowSafeIntMinMax, + AdditionState_CastInt64CheckOverflowMax, + AdditionState_ManualCheckInt64Uint64, + AdditionState_ManualCheck, + AdditionState_Error +}; + +template< typename T, typename U > +class AdditionMethod +{ +public: + enum + { + //unsigned-unsigned + method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax : + (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow : + (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax : + (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow : + (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax : + //unsigned-signed + (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Uint32_IntLT64 || + IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Uint64_Int || + IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax2 : + //signed-signed + (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Int32_IntLT64 || + IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Int64_Int || + IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow : + (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowSafeIntMinMax : + //signed-unsigned + (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax : + (IntRegion< T,U >::IntZone_Int32_UintLT32 || + IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax : + (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax : + (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 : + (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck : + AdditionState_Error) + }; +}; + +template < typename T, typename U, int method > class AdditionHelper; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + //16-bit or less unsigned addition + __int32 tmp = lhs + rhs; + + if( tmp <= (__int32)IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + //16-bit or less unsigned addition + __int32 tmp = lhs + rhs; + + if( tmp <= (__int32)IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // 32-bit or less - both are unsigned + unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; + + //we added didn't get smaller + if( tmp >= lhs ) + { + result = (T)tmp; + return true; + } + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // 32-bit or less - both are unsigned + unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; + + //we added didn't get smaller + if( tmp >= lhs ) + { + result = (T)tmp; + return; + } + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // 32-bit or less - both are unsigned + unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; + + // We added and it didn't get smaller or exceed maxInt + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + //32-bit or less - both are unsigned + unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; + + // We added and it didn't get smaller or exceed maxInt + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs unsigned __int64, rhs unsigned + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it didn't get smaller + if(tmp >= lhs) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs unsigned __int64, rhs unsigned + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it didn't get smaller + if(tmp >= lhs) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + //lhs unsigned __int64, rhs unsigned + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it didn't get smaller + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + //lhs unsigned __int64, rhs unsigned + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it didn't get smaller + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // 16-bit or less - one or both are signed + __int32 tmp = lhs + rhs; + + if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // 16-bit or less - one or both are signed + __int32 tmp = lhs + rhs; + + if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // 32-bit or less - one or both are signed + __int64 tmp = (__int64)lhs + (__int64)rhs; + + if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // 32-bit or less - one or both are signed + __int64 tmp = (__int64)lhs + (__int64)rhs; + + if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // 32-bit or less - lhs signed, rhs unsigned + __int64 tmp = (__int64)lhs + (__int64)rhs; + + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // 32-bit or less - lhs signed, rhs unsigned + __int64 tmp = (__int64)lhs + (__int64)rhs; + + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax > +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is unsigned __int64, rhs signed + unsigned __int64 tmp; + + if( rhs < 0 ) + { + // So we're effectively subtracting + tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + + if( tmp <= lhs ) + { + result = lhs - tmp; + return true; + } + } + else + { + // now we know that rhs can be safely cast into an unsigned __int64 + tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it did not become smaller + if( tmp >= lhs ) + { + result = (T)tmp; + return true; + } + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is unsigned __int64, rhs signed + unsigned __int64 tmp; + + if( rhs < 0 ) + { + // So we're effectively subtracting + tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + + if( tmp <= lhs ) + { + result = lhs - tmp; + return; + } + } + else + { + // now we know that rhs can be safely cast into an unsigned __int64 + tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // We added and it did not become smaller + if( tmp >= lhs ) + { + result = (T)tmp; + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is unsigned and < 64-bit, rhs signed __int64 + if( rhs < 0 ) + { + if( lhs >= ~(unsigned __int64)( rhs ) + 1 )//negation is safe, since rhs is 64-bit + { + result = (T)( lhs + rhs ); + return true; + } + } + else + { + // now we know that rhs can be safely cast into an unsigned __int64 + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff + // it is not possible for the operation above to overflow, so just check max + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is unsigned and < 64-bit, rhs signed __int64 + if( rhs < 0 ) + { + if( lhs >= ~(unsigned __int64)( rhs ) + 1) //negation is safe, since rhs is 64-bit + { + result = (T)( lhs + rhs ); + return; + } + } + else + { + // now we know that rhs can be safely cast into an unsigned __int64 + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff + // it is not possible for the operation above to overflow, so just check max + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is signed __int64, rhs signed + __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); + + if( lhs >= 0 ) + { + // mixed sign cannot overflow + if( rhs >= 0 && tmp < lhs ) + return false; + } + else + { + // lhs negative + if( rhs < 0 && tmp > lhs ) + return false; + } + + result = (T)tmp; + return true; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is signed __int64, rhs signed + __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); + + if( lhs >= 0 ) + { + // mixed sign cannot overflow + if( rhs >= 0 && tmp < lhs ) + E::SafeIntOnOverflow(); + } + else + { + // lhs negative + if( rhs < 0 && tmp > lhs ) + E::SafeIntOnOverflow(); + } + + result = (T)tmp; + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + //rhs is signed __int64, lhs signed + __int64 tmp; + + if( AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::Addition( (__int64)lhs, (__int64)rhs, tmp ) && + tmp <= IntTraits< T >::maxInt && + tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + //rhs is signed __int64, lhs signed + __int64 tmp; + + AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (__int64)lhs, (__int64)rhs, tmp ); + + if( tmp <= IntTraits< T >::maxInt && + tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + //lhs is signed __int64, rhs unsigned < 64-bit + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + if( (__int64)tmp >= lhs ) + { + result = (T)(__int64)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is signed __int64, rhs unsigned < 64-bit + // Some compilers get optimization-happy, let's thwart them + + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; + + if( (__int64)tmp >= lhs ) + { + result = (T)(__int64)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 > +{ +public: + static bool Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + // rhs is unsigned __int64, lhs __int64 + // cast everything to unsigned, perform addition, then + // cast back for check - this is done to stop optimizers from removing the code + unsigned __int64 tmp = (unsigned __int64)lhs + rhs; + + if( (__int64)tmp >= lhs ) + { + result = (__int64)tmp; + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + // rhs is unsigned __int64, lhs __int64 + unsigned __int64 tmp = (unsigned __int64)lhs + rhs; + + if( (__int64)tmp >= lhs ) + { + result = (__int64)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck> +{ +public: + static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // rhs is unsigned __int64, lhs signed, 32-bit or less + if( (unsigned __int32)( rhs >> 32 ) == 0 ) + { + // Now it just happens to work out that the standard behavior does what we want + // Adding explicit casts to show exactly what's happening here + // Note - this is tweaked to keep optimizers from tossing out the code. + unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; + + if( (__int32)tmp >= lhs && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( (__int32)tmp, result ) ) + return true; + } + + return false; + } + + template < typename E > + static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // rhs is unsigned __int64, lhs signed, 32-bit or less + + if( (unsigned __int32)( rhs >> 32 ) == 0 ) + { + // Now it just happens to work out that the standard behavior does what we want + // Adding explicit casts to show exactly what's happening here + unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; + + if( (__int32)tmp >= lhs ) + { + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( (__int32)tmp, result ); + return; + } + } + E::SafeIntOnOverflow(); + } +}; + +enum SubtractionState +{ + SubtractionState_BothUnsigned, + SubtractionState_CastIntCheckSafeIntMinMax, + SubtractionState_CastIntCheckMin, + SubtractionState_CastInt64CheckSafeIntMinMax, + SubtractionState_CastInt64CheckMin, + SubtractionState_Uint64Int, + SubtractionState_UintInt64, + SubtractionState_Int64Int, + SubtractionState_IntInt64, + SubtractionState_Int64Uint, + SubtractionState_IntUint64, + SubtractionState_Int64Uint64, + // states for SubtractionMethod2 + SubtractionState_BothUnsigned2, + SubtractionState_CastIntCheckSafeIntMinMax2, + SubtractionState_CastInt64CheckSafeIntMinMax2, + SubtractionState_Uint64Int2, + SubtractionState_UintInt642, + SubtractionState_Int64Int2, + SubtractionState_IntInt642, + SubtractionState_Int64Uint2, + SubtractionState_IntUint642, + SubtractionState_Int64Uint642, + SubtractionState_Error +}; + +template < typename T, typename U > class SubtractionMethod +{ +public: + enum + { + // unsigned-unsigned + method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || + (IntRegion< T,U >::IntZone_Uint32_UintLT64) || + (IntRegion< T,U >::IntZone_UintLT32_Uint32) || + (IntRegion< T,U >::IntZone_Uint64_Uint) || + (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned : + // unsigned-signed + (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Uint32_IntLT64 || + IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Uint64_Int || + IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int : + (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : + // signed-signed + (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Int32_IntLT64 || + IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : + (IntRegion< T,U >::IntZone_Int64_Int || + IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int : + (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 : + // signed-unsigned + (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin : + (IntRegion< T,U >::IntZone_Int32_UintLT32 || + IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin : + (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint : + (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 : + (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 : + SubtractionState_Error) + }; +}; + +// this is for the case of U - SafeInt< T, E > +template < typename T, typename U > class SubtractionMethod2 +{ +public: + enum + { + // unsigned-unsigned + method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || + (IntRegion< T,U >::IntZone_Uint32_UintLT64) || + (IntRegion< T,U >::IntZone_UintLT32_Uint32) || + (IntRegion< T,U >::IntZone_Uint64_Uint) || + (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 : + // unsigned-signed + (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Uint32_IntLT64 || + IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Uint64_Int || + IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 : + (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : + // signed-signed + (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Int32_IntLT64 || + IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Int64_Int || + IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 : + (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 : + // signed-unsigned + (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Int32_UintLT32 || + IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : + (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 : + (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 : + (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 : + SubtractionState_Error) + }; +}; + +template < typename T, typename U, int method > class SubtractionHelper; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // both are unsigned - easy case + if( rhs <= lhs ) + { + result = (T)( lhs - rhs ); + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // both are unsigned - easy case + if( rhs <= lhs ) + { + result = (T)( lhs - rhs ); + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW + { + // both are unsigned - easy case + // Except we do have to check for overflow - lhs could be larger than result can hold + if( rhs <= lhs ) + { + T tmp = (T)(lhs - rhs); + return SafeCastHelper< U, T, GetCastMethod::method>::Cast( tmp, result); + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW + { + // both are unsigned - easy case + if( rhs <= lhs ) + { + T tmp = (T)(lhs - rhs); + SafeCastHelper< U, T, GetCastMethod::method >::template CastThrow( tmp, result); + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 16-bit or less + // rhs is signed, so could end up increasing or decreasing + __int32 tmp = lhs - rhs; + + if( SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ) ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 16-bit or less + // rhs is signed, so could end up increasing or decreasing + __int32 tmp = lhs - rhs; + + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); + } +}; + +template class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 16-bit or less + // rhs is signed, so could end up increasing or decreasing + __int32 tmp = lhs - rhs; + + return SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ); + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 16-bit or less + // rhs is signed, so could end up increasing or decreasing + __int32 tmp = lhs - rhs; + + SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 16-bit or less + // rhs is unsigned - check only minimum + __int32 tmp = lhs - rhs; + + if( tmp >= (__int32)IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 16-bit or less + // rhs is unsigned - check only minimum + __int32 tmp = lhs - rhs; + + if( tmp >= (__int32)IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 32-bit or less + // rhs is signed, so could end up increasing or decreasing + __int64 tmp = (__int64)lhs - (__int64)rhs; + + return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 32-bit or less + // rhs is signed, so could end up increasing or decreasing + __int64 tmp = (__int64)lhs - (__int64)rhs; + + SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); + } +}; + +template class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 32-bit or less + // rhs is signed, so could end up increasing or decreasing + __int64 tmp = (__int64)lhs - (__int64)rhs; + + return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 32-bit or less + // rhs is signed, so could end up increasing or decreasing + __int64 tmp = (__int64)lhs - (__int64)rhs; + + SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // both values are 32-bit or less + // rhs is unsigned - check only minimum + __int64 tmp = (__int64)lhs - (__int64)rhs; + + if( tmp >= (__int64)IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // both values are 32-bit or less + // rhs is unsigned - check only minimum + __int64 tmp = (__int64)lhs - (__int64)rhs; + + if( tmp >= (__int64)IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is an unsigned __int64, rhs signed + // must first see if rhs is positive or negative + if( rhs >= 0 ) + { + if( (unsigned __int64)rhs <= lhs ) + { + result = (T)( lhs - (unsigned __int64)rhs ); + return true; + } + } + else + { + T tmp = lhs; + // we're now effectively adding + result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + + if(result >= tmp) + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is an unsigned __int64, rhs signed + // must first see if rhs is positive or negative + if( rhs >= 0 ) + { + if( (unsigned __int64)rhs <= lhs ) + { + result = (T)( lhs - (unsigned __int64)rhs ); + return; + } + } + else + { + T tmp = lhs; + // we're now effectively adding + result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); + + if(result >= tmp) + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // U is unsigned __int64, T is signed + if( rhs < 0 ) + { + // treat this as addition + unsigned __int64 tmp; + + tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); + + // must check for addition overflow and max + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works + { + // result is negative + // implies that lhs must fit into T, and result cannot overflow + // Also allows us to drop to 32-bit math, which is faster on a 32-bit system + result = (T)lhs - (T)rhs; + return true; + } + else + { + // result is positive + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + + return false; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // U is unsigned __int64, T is signed + if( rhs < 0 ) + { + // treat this as addition + unsigned __int64 tmp; + + tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); + + // must check for addition overflow and max + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works + { + // result is negative + // implies that lhs must fit into T, and result cannot overflow + // Also allows us to drop to 32-bit math, which is faster on a 32-bit system + result = (T)lhs - (T)rhs; + return; + } + else + { + // result is positive + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is an unsigned int32 or smaller, rhs signed __int64 + // must first see if rhs is positive or negative + if( rhs >= 0 ) + { + if( (unsigned __int64)rhs <= lhs ) + { + result = (T)( lhs - (T)rhs ); + return true; + } + } + else + { + // we're now effectively adding + // since lhs is 32-bit, and rhs cannot exceed 2^63 + // this addition cannot overflow + unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe + + // but we could exceed MaxInt + if(tmp <= IntTraits< T >::maxInt) + { + result = (T)tmp; + return true; + } + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is an unsigned int32 or smaller, rhs signed __int64 + // must first see if rhs is positive or negative + if( rhs >= 0 ) + { + if( (unsigned __int64)rhs <= lhs ) + { + result = (T)( lhs - (T)rhs ); + return; + } + } + else + { + // we're now effectively adding + // since lhs is 32-bit, and rhs cannot exceed 2^63 + // this addition cannot overflow + unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe + + // but we could exceed MaxInt + if(tmp <= IntTraits< T >::maxInt) + { + result = (T)tmp; + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template class SubtractionHelper< U, T, SubtractionState_UintInt642 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // U unsigned 32-bit or less, T __int64 + if( rhs >= 0 ) + { + // overflow not possible + result = (T)( (__int64)lhs - rhs ); + return true; + } + else + { + // we effectively have an addition + // which cannot overflow internally + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); + + if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + + return false; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // U unsigned 32-bit or less, T __int64 + if( rhs >= 0 ) + { + // overflow not possible + result = (T)( (__int64)lhs - rhs ); + return; + } + else + { + // we effectively have an addition + // which cannot overflow internally + unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); + + if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is an __int64, rhs signed (up to 64-bit) + // we have essentially 4 cases: + // + // 1) lhs positive, rhs positive - overflow not possible + // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error + // 3) lhs negative, rhs positive - check result <= lhs + // 4) lhs negative, rhs negative - overflow not possible + + __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); + + // Note - ideally, we can order these so that true conditionals + // lead to success, which enables better pipelining + // It isn't practical here + if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 + ( rhs >= 0 && tmp > lhs ) ) // condition 3 + { + return false; + } + + result = (T)tmp; + return true; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is an __int64, rhs signed (up to 64-bit) + // we have essentially 4 cases: + // + // 1) lhs positive, rhs positive - overflow not possible + // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error + // 3) lhs negative, rhs positive - check result <= lhs + // 4) lhs negative, rhs negative - overflow not possible + + __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); + + // Note - ideally, we can order these so that true conditionals + // lead to success, which enables better pipelining + // It isn't practical here + if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 + ( rhs >= 0 && tmp > lhs ) ) // condition 3 + { + E::SafeIntOnOverflow(); + } + + result = (T)tmp; + } +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs __int64, rhs any signed int (including __int64) + __int64 tmp = lhs - rhs; + + // we have essentially 4 cases: + // + // 1) lhs positive, rhs positive - overflow not possible in tmp + // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error + // 3) lhs negative, rhs positive - check result <= lhs + // 4) lhs negative, rhs negative - overflow not possible in tmp + + if( lhs >= 0 ) + { + // if both positive, overflow to negative not possible + // which is why we'll explicitly check maxInt, and not call SafeCast + if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) || + ( rhs < 0 && tmp < lhs ) ) + { + return false; + } + } + else + { + // lhs negative + if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) || + ( rhs >=0 && tmp > lhs ) ) + { + return false; + } + } + + result = (T)tmp; + return true; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs __int64, rhs any signed int (including __int64) + __int64 tmp = lhs - rhs; + + // we have essentially 4 cases: + // + // 1) lhs positive, rhs positive - overflow not possible in tmp + // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error + // 3) lhs negative, rhs positive - check result <= lhs + // 4) lhs negative, rhs negative - overflow not possible in tmp + + if( lhs >= 0 ) + { + // if both positive, overflow to negative not possible + // which is why we'll explicitly check maxInt, and not call SafeCast + if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp > IntTraits< T >::maxInt ) || + ( rhs < 0 && tmp < lhs ) ) + { + E::SafeIntOnOverflow(); + } + } + else + { + // lhs negative + if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp < IntTraits< T >::minInt) || + ( rhs >=0 && tmp > lhs ) ) + { + E::SafeIntOnOverflow(); + } + } + + result = (T)tmp; + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is a 32-bit int or less, rhs __int64 + // we have essentially 4 cases: + // + // lhs positive, rhs positive - rhs could be larger than lhs can represent + // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int + // lhs negative, rhs positive - check tmp <= lhs and tmp < min int + // lhs negative, rhs negative - addition cannot internally overflow, check against max + + __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); + + if( lhs >= 0 ) + { + // first case + if( rhs >= 0 ) + { + if( tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + } + else + { + // second case + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + } + else + { + // lhs < 0 + // third case + if( rhs >= 0 ) + { + if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return true; + } + } + else + { + // fourth case + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return true; + } + } + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is a 32-bit int or less, rhs __int64 + // we have essentially 4 cases: + // + // lhs positive, rhs positive - rhs could be larger than lhs can represent + // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int + // lhs negative, rhs positive - check tmp <= lhs and tmp < min int + // lhs negative, rhs negative - addition cannot internally overflow, check against max + + __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); + + if( lhs >= 0 ) + { + // first case + if( rhs >= 0 ) + { + if( tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + } + else + { + // second case + if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + } + else + { + // lhs < 0 + // third case + if( rhs >= 0 ) + { + if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) + { + result = (T)tmp; + return; + } + } + else + { + // fourth case + if( tmp <= IntTraits< T >::maxInt ) + { + result = (T)tmp; + return; + } + } + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is any signed int32 or smaller, rhs is int64 + __int64 tmp = (__int64)lhs - rhs; + + if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || + ( rhs > 0 && tmp > lhs ) ) + { + return false; + //else OK + } + + result = (T)tmp; + return true; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is any signed int32 or smaller, rhs is int64 + __int64 tmp = (__int64)lhs - rhs; + + if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || + ( rhs > 0 && tmp > lhs ) ) + { + E::SafeIntOnOverflow(); + //else OK + } + + result = (T)tmp; + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is a 64-bit int, rhs unsigned int32 or smaller + // perform test as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( (__int64)tmp <= lhs ) + { + result = (T)(__int64)tmp; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is a 64-bit int, rhs unsigned int32 or smaller + // perform test as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( (__int64)tmp <= lhs ) + { + result = (T)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 > +{ +public: + // lhs is __int64, rhs is unsigned 32-bit or smaller + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // Do this as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) + { + result = (T)(__int64)tmp; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // Do this as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; + + if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) + { + result = (T)(__int64)tmp; + return; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 > +{ +public: + static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW + { + // lhs is any signed int, rhs unsigned int64 + // check against available range + + // We need the absolute value of IntTraits< T >::minInt + // This will give it to us without extraneous compiler warnings + const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; + + if( lhs < 0 ) + { + if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) + { + result = (T)( lhs - rhs ); + return true; + } + } + else + { + if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) + { + result = (T)( lhs - rhs ); + return true; + } + } + + return false; + } + + template < typename E > + static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW + { + // lhs is any signed int, rhs unsigned int64 + // check against available range + + // We need the absolute value of IntTraits< T >::minInt + // This will give it to us without extraneous compiler warnings + const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; + + if( lhs < 0 ) + { + if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) + { + result = (T)( lhs - rhs ); + return; + } + } + else + { + if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) + { + result = (T)( lhs - rhs ); + return; + } + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 > +{ +public: + static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW + { + // We run into upcasting problems on comparison - needs 2 checks + if( lhs >= 0 && (T)lhs >= rhs ) + { + result = (T)((U)lhs - (U)rhs); + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW + { + // We run into upcasting problems on comparison - needs 2 checks + if( lhs >= 0 && (T)lhs >= rhs ) + { + result = (T)((U)lhs - (U)rhs); + return; + } + + E::SafeIntOnOverflow(); + } + +}; + +template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 > +{ +public: + static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + // if we subtract, and it gets larger, there's a problem + // Perform test as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - rhs; + + if( (__int64)tmp <= lhs ) + { + result = (__int64)tmp; + return true; + } + return false; + } + + template < typename E > + static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); + // if we subtract, and it gets larger, there's a problem + // Perform test as unsigned to prevent unwanted optimizations + unsigned __int64 tmp = (unsigned __int64)lhs - rhs; + + if( (__int64)tmp <= lhs ) + { + result = (__int64)tmp; + return; + } + + E::SafeIntOnOverflow(); + } + +}; + +template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 > +{ +public: + // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it + // get smaller. If rhs > lhs, then it would also go negative, which is the other case + static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_NOTHROW + { + C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); + if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) + { + result = (unsigned __int64)lhs - rhs; + return true; + } + + return false; + } + + template < typename E > + static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW + { + C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); + if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) + { + result = (unsigned __int64)lhs - rhs; + return; + } + + E::SafeIntOnOverflow(); + } + +}; + +enum BinaryState +{ + BinaryState_OK, + BinaryState_Int8, + BinaryState_Int16, + BinaryState_Int32 +}; + +template < typename T, typename U > class BinaryMethod +{ +public: + enum + { + // If both operands are unsigned OR + // return type is smaller than rhs OR + // return type is larger and rhs is unsigned + // Then binary operations won't produce unexpected results + method = ( sizeof( T ) <= sizeof( U ) || + SafeIntCompare< T, U >::isBothUnsigned || + !IntTraits< U >::isSigned ) ? BinaryState_OK : + IntTraits< U >::isInt8 ? BinaryState_Int8 : + IntTraits< U >::isInt16 ? BinaryState_Int16 + : BinaryState_Int32 + }; +}; + +#ifdef SAFEINT_DISABLE_BINARY_ASSERT +#define BinaryAssert(x) +#else +#define BinaryAssert(x) SAFEINT_ASSERT(x) +#endif + +template < typename T, typename U, int method > class BinaryAndHelper; + +template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK > +{ +public: + static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); } +}; + +template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 > +{ +public: + static T And( T lhs, U rhs ) SAFEINT_NOTHROW + { + // cast forces sign extension to be zeros + BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) ); + return (T)( lhs & (unsigned __int8)rhs ); + } +}; + +template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 > +{ +public: + static T And( T lhs, U rhs ) SAFEINT_NOTHROW + { + //cast forces sign extension to be zeros + BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) ); + return (T)( lhs & (unsigned __int16)rhs ); + } +}; + +template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 > +{ +public: + static T And( T lhs, U rhs ) SAFEINT_NOTHROW + { + //cast forces sign extension to be zeros + BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) ); + return (T)( lhs & (unsigned __int32)rhs ); + } +}; + +template < typename T, typename U, int method > class BinaryOrHelper; + +template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK > +{ +public: + static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); } +}; + +template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 > +{ +public: + static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + { + //cast forces sign extension to be zeros + BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) ); + return (T)( lhs | (unsigned __int8)rhs ); + } +}; + +template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 > +{ +public: + static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + { + //cast forces sign extension to be zeros + BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) ); + return (T)( lhs | (unsigned __int16)rhs ); + } +}; + +template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 > +{ +public: + static T Or( T lhs, U rhs ) SAFEINT_NOTHROW + { + //cast forces sign extension to be zeros + BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) ); + return (T)( lhs | (unsigned __int32)rhs ); + } +}; + +template class BinaryXorHelper; + +template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK > +{ +public: + static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); } +}; + +template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 > +{ +public: + static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + { + // cast forces sign extension to be zeros + BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) ); + return (T)( lhs ^ (unsigned __int8)rhs ); + } +}; + +template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 > +{ +public: + static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + { + // cast forces sign extension to be zeros + BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) ); + return (T)( lhs ^ (unsigned __int16)rhs ); + } +}; + +template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 > +{ +public: + static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW + { + // cast forces sign extension to be zeros + BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) ); + return (T)( lhs ^ (unsigned __int32)rhs ); + } +}; + +/***************** External functions ****************************************/ + +// External functions that can be used where you only need to check one operation +// non-class helper function so that you can check for a cast's validity +// and handle errors how you like +template < typename T, typename U > +inline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW +{ + return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To ); +} + +template < typename T, typename U > +inline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW +{ + return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); +} + +template < typename T, typename U > +inline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW +{ + return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); +} + +template < typename T, typename U > +inline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW +{ + return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); +} + +template < typename T, typename U > +inline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); +} + +template < typename T, typename U > +inline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW +{ + return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); +} + +template < typename T, typename U > +inline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); +} + +template < typename T, typename U > +inline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW +{ + return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError ); +} + +template < typename T, typename U > +inline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW +{ + return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result ); +} + +template < typename T, typename U > +inline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW +{ + return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError ); +} + +template < typename T, typename U > +inline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW +{ + return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result ); +} + +template < typename T, typename U > +inline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW +{ + return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result ); +} + +/***************** end external functions ************************************/ + +// Main SafeInt class +// Assumes exceptions can be thrown +template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt +{ +public: + SafeInt() SAFEINT_NOTHROW + { + C_ASSERT( NumericType< T >::isInt ); + m_int = 0; + } + + // Having a constructor for every type of int + // avoids having the compiler evade our checks when doing implicit casts - + // e.g., SafeInt s = 0x7fffffff; + SafeInt( const T& i ) SAFEINT_NOTHROW + { + C_ASSERT( NumericType< T >::isInt ); + //always safe + m_int = i; + } + + // provide explicit boolean converter + SafeInt( bool b ) SAFEINT_NOTHROW + { + C_ASSERT( NumericType< T >::isInt ); + m_int = (T)( b ? 1 : 0 ); + } + + template < typename U > + SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW + { + C_ASSERT( NumericType< T >::isInt ); + *this = SafeInt< T, E >( (U)u ); + } + + template < typename U > + SafeInt( const U& i ) SAFEINT_CPP_THROW + { + C_ASSERT( NumericType< T >::isInt ); + // SafeCast will throw exceptions if i won't fit in type T + SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int ); + } + + // The destructor is intentionally commented out - no destructor + // vs. a do-nothing destructor makes a huge difference in + // inlining characteristics. It wasn't doing anything anyway. + // ~SafeInt(){}; + + + // now start overloading operators + // assignment operator + // constructors exist for all int types and will ensure safety + + template < typename U > + SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW + { + // use constructor to test size + // constructor is optimized to do minimal checking based + // on whether T can contain U + // note - do not change this + *this = SafeInt< T, E >( rhs ); + return *this; + } + + SafeInt< T, E >& operator =( const T& rhs ) SAFEINT_NOTHROW + { + m_int = rhs; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW + { + SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int ); + return *this; + } + + SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) SAFEINT_NOTHROW + { + m_int = rhs.m_int; + return *this; + } + + // Casting operators + + operator bool() const SAFEINT_NOTHROW + { + return !!m_int; + } + + operator char() const SAFEINT_CPP_THROW + { + char val; + SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator signed char() const SAFEINT_CPP_THROW + { + signed char val; + SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator unsigned char() const SAFEINT_CPP_THROW + { + unsigned char val; + SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator __int16() const SAFEINT_CPP_THROW + { + __int16 val; + SafeCastHelper< __int16, T, GetCastMethod< __int16, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator unsigned __int16() const SAFEINT_CPP_THROW + { + unsigned __int16 val; + SafeCastHelper< unsigned __int16, T, GetCastMethod< unsigned __int16, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator __int32() const SAFEINT_CPP_THROW + { + __int32 val; + SafeCastHelper< __int32, T, GetCastMethod< __int32, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator unsigned __int32() const SAFEINT_CPP_THROW + { + unsigned __int32 val; + SafeCastHelper< unsigned __int32, T, GetCastMethod< unsigned __int32, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + // The compiler knows that int == __int32 + // but not that long == __int32 + operator long() const SAFEINT_CPP_THROW + { + long val; + SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator unsigned long() const SAFEINT_CPP_THROW + { + unsigned long val; + SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator __int64() const SAFEINT_CPP_THROW + { + __int64 val; + SafeCastHelper< __int64, T, GetCastMethod< __int64, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator unsigned __int64() const SAFEINT_CPP_THROW + { + unsigned __int64 val; + SafeCastHelper< unsigned __int64, T, GetCastMethod< unsigned __int64, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + +#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED + operator wchar_t() const SAFEINT_CPP_THROW + { + wchar_t val; + SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } +#endif + +#ifdef SIZE_T_CAST_NEEDED + // We also need an explicit cast to size_t, or the compiler will complain + // Apparently, only SOME compilers complain, and cl 14.00.50727.42 isn't one of them + // Leave here in case we decide to backport this to an earlier compiler + operator size_t() const SAFEINT_CPP_THROW + { + size_t val; + SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } +#endif + + // Also provide a cast operator for floating point types + operator float() const SAFEINT_CPP_THROW + { + float val; + SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + operator double() const SAFEINT_CPP_THROW + { + double val; + SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + operator long double() const SAFEINT_CPP_THROW + { + long double val; + SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val ); + return val; + } + + // If you need a pointer to the data + // this could be dangerous, but allows you to correctly pass + // instances of this class to APIs that take a pointer to an integer + // also see overloaded address-of operator below + T* Ptr() SAFEINT_NOTHROW { return &m_int; } + const T* Ptr() const SAFEINT_NOTHROW { return &m_int; } + const T& Ref() const SAFEINT_NOTHROW { return m_int; } + + // Or if SafeInt< T, E >::Ptr() is inconvenient, use the overload + // operator & + // This allows you to do unsafe things! + // It is meant to allow you to more easily + // pass a SafeInt into things like ReadFile + T* operator &() SAFEINT_NOTHROW { return &m_int; } + const T* operator &() const SAFEINT_NOTHROW { return &m_int; } + + // Unary operators + bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; } + + // operator + (unary) + // note - normally, the '+' and '-' operators will upcast to a signed int + // for T < 32 bits. This class changes behavior to preserve type + const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; } + + //unary - + + SafeInt< T, E > operator -() const SAFEINT_CPP_THROW + { + // Note - unsigned still performs the bitwise manipulation + // will warn at level 2 or higher if the value is 32-bit or larger + return SafeInt(NegationHelper::isSigned>::template NegativeThrow(m_int)); + } + + // prefix increment operator + SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW + { + if( m_int != IntTraits< T >::maxInt ) + { + ++m_int; + return *this; + } + E::SafeIntOnOverflow(); + } + + // prefix decrement operator + SafeInt< T, E >& operator --() SAFEINT_CPP_THROW + { + if( m_int != IntTraits< T >::minInt ) + { + --m_int; + return *this; + } + E::SafeIntOnOverflow(); + } + + // note that postfix operators have inherently worse perf + // characteristics + + // postfix increment operator + SafeInt< T, E > operator ++( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec + { + if( m_int != IntTraits< T >::maxInt ) + { + SafeInt< T, E > tmp( m_int ); + + m_int++; + return tmp; + } + E::SafeIntOnOverflow(); + } + + // postfix decrement operator + SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec + { + if( m_int != IntTraits< T >::minInt ) + { + SafeInt< T, E > tmp( m_int ); + m_int--; + return tmp; + } + E::SafeIntOnOverflow(); + } + + // One's complement + // Note - this operator will normally change size to an int + // cast in return improves perf and maintains type + SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); } + + // Binary operators + // + // arithmetic binary operators + // % modulus + // * multiplication + // / division + // + addition + // - subtraction + // + // For each of the arithmetic operators, you will need to + // use them as follows: + // + // SafeInt c = 2; + // SafeInt i = 3; + // + // SafeInt i2 = i op (char)c; + // OR + // SafeInt i2 = (int)i op c; + // + // The base problem is that if the lhs and rhs inputs are different SafeInt types + // it is not possible in this implementation to determine what type of SafeInt + // should be returned. You have to let the class know which of the two inputs + // need to be the return type by forcing the other value to the base integer type. + // + // Note - as per feedback from Scott Meyers, I'm exploring how to get around this. + // 3.0 update - I'm still thinking about this. It can be done with template metaprogramming, + // but it is tricky, and there's a perf vs. correctness tradeoff where the right answer + // is situational. + // + // The case of: + // + // SafeInt< T, E > i, j, k; + // i = j op k; + // + // works just fine and no unboxing is needed because the return type is not ambiguous. + + // Modulus + // Modulus has some convenient properties - + // first, the magnitude of the return can never be + // larger than the lhs operand, and it must be the same sign + // as well. It does, however, suffer from the same promotion + // problems as comparisons, division and other operations + template < typename U > + SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW + { + T result; + ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result ); + return SafeInt< T, E >( result ); + } + + SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + { + T result; + ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result ); + return SafeInt< T, E >( result ); + } + + // Modulus assignment + template < typename U > + SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW + { + ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + { + ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int ); + return *this; + } + + // Multiplication + template < typename U > + SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret ); + return SafeInt< T, E >( ret ); + } + + SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret ); + return SafeInt< T, E >( ret ); + } + + // Multiplication assignment + SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + { + MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW + { + MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + { + MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int ); + return *this; + } + + // Division + template < typename U > + SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret ); + return SafeInt< T, E >( ret ); + } + + SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret ); + return SafeInt< T, E >( ret ); + } + + // Division assignment + SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW + { + DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int ); + return *this; + } + + template < typename U > SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW + { + DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int ); + return *this; + } + + template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i ) + { + DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int ); + return *this; + } + + // For addition and subtraction + + // Addition + SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret ); + return SafeInt< T, E >( ret ); + } + + template < typename U > + SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret ); + return SafeInt< T, E >( ret ); + } + + //addition assignment + SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + { + AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW + { + AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + { + AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int ); + return *this; + } + + // Subtraction + template < typename U > + SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW + { + T ret( 0 ); + SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret ); + return SafeInt< T, E >( ret ); + } + + SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW + { + T ret( 0 ); + SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret ); + return SafeInt< T, E >( ret ); + } + + // Subtraction assignment + SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW + { + SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW + { + SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW + { + SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int ); + return *this; + } + + // Shift operators + // Note - shift operators ALWAYS return the same type as the lhs + // specific version for SafeInt< T, E > not needed - + // code path is exactly the same as for SafeInt< U, E > as rhs + + // Left shift + // Also, shifting > bitcount is undefined - trap in debug +#ifdef SAFEINT_DISABLE_SHIFT_ASSERT + #define ShiftAssert(x) +#else + #define ShiftAssert(x) SAFEINT_ASSERT(x) +#endif + + template < typename U > + SafeInt< T, E > operator <<( U bits ) const SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); + ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + + return SafeInt< T, E >( (T)( m_int << bits ) ); + } + + template < typename U > + SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); + ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + + return SafeInt< T, E >( (T)( m_int << (U)bits ) ); + } + + // Left shift assignment + + template < typename U > + SafeInt< T, E >& operator <<=( U bits ) SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); + ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + + m_int <<= bits; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); + ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + + m_int <<= (U)bits; + return *this; + } + + // Right shift + template < typename U > + SafeInt< T, E > operator >>( U bits ) const SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); + ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + + return SafeInt< T, E >( (T)( m_int >> bits ) ); + } + + template < typename U > + SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); + ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + + return SafeInt< T, E >( (T)(m_int >> (U)bits) ); + } + + // Right shift assignment + template < typename U > + SafeInt< T, E >& operator >>=( U bits ) SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); + ShiftAssert( bits < (int)IntTraits< T >::bitCount ); + + m_int >>= bits; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_NOTHROW + { + ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); + ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); + + m_int >>= (U)bits; + return *this; + } + + // Bitwise operators + // This only makes sense if we're dealing with the same type and size + // demand a type T, or something that fits into a type T + + // Bitwise & + SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW + { + return SafeInt< T, E >( m_int & (T)rhs ); + } + + template < typename U > + SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW + { + // we want to avoid setting bits by surprise + // consider the case of lhs = int, value = 0xffffffff + // rhs = char, value = 0xff + // + // programmer intent is to get only the lower 8 bits + // normal behavior is to upcast both sides to an int + // which then sign extends rhs, setting all the bits + + // If you land in the assert, this is because the bitwise operator + // was causing unexpected behavior. Fix is to properly cast your inputs + // so that it works like you meant, not unexpectedly + + return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) ); + } + + // Bitwise & assignment + SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + { + m_int &= (T)rhs; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW + { + m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + { + m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs ); + return *this; + } + + // XOR + SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW + { + return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) ); + } + + template < typename U > + SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW + { + // If you land in the assert, this is because the bitwise operator + // was causing unexpected behavior. Fix is to properly cast your inputs + // so that it works like you meant, not unexpectedly + + return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) ); + } + + // XOR assignment + SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + { + m_int ^= (T)rhs; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW + { + m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + { + m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs ); + return *this; + } + + // bitwise OR + SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW + { + return SafeInt< T, E >( (T)( m_int | (T)rhs ) ); + } + + template < typename U > + SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW + { + return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) ); + } + + // bitwise OR assignment + SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW + { + m_int |= (T)rhs; + return *this; + } + + template < typename U > + SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW + { + m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ); + return *this; + } + + template < typename U > + SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW + { + m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs ); + return *this; + } + + // Miscellaneous helper functions + SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = IntTraits< T >::minInt ) const SAFEINT_NOTHROW + { + T tmp = test < m_int ? (T)test : m_int; + return tmp < floor ? floor : tmp; + } + + SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = IntTraits< T >::maxInt ) const SAFEINT_NOTHROW + { + T tmp = test > m_int ? (T)test : m_int; + return tmp > upper ? upper : tmp; + } + + void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW + { + T temp( m_int ); + m_int = with.m_int; + with.m_int = temp; + } + + static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW + { + return SafeTtoI( input ); + } + + static SafeInt< T, E > SafeWtoI( const wchar_t* input ) + { + return SafeTtoI( input ); + } + + enum alignBits + { + align2 = 1, + align4 = 2, + align8 = 3, + align16 = 4, + align32 = 5, + align64 = 6, + align128 = 7, + align256 = 8 + }; + + template < alignBits bits > + const SafeInt< T, E >& Align() SAFEINT_CPP_THROW + { + // Zero is always aligned + if( m_int == 0 ) + return *this; + + // We don't support aligning negative numbers at this time + // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255) + // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127). + // Also makes no sense to try to align on negative or no bits. + + ShiftAssert( ( ( IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount - 1 ) + || ( !IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount ) ) && + bits >= 0 && ( !IntTraits::isSigned || m_int > 0 ) ); + + const T AlignValue = ( (T)1 << bits ) - 1; + + m_int = (T)( ( m_int + AlignValue ) & ~AlignValue ); + + if( m_int <= 0 ) + E::SafeIntOnOverflow(); + + return *this; + } + + // Commonly needed alignments: + const SafeInt< T, E >& Align2() { return Align< align2 >(); } + const SafeInt< T, E >& Align4() { return Align< align4 >(); } + const SafeInt< T, E >& Align8() { return Align< align8 >(); } + const SafeInt< T, E >& Align16() { return Align< align16 >(); } + const SafeInt< T, E >& Align32() { return Align< align32 >(); } + const SafeInt< T, E >& Align64() { return Align< align64 >(); } +private: + + // This is almost certainly not the best optimized version of atoi, + // but it does not display a typical bug where it isn't possible to set MinInt + // and it won't allow you to overflow your integer. + // This is here because it is useful, and it is an example of what + // can be done easily with SafeInt. + template < typename U > + static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW + { + U* tmp = input; + SafeInt< T, E > s; + bool negative = false; + + // Bad input, or empty string + if( input == nullptr || input[0] == 0 ) + E::SafeIntOnOverflow(); + + switch( *tmp ) + { + case '-': + tmp++; + negative = true; + break; + case '+': + tmp++; + break; + } + + while( *tmp != 0 ) + { + if( *tmp < '0' || *tmp > '9' ) + break; + + if( (T)s != 0 ) + s *= (T)10; + + if( !negative ) + s += (T)( *tmp - '0' ); + else + s -= (T)( *tmp - '0' ); + + tmp++; + } + + return s; + } + + T m_int; +}; + +// Helper function used to subtract pointers. +// Used to squelch warnings +template +SafeInt SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW +{ + return SafeInt( p1 - p2 ); +} + +// Comparison operators + +//Less than +template < typename T, typename U, typename E > +bool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); +} + +template < typename T, typename U, typename E > +bool operator <( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); +} + +template < typename T, typename U, typename E > +bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs ); +} + +// Greater than +template < typename T, typename U, typename E > +bool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); +} + +template < typename T, typename U, typename E > +bool operator >( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); +} + +template < typename T, typename U, typename E > +bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); +} + +// Greater than or equal +template < typename T, typename U, typename E > +bool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); +} + +template < typename T, typename U, typename E > +bool operator >=( SafeInt lhs, U rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); +} + +template < typename T, typename U, typename E > +bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs ); +} + +// Less than or equal +template < typename T, typename U, typename E > +bool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); +} + +template < typename T, typename U, typename E > +bool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); +} + +template < typename T, typename U, typename E > +bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); +} + +// equality +// explicit overload for bool +template < typename T, typename E > +bool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return lhs == ( (T)rhs == 0 ? false : true ); +} + +template < typename T, typename E > +bool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW +{ + return rhs == ( (T)lhs == 0 ? false : true ); +} + +template < typename T, typename U, typename E > +bool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs); +} + +template < typename T, typename U, typename E > +bool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +{ + return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); +} + +template < typename T, typename U, typename E > +bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs ); +} + +//not equals +template < typename T, typename U, typename E > +bool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs ); +} + +template < typename T, typename U, typename E > +bool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW +{ + return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); +} + +template < typename T, typename U, typename E > +bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs ); +} + + +template < typename T, typename E > +bool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return ( (T)rhs == 0 ? false : true ) != lhs; +} + +template < typename T, typename E > +bool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW +{ + return ( (T)lhs == 0 ? false : true ) != rhs; +} + + +template < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper; + +template < typename T, typename E, int method > class ModulusSignedCaseHelper; + +template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true > +{ +public: + static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW + { + if( (T)rhs == (T)-1 ) + { + result = 0; + return true; + } + return false; + } +}; + +template < typename T, typename E > class ModulusSignedCaseHelper < T, E, false > +{ +public: + static bool SignedCase( SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW + { + return false; + } +}; + +template < typename T, typename U, typename E > +class ModulusSimpleCaseHelper < T, U, E, true > +{ +public: + static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW + { + if( rhs != 0 ) + { + if( ModulusSignedCaseHelper< T, E, IntTraits< T >::isSigned >::SignedCase( rhs, result ) ) + return true; + + result = SafeInt< T, E >( (T)( lhs % (T)rhs ) ); + return true; + } + + E::SafeIntOnDivZero(); + } +}; + +template< typename T, typename U, typename E > +class ModulusSimpleCaseHelper < T, U, E, false > +{ +public: + static bool ModulusSimpleCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW + { + return false; + } +}; + +// Modulus +template < typename T, typename U, typename E > +SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +{ + // Value of return depends on sign of lhs + // This one may not be safe - bounds check in constructor + // if lhs is negative and rhs is unsigned, this will throw an exception. + + // Fast-track the simple case + // same size and same sign + SafeInt< T, E > result; + + if( ModulusSimpleCaseHelper< T, U, E, + sizeof(T) == sizeof(U) && (bool)IntTraits< T >::isSigned == (bool)IntTraits< U >::isSigned >::ModulusSimpleCase( lhs, rhs, result ) ) + return result; + + return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) ); +} + +// Multiplication +template < typename T, typename U, typename E > +SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret ); + return SafeInt< T, E >(ret); +} + +template < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper; + +template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true > +{ +public: + static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + { + // Problem case - normal casting behavior changes meaning + // flip rhs to positive + // any operator casts now do the right thing + U tmp; + + if( CompileConst< sizeof(T) == 4 >::Value() ) + tmp = lhs/(U)( ~(unsigned __int32)(T)rhs + 1 ); + else + tmp = lhs/(U)( ~(unsigned __int64)(T)rhs + 1 ); + + if( tmp <= (U)IntTraits< T >::maxInt ) + { + result = SafeInt< T, E >( (T)(~(unsigned __int64)tmp + 1) ); + return true; + } + + // Corner case + T maxT = IntTraits< T >::maxInt; + if( tmp == (U)maxT + 1 ) + { + T minT = IntTraits< T >::minInt; + result = SafeInt< T, E >( minT ); + return true; + } + + E::SafeIntOnOverflow(); + } +}; + +template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false > +{ +public: + static bool NegativeCornerCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + { + return false; + } +}; + +template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper; + +template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true > +{ +public: + static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + { + if( (T)rhs > 0 ) + { + result = SafeInt< T, E >( lhs/(T)rhs ); + return true; + } + + // Now rhs is either negative, or zero + if( (T)rhs != 0 ) + { + if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) ) + return true; + + result = SafeInt< T, E >(lhs/(T)rhs); + return true; + } + + E::SafeIntOnDivZero(); + } +}; + +template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false > +{ +public: + static bool DivisionCornerCase1( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + { + return false; + } +}; + +template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2; + +template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true > +{ +public: + static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW + { + if( lhs == IntTraits< U >::minInt && (T)rhs == -1 ) + { + // corner case of a corner case - lhs = min int, rhs = -1, + // but rhs is the return type, so in essence, we can return -lhs + // if rhs is a larger type than lhs + // If types are wrong, throws + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning(push) +//cast truncates constant value +#pragma warning(disable:4310) +#endif + + if( CompileConst::Value() ) + result = SafeInt< T, E >( (T)( -(T)IntTraits< U >::minInt ) ); + else + E::SafeIntOnOverflow(); + +#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER +#pragma warning(pop) +#endif + + return true; + } + + return false; + } +}; + +template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false > +{ +public: + static bool DivisionCornerCase2( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW + { + return false; + } +}; + +// Division +template < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +{ + // Corner case - has to be handled seperately + SafeInt< T, E > result; + if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) ) + return result; + + if( DivisionCornerCaseHelper2< T, U, E, SafeIntCompare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) ) + return result; + + // Otherwise normal logic works with addition of bounds check when casting from U->T + U ret; + DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret ); + return SafeInt< T, E >( ret ); +} + +// Addition +template < typename T, typename U, typename E > +SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret ); + return SafeInt< T, E >( ret ); +} + +// Subtraction +template < typename T, typename U, typename E > +SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret ); + + return SafeInt< T, E >( ret ); +} + +// Overrides designed to deal with cases where a SafeInt is assigned out +// to a normal int - this at least makes the last operation safe +// += +template < typename T, typename U, typename E > +T& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret ); + lhs = ret; + return lhs; +} + +template < typename T, typename U, typename E > +T& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret ); + lhs = ret; + return lhs; +} + +template < typename T, typename U, typename E > +T& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret ); + lhs = ret; + return lhs; +} + +template < typename T, typename U, typename E > +T& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret ); + lhs = ret; + return lhs; +} + +template < typename T, typename U, typename E > +T& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + T ret( 0 ); + ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret ); + lhs = ret; + return lhs; +} + +template < typename T, typename U, typename E > +T& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs ); + return lhs; +} + +template < typename T, typename U, typename E > +T& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs ); + return lhs; +} + +template < typename T, typename U, typename E > +T& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs ); + return lhs; +} + +template < typename T, typename U, typename E > +T& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs ); + return lhs; +} + +template < typename T, typename U, typename E > +T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW +{ + lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs ); + return lhs; +} + +// Specific pointer overrides +// Note - this function makes no attempt to ensure +// that the resulting pointer is still in the buffer, only +// that no int overflows happened on the way to getting the new pointer +template < typename T, typename U, typename E > +T*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + // Cast the pointer to a number so we can do arithmetic + SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); + // Check first that rhs is valid for the type of ptrdiff_t + // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t + // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff + // Finally, cast the number back to a pointer of the correct type + lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); + return lhs; +} + +template < typename T, typename U, typename E > +T*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW +{ + // Cast the pointer to a number so we can do arithmetic + SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); + // See above for comments + lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); + return lhs; +} + +template < typename T, typename U, typename E > +T*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +template < typename T, typename U, typename E > +T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW +{ + // This operator explicitly not supported + C_ASSERT( sizeof(T) == 0 ); + return (lhs = NULL); +} + +// Shift operators +// NOTE - shift operators always return the type of the lhs argument + +// Left shift +template < typename T, typename U, typename E > +SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW +{ + ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); + ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); + + return SafeInt< U, E >( (U)( lhs << (T)bits ) ); +} + +// Right shift +template < typename T, typename U, typename E > +SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW +{ + ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); + ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); + + return SafeInt< U, E >( (U)( lhs >> (T)bits ) ); +} + +// Bitwise operators +// This only makes sense if we're dealing with the same type and size +// demand a type T, or something that fits into a type T. + +// Bitwise & +template < typename T, typename U, typename E > +SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) ); +} + +// Bitwise XOR +template < typename T, typename U, typename E > +SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) ); +} + +// Bitwise OR +template < typename T, typename U, typename E > +SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW +{ + return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) ); +} + +#if SAFEINT_COMPILER == GCC_COMPILER +#pragma GCC diagnostic pop +#endif + +#if SAFEINT_COMPILER == CLANG_COMPILER +#pragma clang diagnostic pop +#endif + +} // utilities +} // safeint3 + diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h b/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h new file mode 100755 index 000000000..ea28f8260 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h @@ -0,0 +1,140 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Platform-dependent type definitions +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#include +#include +#include +#include +#include "cpprest/details/cpprest_compat.h" + +#ifndef _WIN32 +# define __STDC_LIMIT_MACROS +# include +#else +#include +#endif + +#include "cpprest/details/SafeInt3.hpp" + +namespace utility +{ + +#ifdef _WIN32 +#define _UTF16_STRINGS +#endif + +// We should be using a 64-bit size type for most situations that do +// not involve specifying the size of a memory allocation or buffer. +typedef uint64_t size64_t; + +#ifndef _WIN32 +typedef uint32_t HRESULT; // Needed for PPLX +#endif + +#ifdef _UTF16_STRINGS +// +// On Windows, all strings are wide +// +typedef wchar_t char_t ; +typedef std::wstring string_t; +#define _XPLATSTR(x) L ## x +typedef std::wostringstream ostringstream_t; +typedef std::wofstream ofstream_t; +typedef std::wostream ostream_t; +typedef std::wistream istream_t; +typedef std::wifstream ifstream_t; +typedef std::wistringstream istringstream_t; +typedef std::wstringstream stringstream_t; +#define ucout std::wcout +#define ucin std::wcin +#define ucerr std::wcerr +#else +// +// On POSIX platforms, all strings are narrow +// +typedef char char_t; +typedef std::string string_t; +#define _XPLATSTR(x) x +typedef std::ostringstream ostringstream_t; +typedef std::ofstream ofstream_t; +typedef std::ostream ostream_t; +typedef std::istream istream_t; +typedef std::ifstream ifstream_t; +typedef std::istringstream istringstream_t; +typedef std::stringstream stringstream_t; +#define ucout std::cout +#define ucin std::cin +#define ucerr std::cerr +#endif // endif _UTF16_STRINGS + +#ifndef _TURN_OFF_PLATFORM_STRING +#define U(x) _XPLATSTR(x) +#endif // !_TURN_OFF_PLATFORM_STRING + +}// namespace utility + +typedef char utf8char; +typedef std::string utf8string; +typedef std::stringstream utf8stringstream; +typedef std::ostringstream utf8ostringstream; +typedef std::ostream utf8ostream; +typedef std::istream utf8istream; +typedef std::istringstream utf8istringstream; + +#ifdef _UTF16_STRINGS +typedef wchar_t utf16char; +typedef std::wstring utf16string; +typedef std::wstringstream utf16stringstream; +typedef std::wostringstream utf16ostringstream; +typedef std::wostream utf16ostream; +typedef std::wistream utf16istream; +typedef std::wistringstream utf16istringstream; +#else +typedef char16_t utf16char; +typedef std::u16string utf16string; +typedef std::basic_stringstream utf16stringstream; +typedef std::basic_ostringstream utf16ostringstream; +typedef std::basic_ostream utf16ostream; +typedef std::basic_istream utf16istream; +typedef std::basic_istringstream utf16istringstream; +#endif + + +#if defined(_WIN32) +// Include on everything except Windows Desktop ARM, unless explicitly excluded. +#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) +#if defined(WINAPI_FAMILY) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM) +#define CPPREST_EXCLUDE_WEBSOCKETS +#endif +#else +#if defined(_M_ARM) +#define CPPREST_EXCLUDE_WEBSOCKETS +#endif +#endif +#endif +#endif diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h b/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h new file mode 100755 index 000000000..240a33899 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h @@ -0,0 +1,97 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Standard macros and definitions. +* This header has minimal dependency on windows headers and is safe for use in the public API +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#if defined(_WIN32) // Settings specific to Windows + +#if _MSC_VER >= 1900 +#define CPPREST_NOEXCEPT noexcept +#else +#define CPPREST_NOEXCEPT +#endif + +#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x) + +#include + +#else // End settings specific to Windows + +// Settings common to all but Windows + +#define __declspec(x) __attribute__ ((x)) +#define dllimport +#define novtable /* no novtable equivalent */ +#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false) +#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x +#define CPPREST_NOEXCEPT noexcept + +#include +#define _ASSERTE(x) assert(x) + +// No SAL on non Windows platforms +#include "cpprest/details/nosal.h" + +#if not defined __cdecl +#if defined cdecl +#define __cdecl __attribute__ ((cdecl)) +#else +#define __cdecl +#endif + +#if defined(__ANDROID__) +// This is needed to disable the use of __thread inside the boost library. +// Android does not support thread local storage -- if boost is included +// without this macro defined, it will create references to __tls_get_addr +// which (while able to link) will not be available at runtime and prevent +// the .so from loading. +#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION +#endif + +#ifdef __clang__ +#include +#endif + +#endif // defined(__APPLE__) + +#endif + + +#ifdef _NO_ASYNCRTIMP +#define _ASYNCRTIMP +#else +#ifdef _ASYNCRT_EXPORT +#define _ASYNCRTIMP __declspec(dllexport) +#else +#define _ASYNCRTIMP __declspec(dllimport) +#endif +#endif + +#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS +#define CASABLANCA_DEPRECATED(x) +#else +#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x)) +#endif diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h b/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h new file mode 100755 index 000000000..4d7e583a7 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h @@ -0,0 +1,89 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +***/ + +#pragma once +// selected MS SAL annotations + +#ifdef _In_ +#undef _In_ +#endif +#define _In_ + +#ifdef _Inout_ +#undef _Inout_ +#endif +#define _Inout_ + +#ifdef _Out_ +#undef _Out_ +#endif +#define _Out_ + +#ifdef _In_z_ +#undef _In_z_ +#endif +#define _In_z_ + +#ifdef _Out_z_ +#undef _Out_z_ +#endif +#define _Out_z_ + +#ifdef _Inout_z_ +#undef _Inout_z_ +#endif +#define _Inout_z_ + +#ifdef _In_opt_ +#undef _In_opt_ +#endif +#define _In_opt_ + +#ifdef _Out_opt_ +#undef _Out_opt_ +#endif +#define _Out_opt_ + +#ifdef _Inout_opt_ +#undef _Inout_opt_ +#endif +#define _Inout_opt_ + +#ifdef _Out_writes_ +#undef _Out_writes_ +#endif +#define _Out_writes_(x) + +#ifdef _Out_writes_opt_ +#undef _Out_writes_opt_ +#endif +#define _Out_writes_opt_(x) + +#ifdef _In_reads_ +#undef _In_reads_ +#endif +#define _In_reads_(x) + +#ifdef _Inout_updates_bytes_ +#undef _Inout_updates_bytes_ +#endif +#define _Inout_updates_bytes_(x) \ No newline at end of file diff --git a/src/corehost/cli/json/casablanca/include/cpprest/json.h b/src/corehost/cli/json/casablanca/include/cpprest/json.h new file mode 100755 index 000000000..704cbfad9 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/cpprest/json.h @@ -0,0 +1,1936 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* HTTP Library: JSON parser and writer +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ +#pragma once + +#ifndef _CASA_JSON_H +#define _CASA_JSON_H + +#include +#include +#include +#include +#include +#include +#include "cpprest/details/basic_types.h" +#include "cpprest/asyncrt_utils.h" + +namespace web +{ +/// Library for parsing and serializing JSON values to and from C++ types. +namespace json +{ + // Various forward declarations. + namespace details + { + class _Value; + class _Number; + class _Null; + class _Boolean; + class _String; + class _Object; + class _Array; + template class JSON_Parser; + } + + namespace details + { + extern bool g_keep_json_object_unsorted; + } + + /// + /// Preserve the order of the name/value pairs when parsing a JSON object. + /// The default is false, which can yield better performance. + /// + /// true if ordering should be preserved when parsing, false otherwise. + /// Note this is a global setting and affects all JSON parsing done. + void _ASYNCRTIMP __cdecl keep_object_element_order(bool keep_order); + +#ifdef _WIN32 +#ifdef _DEBUG +#define ENABLE_JSON_VALUE_VISUALIZER +#endif +#endif + + class number; + class array; + class object; + + /// + /// A JSON value represented as a C++ class. + /// + class value + { + public: + /// + /// This enumeration represents the various kinds of JSON values. + /// + enum value_type + { + /// Number value + Number, + /// Boolean value + Boolean, + /// String value + String, + /// Object value + Object, + /// Array value + Array, + /// Null value + Null + }; + + /// + /// Constructor creating a null value + /// + _ASYNCRTIMP value(); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(int32_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(uint32_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(int64_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(uint64_t value); + + /// + /// Constructor creating a JSON number value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP value(double value); + + /// + /// Constructor creating a JSON Boolean value + /// + /// The C++ value to create a JSON value from + _ASYNCRTIMP explicit value(bool value); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width + /// + /// This constructor has O(n) performance because it tries to determine if + /// specified string has characters that should be properly escaped in JSON. + /// + _ASYNCRTIMP explicit value(utility::string_t value); + + /// + /// Constructor creating a JSON string value specifying if the string contains characters to escape + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width + /// Whether contains characters + /// that should be escaped in JSON value + /// + /// This constructor has O(1) performance. + /// + _ASYNCRTIMP explicit value(utility::string_t value, bool has_escape_chars); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width + /// + /// + /// This constructor has O(n) performance because it tries to determine if + /// specified string has characters that should be properly escaped in JSON. + /// + /// + /// This constructor exists in order to avoid string literals matching another constructor, + /// as is very likely. For example, conversion to bool does not require a user-defined conversion, + /// and will therefore match first, which means that the JSON value turns up as a boolean. + /// + /// + _ASYNCRTIMP explicit value(const utility::char_t* value); + + /// + /// Constructor creating a JSON string value + /// + /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width + /// Whether contains characters + /// + /// + /// This overload has O(1) performance. + /// + /// + /// This constructor exists in order to avoid string literals matching another constructor, + /// as is very likely. For example, conversion to bool does not require a user-defined conversion, + /// and will therefore match first, which means that the JSON value turns up as a boolean. + /// + /// + _ASYNCRTIMP explicit value(const utility::char_t* value, bool has_escape_chars); + + /// + /// Copy constructor + /// + _ASYNCRTIMP value(const value &); + + /// + /// Move constructor + /// + _ASYNCRTIMP value(value &&) CPPREST_NOEXCEPT ; + + /// + /// Assignment operator. + /// + /// The JSON value object that contains the result of the assignment. + _ASYNCRTIMP value &operator=(const value &); + + /// + /// Move assignment operator. + /// + /// The JSON value object that contains the result of the assignment. + _ASYNCRTIMP value &operator=(value &&) CPPREST_NOEXCEPT ; + + // Static factories + + /// + /// Creates a null value + /// + /// A JSON null value + static _ASYNCRTIMP value __cdecl null(); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(double value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(int32_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(uint32_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(int64_t value); + + /// + /// Creates a number value + /// + /// The C++ value to create a JSON value from + /// A JSON number value + static _ASYNCRTIMP value __cdecl number(uint64_t value); + + /// + /// Creates a Boolean value + /// + /// The C++ value to create a JSON value from + /// A JSON Boolean value + static _ASYNCRTIMP value __cdecl boolean(bool value); + + /// + /// Creates a string value + /// + /// The C++ value to create a JSON value from + /// A JSON string value + /// + /// This overload has O(n) performance because it tries to determine if + /// specified string has characters that should be properly escaped in JSON. + /// + static _ASYNCRTIMP value __cdecl string(utility::string_t value); + + /// + /// Creates a string value specifying if the string contains characters to escape + /// + /// The C++ value to create a JSON value from + /// Whether contains characters + /// that should be escaped in JSON value + /// A JSON string value + /// + /// This overload has O(1) performance. + /// + static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars); + +#ifdef _WIN32 +private: + // Only used internally by JSON parser. + static _ASYNCRTIMP value __cdecl string(const std::string &value); +public: +#endif + + /// + /// Creates an object value + /// + /// Whether to preserve the original order of the fields + /// An empty JSON object value + static _ASYNCRTIMP json::value __cdecl object(bool keep_order = false); + + /// + /// Creates an object value from a collection of field/values + /// + /// Field names associated with JSON values + /// Whether to preserve the original order of the fields + /// A non-empty JSON object value + static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, bool keep_order = false); + + /// + /// Creates an empty JSON array + /// + /// An empty JSON array value + static _ASYNCRTIMP json::value __cdecl array(); + + /// + /// Creates a JSON array + /// + /// The initial number of elements of the JSON value + /// A JSON array value + static _ASYNCRTIMP json::value __cdecl array(size_t size); + + /// + /// Creates a JSON array + /// + /// A vector of JSON values + /// A JSON array value + static _ASYNCRTIMP json::value __cdecl array(std::vector elements); + + /// + /// Accesses the type of JSON value the current value instance is + /// + /// The value's type + _ASYNCRTIMP json::value::value_type type() const; + + /// + /// Is the current value a null value? + /// + /// true if the value is a null value, false otherwise + bool is_null() const { return type() == Null; }; + + /// + /// Is the current value a number value? + /// + /// true if the value is a number value, false otherwise + bool is_number() const { return type() == Number; } + + /// + /// Is the current value represented as an integer number value? + /// + /// + /// Note that if a json value is a number but represented as a double it can still + /// be retrieved as a integer using as_integer(), however the value will be truncated. + /// + /// true if the value is an integer value, false otherwise. + _ASYNCRTIMP bool is_integer() const; + + /// + /// Is the current value represented as an double number value? + /// + /// + /// Note that if a json value is a number but represented as a int it can still + /// be retrieved as a double using as_double(). + /// + /// true if the value is an double value, false otherwise. + _ASYNCRTIMP bool is_double() const; + + /// + /// Is the current value a Boolean value? + /// + /// true if the value is a Boolean value, false otherwise + bool is_boolean() const { return type() == Boolean; } + + /// + /// Is the current value a string value? + /// + /// true if the value is a string value, false otherwise + bool is_string() const { return type() == String; } + + /// + /// Is the current value an array? + /// + /// true if the value is an array, false otherwise + bool is_array() const { return type() == Array; } + + /// + /// Is the current value an object? + /// + /// true if the value is an object, false otherwise + bool is_object() const { return type() == Object; } + + /// + /// Gets the number of children of the value. + /// + /// The number of children. 0 for all non-composites. + size_t size() const; + + /// + /// Parses a string and construct a JSON value. + /// + /// The C++ value to create a JSON value from, a C++ STL double-byte string + _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value); + + /// + /// Attempts to parse a string and construct a JSON value. + /// + /// The C++ value to create a JSON value from, a C++ STL double-byte string + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value, std::error_code &errorCode); + + /// + /// Serializes the current JSON value to a C++ string. + /// + /// A string representation of the value + _ASYNCRTIMP utility::string_t serialize() const; + + /// + /// Serializes the current JSON value to a C++ string. + /// + /// A string representation of the value + CASABLANCA_DEPRECATED("This API is deprecated and has been renamed to avoid confusion with as_string(), use ::web::json::value::serialize() instead.") + _ASYNCRTIMP utility::string_t to_string() const; + + /// + /// Parses a JSON value from the contents of an input stream using the native platform character width. + /// + /// The stream to read the JSON value from + /// The JSON value object created from the input stream. + _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input); + + /// + /// Parses a JSON value from the contents of an input stream using the native platform character width. + /// + /// The stream to read the JSON value from + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input, std::error_code &errorCode); + + /// + /// Writes the current JSON value to a stream with the native platform character width. + /// + /// The stream that the JSON string representation should be written to. + _ASYNCRTIMP void serialize(utility::ostream_t &stream) const; + +#ifdef _WIN32 + /// + /// Parses a JSON value from the contents of a single-byte (UTF8) stream. + /// + /// The stream to read the JSON value from + _ASYNCRTIMP static value __cdecl parse(std::istream& stream); + + /// + /// Parses a JSON value from the contents of a single-byte (UTF8) stream. + /// + /// The stream to read the JSON value from + /// If parsing fails, the error code is greater than 0 + /// The parsed object. Returns web::json::value::null if failed + _ASYNCRTIMP static value __cdecl parse(std::istream& stream, std::error_code& error); + + /// + /// Serializes the content of the value into a single-byte (UTF8) stream. + /// + /// The stream that the JSON string representation should be written to. + _ASYNCRTIMP void serialize(std::ostream& stream) const; +#endif + + /// + /// Converts the JSON value to a C++ double, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// A double representation of the value + _ASYNCRTIMP double as_double() const; + + /// + /// Converts the JSON value to a C++ integer, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// An integer representation of the value + _ASYNCRTIMP int as_integer() const; + + /// + /// Converts the JSON value to a number class, if and only if it is a number value. + /// Throws if the value is not a number + /// + /// An instance of number class + _ASYNCRTIMP const json::number& as_number() const; + + /// + /// Converts the JSON value to a C++ bool, if and only if it is a Boolean value. + /// + /// A C++ bool representation of the value + _ASYNCRTIMP bool as_bool() const; + + /// + /// Converts the JSON value to a json array, if and only if it is an array value. + /// + /// The returned json::array should have the same or shorter lifetime as this + /// An array representation of the value + _ASYNCRTIMP json::array& as_array(); + + /// + /// Converts the JSON value to a json array, if and only if it is an array value. + /// + /// The returned json::array should have the same or shorter lifetime as this + /// An array representation of the value + _ASYNCRTIMP const json::array& as_array() const; + + /// + /// Converts the JSON value to a json object, if and only if it is an object value. + /// + /// An object representation of the value + _ASYNCRTIMP json::object& as_object(); + + /// + /// Converts the JSON value to a json object, if and only if it is an object value. + /// + /// An object representation of the value + _ASYNCRTIMP const json::object& as_object() const; + + /// + /// Converts the JSON value to a C++ STL string, if and only if it is a string value. + /// + /// A C++ STL string representation of the value + _ASYNCRTIMP const utility::string_t& as_string() const; + + /// + /// Compares two JSON values for equality. + /// + /// The JSON value to compare with. + /// True iff the values are equal. + _ASYNCRTIMP bool operator==(const value& other) const; + + /// + /// Compares two JSON values for inequality. + /// + /// The JSON value to compare with. + /// True iff the values are unequal. + bool operator!=(const value& other) const + { + return !((*this) == other); + } + + /// + /// Tests for the presence of a field. + /// + /// The name of the field + /// True if the field exists, false otherwise. + bool has_field(const utility::string_t &key) const; + + /// + /// Accesses a field of a JSON object. + /// + /// The name of the field + /// The value kept in the field; null if the field does not exist + CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.") + value get(const utility::string_t &key) const; + + /// + /// Erases an element of a JSON array. Throws if index is out of bounds. + /// + /// The index of the element to erase in the JSON array. + _ASYNCRTIMP void erase(size_t index); + + /// + /// Erases an element of a JSON object. Throws if the key doesn't exist. + /// + /// The key of the element to erase in the JSON object. + _ASYNCRTIMP void erase(const utility::string_t &key); + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value. + _ASYNCRTIMP json::value& at(size_t index); + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value. + _ASYNCRTIMP const json::value& at(size_t index) const; + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value. + _ASYNCRTIMP json::value& at(const utility::string_t& key); + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value. + _ASYNCRTIMP const json::value& at(const utility::string_t& key) const; + + /// + /// Accesses a field of a JSON object. + /// + /// The name of the field + /// A reference to the value kept in the field. + _ASYNCRTIMP value & operator [] (const utility::string_t &key); + +#ifdef _WIN32 +private: + // Only used internally by JSON parser + _ASYNCRTIMP value & operator [] (const std::string &key) + { + // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid + return operator[](utility::conversions::to_string_t(key)); + } +public: +#endif + + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array + /// The value kept at the array index; null if outside the boundaries of the array + CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.") + value get(size_t index) const; + + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + _ASYNCRTIMP value & operator [] (size_t index); + + private: + friend class web::json::details::_Object; + friend class web::json::details::_Array; + template friend class web::json::details::JSON_Parser; + +#ifdef _WIN32 + /// + /// Writes the current JSON value as a double-byte string to a string instance. + /// + /// The string that the JSON representation should be written to. + _ASYNCRTIMP void format(std::basic_string &string) const; +#endif + /// + /// Serializes the content of the value into a string instance in UTF8 format + /// + /// The string that the JSON representation should be written to + _ASYNCRTIMP void format(std::basic_string& string) const; + +#ifdef ENABLE_JSON_VALUE_VISUALIZER + explicit value(std::unique_ptr v, value_type kind) : m_value(std::move(v)), m_kind(kind) +#else + explicit value(std::unique_ptr v) : m_value(std::move(v)) +#endif + {} + + std::unique_ptr m_value; +#ifdef ENABLE_JSON_VALUE_VISUALIZER + value_type m_kind; +#endif + }; + + /// + /// A single exception type to represent errors in parsing, converting, and accessing + /// elements of JSON values. + /// + class json_exception : public std::exception + { + private: + std::string _message; + public: + json_exception(const utility::char_t * const &message) : _message(utility::conversions::to_utf8string(message)) { } + + // Must be narrow string because it derives from std::exception + const char* what() const CPPREST_NOEXCEPT + { + return _message.c_str(); + } + }; + + namespace details + { + enum json_error + { + left_over_character_in_stream = 1, + malformed_array_literal, + malformed_comment, + malformed_literal, + malformed_object_literal, + malformed_numeric_literal, + malformed_string_literal, + malformed_token, + mismatched_brances, + nesting, + unexpected_token + }; + + class json_error_category_impl : public std::error_category + { + public: + virtual const char* name() const CPPREST_NOEXCEPT override + { + return "json"; + } + + virtual std::string message(int ev) const override + { + switch (ev) + { + case json_error::left_over_character_in_stream: + return "Left-over characters in stream after parsing a JSON value"; + case json_error::malformed_array_literal: + return "Malformed array literal"; + case json_error::malformed_comment: + return "Malformed comment"; + case json_error::malformed_literal: + return "Malformed literal"; + case json_error::malformed_object_literal: + return "Malformed object literal"; + case json_error::malformed_numeric_literal: + return "Malformed numeric literal"; + case json_error::malformed_string_literal: + return "Malformed string literal"; + case json_error::malformed_token: + return "Malformed token"; + case json_error::mismatched_brances: + return "Mismatched braces"; + case json_error::nesting: + return "Nesting too deep"; + case json_error::unexpected_token: + return "Unexpected token"; + default: + return "Unknown json error"; + } + } + }; + + const json_error_category_impl& json_error_category(); + } + + /// + /// A JSON array represented as a C++ class. + /// + class array + { + typedef std::vector storage_type; + + public: + typedef storage_type::iterator iterator; + typedef storage_type::const_iterator const_iterator; + typedef storage_type::reverse_iterator reverse_iterator; + typedef storage_type::const_reverse_iterator const_reverse_iterator; + typedef storage_type::size_type size_type; + + private: + array() : m_elements() { } + array(size_type size) : m_elements(size) { } + array(storage_type elements) : m_elements(std::move(elements)) { } + + public: + /// + /// Gets the beginning iterator element of the array + /// + /// An iterator to the beginning of the JSON array. + iterator begin() + { + return m_elements.begin(); + } + + /// + /// Gets the beginning const iterator element of the array. + /// + /// A const_iterator to the beginning of the JSON array. + const_iterator begin() const + { + return m_elements.cbegin(); + } + + /// + /// Gets the end iterator element of the array + /// + /// An iterator to the end of the JSON array. + iterator end() + { + return m_elements.end(); + } + + /// + /// Gets the end const iterator element of the array. + /// + /// A const_iterator to the end of the JSON array. + const_iterator end() const + { + return m_elements.cend(); + } + + /// + /// Gets the beginning reverse iterator element of the array + /// + /// An reverse_iterator to the beginning of the JSON array. + reverse_iterator rbegin() + { + return m_elements.rbegin(); + } + + /// + /// Gets the beginning const reverse iterator element of the array + /// + /// An const_reverse_iterator to the beginning of the JSON array. + const_reverse_iterator rbegin() const + { + return m_elements.rbegin(); + } + + /// + /// Gets the end reverse iterator element of the array + /// + /// An reverse_iterator to the end of the JSON array. + reverse_iterator rend() + { + return m_elements.rend(); + } + + /// + /// Gets the end const reverse iterator element of the array + /// + /// An const_reverse_iterator to the end of the JSON array. + const_reverse_iterator rend() const + { + return m_elements.crend(); + } + + /// + /// Gets the beginning const iterator element of the array. + /// + /// A const_iterator to the beginning of the JSON array. + const_iterator cbegin() const + { + return m_elements.cbegin(); + } + + /// + /// Gets the end const iterator element of the array. + /// + /// A const_iterator to the end of the JSON array. + const_iterator cend() const + { + return m_elements.cend(); + } + + /// + /// Gets the beginning const reverse iterator element of the array. + /// + /// A const_reverse_iterator to the beginning of the JSON array. + const_reverse_iterator crbegin() const + { + return m_elements.crbegin(); + } + + /// + /// Gets the end const reverse iterator element of the array. + /// + /// A const_reverse_iterator to the end of the JSON array. + const_reverse_iterator crend() const + { + return m_elements.crend(); + } + + /// + /// Deletes an element of the JSON array. + /// + /// A const_iterator to the element to delete. + /// Iterator to the new location of the element following the erased element. + /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed. + iterator erase(iterator position) + { + return m_elements.erase(position); + } + + /// + /// Deletes the element at an index of the JSON array. + /// + /// The index of the element to delete. + void erase(size_type index) + { + if (index >= m_elements.size()) + { + throw json_exception(_XPLATSTR("index out of bounds")); + } + m_elements.erase(m_elements.begin() + index); + } + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + json::value& at(size_type index) + { + if (index >= m_elements.size()) + throw json_exception(_XPLATSTR("index out of bounds")); + + return m_elements[index]; + } + + /// + /// Accesses an element of a JSON array. Throws when index out of bounds. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + const json::value& at(size_type index) const + { + if (index >= m_elements.size()) + throw json_exception(_XPLATSTR("index out of bounds")); + + return m_elements[index]; + } + + /// + /// Accesses an element of a JSON array. + /// + /// The index of an element in the JSON array. + /// A reference to the value kept in the field. + json::value& operator[](size_type index) + { + msl::safeint3::SafeInt nMinSize(index); + nMinSize += 1; + msl::safeint3::SafeInt nlastSize(m_elements.size()); + if (nlastSize < nMinSize) + m_elements.resize(nMinSize); + + return m_elements[index]; + } + + /// + /// Gets the number of elements of the array. + /// + /// The number of elements. + size_type size() const + { + return m_elements.size(); + } + + private: + storage_type m_elements; + + friend class details::_Array; + template friend class json::details::JSON_Parser; + }; + + /// + /// A JSON object represented as a C++ class. + /// + class object + { + typedef std::vector> storage_type; + + public: + typedef storage_type::iterator iterator; + typedef storage_type::const_iterator const_iterator; + typedef storage_type::reverse_iterator reverse_iterator; + typedef storage_type::const_reverse_iterator const_reverse_iterator; + typedef storage_type::size_type size_type; + + private: + object(bool keep_order = false) : m_elements(), m_keep_order(keep_order) { } + object(storage_type elements, bool keep_order = false) : m_elements(std::move(elements)), m_keep_order(keep_order) + { + if (!keep_order) { + sort(m_elements.begin(), m_elements.end(), compare_pairs); + } + } + + public: + /// + /// Gets the beginning iterator element of the object + /// + /// An iterator to the beginning of the JSON object. + iterator begin() + { + return m_elements.begin(); + } + + /// + /// Gets the beginning const iterator element of the object. + /// + /// A const_iterator to the beginning of the JSON object. + const_iterator begin() const + { + return m_elements.cbegin(); + } + + /// + /// Gets the end iterator element of the object + /// + /// An iterator to the end of the JSON object. + iterator end() + { + return m_elements.end(); + } + + /// + /// Gets the end const iterator element of the object. + /// + /// A const_iterator to the end of the JSON object. + const_iterator end() const + { + return m_elements.cend(); + } + + /// + /// Gets the beginning reverse iterator element of the object + /// + /// An reverse_iterator to the beginning of the JSON object. + reverse_iterator rbegin() + { + return m_elements.rbegin(); + } + + /// + /// Gets the beginning const reverse iterator element of the object + /// + /// An const_reverse_iterator to the beginning of the JSON object. + const_reverse_iterator rbegin() const + { + return m_elements.rbegin(); + } + + /// + /// Gets the end reverse iterator element of the object + /// + /// An reverse_iterator to the end of the JSON object. + reverse_iterator rend() + { + return m_elements.rend(); + } + + /// + /// Gets the end const reverse iterator element of the object + /// + /// An const_reverse_iterator to the end of the JSON object. + const_reverse_iterator rend() const + { + return m_elements.crend(); + } + + /// + /// Gets the beginning const iterator element of the object. + /// + /// A const_iterator to the beginning of the JSON object. + const_iterator cbegin() const + { + return m_elements.cbegin(); + } + + /// + /// Gets the end const iterator element of the object. + /// + /// A const_iterator to the end of the JSON object. + const_iterator cend() const + { + return m_elements.cend(); + } + + /// + /// Gets the beginning const reverse iterator element of the object. + /// + /// A const_reverse_iterator to the beginning of the JSON object. + const_reverse_iterator crbegin() const + { + return m_elements.crbegin(); + } + + /// + /// Gets the end const reverse iterator element of the object. + /// + /// A const_reverse_iterator to the end of the JSON object. + const_reverse_iterator crend() const + { + return m_elements.crend(); + } + + /// + /// Deletes an element of the JSON object. + /// + /// A const_iterator to the element to delete. + /// Iterator to the new location of the element following the erased element. + /// GCC doesn't support erase with const_iterator on vector yet. In the future this should be changed. + iterator erase(iterator position) + { + return m_elements.erase(position); + } + + /// + /// Deletes an element of the JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + void erase(const utility::string_t &key) + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) + { + throw web::json::json_exception(_XPLATSTR("Key not found")); + } + + m_elements.erase(iter); + } + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field. + json::value& at(const utility::string_t& key) + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) + { + throw web::json::json_exception(_XPLATSTR("Key not found")); + } + + return iter->second; + } + + /// + /// Accesses an element of a JSON object. If the key doesn't exist, this method throws. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field. + const json::value& at(const utility::string_t& key) const + { + auto iter = find_by_key(key); + if (iter == m_elements.end()) + { + throw web::json::json_exception(_XPLATSTR("Key not found")); + } + + return iter->second; + } + + /// + /// Accesses an element of a JSON object. + /// + /// The key of an element in the JSON object. + /// If the key exists, a reference to the value kept in the field, otherwise a newly created null value that will be stored for the given key. + json::value& operator[](const utility::string_t& key) + { + auto iter = find_insert_location(key); + + if (iter == m_elements.end() || key != iter->first) + { + return m_elements.insert(iter, std::pair(key, value()))->second; + } + + return iter->second; + } + + /// + /// Gets an iterator to an element of a JSON object. + /// + /// The key of an element in the JSON object. + /// A const iterator to the value kept in the field. + const_iterator find(const utility::string_t& key) const + { + return find_by_key(key); + } + + /// + /// Gets the number of elements of the object. + /// + /// The number of elements. + size_type size() const + { + return m_elements.size(); + } + + /// + /// Checks if there are any elements in the JSON object. + /// + /// True iff empty. + bool empty() const + { + return m_elements.empty(); + } + private: + + static bool compare_pairs(const std::pair& p1, const std::pair& p2) + { + return p1.first < p2.first; + } + static bool compare_with_key(const std::pair& p1, const utility::string_t& key) + { + return p1.first < key; + } + + storage_type::iterator find_insert_location(const utility::string_t &key) + { + if (m_keep_order) + { + return std::find_if(m_elements.begin(), m_elements.end(), + [&key](const std::pair& p) { + return p.first == key; + }); + } + else + { + return std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); + } + } + + storage_type::const_iterator find_by_key(const utility::string_t& key) const + { + if (m_keep_order) + { + return std::find_if(m_elements.begin(), m_elements.end(), + [&key](const std::pair& p) { + return p.first == key; + }); + } + else + { + auto iter = std::lower_bound(m_elements.begin(), m_elements.end(), key, compare_with_key); + if (iter != m_elements.end() && key != iter->first) + { + return m_elements.end(); + } + return iter; + } + } + + storage_type::iterator find_by_key(const utility::string_t& key) + { + auto iter = find_insert_location(key); + if (iter != m_elements.end() && key != iter->first) + { + return m_elements.end(); + } + return iter; + } + + storage_type m_elements; + bool m_keep_order; + friend class details::_Object; + + template friend class json::details::JSON_Parser; + }; + + /// + /// A JSON number represented as a C++ class. + /// + class number + { + // Note that these constructors make sure that only negative integers are stored as signed int64 (while others convert to unsigned int64). + // This helps handling number objects e.g. comparing two numbers. + + number(double value) : m_value(value), m_type(double_type) { } + number(int32_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { } + number(uint32_t value) : m_intval(value), m_type(unsigned_type) { } + number(int64_t value) : m_intval(value), m_type(value < 0 ? signed_type : unsigned_type) { } + number(uint64_t value) : m_uintval(value), m_type(unsigned_type) { } + + public: + + /// + /// Does the number fit into int32? + /// + /// true if the number fits into int32, false otherwise + _ASYNCRTIMP bool is_int32() const; + + /// + /// Does the number fit into unsigned int32? + /// + /// true if the number fits into unsigned int32, false otherwise + _ASYNCRTIMP bool is_uint32() const; + + /// + /// Does the number fit into int64? + /// + /// true if the number fits into int64, false otherwise + _ASYNCRTIMP bool is_int64() const; + + /// + /// Does the number fit into unsigned int64? + /// + /// true if the number fits into unsigned int64, false otherwise + bool is_uint64() const + { + switch (m_type) + { + case signed_type : return m_intval >= 0; + case unsigned_type : return true; + case double_type : + default : + return false; + } + } + + /// + /// Converts the JSON number to a C++ double. + /// + /// A double representation of the number + double to_double() const + { + switch (m_type) + { + case double_type : return m_value; + case signed_type : return static_cast(m_intval); + case unsigned_type : return static_cast(m_uintval); + default : return false; + } + } + + /// + /// Converts the JSON number to int32. + /// + /// An int32 representation of the number + int32_t to_int32() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } + + /// + /// Converts the JSON number to unsigned int32. + /// + /// An usigned int32 representation of the number + uint32_t to_uint32() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } + + /// + /// Converts the JSON number to int64. + /// + /// An int64 representation of the number + int64_t to_int64() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } + + /// + /// Converts the JSON number to unsigned int64. + /// + /// An unsigned int64 representation of the number + uint64_t to_uint64() const + { + if (m_type == double_type) + return static_cast(m_value); + else + return static_cast(m_intval); + } + + /// + /// Is the number represented internally as an integral type? + /// + /// true if the number is represented as an integral type, false otherwise + bool is_integral() const + { + return m_type != double_type; + } + + /// + /// Compares two JSON numbers for equality. + /// + /// The JSON number to compare with. + /// True iff the numbers are equal. + bool operator==(const number &other) const + { + if (m_type != other.m_type) + return false; + + switch (m_type) + { + case json::number::type::signed_type : + return m_intval == other.m_intval; + case json::number::type::unsigned_type : + return m_uintval == other.m_uintval; + case json::number::type::double_type : + return m_value == other.m_value; + } + __assume(0); + } + + private: + union + { + int64_t m_intval; + uint64_t m_uintval; + double m_value; + }; + + enum type + { + signed_type=0, unsigned_type, double_type + } m_type; + + friend class details::_Number; + }; + + namespace details + { + class _Value + { + public: + virtual std::unique_ptr<_Value> _copy_value() = 0; + + virtual bool has_field(const utility::string_t &) const { return false; } + virtual value get_field(const utility::string_t &) const { throw json_exception(_XPLATSTR("not an object")); } + virtual value get_element(array::size_type) const { throw json_exception(_XPLATSTR("not an array")); } + + virtual value &index(const utility::string_t &) { throw json_exception(_XPLATSTR("not an object")); } + virtual value &index(array::size_type) { throw json_exception(_XPLATSTR("not an array")); } + + virtual const value &cnst_index(const utility::string_t &) const { throw json_exception(_XPLATSTR("not an object")); } + virtual const value &cnst_index(array::size_type) const { throw json_exception(_XPLATSTR("not an array")); } + + // Common function used for serialization to strings and streams. + virtual void serialize_impl(std::string& str) const + { + format(str); + } +#ifdef _WIN32 + virtual void serialize_impl(std::wstring& str) const + { + format(str); + } +#endif + + virtual utility::string_t to_string() const + { + utility::string_t str; + serialize_impl(str); + return str; + } + + virtual json::value::value_type type() const { return json::value::Null; } + + virtual bool is_integer() const { throw json_exception(_XPLATSTR("not a number")); } + virtual bool is_double() const { throw json_exception(_XPLATSTR("not a number")); } + + virtual const json::number& as_number() { throw json_exception(_XPLATSTR("not a number")); } + virtual double as_double() const { throw json_exception(_XPLATSTR("not a number")); } + virtual int as_integer() const { throw json_exception(_XPLATSTR("not a number")); } + virtual bool as_bool() const { throw json_exception(_XPLATSTR("not a boolean")); } + virtual json::array& as_array() { throw json_exception(_XPLATSTR("not an array")); } + virtual const json::array& as_array() const { throw json_exception(_XPLATSTR("not an array")); } + virtual json::object& as_object() { throw json_exception(_XPLATSTR("not an object")); } + virtual const json::object& as_object() const { throw json_exception(_XPLATSTR("not an object")); } + virtual const utility::string_t& as_string() const { throw json_exception(_XPLATSTR("not a string")); } + + virtual size_t size() const { return 0; } + + virtual ~_Value() {} + + protected: + _Value() {} + + virtual void format(std::basic_string& stream) const + { + stream.append("null"); + } +#ifdef _WIN32 + virtual void format(std::basic_string& stream) const + { + stream.append(L"null"); + } +#endif + private: + + friend class web::json::value; + }; + + class _Null : public _Value + { + public: + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_Null>(); + } + virtual json::value::value_type type() const { return json::value::Null; } + }; + + class _Number : public _Value + { + public: + _Number(double value) : m_number(value) { } + _Number(int32_t value) : m_number(value) { } + _Number(uint32_t value) : m_number(value) { } + _Number(int64_t value) : m_number(value) { } + _Number(uint64_t value) : m_number(value) { } + + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_Number>(*this); + } + + virtual json::value::value_type type() const { return json::value::Number; } + + virtual bool is_integer() const { return m_number.is_integral(); } + virtual bool is_double() const { return !m_number.is_integral(); } + + virtual double as_double() const + { + return m_number.to_double(); + } + + virtual int as_integer() const + { + return m_number.to_int32(); + } + + virtual const number& as_number() { return m_number; } + + protected: + virtual void format(std::basic_string& stream) const ; +#ifdef _WIN32 + virtual void format(std::basic_string& stream) const; +#endif + private: + template friend class json::details::JSON_Parser; + + json::number m_number; + }; + + class _Boolean : public _Value + { + public: + _Boolean(bool value) : m_value(value) { } + + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_Boolean>(*this); + } + + virtual json::value::value_type type() const { return json::value::Boolean; } + + virtual bool as_bool() const { return m_value; } + + protected: + virtual void format(std::basic_string& stream) const + { + stream.append(m_value ? "true" : "false"); + } + +#ifdef _WIN32 + virtual void format(std::basic_string& stream) const + { + stream.append(m_value ? L"true" : L"false"); + } +#endif + private: + template friend class json::details::JSON_Parser; + bool m_value; + }; + + class _String : public _Value + { + public: + + _String(utility::string_t value) : m_string(std::move(value)) + { + m_has_escape_char = has_escape_chars(*this); + } + _String(utility::string_t value, bool escaped_chars) + : m_string(std::move(value)), + m_has_escape_char(escaped_chars) + { } + +#ifdef _WIN32 + _String(std::string &&value) : m_string(utility::conversions::to_utf16string(std::move(value))) + { + m_has_escape_char = has_escape_chars(*this); + } + _String(std::string &&value, bool escape_chars) + : m_string(utility::conversions::to_utf16string(std::move(value))), + m_has_escape_char(escape_chars) + { } +#endif + + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_String>(*this); + } + + virtual json::value::value_type type() const { return json::value::String; } + + virtual const utility::string_t & as_string() const; + + virtual void serialize_impl(std::string& str) const + { + serialize_impl_char_type(str); + } +#ifdef _WIN32 + virtual void serialize_impl(std::wstring& str) const + { + serialize_impl_char_type(str); + } +#endif + + protected: + virtual void format(std::basic_string& str) const; +#ifdef _WIN32 + virtual void format(std::basic_string& str) const; +#endif + + private: + friend class _Object; + friend class _Array; + + size_t get_reserve_size() const + { + return m_string.size() + 2; + } + + template + void serialize_impl_char_type(std::basic_string& str) const + { + // To avoid repeated allocations reserve some space all up front. + // size of string + 2 for quotes + str.reserve(get_reserve_size()); + format(str); + } + + std::string as_utf8_string() const; + utf16string as_utf16_string() const; + + utility::string_t m_string; + + // There are significant performance gains that can be made by knowning whether + // or not a character that requires escaping is present. + bool m_has_escape_char; + static bool has_escape_chars(const _String &str); + }; + + template + _ASYNCRTIMP void append_escape_string(std::basic_string& str, const std::basic_string& escaped); + + void format_string(const utility::string_t& key, utility::string_t& str); + +#ifdef _WIN32 + void format_string(const utility::string_t& key, std::string& str); +#endif + + class _Object : public _Value + { + public: + + _Object(bool keep_order) : m_object(keep_order) { } + _Object(object::storage_type fields, bool keep_order) : m_object(std::move(fields), keep_order) { } + + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_Object>(*this); + } + + virtual json::object& as_object() { return m_object; } + + virtual const json::object& as_object() const { return m_object; } + + virtual json::value::value_type type() const { return json::value::Object; } + + virtual bool has_field(const utility::string_t &) const; + + virtual json::value &index(const utility::string_t &key); + + bool is_equal(const _Object* other) const + { + if (m_object.size() != other->m_object.size()) + return false; + + return std::equal(std::begin(m_object), std::end(m_object), std::begin(other->m_object)); + } + + virtual void serialize_impl(std::string& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } +#ifdef _WIN32 + virtual void serialize_impl(std::wstring& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } +#endif + size_t size() const { return m_object.size(); } + + protected: + virtual void format(std::basic_string& str) const + { + format_impl(str); + } +#ifdef _WIN32 + virtual void format(std::basic_string& str) const + { + format_impl(str); + } +#endif + + private: + json::object m_object; + + template friend class json::details::JSON_Parser; + + template + void format_impl(std::basic_string& str) const + { + str.push_back('{'); + if(!m_object.empty()) + { + auto lastElement = m_object.end() - 1; + for (auto iter = m_object.begin(); iter != lastElement; ++iter) + { + format_string(iter->first, str); + str.push_back(':'); + iter->second.format(str); + str.push_back(','); + } + format_string(lastElement->first, str); + str.push_back(':'); + lastElement->second.format(str); + } + str.push_back('}'); + } + + size_t get_reserve_size() const + { + // This is a heuristic we can tune more in the future: + // Basically size of string plus + // sum size of value if an object, array, or string. + size_t reserveSize = 2; // For brackets {} + for(auto iter = m_object.begin(); iter != m_object.end(); ++iter) + { + reserveSize += iter->first.length() + 2; // 2 for quotes + size_t valueSize = iter->second.size() * 20; // Multipler by each object/array element + if(valueSize == 0) + { + if(iter->second.type() == json::value::String) + { + valueSize = static_cast<_String *>(iter->second.m_value.get())->get_reserve_size(); + } + else + { + valueSize = 5; // true, false, or null + } + } + reserveSize += valueSize; + } + return reserveSize; + } + }; + + class _Array : public _Value + { + public: + _Array() {} + _Array(array::size_type size) : m_array(size) {} + _Array(array::storage_type elements) : m_array(std::move(elements)) { } + + virtual std::unique_ptr<_Value> _copy_value() + { + return utility::details::make_unique<_Array>(*this); + } + + virtual json::value::value_type type() const { return json::value::Array; } + + virtual json::array& as_array() { return m_array; } + virtual const json::array& as_array() const { return m_array; } + + virtual json::value &index(json::array::size_type index) + { + return m_array[index]; + } + + bool is_equal(const _Array* other) const + { + if ( m_array.size() != other->m_array.size()) + return false; + + auto iterT = m_array.cbegin(); + auto iterO = other->m_array.cbegin(); + auto iterTe = m_array.cend(); + auto iterOe = other->m_array.cend(); + + for (; iterT != iterTe && iterO != iterOe; ++iterT, ++iterO) + { + if ( *iterT != *iterO ) + return false; + } + + return true; + } + + virtual void serialize_impl(std::string& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } +#ifdef _WIN32 + virtual void serialize_impl(std::wstring& str) const + { + // To avoid repeated allocations reserve some space all up front. + str.reserve(get_reserve_size()); + format(str); + } +#endif + size_t size() const { return m_array.size(); } + + protected: + virtual void format(std::basic_string& str) const + { + format_impl(str); + } +#ifdef _WIN32 + virtual void format(std::basic_string& str) const + { + format_impl(str); + } +#endif + private: + json::array m_array; + + template friend class json::details::JSON_Parser; + + template + void format_impl(std::basic_string& str) const + { + str.push_back('['); + if(!m_array.m_elements.empty()) + { + auto lastElement = m_array.m_elements.end() - 1; + for (auto iter = m_array.m_elements.begin(); iter != lastElement; ++iter) + { + iter->format(str); + str.push_back(','); + } + lastElement->format(str); + } + str.push_back(']'); + } + + size_t get_reserve_size() const + { + // This is a heuristic we can tune more in the future: + // Basically sum size of each value if an object, array, or string by a multiplier. + size_t reserveSize = 2; // For brackets [] + for(auto iter = m_array.cbegin(); iter != m_array.cend(); ++iter) + { + size_t valueSize = iter->size() * 20; // Per each nested array/object + + if(valueSize == 0) + valueSize = 5; // true, false, or null + + reserveSize += valueSize; + } + return reserveSize; + } + }; + } // namespace details + + /// + /// Gets the number of children of the value. + /// + /// The number of children. 0 for all non-composites. + inline size_t json::value::size() const + { + return m_value->size(); + } + + /// + /// Test for the presence of a field. + /// + /// The name of the field + /// True if the field exists, false otherwise. + inline bool json::value::has_field(const utility::string_t& key) const + { + return m_value->has_field(key); + } + + /// + /// Access a field of a JSON object. + /// + /// The name of the field + /// The value kept in the field; null if the field does not exist + inline json::value json::value::get(const utility::string_t& key) const + { + return m_value->get_field(key); + } + + /// + /// Access an element of a JSON array. + /// + /// The index of an element in the JSON array + /// The value kept at the array index; null if outside the boundaries of the array + inline json::value json::value::get(size_t index) const + { + return m_value->get_element(index); + } + + /// + /// A standard std::ostream operator to facilitate writing JSON values to streams. + /// + /// The output stream to write the JSON value to. + /// The JSON value to be written to the stream. + /// The output stream object + _ASYNCRTIMP utility::ostream_t& __cdecl operator << (utility::ostream_t &os, const json::value &val); + + /// + /// A standard std::istream operator to facilitate reading JSON values from streams. + /// + /// The input stream to read the JSON value from. + /// The JSON value object read from the stream. + /// The input stream object. + _ASYNCRTIMP utility::istream_t& __cdecl operator >> (utility::istream_t &is, json::value &val); +}} + +#endif diff --git a/src/corehost/cli/json/casablanca/include/stdafx.h b/src/corehost/cli/json/casablanca/include/stdafx.h new file mode 100644 index 000000000..553d828a6 --- /dev/null +++ b/src/corehost/cli/json/casablanca/include/stdafx.h @@ -0,0 +1,109 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Pre-compiled headers +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#pragma once + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif + +#include +#include +#ifdef _WIN32 +#ifdef CPPREST_TARGET_XP +#include +#ifndef _WIN32_WINNT +#define _WIN32_WINNT _WIN32_WINNT_WS03 //Windows XP with SP2 +#endif +#endif +#include +// use the debug version of the CRT if _DEBUG is defined +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#define NOMINMAX +#endif + +#include +#include + +// Windows Header Files: +#if !defined(__cplusplus_winrt) +#include + +#endif // #if !defined(__cplusplus_winrt) +#else // LINUX or APPLE +#define __STDC_LIMIT_MACROS +#include +#include +#include +#include +#include +#include +#include +#include "pthread.h" +#include +#include +#include +#include +#endif // _WIN32 + +// Macro indicating the C++ Rest SDK product itself is being built. +// This is to help track how many developers are directly building from source themselves. +#define _CASA_BUILD_FROM_SRC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// json +#include "cpprest/json.h" + +#if defined(max) +#error: max macro defined -- make sure to #define NOMINMAX before including windows.h +#endif +#if defined(min) +#error: min macro defined -- make sure to #define NOMINMAX before including windows.h +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + diff --git a/src/corehost/cli/json/casablanca/src/json/json.cpp b/src/corehost/cli/json/casablanca/src/json/json.cpp new file mode 100644 index 000000000..77380460c --- /dev/null +++ b/src/corehost/cli/json/casablanca/src/json/json.cpp @@ -0,0 +1,495 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* HTTP Library: JSON parser and writer +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" + +using namespace web; + +bool json::details::g_keep_json_object_unsorted = false; +void json::keep_object_element_order(bool keep_order) +{ + json::details::g_keep_json_object_unsorted = keep_order; +} + +utility::ostream_t& web::json::operator << (utility::ostream_t &os, const web::json::value &val) +{ + val.serialize(os); + return os; +} + +utility::istream_t& web::json::operator >> (utility::istream_t &is, json::value &val) +{ + val = json::value::parse(is); + return is; +} + +web::json::value::value() : + m_value(utility::details::make_unique()) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Null) +#endif + { } + +web::json::value::value(int32_t value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Number) +#endif + { } + +web::json::value::value(uint32_t value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Number) +#endif + { } + +web::json::value::value(int64_t value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Number) +#endif + { } + +web::json::value::value(uint64_t value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Number) +#endif + { } + +web::json::value::value(double value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Number) +#endif + { } + +web::json::value::value(bool value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::Boolean) +#endif + { } + +web::json::value::value(utility::string_t value) : + m_value(utility::details::make_unique(std::move(value))) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::String) +#endif + { } + +web::json::value::value(utility::string_t value, bool has_escape_chars) : +m_value(utility::details::make_unique(std::move(value), has_escape_chars)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER +, m_kind(value::String) +#endif +{ } + +web::json::value::value(const utility::char_t* value) : + m_value(utility::details::make_unique(value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(value::String) +#endif + { } + +web::json::value::value(const utility::char_t* value, bool has_escape_chars) : +m_value(utility::details::make_unique(utility::string_t(value), has_escape_chars)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER +, m_kind(value::String) +#endif +{ } + +web::json::value::value(const value &other) : + m_value(other.m_value->_copy_value()) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(other.m_kind) +#endif + { } + +web::json::value &web::json::value::operator=(const value &other) +{ + if(this != &other) + { + m_value = std::unique_ptr(other.m_value->_copy_value()); +#ifdef ENABLE_JSON_VALUE_VISUALIZER + m_kind = other.m_kind; +#endif + } + return *this; +} + +web::json::value::value(value &&other) CPPREST_NOEXCEPT : + m_value(std::move(other.m_value)) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,m_kind(other.m_kind) +#endif +{} + +web::json::value &web::json::value::operator=(web::json::value &&other) CPPREST_NOEXCEPT +{ + if(this != &other) + { + m_value.swap(other.m_value); +#ifdef ENABLE_JSON_VALUE_VISUALIZER + m_kind = other.m_kind; +#endif + } + return *this; +} + +web::json::value web::json::value::null() +{ + return web::json::value(); +} + +web::json::value web::json::value::number(double value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::number(int32_t value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::number(uint32_t value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::number(int64_t value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::number(uint64_t value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::boolean(bool value) +{ + return web::json::value(value); +} + +web::json::value web::json::value::string(utility::string_t value) +{ + std::unique_ptr ptr = utility::details::make_unique(std::move(value)); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::String +#endif + ); +} + +web::json::value web::json::value::string(utility::string_t value, bool has_escape_chars) +{ + std::unique_ptr ptr = utility::details::make_unique(std::move(value), has_escape_chars); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::String +#endif + ); +} + +#ifdef _WIN32 +web::json::value web::json::value::string(const std::string &value) +{ + std::unique_ptr ptr = utility::details::make_unique(utility::conversions::to_utf16string(value)); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::String +#endif + ); +} +#endif + +web::json::value web::json::value::object(bool keep_order) +{ + std::unique_ptr ptr = utility::details::make_unique(keep_order); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::Object +#endif + ); +} + +web::json::value web::json::value::object(std::vector> fields, bool keep_order) +{ + std::unique_ptr ptr = utility::details::make_unique(std::move(fields), keep_order); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::Object +#endif + ); +} + +web::json::value web::json::value::array() +{ + std::unique_ptr ptr = utility::details::make_unique(); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::Array +#endif + ); +} + +web::json::value web::json::value::array(size_t size) +{ + std::unique_ptr ptr = utility::details::make_unique(size); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::Array +#endif + ); +} + +web::json::value web::json::value::array(std::vector elements) +{ + std::unique_ptr ptr = utility::details::make_unique(std::move(elements)); + return web::json::value(std::move(ptr) +#ifdef ENABLE_JSON_VALUE_VISUALIZER + ,value::Array +#endif + ); +} + +const web::json::number& web::json::value::as_number() const +{ + return m_value->as_number(); +} + +double web::json::value::as_double() const +{ + return m_value->as_double(); +} + +int web::json::value::as_integer() const +{ + return m_value->as_integer(); +} + +bool web::json::value::as_bool() const +{ + return m_value->as_bool(); +} + +json::array& web::json::value::as_array() +{ + return m_value->as_array(); +} + +const json::array& web::json::value::as_array() const +{ + return m_value->as_array(); +} + +json::object& web::json::value::as_object() +{ + return m_value->as_object(); +} + +const json::object& web::json::value::as_object() const +{ + return m_value->as_object(); +} + +bool web::json::number::is_int32() const +{ + switch (m_type) + { + case signed_type : return m_intval >= std::numeric_limits::min() && m_intval <= std::numeric_limits::max(); + case unsigned_type : return m_uintval <= std::numeric_limits::max(); + case double_type : + default : + return false; + } +} + +bool web::json::number::is_uint32() const +{ + switch (m_type) + { + case signed_type : return m_intval >= 0 && m_intval <= std::numeric_limits::max(); + case unsigned_type : return m_uintval <= std::numeric_limits::max(); + case double_type : + default : + return false; + } +} + +bool web::json::number::is_int64() const +{ + switch (m_type) + { + case signed_type : return true; + case unsigned_type : return m_uintval <= static_cast(std::numeric_limits::max()); + case double_type : + default : + return false; + } +} + +bool web::json::details::_String::has_escape_chars(const _String &str) +{ + return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x) + { + if (x <= 31) { return true; } + if (x == '"') { return true; } + if (x == '\\') { return true; } + return false; + }); +} + +web::json::value::value_type json::value::type() const { return m_value->type(); } + +bool json::value::is_integer() const +{ + if(!is_number()) + { + return false; + } + return m_value->is_integer(); +} + +bool json::value::is_double() const +{ + if(!is_number()) + { + return false; + } + return m_value->is_double(); +} + +json::value& web::json::details::_Object::index(const utility::string_t &key) +{ + return m_object[key]; +} + +bool web::json::details::_Object::has_field(const utility::string_t &key) const +{ + return m_object.find(key) != m_object.end(); +} + +utility::string_t json::value::to_string() const +{ +#ifndef _WIN32 + utility::details::scoped_c_thread_locale locale; +#endif + return m_value->to_string(); +} + +bool json::value::operator==(const json::value &other) const +{ + if (this->m_value.get() == other.m_value.get()) + return true; + if (this->type() != other.type()) + return false; + + switch(this->type()) + { + case Null: + return true; + case Number: + return this->as_number() == other.as_number(); + case Boolean: + return this->as_bool() == other.as_bool(); + case String: + return this->as_string() == other.as_string(); + case Object: + return static_cast(this->m_value.get())->is_equal(static_cast(other.m_value.get())); + case Array: + return static_cast(this->m_value.get())->is_equal(static_cast(other.m_value.get())); + } + __assume(0); +} + +void web::json::value::erase(size_t index) +{ + return this->as_array().erase(index); +} + +void web::json::value::erase(const utility::string_t &key) +{ + return this->as_object().erase(key); +} + +// at() overloads +web::json::value& web::json::value::at(size_t index) +{ + return this->as_array().at(index); +} + +const web::json::value& web::json::value::at(size_t index) const +{ + return this->as_array().at(index); +} + +web::json::value& web::json::value::at(const utility::string_t& key) +{ + return this->as_object().at(key); +} + +const web::json::value& web::json::value::at(const utility::string_t& key) const +{ + return this->as_object().at(key); +} + +web::json::value& web::json::value::operator [] (const utility::string_t &key) +{ + if ( this->is_null() ) + { + m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted)); +#ifdef ENABLE_JSON_VALUE_VISUALIZER + m_kind = value::Object; +#endif + } + return m_value->index(key); +} + +web::json::value& web::json::value::operator[](size_t index) +{ + if ( this->is_null() ) + { + m_value.reset(new web::json::details::_Array()); +#ifdef ENABLE_JSON_VALUE_VISUALIZER + m_kind = value::Array; +#endif + } + return m_value->index(index); +} + +// Remove once VS 2013 is no longer supported. +#if defined(_WIN32) && _MSC_VER < 1900 +static web::json::details::json_error_category_impl instance; +#endif +const web::json::details::json_error_category_impl& web::json::details::json_error_category() +{ +#if !defined(_WIN32) || _MSC_VER >= 1900 + static web::json::details::json_error_category_impl instance; +#endif + return instance; +} diff --git a/src/corehost/cli/json/casablanca/src/json/json_parsing.cpp b/src/corehost/cli/json/casablanca/src/json/json_parsing.cpp new file mode 100644 index 000000000..1cf40dc67 --- /dev/null +++ b/src/corehost/cli/json/casablanca/src/json/json_parsing.cpp @@ -0,0 +1,1312 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* HTTP Library: JSON parser +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" +#include + +#if defined(_MSC_VER) +#pragma warning(disable : 4127) // allow expressions like while(true) pass +#endif +using namespace web; +using namespace web::json; +using namespace utility; +using namespace utility::conversions; + +std::array _hexval = {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }}; + +namespace web { +namespace json +{ +namespace details +{ + +// +// JSON Parsing +// + +template +#if defined(_WIN32) + __declspec(noreturn) +#else + __attribute__((noreturn)) +#endif +void CreateException(const Token &tk, const utility::string_t &message) +{ + utility::ostringstream_t os; + os << _XPLATSTR("* Line ") << tk.start.m_line << _XPLATSTR(", Column ") << tk.start.m_column << _XPLATSTR(" Syntax error: ") << message; + utility::string_t osStr = os.str(); + throw web::json::json_exception(osStr.c_str()); +} + +template +void SetErrorCode(Token &tk, json_error jsonErrorCode) +{ + tk.m_error = std::error_code(jsonErrorCode, json_error_category()); +} + +template +class JSON_Parser +{ +public: + JSON_Parser() + : m_currentLine(1), + m_currentColumn(1), + m_currentParsingDepth(0) + { } + + struct Location + { + size_t m_line; + size_t m_column; + }; + + struct Token + { + enum Kind + { + TKN_EOF, + + TKN_OpenBrace, + TKN_CloseBrace, + TKN_OpenBracket, + TKN_CloseBracket, + TKN_Comma, + TKN_Colon, + TKN_StringLiteral, + TKN_NumberLiteral, + TKN_IntegerLiteral, + TKN_BooleanLiteral, + TKN_NullLiteral, + TKN_Comment + }; + + Token() : kind(TKN_EOF) {} + + Kind kind; + std::basic_string string_val; + + typename JSON_Parser::Location start; + + union + { + double double_val; + int64_t int64_val; + uint64_t uint64_val; + bool boolean_val; + bool has_unescape_symbol; + }; + + bool signed_number; + + std::error_code m_error; + }; + + void GetNextToken(Token &); + + web::json::value ParseValue(typename JSON_Parser::Token &first) + { +#ifndef _WIN32 + utility::details::scoped_c_thread_locale locale; +#endif + +#ifdef ENABLE_JSON_VALUE_VISUALIZER + auto _value = _ParseValue(first); + auto type = _value->type(); + return web::json::value(std::move(_value), type); +#else + return web::json::value(_ParseValue(first)); +#endif + } + +protected: + typedef typename std::char_traits::int_type int_type; + virtual int_type NextCharacter() = 0; + virtual int_type PeekCharacter() = 0; + + virtual bool CompleteComment(Token &token); + virtual bool CompleteStringLiteral(Token &token); + bool handle_unescape_char(Token &token); + +private: + + bool CompleteNumberLiteral(CharType first, Token &token); + bool ParseInt64(CharType first, uint64_t& value); + bool CompleteKeywordTrue(Token &token); + bool CompleteKeywordFalse(Token &token); + bool CompleteKeywordNull(Token &token); + std::unique_ptr _ParseValue(typename JSON_Parser::Token &first); + std::unique_ptr _ParseObject(typename JSON_Parser::Token &tkn); + std::unique_ptr _ParseArray(typename JSON_Parser::Token &tkn); + + JSON_Parser& operator=(const JSON_Parser&); + + int_type EatWhitespace(); + + void CreateToken(typename JSON_Parser::Token& tk, typename Token::Kind kind, Location &start) + { + tk.kind = kind; + tk.start = start; + tk.string_val.clear(); + } + + void CreateToken(typename JSON_Parser::Token& tk, typename Token::Kind kind) + { + tk.kind = kind; + tk.start.m_line = m_currentLine; + tk.start.m_column = m_currentColumn; + tk.string_val.clear(); + } + +protected: + + size_t m_currentLine; + size_t m_currentColumn; + size_t m_currentParsingDepth; + +// The DEBUG macro is defined in XCode but we don't in our CMakeList +// so for now we will keep the same on debug and release. In the future +// this can be increase on release if necessary. +#if defined(__APPLE__) + static const size_t maxParsingDepth = 32; +#else + static const size_t maxParsingDepth = 128; +#endif +}; + +// Replace with template alias once VS 2012 support is removed. +template +typename std::char_traits::int_type eof() +{ + return std::char_traits::eof(); +} + +template +class JSON_StreamParser : public JSON_Parser + { +public: + JSON_StreamParser(std::basic_istream &stream) + : m_streambuf(stream.rdbuf()) + { + } + +protected: + + virtual typename JSON_Parser::int_type NextCharacter(); + virtual typename JSON_Parser::int_type PeekCharacter(); + +private: + typename std::basic_streambuf>* m_streambuf; +}; + +template +class JSON_StringParser : public JSON_Parser +{ +public: + JSON_StringParser(const std::basic_string& string) + : m_position(&string[0]) + { + m_startpos = m_position; + m_endpos = m_position+string.size(); + } + +protected: + + virtual typename JSON_Parser::int_type NextCharacter(); + virtual typename JSON_Parser::int_type PeekCharacter(); + + virtual bool CompleteComment(typename JSON_Parser::Token &token); + virtual bool CompleteStringLiteral(typename JSON_Parser::Token &token); + +private: + bool finish_parsing_string_with_unescape_char(typename JSON_Parser::Token &token); + const CharType* m_position; + const CharType* m_startpos; + const CharType* m_endpos; +}; + + +template +typename JSON_Parser::int_type JSON_StreamParser::NextCharacter() +{ + auto ch = m_streambuf->sbumpc(); + + if (ch == '\n') + { + this->m_currentLine += 1; + this->m_currentColumn = 0; + } + else + { + this->m_currentColumn += 1; + } + + return ch; +} + +template +typename JSON_Parser::int_type JSON_StreamParser::PeekCharacter() +{ + return m_streambuf->sgetc(); +} + +template +typename JSON_Parser::int_type JSON_StringParser::NextCharacter() +{ + if (m_position == m_endpos) + return eof(); + + CharType ch = *m_position; + m_position += 1; + + if ( ch == '\n' ) + { + this->m_currentLine += 1; + this->m_currentColumn = 0; + } + else + { + this->m_currentColumn += 1; + } + + return ch; +} + +template +typename JSON_Parser::int_type JSON_StringParser::PeekCharacter() +{ + if ( m_position == m_endpos ) return eof(); + + return *m_position; +} + +// +// Consume whitespace characters and return the first non-space character or EOF +// +template +typename JSON_Parser::int_type JSON_Parser::EatWhitespace() +{ + auto ch = NextCharacter(); + + while ( ch != eof() && iswspace(static_cast(ch))) + { + ch = NextCharacter(); + } + + return ch; +} + +template +bool JSON_Parser::CompleteKeywordTrue(Token &token) +{ + if (NextCharacter() != 'r') + return false; + if (NextCharacter() != 'u') + return false; + if (NextCharacter() != 'e') + return false; + token.kind = Token::TKN_BooleanLiteral; + token.boolean_val = true; + return true; +} + +template +bool JSON_Parser::CompleteKeywordFalse(Token &token) +{ + if (NextCharacter() != 'a') + return false; + if (NextCharacter() != 'l') + return false; + if (NextCharacter() != 's') + return false; + if (NextCharacter() != 'e') + return false; + token.kind = Token::TKN_BooleanLiteral; + token.boolean_val = false; + return true; +} + +template +bool JSON_Parser::CompleteKeywordNull(Token &token) +{ + if (NextCharacter() != 'u') + return false; + if (NextCharacter() != 'l') + return false; + if (NextCharacter() != 'l') + return false; + token.kind = Token::TKN_NullLiteral; + return true; +} + +// Returns false only on overflow +template +inline bool JSON_Parser::ParseInt64(CharType first, uint64_t& value) +{ + value = first - '0'; + auto ch = PeekCharacter(); + while (ch >= '0' && ch <= '9') + { + unsigned int next_digit = (unsigned int)(ch - '0'); + if (value > (ULLONG_MAX / 10) || (value == ULLONG_MAX/10 && next_digit > ULLONG_MAX%10)) + return false; + + NextCharacter(); + + value *= 10; + value += next_digit; + ch = PeekCharacter(); + } + return true; +} + +// This namespace hides the x-plat helper functions +namespace +{ +#if defined(_WIN32) + static int print_llu(char* ptr, size_t n, uint64_t val64) + { + return _snprintf_s_l(ptr, n, _TRUNCATE, "%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); + } + + static int print_llu(wchar_t* ptr, size_t n, uint64_t val64) + { + return _snwprintf_s_l(ptr, n, _TRUNCATE, L"%I64u", utility::details::scoped_c_thread_locale::c_locale(), val64); + } + static double anystod(const char* str) + { + return _strtod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); + } + static double anystod(const wchar_t* str) + { + return _wcstod_l(str, nullptr, utility::details::scoped_c_thread_locale::c_locale()); + } +#else + static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long long val64) + { + return snprintf(ptr, n, "%llu", val64); + } + static int __attribute__((__unused__)) print_llu(char* ptr, size_t n, unsigned long val64) + { + return snprintf(ptr, n, "%lu", val64); + } + static double __attribute__((__unused__)) anystod(const char* str) + { + return strtod(str, nullptr); + } + static double __attribute__((__unused__)) anystod(const wchar_t* str) + { + return wcstod(str, nullptr); + } +#endif +} + +template +bool JSON_Parser::CompleteNumberLiteral(CharType first, Token &token) +{ + bool minus_sign; + + if (first == '-') + { + minus_sign = true; + + // Safe to cast because the check after this if/else statement will cover EOF. + first = static_cast(NextCharacter()); + } + else + { + minus_sign = false; + } + + if (first < '0' || first > '9') + return false; + + auto ch = PeekCharacter(); + + //Check for two (or more) zeros at the beginning + if (first == '0' && ch == '0') + return false; + + // Parse the number assuming its integer + uint64_t val64; + bool complete = ParseInt64(first, val64); + + ch = PeekCharacter(); + if (complete && ch!='.' && ch!='E' && ch!='e') + { + if (minus_sign) + { + if (val64 > static_cast(1) << 63 ) + { + // It is negative and cannot be represented in int64, so we resort to double + token.double_val = 0 - static_cast(val64); + token.signed_number = true; + token.kind = JSON_Parser::Token::TKN_NumberLiteral; + return true; + } + + // It is negative, but fits into int64 + token.int64_val = 0 - static_cast(val64); + token.kind = JSON_Parser::Token::TKN_IntegerLiteral; + token.signed_number = true; + return true; + } + + // It is positive so we use unsigned int64 + token.uint64_val = val64; + token.kind = JSON_Parser::Token::TKN_IntegerLiteral; + token.signed_number = false; + return true; + } + + // Magic number 5 leaves room for decimal point, null terminator, etc (in most cases) + ::std::vector buf(::std::numeric_limits::digits10 + 5); + int count = print_llu(buf.data(), buf.size(), val64); + _ASSERTE(count >= 0); + _ASSERTE((size_t)count < buf.size()); + // Resize to cut off the null terminator + buf.resize(count); + + bool decimal = false; + + while (ch != eof()) + { + // Digit encountered? + if (ch >= '0' && ch <= '9') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + + // Decimal dot? + else if (ch == '.') + { + if (decimal) + return false; + + decimal = true; + buf.push_back(static_cast(ch)); + + NextCharacter(); + ch = PeekCharacter(); + + // Check that the following char is a digit + if (ch < '0' || ch > '9') + return false; + + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + + // Exponent? + else if (ch == 'E' || ch == 'e') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + + // Check for the exponent sign + if (ch == '+') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + else if (ch == '-') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + + // First number of the exponent + if (ch >= '0' && ch <= '9') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + else return false; + + // The rest of the exponent + while (ch >= '0' && ch <= '9') + { + buf.push_back(static_cast(ch)); + NextCharacter(); + ch = PeekCharacter(); + } + + // The peeked character is not a number, so we can break from the loop and construct the number + break; + } + else + { + // Not expected number character? + break; + } + }; + + buf.push_back('\0'); + token.double_val = anystod(buf.data()); + if (minus_sign) + { + token.double_val = -token.double_val; + } + token.kind = (JSON_Parser::Token::TKN_NumberLiteral); + + return true; +} + +template +bool JSON_Parser::CompleteComment(Token &token) +{ + // We already found a '/' character as the first of a token -- what kind of comment is it? + + auto ch = NextCharacter(); + + if ( ch == eof() || (ch != '/' && ch != '*') ) + return false; + + if ( ch == '/' ) + { + // Line comment -- look for a newline or EOF to terminate. + + ch = NextCharacter(); + + while ( ch != eof() && ch != '\n') + { + ch = NextCharacter(); + } + } + else + { + // Block comment -- look for a terminating "*/" sequence. + + ch = NextCharacter(); + + while ( true ) + { + if ( ch == eof()) + return false; + + if ( ch == '*' ) + { + auto ch1 = PeekCharacter(); + + if ( ch1 == eof()) + return false; + + if ( ch1 == '/' ) + { + // Consume the character + NextCharacter(); + break; + } + + ch = ch1; + } + + ch = NextCharacter(); + } + } + + token.kind = Token::TKN_Comment; + + return true; +} + +template +bool JSON_StringParser::CompleteComment(typename JSON_Parser::Token &token) +{ + // This function is specialized for the string parser, since we can be slightly more + // efficient in copying data from the input to the token: do a memcpy() rather than + // one character at a time. + + auto ch = JSON_StringParser::NextCharacter(); + + if ( ch == eof() || (ch != '/' && ch != '*') ) + return false; + + if ( ch == '/' ) + { + // Line comment -- look for a newline or EOF to terminate. + + ch = JSON_StringParser::NextCharacter(); + + while ( ch != eof() && ch != '\n') + { + ch = JSON_StringParser::NextCharacter(); + } + } + else + { + // Block comment -- look for a terminating "*/" sequence. + + ch = JSON_StringParser::NextCharacter(); + + while ( true ) + { + if ( ch == eof()) + return false; + + if ( ch == '*' ) + { + ch = JSON_StringParser::PeekCharacter(); + + if ( ch == eof()) + return false; + + if ( ch == '/' ) + { + // Consume the character + JSON_StringParser::NextCharacter(); + break; + } + + } + + ch = JSON_StringParser::NextCharacter(); + } + } + + token.kind = JSON_Parser::Token::TKN_Comment; + + return true; +} + +void convert_append_unicode_code_unit(JSON_Parser::Token &token, utf16char value) +{ + token.string_val.push_back(value); +} +void convert_append_unicode_code_unit(JSON_Parser::Token &token, utf16char value) +{ + utf16string utf16(reinterpret_cast(&value), 1); + token.string_val.append(::utility::conversions::utf16_to_utf8(utf16)); +} + +template +inline bool JSON_Parser::handle_unescape_char(Token &token) +{ + token.has_unescape_symbol = true; + + // This function converts unescaped character pairs (e.g. "\t") into their ASCII or Unicode representations (e.g. tab sign) + // Also it handles \u + 4 hexadecimal digits + auto ch = NextCharacter(); + switch (ch) + { + case '\"': + token.string_val.push_back('\"'); + return true; + case '\\': + token.string_val.push_back('\\'); + return true; + case '/': + token.string_val.push_back('/'); + return true; + case 'b': + token.string_val.push_back('\b'); + return true; + case 'f': + token.string_val.push_back('\f'); + return true; + case 'r': + token.string_val.push_back('\r'); + return true; + case 'n': + token.string_val.push_back('\n'); + return true; + case 't': + token.string_val.push_back('\t'); + return true; + case 'u': + { + // A four-hexdigit Unicode character. + // Transform into a 16 bit code point. + int decoded = 0; + for (int i = 0; i < 4; ++i) + { + ch = NextCharacter(); + int ch_int = static_cast(ch); + if (ch_int < 0 || ch_int > 127) + return false; +#ifdef _WIN32 + const int isxdigitResult = _isxdigit_l(ch_int, utility::details::scoped_c_thread_locale::c_locale()); +#else + const int isxdigitResult = isxdigit(ch_int); +#endif + if (!isxdigitResult) + return false; + + int val = _hexval[static_cast(ch_int)]; + _ASSERTE(val != -1); + + // Add the input char to the decoded number + decoded |= (val << (4 * (3 - i))); + } + + // Construct the character based on the decoded number + convert_append_unicode_code_unit(token, static_cast(decoded)); + + return true; + } + default: + return false; + } +} + +template +bool JSON_Parser::CompleteStringLiteral(Token &token) +{ + token.has_unescape_symbol = false; + auto ch = NextCharacter(); + while ( ch != '"' ) + { + if ( ch == '\\' ) + { + handle_unescape_char(token); + } + else if (ch >= CharType(0x0) && ch < CharType(0x20)) + { + return false; + } + else + { + if (ch == eof()) + return false; + + token.string_val.push_back(static_cast(ch)); + } + ch = NextCharacter(); + } + + if ( ch == '"' ) + { + token.kind = Token::TKN_StringLiteral; + } + else + { + return false; + } + + return true; +} + +template +bool JSON_StringParser::CompleteStringLiteral(typename JSON_Parser::Token &token) +{ + // This function is specialized for the string parser, since we can be slightly more + // efficient in copying data from the input to the token: do a memcpy() rather than + // one character at a time. + + auto start = m_position; + token.has_unescape_symbol = false; + + auto ch = JSON_StringParser::NextCharacter(); + + while (ch != '"') + { + if (ch == eof()) + return false; + + if (ch == '\\') + { + const size_t numChars = m_position - start - 1; + const size_t prevSize = token.string_val.size(); + token.string_val.resize(prevSize + numChars); + memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + + if (!JSON_StringParser::handle_unescape_char(token)) + { + return false; + } + + // Reset start position and continue. + start = m_position; + } + else if (ch >= CharType(0x0) && ch < CharType(0x20)) + { + return false; + } + + ch = JSON_StringParser::NextCharacter(); + } + + const size_t numChars = m_position - start - 1; + const size_t prevSize = token.string_val.size(); + token.string_val.resize(prevSize + numChars); + memcpy(const_cast(token.string_val.c_str() + prevSize), start, numChars * sizeof(CharType)); + + token.kind = JSON_Parser::Token::TKN_StringLiteral; + + return true; +} + +template +void JSON_Parser::GetNextToken(typename JSON_Parser::Token& result) +{ +try_again: + auto ch = EatWhitespace(); + + CreateToken(result, Token::TKN_EOF); + + if (ch == eof()) return; + + switch (ch) + { + case '{': + case '[': + { + if(++m_currentParsingDepth > JSON_Parser::maxParsingDepth) + { + SetErrorCode(result, json_error::nesting); + break; + } + + typename JSON_Parser::Token::Kind tk = ch == '{' ? Token::TKN_OpenBrace : Token::TKN_OpenBracket; + CreateToken(result, tk, result.start); + break; + } + case '}': + case ']': + { + if((signed int)(--m_currentParsingDepth) < 0) + { + SetErrorCode(result, json_error::mismatched_brances); + break; + } + + typename JSON_Parser::Token::Kind tk = ch == '}' ? Token::TKN_CloseBrace : Token::TKN_CloseBracket; + CreateToken(result, tk, result.start); + break; + } + case ',': + CreateToken(result, Token::TKN_Comma, result.start); + break; + + case ':': + CreateToken(result, Token::TKN_Colon, result.start); + break; + + case 't': + if (!CompleteKeywordTrue(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } + break; + case 'f': + if (!CompleteKeywordFalse(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } + break; + case 'n': + if (!CompleteKeywordNull(result)) + { + SetErrorCode(result, json_error::malformed_literal); + } + break; + case '/': + if (!CompleteComment(result)) + { + SetErrorCode(result, json_error::malformed_comment); + break; + } + // For now, we're ignoring comments. + goto try_again; + case '"': + if (!CompleteStringLiteral(result)) + { + SetErrorCode(result, json_error::malformed_string_literal); + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!CompleteNumberLiteral(static_cast(ch), result)) + { + SetErrorCode(result, json_error::malformed_numeric_literal); + } + break; + default: + SetErrorCode(result, json_error::malformed_token); + break; + } +} + +template +std::unique_ptr JSON_Parser::_ParseObject(typename JSON_Parser::Token &tkn) +{ + auto obj = utility::details::make_unique(g_keep_json_object_unsorted); + auto& elems = obj->m_object.m_elements; + + GetNextToken(tkn); + if (tkn.m_error) goto error; + + if (tkn.kind != JSON_Parser::Token::TKN_CloseBrace) + { + while (true) + { + // State 1: New field or end of object, looking for field name or closing brace + std::basic_string fieldName; + switch (tkn.kind) + { + case JSON_Parser::Token::TKN_StringLiteral: + fieldName = std::move(tkn.string_val); + break; + default: + goto error; + } + + GetNextToken(tkn); + if (tkn.m_error) goto error; + + // State 2: Looking for a colon. + if (tkn.kind != JSON_Parser::Token::TKN_Colon) goto done; + + GetNextToken(tkn); + if (tkn.m_error) goto error; + + // State 3: Looking for an expression. +#ifdef ENABLE_JSON_VALUE_VISUALIZER + auto fieldValue = _ParseValue(tkn); + auto type = fieldValue->type(); + elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(std::move(fieldValue), type)); +#else + elems.emplace_back(utility::conversions::to_string_t(std::move(fieldName)), json::value(_ParseValue(tkn))); +#endif + if (tkn.m_error) goto error; + + // State 4: Looking for a comma or a closing brace + switch (tkn.kind) + { + case JSON_Parser::Token::TKN_Comma: + GetNextToken(tkn); + if (tkn.m_error) goto error; + break; + case JSON_Parser::Token::TKN_CloseBrace: + goto done; + default: + goto error; + } + } + } + +done: + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + + if (!g_keep_json_object_unsorted) { + ::std::sort(elems.begin(), elems.end(), json::object::compare_pairs); + } + + return std::move(obj); + +error: + if (!tkn.m_error) + { + SetErrorCode(tkn, json_error::malformed_object_literal); + } + return utility::details::make_unique(); +} + +template +std::unique_ptr JSON_Parser::_ParseArray(typename JSON_Parser::Token &tkn) +{ + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + + auto result = utility::details::make_unique(); + + if (tkn.kind != JSON_Parser::Token::TKN_CloseBracket) + { + while (true) + { + // State 1: Looking for an expression. + result->m_array.m_elements.emplace_back(ParseValue(tkn)); + if (tkn.m_error) return utility::details::make_unique(); + + // State 4: Looking for a comma or a closing bracket + switch (tkn.kind) + { + case JSON_Parser::Token::TKN_Comma: + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + break; + case JSON_Parser::Token::TKN_CloseBracket: + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(result); + default: + SetErrorCode(tkn, json_error::malformed_array_literal); + return utility::details::make_unique(); + } + } + } + + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + + return std::move(result); +} + +template +std::unique_ptr JSON_Parser::_ParseValue(typename JSON_Parser::Token &tkn) +{ + switch (tkn.kind) + { + case JSON_Parser::Token::TKN_OpenBrace: + { + return _ParseObject(tkn); + } + case JSON_Parser::Token::TKN_OpenBracket: + { + return _ParseArray(tkn); + } + case JSON_Parser::Token::TKN_StringLiteral: + { + auto value = utility::details::make_unique(std::move(tkn.string_val), tkn.has_unescape_symbol); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } + case JSON_Parser::Token::TKN_IntegerLiteral: + { + std::unique_ptr value; + if (tkn.signed_number) + value = utility::details::make_unique(tkn.int64_val); + else + value = utility::details::make_unique(tkn.uint64_val); + + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } + case JSON_Parser::Token::TKN_NumberLiteral: + { + auto value = utility::details::make_unique(tkn.double_val); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } + case JSON_Parser::Token::TKN_BooleanLiteral: + { + auto value = utility::details::make_unique(tkn.boolean_val); + GetNextToken(tkn); + if (tkn.m_error) return utility::details::make_unique(); + return std::move(value); + } + case JSON_Parser::Token::TKN_NullLiteral: + { + GetNextToken(tkn); + // Returning a null value whether or not an error occurred. + return utility::details::make_unique(); + } + default: + { + SetErrorCode(tkn, json_error::malformed_token); + return utility::details::make_unique(); + } + } +} + +}}} + +static web::json::value _parse_stream(utility::istream_t &stream) +{ + web::json::details::JSON_StreamParser parser(stream); + web::json::details::JSON_Parser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + + auto value = parser.ParseValue(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + } + return value; +} + +static web::json::value _parse_stream(utility::istream_t &stream, std::error_code& error) +{ + web::json::details::JSON_StreamParser parser(stream); + web::json::details::JSON_Parser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + error = std::move(tkn.m_error); + return web::json::value(); + } + + auto returnObject = parser.ParseValue(tkn); + if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream); + } + + error = std::move(tkn.m_error); + return returnObject; +} + +#ifdef _WIN32 +static web::json::value _parse_narrow_stream(std::istream &stream) +{ + web::json::details::JSON_StreamParser parser(stream); + web::json::details::JSON_StreamParser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + + auto value = parser.ParseValue(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + } + return value; +} + +static web::json::value _parse_narrow_stream(std::istream &stream, std::error_code& error) +{ + web::json::details::JSON_StreamParser parser(stream); + web::json::details::JSON_StreamParser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + error = std::move(tkn.m_error); + return web::json::value(); + } + + auto returnObject = parser.ParseValue(tkn); + if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + returnObject = web::json::value(); + web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream); + } + + error = std::move(tkn.m_error); + return returnObject; +} +#endif + +web::json::value web::json::value::parse(const utility::string_t& str) +{ + web::json::details::JSON_StringParser parser(str); + web::json::details::JSON_Parser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + + auto value = parser.ParseValue(tkn); + if (tkn.m_error) + { + web::json::details::CreateException(tkn, utility::conversions::to_string_t(tkn.m_error.message())); + } + else if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + web::json::details::CreateException(tkn, _XPLATSTR("Left-over characters in stream after parsing a JSON value")); + } + return value; +} + +web::json::value web::json::value::parse(const utility::string_t& str, std::error_code& error) +{ + web::json::details::JSON_StringParser parser(str); + web::json::details::JSON_Parser::Token tkn; + + parser.GetNextToken(tkn); + if (tkn.m_error) + { + error = std::move(tkn.m_error); + return web::json::value(); + } + + auto returnObject = parser.ParseValue(tkn); + if (tkn.kind != web::json::details::JSON_Parser::Token::TKN_EOF) + { + returnObject = web::json::value(); + web::json::details::SetErrorCode(tkn, web::json::details::json_error::left_over_character_in_stream); + } + + error = std::move(tkn.m_error); + return returnObject; +} + +web::json::value web::json::value::parse(utility::istream_t &stream) +{ + return _parse_stream(stream); +} + +web::json::value web::json::value::parse(utility::istream_t &stream, std::error_code& error) +{ + return _parse_stream(stream, error); +} + +#ifdef _WIN32 +web::json::value web::json::value::parse(std::istream& stream) +{ + return _parse_narrow_stream(stream); +} + +web::json::value web::json::value::parse(std::istream& stream, std::error_code& error) +{ + return _parse_narrow_stream(stream, error); +} +#endif diff --git a/src/corehost/cli/json/casablanca/src/json/json_serialization.cpp b/src/corehost/cli/json/casablanca/src/json/json_serialization.cpp new file mode 100644 index 000000000..e99e0bc5a --- /dev/null +++ b/src/corehost/cli/json/casablanca/src/json/json_serialization.cpp @@ -0,0 +1,274 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* HTTP Library: JSON parser and writer +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" +#include + +#ifndef _WIN32 +#define __STDC_FORMAT_MACROS +#include +#endif + +using namespace web; +using namespace web::json; +using namespace utility; +using namespace utility::conversions; + +// +// JSON Serialization +// + +#ifdef _WIN32 +void web::json::value::serialize(std::ostream& stream) const +{ + // This has better performance than writing directly to stream. + std::string str; + m_value->serialize_impl(str); + stream << str; +} +void web::json::value::format(std::basic_string &string) const +{ + m_value->format(string); +} +#endif + +void web::json::value::serialize(utility::ostream_t &stream) const +{ +#ifndef _WIN32 + utility::details::scoped_c_thread_locale locale; +#endif + + // This has better performance than writing directly to stream. + utility::string_t str; + m_value->serialize_impl(str); + stream << str; +} + +void web::json::value::format(std::basic_string& string) const +{ + m_value->format(string); +} + +template +void web::json::details::append_escape_string(std::basic_string& str, const std::basic_string& escaped) +{ + for (const auto &ch : escaped) + { + switch (ch) + { + case '\"': + str += '\\'; + str += '\"'; + break; + case '\\': + str += '\\'; + str += '\\'; + break; + case '\b': + str += '\\'; + str += 'b'; + break; + case '\f': + str += '\\'; + str += 'f'; + break; + case '\r': + str += '\\'; + str += 'r'; + break; + case '\n': + str += '\\'; + str += 'n'; + break; + case '\t': + str += '\\'; + str += 't'; + break; + default: + + // If a control character then must unicode escaped. + if (ch >= 0 && ch <= 0x1F) + { + static const std::array intToHex = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } }; + str += '\\'; + str += 'u'; + str += '0'; + str += '0'; + str += intToHex[(ch & 0xF0) >> 4]; + str += intToHex[ch & 0x0F]; + } + else + { + str += ch; + } + } + } +} + +void web::json::details::format_string(const utility::string_t& key, utility::string_t& str) +{ + str.push_back('"'); + append_escape_string(str, key); + str.push_back('"'); +} + +#ifdef _WIN32 +void web::json::details::format_string(const utility::string_t& key, std::string& str) +{ + str.push_back('"'); + append_escape_string(str, utility::conversions::to_utf8string(key)); + str.push_back('"'); +} +#endif + +void web::json::details::_String::format(std::basic_string& str) const +{ + str.push_back('"'); + + if(m_has_escape_char) + { + append_escape_string(str, utility::conversions::to_utf8string(m_string)); + } + else + { + str.append(utility::conversions::to_utf8string(m_string)); + } + + str.push_back('"'); +} + +void web::json::details::_Number::format(std::basic_string& stream) const +{ + if(m_number.m_type != number::type::double_type) + { + // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator. + const size_t tempSize = std::numeric_limits::digits10 + 3; + char tempBuffer[tempSize]; + +#ifdef _WIN32 + // This can be improved performance-wise if we implement our own routine + if (m_number.m_type == number::type::signed_type) + _i64toa_s(m_number.m_intval, tempBuffer, tempSize, 10); + else + _ui64toa_s(m_number.m_uintval, tempBuffer, tempSize, 10); + + const auto numChars = strnlen_s(tempBuffer, tempSize); +#else + int numChars; + if (m_number.m_type == number::type::signed_type) + numChars = snprintf(tempBuffer, tempSize, "%" PRId64, m_number.m_intval); + else + numChars = snprintf(tempBuffer, tempSize, "%" PRIu64, m_number.m_uintval); +#endif + stream.append(tempBuffer, numChars); + } + else + { + // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator + const size_t tempSize = std::numeric_limits::digits10 + 10; + char tempBuffer[tempSize]; +#ifdef _WIN32 + const auto numChars = _sprintf_s_l( + tempBuffer, + tempSize, + "%.*g", + utility::details::scoped_c_thread_locale::c_locale(), + std::numeric_limits::digits10 + 2, + m_number.m_value); +#else + const auto numChars = snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits::digits10 + 2, m_number.m_value); +#endif + stream.append(tempBuffer, numChars); + } +} + +#ifdef _WIN32 + +void web::json::details::_String::format(std::basic_string& str) const +{ + str.push_back(L'"'); + + if(m_has_escape_char) + { + append_escape_string(str, m_string); + } + else + { + str.append(m_string); + } + + str.push_back(L'"'); +} + +void web::json::details::_Number::format(std::basic_string& stream) const +{ + if(m_number.m_type != number::type::double_type) + { + // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator. + const size_t tempSize = std::numeric_limits::digits10 + 3; + wchar_t tempBuffer[tempSize]; + + if (m_number.m_type == number::type::signed_type) + _i64tow_s(m_number.m_intval, tempBuffer, tempSize, 10); + else + _ui64tow_s(m_number.m_uintval, tempBuffer, tempSize, 10); + + stream.append(tempBuffer, wcsnlen_s(tempBuffer, tempSize)); + } + else + { + // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator + const size_t tempSize = std::numeric_limits::digits10 + 10; + wchar_t tempBuffer[tempSize]; + const int numChars = _swprintf_s_l( + tempBuffer, + tempSize, + L"%.*g", + utility::details::scoped_c_thread_locale::c_locale(), + std::numeric_limits::digits10 + 2, + m_number.m_value); + stream.append(tempBuffer, numChars); + } +} + +#endif + +const utility::string_t & web::json::details::_String::as_string() const +{ + return m_string; +} + +const utility::string_t & web::json::value::as_string() const +{ + return m_value->as_string(); +} + +utility::string_t json::value::serialize() const +{ +#ifndef _WIN32 + utility::details::scoped_c_thread_locale locale; +#endif + return m_value->to_string(); +} diff --git a/src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp b/src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp new file mode 100644 index 000000000..87a0d8957 --- /dev/null +++ b/src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp @@ -0,0 +1,496 @@ +/*** +* ==++== +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* ==--== +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* Utilities +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" + +#ifndef _WIN32 +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#endif + +// Could use C++ standard library if not __GLIBCXX__, +// For testing purposes we just the handwritten on all platforms. +#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) +#include +#endif + +using namespace web; +using namespace utility; +using namespace utility::conversions; + +namespace utility +{ +namespace details +{ + +#if !defined(ANDROID) && !defined(__ANDROID__) +std::once_flag g_c_localeFlag; +std::unique_ptr g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){}); +scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale() +{ + std::call_once(g_c_localeFlag, [&]() + { + scoped_c_thread_locale::xplat_locale *clocale = new scoped_c_thread_locale::xplat_locale(); +#ifdef _WIN32 + *clocale = _create_locale(LC_ALL, "C"); + if (*clocale == nullptr) + { + throw std::runtime_error("Unable to create 'C' locale."); + } + auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale) + { + _free_locale(*clocale); + delete clocale; + }; +#else + *clocale = newlocale(LC_ALL, "C", nullptr); + if (*clocale == nullptr) + { + throw std::runtime_error("Unable to create 'C' locale."); + } + auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale) + { + freelocale(*clocale); + delete clocale; + }; +#endif + g_c_locale = std::unique_ptr(clocale, deleter); + }); + return *g_c_locale; +} +#endif + +#ifdef _WIN32 +scoped_c_thread_locale::scoped_c_thread_locale() + : m_prevLocale(), m_prevThreadSetting(-1) +{ + char *prevLocale = setlocale(LC_ALL, nullptr); + if (prevLocale == nullptr) + { + throw std::runtime_error("Unable to retrieve current locale."); + } + + if (std::strcmp(prevLocale, "C") != 0) + { + m_prevLocale = prevLocale; + m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + if (m_prevThreadSetting == -1) + { + throw std::runtime_error("Unable to enable per thread locale."); + } + if (setlocale(LC_ALL, "C") == nullptr) + { + _configthreadlocale(m_prevThreadSetting); + throw std::runtime_error("Unable to set locale"); + } + } +} + +scoped_c_thread_locale::~scoped_c_thread_locale() +{ + if (m_prevThreadSetting != -1) + { + setlocale(LC_ALL, m_prevLocale.c_str()); + _configthreadlocale(m_prevThreadSetting); + } +} +#elif (defined(ANDROID) || defined(__ANDROID__)) +scoped_c_thread_locale::scoped_c_thread_locale() {} +scoped_c_thread_locale::~scoped_c_thread_locale() {} +#else +scoped_c_thread_locale::scoped_c_thread_locale() + : m_prevLocale(nullptr) +{ + char *prevLocale = setlocale(LC_ALL, nullptr); + if (prevLocale == nullptr) + { + throw std::runtime_error("Unable to retrieve current locale."); + } + + if (std::strcmp(prevLocale, "C") != 0) + { + m_prevLocale = uselocale(c_locale()); + if (m_prevLocale == nullptr) + { + throw std::runtime_error("Unable to set locale"); + } + } +} + +scoped_c_thread_locale::~scoped_c_thread_locale() +{ + if (m_prevLocale != nullptr) + { + uselocale(m_prevLocale); + } +} +#endif +} + +namespace details +{ + +const std::error_category & __cdecl platform_category() +{ +#ifdef _WIN32 + return windows_category(); +#else + return linux_category(); +#endif +} + +#ifdef _WIN32 + +// Remove once VS 2013 is no longer supported. +#if _MSC_VER < 1900 +static details::windows_category_impl instance; +#endif +const std::error_category & __cdecl windows_category() +{ +#if _MSC_VER >= 1900 + static details::windows_category_impl instance; +#endif + return instance; +} + +std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT +{ + const size_t buffer_size = 4096; + DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM; + LPCVOID lpSource = NULL; + +#if !defined(__cplusplus_winrt) + if (errorCode >= 12000) + { + dwFlags = FORMAT_MESSAGE_FROM_HMODULE; + lpSource = GetModuleHandleA("winhttp.dll"); // this handle DOES NOT need to be freed + } +#endif + + std::wstring buffer; + buffer.resize(buffer_size); + + const auto result = ::FormatMessageW( + dwFlags, + lpSource, + errorCode, + 0, + &buffer[0], + buffer_size, + NULL); + if (result == 0) + { + std::ostringstream os; + os << "Unable to get an error message for error code: " << errorCode << "."; + return os.str(); + } + + return utility::conversions::to_utf8string(buffer); +} + +std::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT +{ + // First see if the STL implementation can handle the mapping for common cases. + const std::error_condition errCondition = std::system_category().default_error_condition(errorCode); + const std::string errConditionMsg = errCondition.message(); + if(_stricmp(errConditionMsg.c_str(), "unknown error") != 0) + { + return errCondition; + } + + switch(errorCode) + { +#ifndef __cplusplus_winrt + case ERROR_WINHTTP_TIMEOUT: + return std::errc::timed_out; + case ERROR_WINHTTP_CANNOT_CONNECT: + return std::errc::host_unreachable; + case ERROR_WINHTTP_CONNECTION_ERROR: + return std::errc::connection_aborted; +#endif + case INET_E_RESOURCE_NOT_FOUND: + case INET_E_CANNOT_CONNECT: + return std::errc::host_unreachable; + case INET_E_CONNECTION_TIMEOUT: + return std::errc::timed_out; + case INET_E_DOWNLOAD_FAILURE: + return std::errc::connection_aborted; + default: + break; + } + + return std::error_condition(errorCode, *this); +} + +#else + +const std::error_category & __cdecl linux_category() +{ + // On Linux we are using boost error codes which have the exact same + // mapping and are equivalent with std::generic_category error codes. + return std::generic_category(); +} + +#endif + +} + +#define LOW_3BITS 0x7 +#define LOW_4BITS 0xF +#define LOW_5BITS 0x1F +#define LOW_6BITS 0x3F +#define BIT4 0x8 +#define BIT5 0x10 +#define BIT6 0x20 +#define BIT7 0x40 +#define BIT8 0x80 +#define L_SURROGATE_START 0xDC00 +#define L_SURROGATE_END 0xDFFF +#define H_SURROGATE_START 0xD800 +#define H_SURROGATE_END 0xDBFF +#define SURROGATE_PAIR_START 0x10000 + +utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) +{ +#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) + std::wstring_convert, utf16char> conversion; + return conversion.from_bytes(src); +#else + utf16string dest; + // Save repeated heap allocations, use less than source string size assuming some + // of the characters are not just ASCII and collapse. + dest.reserve(static_cast(static_cast(s.size()) * .70)); + + for (auto src = s.begin(); src != s.end(); ++src) + { + if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F + { + dest.push_back(utf16string::value_type(*src)); + } + else + { + unsigned char numContBytes = 0; + uint32_t codePoint; + if ((*src & BIT7) == 0) + { + throw std::range_error("UTF-8 string character can never start with 10xxxxxx"); + } + else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF + { + codePoint = *src & LOW_5BITS; + numContBytes = 1; + } + else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF + { + codePoint = *src & LOW_4BITS; + numContBytes = 2; + } + else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF + { + codePoint = *src & LOW_3BITS; + numContBytes = 3; + } + else + { + throw std::range_error("UTF-8 string has invalid Unicode code point"); + } + + for (unsigned char i = 0; i < numContBytes; ++i) + { + if (++src == s.end()) + { + throw std::range_error("UTF-8 string is missing bytes in character"); + } + if ((*src & BIT8) == 0 || (*src & BIT7) != 0) + { + throw std::range_error("UTF-8 continuation byte is missing leading byte"); + } + codePoint <<= 6; + codePoint |= *src & LOW_6BITS; + } + + if (codePoint >= SURROGATE_PAIR_START) + { + // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. + // - 0x10000 is subtracted from the code point + // - high surrogate is 0xD800 added to the top ten bits + // - low surrogate is 0xDC00 added to the low ten bits + codePoint -= SURROGATE_PAIR_START; + dest.push_back(utf16string::value_type((codePoint >> 10) | H_SURROGATE_START)); + dest.push_back(utf16string::value_type((codePoint & 0x3FF) | L_SURROGATE_START)); + } + else + { + // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value. + // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode + // them if encountered. + dest.push_back(utf16string::value_type(codePoint)); + } + } + } + return dest; +#endif +} + +std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) +{ + #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) + std::wstring_convert, utf16char> conversion; + return conversion.to_bytes(w); + #else + std::string dest; + dest.reserve(w.size()); + for (auto src = w.begin(); src != w.end(); ++src) + { + // Check for high surrogate. + if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END) + { + const auto highSurrogate = *src++; + if (src == w.end()) + { + throw std::range_error("UTF-16 string is missing low surrogate"); + } + const auto lowSurrogate = *src; + if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) + { + throw std::range_error("UTF-16 string has invalid low surrogate"); + } + + // To get from surrogate pair to Unicode code point: + // - subract 0xD800 from high surrogate, this forms top ten bits + // - subract 0xDC00 from low surrogate, this forms low ten bits + // - add 0x10000 + // Leaves a code point in U+10000 to U+10FFFF range. + uint32_t codePoint = highSurrogate - H_SURROGATE_START; + codePoint <<= 10; + codePoint |= lowSurrogate - L_SURROGATE_START; + codePoint += SURROGATE_PAIR_START; + + // 4 bytes need using 21 bits + dest.push_back(char((codePoint >> 18) | 0xF0)); // leading 3 bits + dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8)); // next 6 bits + dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8)); // next 6 bits + dest.push_back(char((codePoint & LOW_6BITS) | BIT8)); // trailing 6 bits + } + else + { + if (*src <= 0x7F) // single byte character + { + dest.push_back(static_cast(*src)); + } + else if (*src <= 0x7FF) // 2 bytes needed (11 bits used) + { + dest.push_back(char((*src >> 6) | 0xC0)); // leading 5 bits + dest.push_back(char((*src & LOW_6BITS) | BIT8)); // trailing 6 bits + } + else // 3 bytes needed (16 bits used) + { + dest.push_back(char((*src >> 12) | 0xE0)); // leading 4 bits + dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits + dest.push_back(char((*src & LOW_6BITS) | BIT8)); // trailing 6 bits + } + } + } + + return dest; + #endif +} + +utf16string __cdecl conversions::usascii_to_utf16(const std::string &s) +{ + // Ascii is a subset of UTF-8 so just convert to UTF-16 + return utf8_to_utf16(s); +} + +utf16string __cdecl conversions::latin1_to_utf16(const std::string &s) +{ + // Latin1 is the first 256 code points in Unicode. + // In UTF-16 encoding each of these is represented as exactly the numeric code point. + utf16string dest; + dest.resize(s.size()); + for (size_t i = 0; i < s.size(); ++i) + { + dest[i] = utf16char(s[i]); + } + return dest; +} + +utf8string __cdecl conversions::latin1_to_utf8(const std::string &s) +{ + return utf16_to_utf8(latin1_to_utf16(s)); +} + +utility::string_t __cdecl conversions::to_string_t(utf16string &&s) +{ +#ifdef _UTF16_STRINGS + return std::move(s); +#else + return utf16_to_utf8(std::move(s)); +#endif +} + +utility::string_t __cdecl conversions::to_string_t(std::string &&s) +{ +#ifdef _UTF16_STRINGS + return utf8_to_utf16(std::move(s)); +#else + return std::move(s); +#endif +} + +utility::string_t __cdecl conversions::to_string_t(const utf16string &s) +{ +#ifdef _UTF16_STRINGS + return s; +#else + return utf16_to_utf8(s); +#endif +} + +utility::string_t __cdecl conversions::to_string_t(const std::string &s) +{ +#ifdef _UTF16_STRINGS + return utf8_to_utf16(s); +#else + return s; +#endif +} + +std::string __cdecl conversions::to_utf8string(std::string value) { return std::move(value); } + +std::string __cdecl conversions::to_utf8string(const utf16string &value) { return utf16_to_utf8(value); } + +utf16string __cdecl conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); } + +utf16string __cdecl conversions::to_utf16string(utf16string value) { return std::move(value); } + +static bool is_digit(utility::char_t c) { return c >= _XPLATSTR('0') && c <= _XPLATSTR('9'); } + +} diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp new file mode 100644 index 000000000..56d030505 --- /dev/null +++ b/src/corehost/cli/libhost.cpp @@ -0,0 +1,61 @@ +// 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. + +#include "pal.h" +#include "utils.h" +#include "trace.h" +#include "libhost.h" + +pal::string_t get_runtime_config_json(const pal::string_t& app_path) +{ + auto name = get_filename_without_ext(app_path); + auto json_name = name + _X(".runtimeconfig.json"); + auto json_path = get_directory(app_path); + + append_path(&json_path, json_name.c_str()); + if (pal::file_exists(json_path)) + { + return json_path; + } + return pal::string_t(); +} + +host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* p_own_dir) +{ + pal::string_t own_path; + if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path)) + { + trace::error(_X("Failed to locate current executable")); + return host_mode_t::invalid; + } + + pal::string_t own_name = get_filename(own_path); + pal::string_t own_dir = get_directory(own_path); + if (p_own_dir) + { + p_own_dir->assign(own_dir); + } + + pal::string_t own_dll_filename = strip_file_ext(own_name) + _X(".dll"); + pal::string_t own_dll = own_dir; + append_path(&own_dll, own_dll_filename.c_str()); + trace::info(_X("Exists %s"), own_dll.c_str()); + if (coreclr_exists_in_dir(own_dir) || pal::file_exists(own_dll)) + { + pal::string_t own_deps_json = own_dir; + pal::string_t own_deps_filename = strip_file_ext(own_name) + _X(".deps.json"); + pal::string_t own_config_filename = strip_file_ext(own_name) + _X(".runtimeconfig.json"); + append_path(&own_deps_json, own_deps_filename.c_str()); + if (trace::is_enabled()) + { + trace::info(_X("Detecting mode... CoreCLR present in own dir [%s] and checking if [%s] file present=[%d]"), + own_dir.c_str(), own_deps_filename.c_str(), pal::file_exists(own_deps_json)); + } + return ((pal::file_exists(own_deps_json) || !pal::file_exists(own_config_filename)) && pal::file_exists(own_dll)) ? host_mode_t::standalone : host_mode_t::split_fx; + } + else + { + return host_mode_t::muxer; + } +} + diff --git a/src/corehost/cli/libhost.h b/src/corehost/cli/libhost.h index 0b8ea823a..fa0d60e9c 100644 --- a/src/corehost/cli/libhost.h +++ b/src/corehost/cli/libhost.h @@ -1,4 +1,70 @@ // 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. +#ifndef __LIBHOST_H__ +#define __LIBHOST_H__ + #define LIBHOST_NAME MAKE_LIBNAME("hostpolicy") + +enum host_mode_t +{ + invalid = 0, + muxer, + standalone, + split_fx +}; + +class runtime_config_t; + +class corehost_init_t +{ + const pal::string_t m_probe_path; + const pal::string_t m_deps_file; + const pal::string_t m_fx_dir; + host_mode_t m_host_mode; + const runtime_config_t* m_runtime_config; +public: + corehost_init_t( + const pal::string_t& deps_file, + const pal::string_t& probe_path, + const pal::string_t& fx_dir, + const host_mode_t mode, + const runtime_config_t* runtime_config) + : m_fx_dir(fx_dir) + , m_runtime_config(runtime_config) + , m_deps_file(deps_file) + , m_probe_path(probe_path) + , m_host_mode(mode) + { + } + + const host_mode_t host_mode() const + { + return m_host_mode; + } + + const pal::string_t& deps_file() const + { + return m_deps_file; + } + + const pal::string_t& probe_dir() const + { + return m_probe_path; + } + + const pal::string_t& fx_dir() const + { + return m_fx_dir; + } + + const runtime_config_t* runtime_config() const + { + return m_runtime_config; + } +}; + +pal::string_t get_runtime_config_json(const pal::string_t& app_path); +host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr); + +#endif // __LIBHOST_H__ diff --git a/src/corehost/cli/runtime_config.cpp b/src/corehost/cli/runtime_config.cpp new file mode 100644 index 000000000..e27c5a3a0 --- /dev/null +++ b/src/corehost/cli/runtime_config.cpp @@ -0,0 +1,114 @@ +// 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. + +#include "pal.h" +#include "utils.h" +#include "cpprest/json.h" +#include "runtime_config.h" +#include + +typedef web::json::value json_value; + +runtime_config_t::runtime_config_t(const pal::string_t& path) + : m_fx_roll_fwd(true) + , m_path(path) + , m_portable(false) + , m_gc_server(_X("0")) +{ + m_valid = ensure_parsed(); +} + +void parse_fx(const json_value& opts, pal::string_t* name, pal::string_t* version, bool* roll_fwd, bool* portable) +{ + name->clear(); + version->clear(); + *roll_fwd = true; + *portable = false; + + if (opts.is_null()) + { + return; + } + + const auto& opts_obj = opts.as_object(); + auto framework = opts_obj.find(_X("framework")); + if (framework == opts_obj.end()) + { + return; + } + + *portable = true; + + const auto& fx_obj = framework->second.as_object(); + *name = fx_obj.at(_X("name")).as_string(); + *version = fx_obj.at(_X("version")).as_string(); + + auto value = fx_obj.find(_X("rollForward")); + if (value == fx_obj.end()) + { + return; + } + + *roll_fwd = value->second.as_bool(); +} + +bool runtime_config_t::ensure_parsed() +{ + pal::string_t retval; + if (!pal::file_exists(m_path)) + { + // Not existing is not an error. + return true; + } + + pal::ifstream_t file(m_path); + if (!file.good()) + { + return false; + } + + try + { + const auto root = json_value::parse(file); + const auto& json = root.as_object(); + const auto iter = json.find(_X("runtimeOptions")); + if (iter != json.end()) + { + parse_fx(iter->second, &m_fx_name, &m_fx_ver, &m_fx_roll_fwd, &m_portable); + } + } + catch (...) + { + return false; + } + return true; +} + +const pal::string_t& runtime_config_t::get_gc_server() const +{ + assert(m_valid); + return m_gc_server; +} + +const pal::string_t& runtime_config_t::get_fx_name() const +{ + assert(m_valid); + return m_fx_name; +} + +const pal::string_t& runtime_config_t::get_fx_version() const +{ + assert(m_valid); + return m_fx_ver; +} + +bool runtime_config_t::get_fx_roll_fwd() const +{ + assert(m_valid); + return m_fx_roll_fwd; +} + +bool runtime_config_t::get_portable() const +{ + return m_portable; +} diff --git a/src/corehost/cli/runtime_config.h b/src/corehost/cli/runtime_config.h new file mode 100644 index 000000000..bdb14fda1 --- /dev/null +++ b/src/corehost/cli/runtime_config.h @@ -0,0 +1,29 @@ +// 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. + +#include "pal.h" + +class runtime_config_t +{ +public: + runtime_config_t(const pal::string_t& path); + bool is_valid() { return m_valid; } + const pal::string_t& get_path() { return m_path; } + const pal::string_t& get_gc_server() const; + const pal::string_t& get_fx_version() const; + const pal::string_t& get_fx_name() const; + bool get_fx_roll_fwd() const; + bool get_portable() const; + +private: + bool ensure_parsed(); + + pal::string_t m_gc_server; + pal::string_t m_fx_name; + pal::string_t m_fx_ver; + bool m_fx_roll_fwd; + + pal::string_t m_path; + bool m_portable; + bool m_valid; +}; diff --git a/src/corehost/cli/servicing_index.cpp b/src/corehost/cli/servicing_index.cpp index 687006ff4..8dd9ebd76 100644 --- a/src/corehost/cli/servicing_index.cpp +++ b/src/corehost/cli/servicing_index.cpp @@ -38,18 +38,33 @@ bool servicing_index_t::find_redirection( auto iter = m_redirections.find(stream.str()); if (iter != m_redirections.end()) { - pal::string_t full_path = m_patch_root; - append_path(&full_path, iter->second.c_str()); - if (pal::file_exists(full_path)) + pal::string_t ni_root = m_patch_root; + append_path(&ni_root, get_arch()); + + // First prefer the architecture specific NI image. + pal::string_t paths[2] = { ni_root, m_patch_root }; + for (pal::string_t& full_path : paths) { - *redirection = full_path; - trace::verbose(_X("Servicing %s with %s"), stream.str().c_str(), redirection->c_str()); - return true; + append_path(&full_path, iter->second.c_str()); + if (pal::file_exists(full_path)) + { + *redirection = full_path; + if (trace::is_enabled()) + { + pal::string_t stream_str = stream.str(); + trace::verbose(_X("Servicing %s with %s"), stream_str.c_str(), redirection->c_str()); + } + return true; + } + trace::verbose(_X("Serviced file %s doesn't exist"), full_path.c_str()); } - trace::verbose(_X("Serviced file %s doesn't exist"), full_path.c_str()); } - trace::verbose(_X("Entry %s not serviced or file doesn't exist"), stream.str().c_str()); + if (trace::is_enabled()) + { + auto stream_str = stream.str(); + trace::verbose(_X("Entry %s not serviced or file doesn't exist"), stream_str.c_str()); + } return false; } @@ -112,7 +127,8 @@ void servicing_index_t::ensure_redirections() if (trace::is_enabled()) { - trace::verbose(_X("Adding servicing entry %s => %s"), sstream.str().c_str(), str.substr(from).c_str()); + auto stream_str = sstream.str(); + trace::verbose(_X("Adding servicing entry %s => %s"), stream_str.c_str(), str.substr(from).c_str()); } // Store just the filename. diff --git a/src/corehost/cli/setup.cmake b/src/corehost/cli/setup.cmake index ef2028035..d3e65f55d 100644 --- a/src/corehost/cli/setup.cmake +++ b/src/corehost/cli/setup.cmake @@ -33,4 +33,20 @@ if(WIN32) set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF") set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF") +else() + add_compile_options(-Wno-unused-local-typedef) +endif() + +if(CLI_CMAKE_PLATFORM_ARCH_I386) + add_definitions(-D_TARGET_X86_=1) +elseif(CLI_CMAKE_PLATFORM_ARCH_AMD64) + add_definitions(-D_TARGET_AMD64_=1) +else() + message(FATAL_ERROR "Unknown target architecture") +endif() + +if(${CLI_CMAKE_RUNTIME_ID} STREQUAL "") + message(FATAL_ERROR "Runtime ID not specified") +else() + add_definitions(-DTARGET_RUNTIME_ID="${CLI_CMAKE_RUNTIME_ID}") endif() diff --git a/src/corehost/common/pal.h b/src/corehost/common/pal.h index 930104d34..dfd76b3a6 100644 --- a/src/corehost/common/pal.h +++ b/src/corehost/common/pal.h @@ -15,10 +15,12 @@ #include #include #include +#include #if defined(_WIN32) -#include +#define NOMINMAX +#include #define HOST_EXE_NAME L"corehost.exe" #define xerr std::wcerr @@ -93,11 +95,17 @@ namespace pal typedef HMODULE dll_t; typedef FARPROC proc_t; + pal::string_t to_string(int value); + + bool getcwd(pal::string_t* recv); + inline int strcmp(const char_t* str1, const char_t* str2) { return ::wcscmp(str1, str2); } inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::_wcsicmp(str1, str2); } inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::wcsncmp(str1, str2, len); } inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::_wcsnicmp(str1, str2, len); } + pal::string_t to_lower(const pal::string_t& in); + inline size_t strlen(const char_t* str) { return ::wcslen(str); } inline void err_vprintf(const char_t* format, va_list vl) { ::vfwprintf(stderr, format, vl); ::fputws(_X("\r\n"), stderr); } @@ -126,10 +134,17 @@ namespace pal typedef void* dll_t; typedef void* proc_t; + pal::string_t to_string(int value); + + bool getcwd(pal::string_t* recv); + inline int strcmp(const char_t* str1, const char_t* str2) { return ::strcmp(str1, str2); } inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::strcasecmp(str1, str2); } inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::strncmp(str1, str2, len); } inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::strncasecmp(str1, str2, len); } + + pal::string_t to_lower(const pal::string_t& in); + inline size_t strlen(const char_t* str) { return ::strlen(str); } inline void err_vprintf(const char_t* format, va_list vl) { ::vfprintf(stderr, format, vl); ::fputc('\n', stderr); } inline pal::string_t to_palstring(const std::string& str) { return str; } diff --git a/src/corehost/common/pal.unix.cpp b/src/corehost/common/pal.unix.cpp index ead8034d8..a58ad8761 100644 --- a/src/corehost/common/pal.unix.cpp +++ b/src/corehost/common/pal.unix.cpp @@ -10,6 +10,8 @@ #include #include +#include + #if defined(__APPLE__) #include #endif @@ -20,6 +22,33 @@ #define symlinkEntrypointExecutable "/proc/curproc/exe" #endif +pal::string_t pal::to_string(int value) { return std::to_string(value); } + +pal::string_t pal::to_lower(const pal::string_t& in) +{ + pal::string_t ret = in; + std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower); + return ret; +} + +bool pal::getcwd(pal::string_t* recv) +{ + recv->clear(); + pal::char_t* buf = ::getcwd(nullptr, PATH_MAX + 1); + if (buf == nullptr) + { + if (errno == ENOENT) + { + return false; + } + perror("getcwd()"); + return false; + } + recv->assign(buf); + ::free(buf); + return true; +} + bool pal::find_coreclr(pal::string_t* recv) { pal::string_t candidate; @@ -133,8 +162,7 @@ bool pal::getenv(const pal::char_t* name, pal::string_t* recv) bool pal::realpath(pal::string_t* path) { - pal::char_t buf[PATH_MAX]; - auto resolved = ::realpath(path->c_str(), buf); + auto resolved = ::realpath(path->c_str(), nullptr); if (resolved == nullptr) { if (errno == ENOENT) @@ -145,6 +173,7 @@ bool pal::realpath(pal::string_t* path) return false; } path->assign(resolved); + ::free(resolved); return true; } diff --git a/src/corehost/common/pal.windows.cpp b/src/corehost/common/pal.windows.cpp index d70bd60e9..a5ce39c7f 100644 --- a/src/corehost/common/pal.windows.cpp +++ b/src/corehost/common/pal.windows.cpp @@ -11,6 +11,18 @@ static std::wstring_convert, wchar_t> g_converter; +pal::string_t pal::to_lower(const pal::string_t& in) +{ + pal::string_t ret = in; + std::transform(ret.begin(), ret.end(), ret.begin(), ::towlower); + return ret; +} + +pal::string_t pal::to_string(int value) +{ + return std::to_wstring(value); +} + bool pal::find_coreclr(pal::string_t* recv) { pal::string_t candidate; @@ -31,6 +43,35 @@ bool pal::find_coreclr(pal::string_t* recv) return false; } + +bool pal::getcwd(pal::string_t* recv) +{ + recv->clear(); + + pal::char_t buf[MAX_PATH]; + DWORD result = GetCurrentDirectoryW(MAX_PATH, buf); + if (result < MAX_PATH) + { + recv->assign(buf); + return true; + } + else if (result != 0) + { + std::vector str; + str.resize(result); + result = GetCurrentDirectoryW(str.size(), str.data()); + assert(result <= str.size()); + if (result != 0) + { + recv->assign(str.data()); + return true; + } + } + assert(result == 0); + trace::error(_X("Failed to obtain working directory, HRESULT: 0x%X"), HRESULT_FROM_WIN32(GetLastError())); + return false; +} + bool pal::load_library(const char_t* path, dll_t* dll) { *dll = ::LoadLibraryW(path); diff --git a/src/corehost/common/utils.cpp b/src/corehost/common/utils.cpp index 2515b2155..65f1b8c42 100644 --- a/src/corehost/common/utils.cpp +++ b/src/corehost/common/utils.cpp @@ -55,16 +55,43 @@ pal::string_t get_executable(const pal::string_t& filename) return result; } -pal::string_t get_filename(const pal::string_t& path) +pal::string_t strip_file_ext(const pal::string_t& path) { - // Find the last dir separator - auto path_sep = path.find_last_of(DIR_SEPARATOR); - if (path_sep == pal::string_t::npos) + if (path.empty()) { - return pal::string_t(path); + return path; + } + return path.substr(0, path.rfind(_X('.'))); +} + +pal::string_t get_filename_without_ext(const pal::string_t& path) +{ + if (path.empty()) + { + return path; } - return path.substr(path_sep + 1); + size_t name_pos = path.find_last_of(_X("/\\")); + size_t dot_pos = path.rfind(_X('.')); + size_t start_pos = (name_pos == pal::string_t::npos) ? 0 : (name_pos + 1); + size_t count = (dot_pos == pal::string_t::npos) ? pal::string_t::npos : (dot_pos - start_pos); + return path.substr(start_pos, count); +} + +pal::string_t get_filename(const pal::string_t& path) +{ + if (path.empty()) + { + return path; + } + + auto name_pos = path.find_last_of(DIR_SEPARATOR); + if (name_pos == pal::string_t::npos) + { + return path; + } + + return path.substr(name_pos + 1); } pal::string_t get_directory(const pal::string_t& path) @@ -87,3 +114,49 @@ void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl) (*path)[pos] = repl; } } + +const pal::char_t* get_arch() +{ +#if _TARGET_AMD64_ + return _X("x64"); +#elif _TARGET_X86_ + return _X("x86"); +#else +#error "Unknown target" +#endif +} + +bool parse_known_args( + const int argc, + const pal::char_t* argv[], + const std::vector& known_opts, + std::unordered_map* opts, + int* num_args) +{ + int arg_i = *num_args; + while (arg_i < argc) + { + pal::string_t arg = argv[arg_i]; + if (std::find(known_opts.begin(), known_opts.end(), pal::to_lower(arg)) == known_opts.end()) + { + // Unknown argument. + break; + } + + // Known argument, so expect one more arg (value) to be present. + if (arg_i + 1 >= argc) + { + return false; + } + + (*opts)[arg] = argv[arg_i + 1]; + + // Increment for both the option and its value. + arg_i += 2; + } + + *num_args = arg_i; + + return true; +} + diff --git a/src/corehost/common/utils.h b/src/corehost/common/utils.h index 9d2dc2098..bbcdae4ad 100644 --- a/src/corehost/common/utils.h +++ b/src/corehost/common/utils.h @@ -10,8 +10,17 @@ bool ends_with(const pal::string_t& value, const pal::string_t& suffix, bool mat bool starts_with(const pal::string_t& value, const pal::string_t& prefix, bool match_case); pal::string_t get_executable(const pal::string_t& filename); pal::string_t get_directory(const pal::string_t& path); +pal::string_t strip_file_ext(const pal::string_t& path); pal::string_t get_filename(const pal::string_t& path); +pal::string_t get_filename_without_ext(const pal::string_t& path); void append_path(pal::string_t* path1, const pal::char_t* path2); bool coreclr_exists_in_dir(const pal::string_t& candidate); void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl); +const pal::char_t* get_arch(); +bool parse_known_args( + const int argc, + const pal::char_t* argv[], + const std::vector& known_opts, + std::unordered_map* opts, + int* num_args); #endif diff --git a/src/corehost/corehost.cpp b/src/corehost/corehost.cpp index 70e4d7d36..bf1904faa 100644 --- a/src/corehost/corehost.cpp +++ b/src/corehost/corehost.cpp @@ -2,64 +2,140 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include "trace.h" -#include "pal.h" #include "utils.h" -#include "libhost.h" +#include "corehost.h" +#include "fx_ver.h" +#include "error_codes.h" +#include "policy_load.h" +#include -extern int corehost_main(const int argc, const pal::char_t* argv[]); +#define LIBFXR_NAME MAKE_LIBNAME("hostfxr") -namespace +bool corehost_t::hostpolicy_exists_in_svc(pal::string_t* resolved_dir) { -enum StatusCode -{ - Success = 0, - CoreHostLibLoadFailure = 0x41, - CoreHostLibMissingFailure = 0x42, - CoreHostEntryPointFailure = 0x43, - CoreHostCurExeFindFailure = 0x44, -}; - -typedef int (*corehost_main_fn) (const int argc, const pal::char_t* argv[]); - -// ----------------------------------------------------------------------------- -// Load the corehost library from the path specified -// -// Parameters: -// lib_dir - dir path to the corehost library -// h_host - handle to the library which will be kept live -// main_fn - Contains the entrypoint "corehost_main" when returns success. -// -// Returns: -// Non-zero exit code on failure. "main_fn" contains "corehost_main" -// entrypoint on success. -// -StatusCode load_host_lib(const pal::string_t& lib_dir, pal::dll_t* h_host, corehost_main_fn* main_fn) -{ - pal::string_t host_path = lib_dir; - append_path(&host_path, LIBHOST_NAME); - - // Missing library - if (!pal::file_exists(host_path)) +#ifdef COREHOST_PACKAGE_SERVICING + pal::string_t svc_dir; + if (!pal::getenv(_X("DOTNET_SERVICING"), &svc_dir)) { - return StatusCode::CoreHostLibMissingFailure; + return false; } - // Load library - if (!pal::load_library(host_path.c_str(), h_host)) + pal::string_t path = svc_dir; + append_path(&path, COREHOST_PACKAGE_NAME); + append_path(&path, COREHOST_PACKAGE_VERSION); + append_path(&path, COREHOST_PACKAGE_COREHOST_RELATIVE_DIR); + if (library_exists_in_dir(path, LIBHOST_NAME)) { - trace::info(_X("Load library of %s failed"), host_path.c_str()); + resolved_dir->assign(path); + } + return true; +#else + return false; +#endif +} + +pal::string_t corehost_t::resolve_fxr_path(const pal::string_t& own_dir) +{ + pal::string_t fxr_path; + + pal::string_t fxr_dir = own_dir; + append_path(&fxr_dir, _X("dotnethost")); + append_path(&fxr_dir, _X("fxr")); + if (pal::directory_exists(fxr_dir)) + { + trace::info(_X("Reading fx resolver directory=[%s]"), fxr_dir.c_str()); + + std::vector list; + pal::readdir(fxr_dir, &list); + + fx_ver_t max_ver(-1, -1, -1); + for (const auto& dir : list) + { + trace::info(_X("Considering fxr version=[%s]..."), dir.c_str()); + + pal::string_t ver = get_filename(dir); + + fx_ver_t fx_ver(-1, -1, -1); + if (fx_ver_t::parse(ver, &fx_ver, false)) + { + max_ver = std::max(max_ver, fx_ver); + } + } + + pal::string_t max_ver_str = max_ver.as_str(); + append_path(&fxr_dir, max_ver_str.c_str()); + trace::info(_X("Detected latest fxr version=[%s]..."), fxr_dir.c_str()); + } + + const pal::string_t* dirs[] = { &fxr_dir, &own_dir }; + for (const auto& dir : dirs) + { + trace::info(_X("Considering fxr dir=[%s]..."), fxr_dir.c_str()); + if (policy_load_t::library_exists_in_dir(*dir, LIBFXR_NAME, &fxr_path)) + { + trace::info(_X("Resolved fxr [%s]..."), fxr_path.c_str()); + return fxr_path; + } + } + return pal::string_t(); +} + +int corehost_t::resolve_fx_and_execute_app(const pal::string_t& own_dir, const int argc, const pal::char_t* argv[]) +{ + pal::dll_t fxr; + + pal::string_t fxr_path = resolve_fxr_path(own_dir); + + // Load library + if (!pal::load_library(fxr_path.c_str(), &fxr)) + { + trace::info(_X("Load library of %s failed"), fxr_path.c_str()); return StatusCode::CoreHostLibLoadFailure; } - // Obtain entrypoint symbol - *main_fn = (corehost_main_fn) pal::get_symbol(*h_host, "corehost_main"); - - return (*main_fn != nullptr) - ? StatusCode::Success - : StatusCode::CoreHostEntryPointFailure; + // Obtain entrypoint symbols + hostfxr_main_fn main_fn = (hostfxr_main_fn) pal::get_symbol(fxr, "hostfxr_main"); + return main_fn(argc, argv); } -}; // end of anonymous namespace +int corehost_t::run(const int argc, const pal::char_t* argv[]) +{ + pal::string_t own_dir; + auto mode = detect_operating_mode(argc, argv, &own_dir); + + switch (mode) + { + case muxer: + trace::info(_X("Host operating in Muxer mode")); + return resolve_fx_and_execute_app(own_dir, argc, argv); + + case split_fx: + { + trace::info(_X("Host operating in split mode; own dir=[%s]"), own_dir.c_str()); + corehost_init_t init(_X(""), _X(""), own_dir, host_mode_t::split_fx, nullptr); + return policy_load_t::execute_app(own_dir, &init, argc, argv); + } + + case standalone: + { + trace::info(_X("Host operating from standalone app dir %s"), own_dir.c_str()); + + pal::string_t svc_dir; + corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::standalone, nullptr); + return policy_load_t::execute_app( + hostpolicy_exists_in_svc(&svc_dir) ? svc_dir : own_dir, &init, argc, argv); + } + return StatusCode::CoreHostLibMissingFailure; + + default: + trace::error(_X("Unknown mode detected or could not resolve the mode.")); + return StatusCode::CoreHostResolveModeFailure; + } +} + +#include + +#include "deps_format.h" #if defined(_WIN32) int __cdecl wmain(const int argc, const pal::char_t* argv[]) @@ -69,56 +145,19 @@ int main(const int argc, const pal::char_t* argv[]) { trace::setup(); - pal::dll_t corehost; + //deps_json_t deps(true, _X("H:\\code\\sharedfx\\PortableApp\\PortableAppWithNative.deps.json")); + //deps_json_t deps2(false, _X("H:\\code\\sharedfx\\StandaloneApp\\StandaloneApp.deps.json")); -#ifdef COREHOST_PACKAGE_SERVICING - // No custom host asked, so load the corehost if serviced first. - pal::string_t svc_dir; - if (pal::getenv(_X("DOTNET_SERVICING"), &svc_dir)) + if (trace::is_enabled()) { - pal::string_t path = svc_dir; - append_path(&path, COREHOST_PACKAGE_NAME); - append_path(&path, COREHOST_PACKAGE_VERSION); - append_path(&path, COREHOST_PACKAGE_COREHOST_RELATIVE_DIR); - - corehost_main_fn host_main; - StatusCode code = load_host_lib(path, &corehost, &host_main); - if (code != StatusCode::Success) + trace::info(_X("--- Invoked host main = {")); + for (int i = 0; i < argc; ++i) { - trace::info(_X("Failed to load host library from servicing dir: %s; Status=%08X"), path.c_str(), code); - // Ignore all errors for the servicing case, and proceed to the next step. - } - else - { - trace::info(_X("Calling host entrypoint from library at servicing dir %s"), path.c_str()); - return host_main(argc, argv); + trace::info(_X("%s"), argv[i]); } + trace::info(_X("}")); } -#endif - - // Get current path to look for the library app locally. - pal::string_t own_path; - if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path)) - { - trace::error(_X("Failed to locate current executable")); - return StatusCode::CoreHostCurExeFindFailure; - } - - // Local load of the corehost library. - auto own_dir = get_directory(own_path); - - corehost_main_fn host_main; - StatusCode code = load_host_lib(own_dir, &corehost, &host_main); - switch (code) - { - // Success, call the entrypoint. - case StatusCode::Success: - trace::info(_X("Calling host entrypoint from library at own dir %s"), own_dir.c_str()); - return host_main(argc, argv); - - // Some other fatal error including StatusCode::CoreHostLibMissingFailure. - default: - trace::error(_X("Error loading the host library from own dir: %s; Status=%08X"), own_dir.c_str(), code); - return code; - } + corehost_t corehost; + return corehost.run(argc, argv); } + diff --git a/src/corehost/corehost.h b/src/corehost/corehost.h new file mode 100644 index 000000000..92063e673 --- /dev/null +++ b/src/corehost/corehost.h @@ -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. + +#include "pal.h" +#include "libhost.h" +#include "policy_load.h" + +typedef int(*hostfxr_main_fn) (const int argc, const pal::char_t* argv[]); + +class corehost_t +{ +public: + + int run(const int argc, const pal::char_t* argv[]); + static int execute_app( + const pal::string_t& policy_dir, + const pal::string_t& fx_dir, + const runtime_config_t* config, + const int argc, + const pal::char_t* argv[]); + +private: + + static int load_host_library( + const pal::string_t& lib_dir, + pal::dll_t* h_host, + corehost_load_fn* load_fn, + corehost_main_fn* main_fn, + corehost_unload_fn* unload_fn); + + pal::string_t resolve_fxr_path(const pal::string_t& own_dir); + int resolve_fx_and_execute_app(const pal::string_t& own_dir, const int argc, const pal::char_t* argv[]); + + static bool hostpolicy_exists_in_svc(pal::string_t* resolved_path); + static bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path); +}; diff --git a/src/corehost/error_codes.h b/src/corehost/error_codes.h new file mode 100644 index 000000000..d5a0bc141 --- /dev/null +++ b/src/corehost/error_codes.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef __ERROR_CODES_H__ +#define __ERROR_CODES_H__ +enum StatusCode +{ + Success = 0, + InvalidArgFailure = 0x81, + CoreHostLibLoadFailure = 0x82, + CoreHostLibMissingFailure = 0x83, + CoreHostEntryPointFailure = 0x84, + CoreHostCurExeFindFailure = 0x85, + CoreHostResolveModeFailure = 0x86, + CoreClrResolveFailure = 0x87, + CoreClrBindFailure = 0x88, + CoreClrInitFailure = 0x89, + CoreClrExeFailure = 0x90, + ResolverInitFailure = 0x91, + ResolverResolveFailure = 0x92, + LibHostCurExeFindFailure = 0x93, + LibHostInitFailure = 0x94, + LibHostMuxFailure = 0x95, + LibHostExecModeFailure = 0x96, + LibHostSdkFindFailure = 0x97, + LibHostInvalidArgs = 0x98, + InvalidConfigFile = 0x99, +}; +#endif // __ERROR_CODES_H__ diff --git a/src/corehost/policy_load.cpp b/src/corehost/policy_load.cpp new file mode 100644 index 000000000..514f8a086 --- /dev/null +++ b/src/corehost/policy_load.cpp @@ -0,0 +1,79 @@ +// 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. + +#include "policy_load.h" +#include "corehost.h" + +bool policy_load_t::library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path) +{ + pal::string_t host_path = lib_dir; + append_path(&host_path, lib_name.c_str()); + + if (!pal::file_exists(host_path)) + { + return false; + } + if (p_host_path) + { + *p_host_path = host_path; + } + return true; +} + +int policy_load_t::load_host_library( + const pal::string_t& lib_dir, + pal::dll_t* h_host, + corehost_load_fn* load_fn, + corehost_main_fn* main_fn, + corehost_unload_fn* unload_fn) +{ + pal::string_t host_path; + if (!library_exists_in_dir(lib_dir, LIBHOST_NAME, &host_path)) + { + return StatusCode::CoreHostLibMissingFailure; + } + + // Load library + if (!pal::load_library(host_path.c_str(), h_host)) + { + trace::info(_X("Load library of %s failed"), host_path.c_str()); + return StatusCode::CoreHostLibLoadFailure; + } + + // Obtain entrypoint symbols + *load_fn = (corehost_load_fn)pal::get_symbol(*h_host, "corehost_load"); + *main_fn = (corehost_main_fn)pal::get_symbol(*h_host, "corehost_main"); + *unload_fn = (corehost_unload_fn)pal::get_symbol(*h_host, "corehost_unload"); + + return (*main_fn) && (*load_fn) && (*unload_fn) + ? StatusCode::Success + : StatusCode::CoreHostEntryPointFailure; +} + +int policy_load_t::execute_app( + const pal::string_t& impl_dll_dir, + const corehost_init_t* init, + const int argc, + const pal::char_t* argv[]) +{ + pal::dll_t corehost; + corehost_main_fn host_main = nullptr; + corehost_load_fn host_load = nullptr; + corehost_unload_fn host_unload = nullptr; + + int code = load_host_library(impl_dll_dir, &corehost, &host_load, &host_main, &host_unload); + + if (code != StatusCode::Success) + { + trace::error(_X("Could not load host policy library [%s]"), impl_dll_dir.c_str()); + return code; + } + + if ((code = host_load(init)) == 0) + { + code = host_main(argc, argv); + (void) host_unload(); + } + return code; +} + diff --git a/src/corehost/policy_load.h b/src/corehost/policy_load.h new file mode 100644 index 000000000..8d3cc7411 --- /dev/null +++ b/src/corehost/policy_load.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef __POLICY_LOAD_H__ +#define __POLICY_LOAD_H__ + +#include "pal.h" +#include "utils.h" +#include "trace.h" +#include "error_codes.h" + +class corehost_init_t; +class runtime_config_t; + +typedef int(*corehost_load_fn) (const corehost_init_t* init); +typedef int(*corehost_main_fn) (const int argc, const pal::char_t* argv[]); +typedef int(*corehost_unload_fn) (); + +class policy_load_t +{ +public: + static int execute_app( + const pal::string_t& impl_dll_dir, + const corehost_init_t* init, + const int argc, + const pal::char_t* argv[]); + + static bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path = nullptr); + + static int load_host_library( + const pal::string_t& lib_dir, + pal::dll_t* h_host, + corehost_load_fn* load_fn, + corehost_main_fn* main_fn, + corehost_unload_fn* unload_fn); +}; + +#endif // __POLICY_LOAD_H__ From 28dfeb026c4f6c186d1d64be85f403685c619419 Mon Sep 17 00:00:00 2001 From: Zlatko Knezevic Date: Tue, 15 Mar 2016 08:11:31 -0700 Subject: [PATCH 44/99] Update known-issues.md Removed the El Capitan section. Not needed anymore. skip ci please Fixes #1815 --- Documentation/known-issues.md | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Documentation/known-issues.md b/Documentation/known-issues.md index a5f8bb038..735164987 100644 --- a/Documentation/known-issues.md +++ b/Documentation/known-issues.md @@ -1,23 +1,6 @@ Known issues & workarounds ========================== -## El Capitan support -If you try to use the `dotnet` commands on El Capitan (OS X 10.11), you will encounter errors as it is not currently -fully supported for all scenarios. - -**Issues tracking this:** - -* [#498](https://github.com/dotnet/cli/issues/498) -* [#291](https://github.com/dotnet/cli/issues/291) - -**Affects:** most of the commands, but more than likely you will not be able to -use `dotnet compile` and `dotnet-run` on El Capitan. For others, there is a -workaround. - -**Workaround:** use the --runtime switch with the value of `osx.10.11-x64` in -`dotnet restore` and `dotnet publish` and you will be able to run your app from -the published directory. - ## Resolving the Standard library packages The StdLib package is on a MyGet feed. In order to restore it, a MyGet feed needs to be added to the NuGet feeds, either locally per application or in a central location. From c10df6b6a58f357f6052c7c2c2b3cec134ff5e8e Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 10 Mar 2016 10:12:43 -0800 Subject: [PATCH 45/99] Add support for loading and merging runtime deps json --- .../FileWrapper.cs | 5 + .../IFile.cs | 4 + .../DependencyContextBuilder.cs | 2 +- .../DependencyContext.cs | 68 +++---- .../DependencyContextCsvReader.cs | 4 +- .../DependencyContextJsonReader.cs | 6 +- .../DependencyContextLoader.cs | 178 ++++++++++++++++++ .../DependencyContextWriter.cs | 8 +- .../IDependencyContextReader.cs | 9 + .../RuntimeFallbacks.cs | 19 ++ .../Mock/FileSystemMockBuilder.cs | 6 + .../DependencyContextJsonReaderTest.cs | 12 +- .../DependencyContextJsonWriterTests.cs | 8 +- .../DependencyContextLoaderTests.cs | 136 +++++++++++++ 14 files changed, 411 insertions(+), 54 deletions(-) create mode 100644 src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs create mode 100644 src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs create mode 100644 src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs create mode 100644 test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextLoaderTests.cs diff --git a/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs b/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs index 8b6efbeac..867d4eab1 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs +++ b/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs @@ -16,5 +16,10 @@ namespace Microsoft.Extensions.EnvironmentAbstractions { return File.ReadAllText(path); } + + public Stream OpenRead(string path) + { + return File.OpenRead(path); + } } } \ No newline at end of file diff --git a/src/Microsoft.DotNet.InternalAbstractions/IFile.cs b/src/Microsoft.DotNet.InternalAbstractions/IFile.cs index 26d029eec..5b0328de9 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/IFile.cs +++ b/src/Microsoft.DotNet.InternalAbstractions/IFile.cs @@ -1,6 +1,8 @@ // 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.IO; + namespace Microsoft.Extensions.EnvironmentAbstractions { internal interface IFile @@ -8,5 +10,7 @@ namespace Microsoft.Extensions.EnvironmentAbstractions bool Exists(string path); string ReadAllText(string path); + + Stream OpenRead(string path); } } \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs index fcfec2cc4..d36ac6f82 100644 --- a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs +++ b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs @@ -55,7 +55,7 @@ namespace Microsoft.Extensions.DependencyModel compilationOptions, GetLibraries(compilationExports, dependencyLookup, runtime: false).Cast(), GetLibraries(runtimeExports, dependencyLookup, runtime: true).Cast(), - new KeyValuePair[0]); + new RuntimeFallbacks[] {}); } private static CompilationOptions GetCompilationOptions(CommonCompilerOptions compilerOptions) diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs index c31ea8dc6..f4f3e34ba 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs @@ -11,9 +11,6 @@ namespace Microsoft.Extensions.DependencyModel { public class DependencyContext { - private const string DepsJsonExtension = ".deps.json"; - private const string DepsFileExtension = ".deps"; - private static readonly Lazy _defaultContext = new Lazy(LoadDefault); public DependencyContext(string targetFramework, @@ -22,7 +19,7 @@ namespace Microsoft.Extensions.DependencyModel CompilationOptions compilationOptions, IEnumerable compileLibraries, IEnumerable runtimeLibraries, - IEnumerable> runtimeGraph) + IEnumerable runtimeGraph) { if (targetFramework == null) { @@ -32,6 +29,10 @@ namespace Microsoft.Extensions.DependencyModel { throw new ArgumentNullException(nameof(runtime)); } + if (compilationOptions == null) + { + throw new ArgumentNullException(nameof(compilationOptions)); + } if (compileLibraries == null) { throw new ArgumentNullException(nameof(compileLibraries)); @@ -68,48 +69,47 @@ namespace Microsoft.Extensions.DependencyModel public IReadOnlyList RuntimeLibraries { get; } - public IReadOnlyList> RuntimeGraph { get; } + public IReadOnlyList RuntimeGraph { get; } + + public DependencyContext Merge(DependencyContext other) + { + if (other == null) + { + throw new ArgumentNullException(nameof(other)); + } + + return new DependencyContext( + TargetFramework, + Runtime, + IsPortable, + CompilationOptions, + CompileLibraries.Union(other.CompileLibraries, new LibraryMergeEqualityComparer()), + RuntimeLibraries.Union(other.RuntimeLibraries, new LibraryMergeEqualityComparer()), + RuntimeGraph.Union(other.RuntimeGraph) + ); + } private static DependencyContext LoadDefault() { - var entryAssembly = Assembly.GetEntryAssembly(); - return Load(entryAssembly); + return DependencyContextLoader.Default.Load(Assembly.GetEntryAssembly()); } public static DependencyContext Load(Assembly assembly) { - if (assembly == null) + return DependencyContextLoader.Default.Load(assembly); + } + + private class LibraryMergeEqualityComparer: IEqualityComparer where T:Library + { + public bool Equals(T x, T y) { - throw new ArgumentNullException(nameof(assembly)); + return string.Equals(x.Name, y.Name, StringComparison.Ordinal); } - using (var stream = assembly.GetManifestResourceStream(assembly.GetName().Name + DepsJsonExtension)) + public int GetHashCode(T obj) { - if (stream != null) - { - return new DependencyContextJsonReader().Read(stream); - } + return obj.Name.GetHashCode(); } - - var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension); - if (File.Exists(depsJsonFile)) - { - using (var stream = File.OpenRead(depsJsonFile)) - { - return new DependencyContextJsonReader().Read(stream); - } - } - - var depsFile = Path.ChangeExtension(assembly.Location, DepsFileExtension); - if (File.Exists(depsFile)) - { - using (var stream = File.OpenRead(depsFile)) - { - return new DependencyContextCsvReader().Read(stream); - } - } - - return null; } } } diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs index ebab91f2e..0e1e5e54a 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs @@ -9,7 +9,7 @@ using System.Text; namespace Microsoft.Extensions.DependencyModel { - public class DependencyContextCsvReader + public class DependencyContextCsvReader: IDependencyContextReader { public DependencyContext Read(Stream stream) { @@ -62,7 +62,7 @@ namespace Microsoft.Extensions.DependencyModel compilationOptions: CompilationOptions.Default, compileLibraries: Enumerable.Empty(), runtimeLibraries: runtimeLibraries.ToArray(), - runtimeGraph: Enumerable.Empty>()); + runtimeGraph: Enumerable.Empty()); } private Tuple PackageIdentity(DepsFileLine line) diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index ca0d90916..12019b06f 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -10,7 +10,7 @@ using Newtonsoft.Json.Linq; namespace Microsoft.Extensions.DependencyModel { - public class DependencyContextJsonReader + public class DependencyContextJsonReader: IDependencyContextReader { public DependencyContext Read(Stream stream) { @@ -79,7 +79,7 @@ namespace Microsoft.Extensions.DependencyModel ); } - private IEnumerable> ReadRuntimeGraph(JObject runtimes) + private IEnumerable ReadRuntimeGraph(JObject runtimes) { if (runtimes == null) { @@ -90,7 +90,7 @@ namespace Microsoft.Extensions.DependencyModel var runtime = (JProperty)targets.Single(); foreach (var pair in (JObject)runtime.Value) { - yield return new KeyValuePair(pair.Key, pair.Value.Values().ToArray()); + yield return new RuntimeFallbacks(pair.Key, pair.Value.Values().ToArray()); } } diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs new file mode 100644 index 000000000..4a4256bb1 --- /dev/null +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.Extensions.DependencyModel +{ + public class DependencyContextLoader + { + private static Lazy _depsFiles = new Lazy(GetHostDepsList); + + private const string DepsJsonExtension = ".deps.json"; + private const string DepsExtension = ".deps"; + + private readonly string _entryPointDepsLocation; + private readonly string _runtimeDepsLocation; + private readonly IFileSystem _fileSystem; + private readonly IDependencyContextReader _jsonReader; + private readonly IDependencyContextReader _csvReader; + + public DependencyContextLoader() : this( + GetDefaultEntrypointDepsLocation(), + GetDefaultRuntimeDepsLocation(), + FileSystemWrapper.Default, + new DependencyContextJsonReader(), + new DependencyContextCsvReader()) + { + } + + internal DependencyContextLoader( + string entryPointDepsLocation, + string runtimeDepsLocation, + IFileSystem fileSystem, + IDependencyContextReader jsonReader, + IDependencyContextReader csvReader) + { + _entryPointDepsLocation = entryPointDepsLocation; + _runtimeDepsLocation = runtimeDepsLocation; + _fileSystem = fileSystem; + _jsonReader = jsonReader; + _csvReader = csvReader; + } + + public static DependencyContextLoader Default { get; } = new DependencyContextLoader(); + + internal virtual bool IsEntryAssembly(Assembly assembly) + { + return assembly.GetName() == Assembly.GetEntryAssembly().GetName(); + } + + internal virtual Stream GetResourceStream(Assembly assembly, string name) + { + return assembly.GetManifestResourceStream(name); + } + + public DependencyContext Load(Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException(nameof(assembly)); + } + + DependencyContext context = null; + + if (IsEntryAssembly(assembly)) + { + context = LoadEntryAssemblyContext(); + } + + if (context == null) + { + context = LoadAssemblyContext(assembly); + } + + if (context?.IsPortable == true) + { + var runtimeContext = LoadRuntimeContext(); + if (runtimeContext != null) + { + context = context.Merge(runtimeContext); + } + } + return context; + } + + private DependencyContext LoadEntryAssemblyContext() + { + if (!string.IsNullOrEmpty(_entryPointDepsLocation)) + { + Debug.Assert(File.Exists(_entryPointDepsLocation)); + using (var stream = _fileSystem.File.OpenRead(_entryPointDepsLocation)) + { + return _jsonReader.Read(stream); + } + } + return null; + } + + private DependencyContext LoadRuntimeContext() + { + if (!string.IsNullOrEmpty(_runtimeDepsLocation)) + { + Debug.Assert(File.Exists(_runtimeDepsLocation)); + using (var stream = _fileSystem.File.OpenRead(_runtimeDepsLocation)) + { + return _jsonReader.Read(stream); + } + } + return null; + } + + private DependencyContext LoadAssemblyContext(Assembly assembly) + { + using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension)) + { + if (stream != null) + { + return _jsonReader.Read(stream); + } + } + + var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension); + if (_fileSystem.File.Exists(depsJsonFile)) + { + using (var stream = _fileSystem.File.OpenRead(depsJsonFile)) + { + return _jsonReader.Read(stream); + } + } + + var depsFile = Path.ChangeExtension(assembly.Location, DepsExtension); + if (_fileSystem.File.Exists(depsFile)) + { + using (var stream = _fileSystem.File.OpenRead(depsFile)) + { + return _csvReader.Read(stream); + } + } + + return null; + } + + private static string GetDefaultRuntimeDepsLocation() + { + var deps = _depsFiles.Value; + if (deps != null && deps.Length > 1) + { + return deps[1]; + } + return null; + } + + private static string GetDefaultEntrypointDepsLocation() + { + var deps = _depsFiles.Value; + if (deps != null && deps.Length > 0) + { + return deps[0]; + } + return null; + } + + private static string[] GetHostDepsList() + { + // TODO: Were going to replace this with AppContext.GetData + var appDomainType = typeof(object).GetTypeInfo().Assembly?.GetType("System.AppDomain"); + var currentDomain = appDomainType?.GetProperty("CurrentDomain")?.GetValue(null); + var deps = appDomainType?.GetMethod("GetData")?.Invoke(currentDomain, new[] { "APP_CONTEXT_DEPS_FILES" }); + + return (deps as string)?.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries); + } + + } +} diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs index 1a6235345..ecc06a77b 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs @@ -50,7 +50,7 @@ namespace Microsoft.Extensions.DependencyModel private JObject WriteRuntimeGraph(DependencyContext context) { return new JObject( - context.RuntimeGraph.Select(g => new JProperty(g.Key, new JArray(g.Value))) + context.RuntimeGraph.Select(g => new JProperty(g.Runtime, new JArray(g.Fallbacks))) ); } @@ -79,7 +79,7 @@ namespace Microsoft.Extensions.DependencyModel { if (value != null) { - o[name] = value.ToString(); + o.Add(new JProperty(name, value)); } } @@ -168,7 +168,7 @@ namespace Microsoft.Extensions.DependencyModel { return; } - libraryObject.Add( + libraryObject.AddFirst( new JProperty(DependencyContextStrings.DependenciesPropertyName, new JObject( dependencies.Select(dependency => new JProperty(dependency.Name, dependency.Version)))) @@ -232,8 +232,8 @@ namespace Microsoft.Extensions.DependencyModel new JObject(runtimeLibrary.RuntimeTargets.SelectMany(WriteRuntimeTarget))) ); } - AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies); AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies); + AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies); libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries)); dependencies.UnionWith(runtimeLibrary.Dependencies); diff --git a/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs new file mode 100644 index 000000000..57b2a442e --- /dev/null +++ b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace Microsoft.Extensions.DependencyModel +{ + public interface IDependencyContextReader + { + DependencyContext Read(Stream stream); + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs new file mode 100644 index 000000000..d759b1942 --- /dev/null +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs @@ -0,0 +1,19 @@ +// 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.Collections.Generic; + +namespace Microsoft.Extensions.DependencyModel +{ + public class RuntimeFallbacks + { + public string Runtime { get; set; } + public IEnumerable Fallbacks { get; set; } + + public RuntimeFallbacks(string runtime, IEnumerable fallbacks) + { + Runtime = runtime; + Fallbacks = fallbacks; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs index 40ac2aa37..b5bfd5a56 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Microsoft.Extensions.EnvironmentAbstractions; namespace Microsoft.Extensions.DependencyModel.Tests @@ -74,6 +75,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests } return text; } + + public Stream OpenRead(string path) + { + return new MemoryStream(Encoding.UTF8.GetBytes(ReadAllText(path))); + } } private class DirectoryMock : IDirectory diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs index b48d812e5..719559d7a 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs @@ -96,14 +96,14 @@ namespace Microsoft.Extensions.DependencyModel.Tests } } }"); - context.RuntimeGraph.Should().Contain(p => p.Key == "osx.10.10-x64").Which - .Value.Should().BeEquivalentTo(); + context.RuntimeGraph.Should().Contain(p => p.Runtime == "osx.10.10-x64").Which + .Fallbacks.Should().BeEquivalentTo(); - context.RuntimeGraph.Should().Contain(p => p.Key == "osx.10.11-x64").Which - .Value.Should().BeEquivalentTo("osx"); + context.RuntimeGraph.Should().Contain(p => p.Runtime == "osx.10.11-x64").Which + .Fallbacks.Should().BeEquivalentTo("osx"); - context.RuntimeGraph.Should().Contain(p => p.Key == "rhel.7-x64").Which - .Value.Should().BeEquivalentTo("linux-x64", "unix"); + context.RuntimeGraph.Should().Contain(p => p.Runtime == "rhel.7-x64").Which + .Fallbacks.Should().BeEquivalentTo("linux-x64", "unix"); } [Fact] diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs index 2091b157b..f4d4ad721 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs @@ -37,7 +37,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests CompilationOptions compilationOptions = null, CompilationLibrary[] compileLibraries = null, RuntimeLibrary[] runtimeLibraries = null, - IReadOnlyList> runtimeGraph = null) + IReadOnlyList runtimeGraph = null) { return new DependencyContext( target ?? string.Empty, @@ -46,7 +46,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests compilationOptions ?? CompilationOptions.Default, compileLibraries ?? new CompilationLibrary[0], runtimeLibraries ?? new RuntimeLibrary[0], - runtimeGraph ?? new KeyValuePair[0] + runtimeGraph ?? new RuntimeFallbacks[0] ); } @@ -58,8 +58,8 @@ namespace Microsoft.Extensions.DependencyModel.Tests "Target/runtime", runtimeGraph: new[] { - new KeyValuePair("win7-x64", new [] { "win6", "win5"}), - new KeyValuePair("win8-x64", new [] { "win7-x64"}), + new RuntimeFallbacks("win7-x64", new [] { "win6", "win5"}), + new RuntimeFallbacks("win8-x64", new [] { "win7-x64"}), })); var rids = result.Should().HaveProperty("runtimes") diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextLoaderTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextLoaderTests.cs new file mode 100644 index 000000000..3b6e88fea --- /dev/null +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextLoaderTests.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyModel; +using FluentAssertions; +using Xunit; + +namespace Microsoft.Extensions.DependencyModel.Tests +{ + public class DependencyContextTests + { + [Fact] + public void MergeMergesLibraries() + { + var compilationLibraries = new[] + { + CreateCompilation("PackageA"), + CreateCompilation("PackageB"), + }; + + var runtimeLibraries = new[] + { + CreateRuntime("PackageA"), + CreateRuntime("PackageB"), + }; + + var compilationLibrariesRedist = new[] + { + CreateCompilation("PackageB"), + CreateCompilation("PackageC"), + }; + + var runtimeLibrariesRedist = new[] + { + CreateRuntime("PackageB"), + CreateRuntime("PackageC"), + }; + + var context = new DependencyContext( + "Framework", + "runtime", + true, + CompilationOptions.Default, + compilationLibraries, + runtimeLibraries, + new RuntimeFallbacks[] { }); + + var contextRedist = new DependencyContext( + "Framework", + "runtime", + true, + CompilationOptions.Default, + compilationLibrariesRedist, + runtimeLibrariesRedist, + new RuntimeFallbacks[] { }); + + var result = context.Merge(contextRedist); + + result.CompileLibraries.Should().BeEquivalentTo(new[] + { + compilationLibraries[0], + compilationLibraries[1], + compilationLibrariesRedist[1], + }); + + result.RuntimeLibraries.Should().BeEquivalentTo(new[] + { + runtimeLibraries[0], + runtimeLibraries[1], + runtimeLibrariesRedist[1], + }); + } + + public void MergeMergesRuntimeGraph() + { + var context = new DependencyContext( + "Framework", + "runtime", + true, + CompilationOptions.Default, + Enumerable.Empty(), + Enumerable.Empty(), + new RuntimeFallbacks[] + { + new RuntimeFallbacks("win8-x64", new [] { "win8" }), + }); + + var contextRedist = new DependencyContext( + "Framework", + "runtime", + true, + CompilationOptions.Default, + Enumerable.Empty(), + Enumerable.Empty(), + new RuntimeFallbacks[] + { + new RuntimeFallbacks("win8", new [] { "win7-x64", "win7-x86" }), + }); + + var result = context.Merge(contextRedist); + result.RuntimeGraph.Should().Contain(g => g.Runtime == "win8-x64"). + Subject.Fallbacks.Should().BeEquivalentTo("win8"); + result.RuntimeGraph.Should().Contain(g => g.Runtime == "win8"). + Subject.Fallbacks.Should().BeEquivalentTo("win7-x64", "win7-x86"); + } + + private CompilationLibrary CreateCompilation(string name) + { + return new CompilationLibrary( + "project", + name, + "1.1.1", + "HASH", + new string[] { }, + new Dependency[] { }, + false); + } + + private RuntimeLibrary CreateRuntime(string name) + { + return new RuntimeLibrary( + "project", + name, + "1.1.1", + "HASH", + new RuntimeAssembly[] { }, + new string[] { }, + new ResourceAssembly[] { }, + new RuntimeTarget[] { }, + new Dependency[] {}, + false); + } + } +} From ce3c5948802b6e19266817d40030a1fc93c2fad4 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 15 Mar 2016 12:34:32 -0500 Subject: [PATCH 46/99] Removing project.json dependency workarounds that were needed for CoreFX 23901 build. --- scripts/dotnet-cli-build/project.json | 3 --- src/Microsoft.Extensions.Testing.Abstractions/project.json | 1 - src/dotnet/project.json | 3 --- test/ArgumentForwardingTests/project.json | 1 - test/EndToEnd/project.json | 1 - test/Microsoft.DotNet.Cli.Utils.Tests/project.json | 1 - test/Microsoft.DotNet.Compiler.Common.Tests/project.json | 1 - test/Microsoft.DotNet.ProjectModel.Tests/project.json | 1 - test/Microsoft.DotNet.Tools.Tests.Utilities/project.json | 1 - test/Microsoft.Extensions.DependencyModel.Tests/project.json | 1 - test/dotnet-build.Tests/project.json | 1 - test/dotnet-compile.Tests/project.json | 1 - test/dotnet-compile.UnitTests/project.json | 1 - test/dotnet-publish.Tests/project.json | 1 - test/dotnet-resgen.Tests/project.json | 1 - test/dotnet-run.Tests/project.json | 1 - test/dotnet.Tests/project.json | 1 - 17 files changed, 21 deletions(-) diff --git a/scripts/dotnet-cli-build/project.json b/scripts/dotnet-cli-build/project.json index 9d1ebb1d7..72295b954 100755 --- a/scripts/dotnet-cli-build/project.json +++ b/scripts/dotnet-cli-build/project.json @@ -6,9 +6,6 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", - "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23911", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", "WindowsAzure.Storage": "6.2.2-preview", "System.Reflection.Metadata": "1.2.0" diff --git a/src/Microsoft.Extensions.Testing.Abstractions/project.json b/src/Microsoft.Extensions.Testing.Abstractions/project.json index da1777c72..e392da6d6 100644 --- a/src/Microsoft.Extensions.Testing.Abstractions/project.json +++ b/src/Microsoft.Extensions.Testing.Abstractions/project.json @@ -21,7 +21,6 @@ "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", "System.Resources.ResourceManager": "4.0.1-rc2-23911", - "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911", "System.Reflection.TypeExtensions": "4.1.0-rc2-23911" } } diff --git a/src/dotnet/project.json b/src/dotnet/project.json index 2333cf633..df6ac374e 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -54,10 +54,7 @@ "System.Xml.XDocument": "4.0.11-rc2-23911", "System.Resources.ReaderWriter": "4.0.0-rc2-23911", "System.Net.Sockets": "4.1.0-rc2-23911", - "System.IO.Compression.ZipFile": "4.0.1-rc2-23911", "System.Threading.ThreadPool": "4.0.10-rc2-23911", - "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23911", - "System.Private.DataContractSerialization": "4.1.0-rc2-23911", "Microsoft.Win32.Registry": { "version": "4.0.0-rc2-23911", "exclude": "Compile" diff --git a/test/ArgumentForwardingTests/project.json b/test/ArgumentForwardingTests/project.json index ea8695288..ccf9d856b 100644 --- a/test/ArgumentForwardingTests/project.json +++ b/test/ArgumentForwardingTests/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/EndToEnd/project.json b/test/EndToEnd/project.json index f712e1ce7..ef90e4e9e 100644 --- a/test/EndToEnd/project.json +++ b/test/EndToEnd/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json index 1493122d8..02638b27b 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json @@ -5,7 +5,6 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json index e0e51113f..6bcc81722 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/project.json b/test/Microsoft.DotNet.ProjectModel.Tests/project.json index 79747421e..25cf46739 100644 --- a/test/Microsoft.DotNet.ProjectModel.Tests/project.json +++ b/test/Microsoft.DotNet.ProjectModel.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json index 5df2c0e09..ac4cff52e 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json @@ -7,7 +7,6 @@ "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", "System.Collections.Immutable": "1.2.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "FluentAssertions": "4.0.0", "xunit": "2.1.0", "dotnet-test-xunit": "1.0.0-dev-91790-12", diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/project.json b/test/Microsoft.Extensions.DependencyModel.Tests/project.json index 16e06287a..f5f578e2e 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/project.json +++ b/test/Microsoft.Extensions.DependencyModel.Tests/project.json @@ -6,7 +6,6 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/dotnet-build.Tests/project.json b/test/dotnet-build.Tests/project.json index cb6194bc6..23dce9bc7 100644 --- a/test/dotnet-build.Tests/project.json +++ b/test/dotnet-build.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/dotnet-compile.Tests/project.json b/test/dotnet-compile.Tests/project.json index 99db1f04e..c1c79bacd 100644 --- a/test/dotnet-compile.Tests/project.json +++ b/test/dotnet-compile.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/dotnet-compile.UnitTests/project.json b/test/dotnet-compile.UnitTests/project.json index 0fcb3236e..e6cd5027b 100644 --- a/test/dotnet-compile.UnitTests/project.json +++ b/test/dotnet-compile.UnitTests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Cli.Utils": { "target": "project" }, diff --git a/test/dotnet-publish.Tests/project.json b/test/dotnet-publish.Tests/project.json index 328333b55..5a746e56c 100644 --- a/test/dotnet-publish.Tests/project.json +++ b/test/dotnet-publish.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.TestFramework": "1.0.0-*", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" diff --git a/test/dotnet-resgen.Tests/project.json b/test/dotnet-resgen.Tests/project.json index 071591f36..270d4e747 100644 --- a/test/dotnet-resgen.Tests/project.json +++ b/test/dotnet-resgen.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/dotnet-run.Tests/project.json b/test/dotnet-run.Tests/project.json index 1e30b0e77..2380359e2 100644 --- a/test/dotnet-run.Tests/project.json +++ b/test/dotnet-run.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, diff --git a/test/dotnet.Tests/project.json b/test/dotnet.Tests/project.json index 6ace6d28d..4443e85ea 100644 --- a/test/dotnet.Tests/project.json +++ b/test/dotnet.Tests/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", - "System.IO.Compression": "4.1.0-rc2-23911", "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, From dea1e3242d932f43bbdfb46a3bd3fd1d37bfdd61 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Mon, 14 Mar 2016 18:54:45 -0700 Subject: [PATCH 47/99] Create dotnet bundle with CLI SDK, SharedFx MSI and Shared Host MSI. --- packaging/host/windows/registrykeys.wxs | 4 +++- packaging/windows/bundle.wxs | 8 ++++++- packaging/windows/generatebundle.ps1 | 14 +++++++----- packaging/windows/registrykeys.wxs | 2 -- scripts/dotnet-cli-build/MsiTargets.cs | 5 +++-- scripts/dotnet-cli-build/PackageTargets.cs | 25 ++++++++++++++++++++++ 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packaging/host/windows/registrykeys.wxs b/packaging/host/windows/registrykeys.wxs index 6f5a3cad0..3d971599b 100644 --- a/packaging/host/windows/registrykeys.wxs +++ b/packaging/host/windows/registrykeys.wxs @@ -10,16 +10,18 @@ + - + + diff --git a/packaging/windows/bundle.wxs b/packaging/windows/bundle.wxs index 6999e8a3c..664087a99 100644 --- a/packaging/windows/bundle.wxs +++ b/packaging/windows/bundle.wxs @@ -32,7 +32,13 @@ - + + + + + + + diff --git a/packaging/windows/generatebundle.ps1 b/packaging/windows/generatebundle.ps1 index e50300363..dd73daaaa 100644 --- a/packaging/windows/generatebundle.ps1 +++ b/packaging/windows/generatebundle.ps1 @@ -2,7 +2,9 @@ # Licensed under the MIT license. See LICENSE file in the project root for full license information. param( - [Parameter(Mandatory=$true)][string]$DotnetMSIFile, + [Parameter(Mandatory=$true)][string]$CLISDKMSIFile, + [Parameter(Mandatory=$true)][string]$SharedFxMSIFile, + [Parameter(Mandatory=$true)][string]$SharedHostMSIFile, [Parameter(Mandatory=$true)][string]$DotnetBundleOutput, [Parameter(Mandatory=$true)][string]$WixRoot, [Parameter(Mandatory=$true)][string]$DotnetMSIVersion, @@ -28,7 +30,9 @@ function RunCandleForBundle -dBuildVersion="$DotnetMSIVersion" ` -dDisplayVersion="$DotnetCLIVersion" ` -dReleaseSuffix="$ReleaseSuffix" ` - -dMsiSourcePath="$DotnetMSIFile" ` + -dCLISDKMsiSourcePath="$CLISDKMSIFile" ` + -dSharedFXMsiSourcePath="$SharedFxMSIFile" ` + -dSharedHostMsiSourcePath="$SharedHostMSIFile" ` -arch "$Architecture" ` -ext WixBalExtension.dll ` -ext WixUtilExtension.dll ` @@ -73,9 +77,9 @@ function RunLightForBundle } -if(!(Test-Path $DotnetMSIFile)) +if(!(Test-Path $CLISDKMSIFile)) { - throw "$DotnetMSIFile not found" + throw "$CLISDKMSIFile not found" } Write-Host "Creating dotnet Bundle at $DotnetBundleOutput" @@ -103,6 +107,6 @@ if(!(Test-Path $DotnetBundleOutput)) Write-Host -ForegroundColor Green "Successfully created dotnet bundle - $DotnetBundleOutput" -_ $RepoRoot\test\Installer\testmsi.ps1 @("$DotnetMSIFile") +_ $RepoRoot\test\Installer\testmsi.ps1 @("$CLISDKMSIFile") exit $LastExitCode diff --git a/packaging/windows/registrykeys.wxs b/packaging/windows/registrykeys.wxs index 9bd84eb25..efb5c2b39 100644 --- a/packaging/windows/registrykeys.wxs +++ b/packaging/windows/registrykeys.wxs @@ -23,8 +23,6 @@ - - diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index e0e3ecb37..aa50fcac8 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -94,9 +94,10 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateCliSdkMsi(BuildTargetContext c) { + var cliSdkRoot = c.BuildContext.Get("CLISDKRoot"); Cmd("powershell", "-NoProfile", "-NoLogo", Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatemsi.ps1"), - Dirs.Stage2, SdkMsi, WixRoot, MsiVersion, CliVersion, Arch, Channel) + cliSdkRoot, SdkMsi, WixRoot, MsiVersion, CliVersion, Arch, Channel) .Execute() .EnsureSuccessful(); return c.Success(); @@ -156,7 +157,7 @@ namespace Microsoft.DotNet.Cli.Build { Cmd("powershell", "-NoProfile", "-NoLogo", Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatebundle.ps1"), - SdkMsi, SdkBundle, WixRoot, MsiVersion, CliVersion, Arch, Channel) + SdkMsi, SharedFrameworkMsi, SharedHostMsi, SdkBundle, WixRoot, MsiVersion, CliVersion, Arch, Channel) .EnvironmentVariable("Stage2Dir", Dirs.Stage2) .Execute() .EnsureSuccessful(); diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 11ba01b43..77b9300a8 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PrepareTargets.Init), nameof(PackageTargets.InitPackage), nameof(PackageTargets.GenerateVersionBadge), + nameof(PackageTargets.CopyCLISDKLayout), nameof(SharedFrameworkTargets.PublishSharedHost), nameof(SharedFrameworkTargets.PublishSharedFramework), nameof(PackageTargets.GenerateCompressedFile), @@ -47,6 +48,30 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + public static BuildTargetResult CopyCLISDKLayout(BuildTargetContext c) + { + var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; + var cliSdkRoot = Path.Combine(Dirs.Output, "obj", "clisdk"); + var cliSdk = Path.Combine(cliSdkRoot, "sdk", nugetVersion); + + if (Directory.Exists(cliSdkRoot)) + { + Directory.Delete(cliSdkRoot, true); + } + + Directory.CreateDirectory(cliSdk); + + foreach (var file in Directory.GetFiles(Dirs.Stage2, "*", SearchOption.AllDirectories)) + { + string destFile = Path.Combine(cliSdk, Path.GetFileName(file)); + File.Copy(file, destFile, true); + } + + c.BuildContext["CLISDKRoot"] = cliSdkRoot; + return c.Success(); + } + [Target(nameof(PackageTargets.GenerateZip), nameof(PackageTargets.GenerateTarBall))] public static BuildTargetResult GenerateCompressedFile(BuildTargetContext c) { From fd1b2e9b96e40aea897556de09d02cf7608f8b9d Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 15 Mar 2016 11:35:55 -0700 Subject: [PATCH 48/99] Ensure .version file is added to the debian package by enabling hidden files to be picked up in the debian tool --- tools/DebianPackageTool/scripts/debian_build_lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/DebianPackageTool/scripts/debian_build_lib.sh b/tools/DebianPackageTool/scripts/debian_build_lib.sh index 0b3f4141d..97c4c0ead 100755 --- a/tools/DebianPackageTool/scripts/debian_build_lib.sh +++ b/tools/DebianPackageTool/scripts/debian_build_lib.sh @@ -142,6 +142,7 @@ _get_files_in_dir_tree(){ # Use Globstar expansion to enumerate all directories and files in the tree shopt -s globstar + shopt -s dotglob dir_tree_list=( "${root_dir}/"** ) # Build a new array with only the Files contained in $dir_tree_list From c9227a36d00d9c2661da90ce5918b41b8e0eef63 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 15 Mar 2016 11:55:56 -0700 Subject: [PATCH 49/99] republish the deb file --- scripts/dotnet-cli-build/PublishTargets.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index b7308312e..b624656ad 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -46,6 +46,7 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PublishTargets.PublishVersionBadge), nameof(PublishTargets.PublishCompressedFile), nameof(PublishTargets.PublishSdkInstallerFile), + nameof(PublishTargets.PublishDebFileToDebianRepo), nameof(PublishTargets.PublishSharedFrameworkCompressedFile), nameof(PublishTargets.PublishSharedHostCompressedFile), nameof(PublishTargets.PublishLatestVersionTextFile))] From 4304ca9848eced94a0f39829fd31b2a3cf601bec Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 15 Mar 2016 13:08:46 -0500 Subject: [PATCH 50/99] Update the .xproj files to reference the "DotNet" targets and props instead of "DNX". --- TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj | 4 ++-- .../FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj | 4 ++-- .../dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj | 4 ++-- .../dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj | 4 ++-- .../DependencyContextValidator.xproj | 4 ++-- .../OutputStandardOutputAndError.xproj | 4 ++-- .../TestAppCompilationContext/TestLibrary/TestLibrary.xproj | 4 ++-- TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj | 4 ++-- .../TestAppWithContentPackage/TestAppWithContentPackage.xproj | 4 ++-- .../TestAppWithContents/TestAppWithContents.xproj | 4 ++-- .../TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj | 4 ++-- .../TestAppWithLibrary/TestLibrary/TestLibrary.xproj | 4 ++-- TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj | 4 ++-- .../TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj | 4 ++-- .../TestLibrary/TestLibrary.xproj | 4 ++-- .../TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj | 4 ++-- .../TestProjectWithCultureSpecificResource.xproj | 4 ++-- .../TestProjectWithResource/TestProjectWithResource.xproj | 4 ++-- .../TestProjects/TestSimpleIncrementalApp/TestApp.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Build.Framework.xproj | 4 ++-- scripts/dotnet-cli-build/dotnet-cli-build.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Utils.xproj | 4 ++-- .../Microsoft.Dotnet.Compiler.Common.xproj | 4 ++-- src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj | 4 ++-- .../Microsoft.DotNet.InternalAbstractions.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Loader.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Workspaces.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.xproj | 4 ++-- .../Microsoft.DotNet.TestFramework.xproj | 4 ++-- .../Microsoft.Extensions.DependencyModel.xproj | 4 ++-- .../Microsoft.Extensions.Testing.Abstractions.xproj | 4 ++-- src/dotnet/commands/dotnet-test/dotnet-test.xproj | 4 ++-- src/dotnet/dotnet.xproj | 4 ++-- test/ArgumentForwardingTests/ArgumentForwardingTests.xproj | 4 ++-- test/ArgumentsReflector/Reflector.xproj | 4 ++-- test/EndToEnd/EndToEnd.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Msi.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Utils.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Compiler.Common.Tests.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Tools.Test.Utilities.xproj | 4 ++-- .../Microsoft.Extensions.DependencyModel.Tests.xproj | 4 ++-- test/ScriptExecutorTests/ScriptExecutorTests.xproj | 4 ++-- test/dotnet-build.Tests/dotnet-build.Tests.xproj | 4 ++-- test/dotnet-compile.Tests/dotnet-compile.Tests.xproj | 4 ++-- test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj | 4 ++-- test/dotnet-pack.Tests/dotnet-pack.Tests.xproj | 4 ++-- .../dotnet-projectmodel-server.Tests.xproj | 4 ++-- test/dotnet-publish.Tests/dotnet-publish.Tests.xproj | 4 ++-- test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj | 4 ++-- test/dotnet-run.Tests/dotnet-run.Tests.xproj | 4 ++-- test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj | 4 ++-- test/dotnet.Tests/dotnet.Tests.xproj | 4 ++-- tools/MultiProjectValidator/MultiProjectValidator.xproj | 4 ++-- 54 files changed, 108 insertions(+), 108 deletions(-) diff --git a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj index 4b792e869..e48ab0105 100644 --- a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj +++ b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + a666217d-2aca-4866-b109-ea476e51c7aa FSharpTestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj index ae10bbff6..de36bbed6 100644 --- a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj +++ b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + ec801982-096b-4af3-a42b-7881b1a7380e FSharpTestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj index 635819547..d49a161f4 100644 --- a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj +++ b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + b8055234-9a66-4ba0-8b4c-d5e431494fe3 dotnet-hello @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj index 7011c102d..7c2da659a 100644 --- a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj +++ b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 282c5014-d0cd-4dde-af4e-531e4a2e7bcd dotnet-hello @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj index c827617ac..8a2f395fd 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj +++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6d84ef36-a5d5-4eaf-b38b-ced635473785 DependencyContextValidator @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj index ee6ccb69d..0443b706a 100644 --- a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj +++ b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e OutputStandardOutputAndError @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj index eb9f8bc2d..ae7910d0d 100644 --- a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj index fbd214cbd..70d47bf5c 100644 --- a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj +++ b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + da8e0e9e-a6d6-4583-864c-8f40465e3a48 TestAppWithArgs @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj index 718199108..7cc51e6eb 100644 --- a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj +++ b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + ea239e10-75e8-4305-966e-fec926a5aee6 TestAppWithContentPackage @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj index 00103e020..1f1eafbea 100644 --- a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj +++ b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0138cb8f-4aa9-4029-a21e-c07c30f425ba TestAppWithContents @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj index 4cef17daa..75b98c80d 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj index eb9f8bc2d..ae7910d0d 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj index 4cef17daa..75b98c80d 100644 --- a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj index 4cef17daa..75b98c80d 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj index eb9f8bc2d..ae7910d0d 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj index 4cef17daa..75b98c80d 100644 --- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj index d8121765f..f09a83c44 100644 --- a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj +++ b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + fea4ab27-d004-4580-8abe-b171e30b68cc TestProjectWithCultureSpecificResource @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj index aee14e286..cc3bb2c74 100644 --- a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj +++ b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4909876ed864 TestProjectWithResource @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj index 088568e54..518aa7600 100644 --- a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145edaaa TestSimpleIncrementalApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj index d4c58d0e8..5e45f32ed 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 49beb486-ab5a-4416-91ea-8cd34abb0c9d Microsoft.DotNet.Cli.Build.Framework @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/scripts/dotnet-cli-build/dotnet-cli-build.xproj b/scripts/dotnet-cli-build/dotnet-cli-build.xproj index fd8546624..fdd8f182d 100644 --- a/scripts/dotnet-cli-build/dotnet-cli-build.xproj +++ b/scripts/dotnet-cli-build/dotnet-cli-build.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + d7b9695d-23eb-4ea8-b8ab-707a0092e1d5 Microsoft.DotNet.Cli.Build @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj index 68df775cf..e5fda6870 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj +++ b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 61b7c351-c77d-43f7-b56f-bb1440178e10 Microsoft.DotNet.Cli.Utils @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj index e7b0225ee..50899a805 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj +++ b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + a16958e1-24c7-4f1e-b317-204ad91625dd Microsoft.Dotnet.Cli.Compiler.Common @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj index 0dca981d4..15a95077a 100644 --- a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj +++ b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + d521dd9f-0614-4929-93b4-d8fa5682c174 Microsoft.DotNet.Files @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj index 2f07cc659..2a323b565 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj +++ b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + bd4f0750-4e81-4ad2-90b5-e470881792c3 Microsoft.DotNet.InternalAbstractions @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj index 049c639a2..51615b07a 100644 --- a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj +++ b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + c7af0290-ef0d-44dc-9edc-600803b664f8 Microsoft.DotNet.ProjectModel.Loader @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj index 3227dea0a..fa941946f 100644 --- a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj +++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + bd7833f8-3209-4682-bf75-b4bca883e279 Microsoft.DotNet.ProjectModel.Workspaces @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj index c33400887..d56e4bae5 100644 --- a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj +++ b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 303677d5-7312-4c3f-baee-beb1a9bd9fe6 Microsoft.DotNet.ProjectModel @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj index e6f1e6339..4fc8570fb 100644 --- a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj +++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0724ed7c-56e3-4604-9970-25e600611383 Microsoft.DotNet.TestFramework @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj index 8c6e7884f..8e2d9aca8 100644 --- a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj +++ b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 688870c8-9843-4f9e-8576-d39290ad0f25 Microsoft.Extensions.DependencyModel @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj index a364b40ec..9d149a5c3 100644 --- a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj +++ b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + dcdfe282-03de-4dbc-b90c-cc3ce3ec8162 Microsoft.Extensions.Testing.Abstractions @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-test/dotnet-test.xproj b/src/dotnet/commands/dotnet-test/dotnet-test.xproj index 7f173a43e..fcacb1dd3 100644 --- a/src/dotnet/commands/dotnet-test/dotnet-test.xproj +++ b/src/dotnet/commands/dotnet-test/dotnet-test.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + f003f228-2ae2-4e9d-877b-93eb773b5061 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/dotnet/dotnet.xproj b/src/dotnet/dotnet.xproj index eb07f538d..a8a83293d 100644 --- a/src/dotnet/dotnet.xproj +++ b/src/dotnet/dotnet.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 60cf7e6c-d6c8-439d-b7b7-d8a27e29be2c Microsoft.DotNet.Cli @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj b/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj index 5b9cd4886..6ccc31090 100644 --- a/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj +++ b/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6973e08d-11ec-49dc-82ef-d5effec7c6e9 Microsoft.DotNet.Tests.ArgumentForwarding @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/ArgumentsReflector/Reflector.xproj b/test/ArgumentsReflector/Reflector.xproj index 06cbe2be6..5c40febb9 100644 --- a/test/ArgumentsReflector/Reflector.xproj +++ b/test/ArgumentsReflector/Reflector.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6f2e6f25-b43b-495d-9ca5-7f207d1dd604 Microsoft.DotNet.Tests.ArgumentForwarding @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/EndToEnd/EndToEnd.xproj b/test/EndToEnd/EndToEnd.xproj index cfee5a0ea..d3dcb255f 100644 --- a/test/EndToEnd/EndToEnd.xproj +++ b/test/EndToEnd/EndToEnd.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 65741cb1-8aee-4c66-8198-10a7ea0e4258 Microsoft.DotNet.Tests.EndToEnd @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj index 64ee27ba4..989b970a6 100644 --- a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj +++ b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0B31C336-149D-471A-B7B1-27B0F1E80F83 Microsoft.DotNet.Cli.Msi.Tests @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj b/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj index e7b914485..2d287f25f 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 09c52f96-efdd-4448-95ec-6d362dd60baa Microsoft.DotNet.Cli.Utils @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj b/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj index 297d01c2b..8d39d9bb5 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 44e7d1ac-dcf1-4a18-9c22-f09e6bb302b5 Microsoft.DotNet.Cli.Utils @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj b/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj index f0b4029a5..b2001d9f8 100644 --- a/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj +++ b/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0745410a-6629-47eb-aab5-08d6288cad72 Microsoft.DotNet.ProjectModel.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj index 19010ace5..48a117951 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + e4f46eab-b5a5-4e60-9b9d-40a1fadbf45c Microsoft.DotNet.Tools.Test.Utilities @@ -16,5 +16,5 @@ 2.0 - + diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj b/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj index f6f7d2856..5b7cd1e50 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj +++ b/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 4a4711d8-4312-49fc-87b5-4f183f4c6a51 Microsoft.Extensions.DependencyModel.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/ScriptExecutorTests/ScriptExecutorTests.xproj b/test/ScriptExecutorTests/ScriptExecutorTests.xproj index e114297b9..b3c5668f3 100644 --- a/test/ScriptExecutorTests/ScriptExecutorTests.xproj +++ b/test/ScriptExecutorTests/ScriptExecutorTests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48833333 Microsoft.DotNet.Cli.Utils.ScriptExecutorTests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-build.Tests/dotnet-build.Tests.xproj b/test/dotnet-build.Tests/dotnet-build.Tests.xproj index b23863bda..a3aca10c4 100644 --- a/test/dotnet-build.Tests/dotnet-build.Tests.xproj +++ b/test/dotnet-build.Tests/dotnet-build.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48833333 Microsoft.DotNet.Tools.Builder.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj b/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj index 109254497..93ffc1f97 100644 --- a/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj +++ b/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48893d6e Microsoft.DotNet.Tools.Compiler.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj b/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj index 458f8ad82..87bee84c4 100644 --- a/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj +++ b/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 920b71d8-62da-4f5e-8a26-926c113f1d97 dotnet-compile.UnitTests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj b/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj index b0d2ba45f..0dd8575bb 100644 --- a/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj +++ b/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 5fda6d37-3a3e-4333-ba5c-f0b28be316f4 dotnet-pack.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj b/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj index 29f474eb4..cc567f6fd 100644 --- a/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj +++ b/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 11c77123-e4da-499f-8900-80c88c2c69f2 Microsoft.DotNet.ProjectModel.Server.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj b/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj index 5300386c1..55201e8b1 100644 --- a/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj +++ b/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 386d412c-003c-47b1-8258-0e35865cb7c4 Microsoft.DotNet.Tools.Publish.Tests @@ -18,5 +18,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj b/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj index 279ade660..7ca087810 100644 --- a/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj +++ b/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 386d412c-003c-47b1-8258-0e35865cb7c4 Microsoft.DotNet.Tools.Resgen.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-run.Tests/dotnet-run.Tests.xproj b/test/dotnet-run.Tests/dotnet-run.Tests.xproj index a48fde4f7..1921817f6 100644 --- a/test/dotnet-run.Tests/dotnet-run.Tests.xproj +++ b/test/dotnet-run.Tests/dotnet-run.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 35e3c2dc-9b38-4ec5-8dd7-c32458dc485f dotnet-run.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj b/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj index 968a14550..b54973d91 100644 --- a/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj +++ b/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 857274ac-e741-4266-a7fd-14dee0c1cc96 Microsoft.Dotnet.Tools.Test.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet.Tests/dotnet.Tests.xproj b/test/dotnet.Tests/dotnet.Tests.xproj index 35608f3d2..5727980e1 100644 --- a/test/dotnet.Tests/dotnet.Tests.xproj +++ b/test/dotnet.Tests/dotnet.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + cb710268-4a82-48e4-9531-faf1c8f78f4b Microsoft.DotNet.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/tools/MultiProjectValidator/MultiProjectValidator.xproj b/tools/MultiProjectValidator/MultiProjectValidator.xproj index 27627c2bb..a940c18c6 100644 --- a/tools/MultiProjectValidator/MultiProjectValidator.xproj +++ b/tools/MultiProjectValidator/MultiProjectValidator.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 08a68c6a-86f6-4ed2-89a7-b166d33e9f85 ProjectSanity @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file From e1a7044b453b589a82a930af8bbc4603bd262036 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Tue, 15 Mar 2016 10:42:59 -0700 Subject: [PATCH 51/99] add manual merge of RID fallback graph for Windows --- .../SharedFrameworkTargets.cs | 22 ++++++++++++++++++- .../rid-fallbacks/windows.json | 12 ++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/sharedframework/rid-fallbacks/windows.json diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index e6bd47a78..2892bc2f2 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -9,6 +9,8 @@ using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.Extensions.PlatformAbstractions; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; namespace Microsoft.DotNet.Cli.Build { @@ -65,10 +67,28 @@ namespace Microsoft.DotNet.Cli.Build File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}")); File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll")); File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.runtimeconfig.json")); // Rename the .deps file + var destinationDeps = Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json"); File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); - File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json")); + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps); + + // Merge in the RID fallback graph + var fallbackFileName = PlatformServices.Default.Runtime.OperatingSystemPlatform.ToString().ToLowerInvariant() + ".json"; + var fallbackFile = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "rid-fallbacks", fallbackFileName); + if (File.Exists(fallbackFile)) + { + c.Info($"Merging in RID fallback graph: {fallbackFile}"); + var deps = JObject.Parse(File.ReadAllText(destinationDeps)); + var ridfallback = JObject.Parse(File.ReadAllText(fallbackFile)); + deps["runtimes"] = ridfallback["runtimes"]; + File.WriteAllText(destinationDeps, deps.ToString(Formatting.Indented)); + } + else + { + c.Warn($"RID fallback graph file not found: {fallbackFile}"); + } // corehost will be renamed to dotnet at some point and then we will not need to rename it here. File.Copy( diff --git a/src/sharedframework/rid-fallbacks/windows.json b/src/sharedframework/rid-fallbacks/windows.json new file mode 100644 index 000000000..aff335e39 --- /dev/null +++ b/src/sharedframework/rid-fallbacks/windows.json @@ -0,0 +1,12 @@ +{ + "runtimes": { + "win10-x64": [ "win10", "win81-x64", "win81", "win8-x64", "win8", "win7-x64", "win7", "win-x64", "win", "any", "base" ], + "win10-x86": [ "win10", "win81-x86", "win81", "win8-x86", "win8", "win7-x86", "win7", "win-x86", "win", "any", "base" ], + "win81-x64": [ "win81", "win8-x64", "win8", "win7-x64", "win7", "win-x64", "win", "any", "base" ], + "win81-x86": [ "win81", "win8-x86", "win8", "win7-x86", "win7", "win-x86", "win", "any", "base" ], + "win8-x64": [ "win8", "win7-x64", "win7", "win-x64", "win", "any", "base" ], + "win8-x86": [ "win8", "win7-x86", "win7", "win-x86", "win", "any", "base" ], + "win7-x64": [ "win7", "win-x64", "win", "any", "base" ], + "win7-x86": [ "win7", "win-x86", "win", "any", "base" ] + } +} From 9fb3b8788e99e804d5659a78ac8ba8ee021817de Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Tue, 15 Mar 2016 12:10:02 -0700 Subject: [PATCH 52/99] Add hostfxr.dll to windows host msi --- packaging/host/windows/host.wxs | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/host/windows/host.wxs b/packaging/host/windows/host.wxs index 736beb665..a2bc03f95 100644 --- a/packaging/host/windows/host.wxs +++ b/packaging/host/windows/host.wxs @@ -38,6 +38,7 @@ + From 236fd005b671b0d673daf049f70a39a445eace57 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Tue, 15 Mar 2016 12:30:46 -0700 Subject: [PATCH 53/99] Fix bug in copying teh CLI SDK layout for shared fx. --- scripts/dotnet-cli-build/PackageTargets.cs | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 77b9300a8..4b54013cf 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -57,14 +57,36 @@ namespace Microsoft.DotNet.Cli.Build if (Directory.Exists(cliSdkRoot)) { + string[] files = Directory.GetFiles(cliSdkRoot, "*", SearchOption.AllDirectories); + foreach (string file in files) + { + File.SetAttributes(file, FileAttributes.Normal); + File.Delete(file); + } + Directory.Delete(cliSdkRoot, true); } Directory.CreateDirectory(cliSdk); + var binPath = Path.Combine(Dirs.Stage2, "bin"); + foreach (var file in Directory.GetFiles(binPath, "*", SearchOption.AllDirectories)) + { + string destFile = file.Replace(binPath, cliSdk); + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(file, destFile, true); + } + + File.Copy(Path.Combine(Dirs.Stage2, ".version"), Path.Combine(cliSdk, ".version"), true); + + // copy stage2 to "cliSdkRoot\bin". + // this is a temp hack until we fix the build scripts to use the new shared fx and shared host + // the current build scripts need the CLI sdk to be in the bin folder. + foreach (var file in Directory.GetFiles(Dirs.Stage2, "*", SearchOption.AllDirectories)) { - string destFile = Path.Combine(cliSdk, Path.GetFileName(file)); + string destFile = file.Replace(Dirs.Stage2, cliSdkRoot); + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); File.Copy(file, destFile, true); } @@ -84,7 +106,7 @@ namespace Microsoft.DotNet.Cli.Build { CreateZipFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); - CreateZipFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile")); + CreateZipFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); return c.Success(); } @@ -95,7 +117,7 @@ namespace Microsoft.DotNet.Cli.Build { CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); - CreateTarBallFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile")); + CreateTarBallFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); return c.Success(); } From 2d3d2a90780ae1291ba2ad762747097abfa6023b Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Mon, 14 Mar 2016 10:14:15 -0700 Subject: [PATCH 54/99] Bump NuGet to 763, --verbosity verbose, --disable-parallel --- scripts/dotnet-cli-build/PrepareTargets.cs | 4 ++-- scripts/dotnet-cli-build/TestTargets.cs | 10 +++++----- src/Microsoft.DotNet.ProjectModel/project.json | 2 +- src/dotnet/project.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 08dca3e05..1c87e132f 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -190,8 +190,8 @@ namespace Microsoft.DotNet.Cli.Build { var dotnet = DotNetCli.Stage0; - dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful(); - dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful(); return c.Success(); } diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index 375a984be..8526400a3 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -60,7 +60,7 @@ namespace Microsoft.DotNet.Cli.Build CleanNuGetTempCache(); var dotnet = DotNetCli.Stage2; - dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")).Execute().EnsureSuccessful(); return c.Success(); } @@ -75,16 +75,16 @@ namespace Microsoft.DotNet.Cli.Build var dotnet = DotNetCli.Stage2; - dotnet.Restore("--fallbacksource", Dirs.TestPackages) + dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--fallbacksource", Dirs.TestPackages) .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestProjects")) .Execute().EnsureSuccessful(); // The 'ProjectModelServer' directory contains intentionally-unresolved dependencies, so don't check for success. Also, suppress the output - dotnet.Restore() + dotnet.Restore("--verbosity", "verbose", "--disable-parallel") .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthTestProjects")) .Execute(); - dotnet.Restore() + dotnet.Restore("--verbosity", "verbose", "--disable-parallel") .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthUpdateSearchPathSample")) .Execute(); @@ -152,7 +152,7 @@ namespace Microsoft.DotNet.Cli.Build CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test")); CleanNuGetTempCache(); - DotNetCli.Stage2.Restore("--fallbacksource", Dirs.TestPackages) + DotNetCli.Stage2.Restore("--verbosity", "verbose", "--disable-parallel", "--fallbacksource", Dirs.TestPackages) .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "test")) .Execute() .EnsureSuccessful(); diff --git a/src/Microsoft.DotNet.ProjectModel/project.json b/src/Microsoft.DotNet.ProjectModel/project.json index 2cce12e3a..46cd0f97c 100644 --- a/src/Microsoft.DotNet.ProjectModel/project.json +++ b/src/Microsoft.DotNet.ProjectModel/project.json @@ -6,7 +6,7 @@ "description": "Types to model a .NET Project", "dependencies": { "System.Reflection.Metadata": "1.2.0-rc2-23911", - "NuGet.Packaging": "3.4.0-rtm-0733", + "NuGet.Packaging": "3.4.0-rtm-0763", "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996", "Microsoft.Extensions.JsonParser.Sources": { "type": "build", diff --git a/src/dotnet/project.json b/src/dotnet/project.json index df6ac374e..7938f0157 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -22,7 +22,7 @@ "Microsoft.Net.CSharp.Interactive.netcore": "1.3.0-beta1-20160225-02", "Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160225-02", "Microsoft.DiaSymReader.Native": "1.3.3", - "NuGet.CommandLine.XPlat": "3.4.0-rtm-0733", + "NuGet.CommandLine.XPlat": "3.4.0-rtm-0763", "System.CommandLine": "0.1.0-e160119-1", "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.DotNet.Compiler.Common": "1.0.0-*", From a76558f5605bd34be034b83d5b0c9af891e27856 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 15 Mar 2016 12:51:43 -0700 Subject: [PATCH 55/99] Fix runtime graph reader --- .../DependencyContextJsonReader.cs | 4 +--- .../DependencyContextJsonReaderTest.cs | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index 12019b06f..80ee0d8bd 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -86,9 +86,7 @@ namespace Microsoft.Extensions.DependencyModel yield break; } - var targets = runtimes.Children(); - var runtime = (JProperty)targets.Single(); - foreach (var pair in (JObject)runtime.Value) + foreach (var pair in runtimes) { yield return new RuntimeFallbacks(pair.Key, pair.Value.Values().ToArray()); } diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs index 719559d7a..e3cae30e5 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs @@ -89,11 +89,9 @@ namespace Microsoft.Extensions.DependencyModel.Tests var context = Read( @"{ ""runtimes"": { - "".NETStandardApp,Version=v1.5"": { - ""osx.10.10-x64"": [ ], - ""osx.10.11-x64"": [ ""osx"" ], - ""rhel.7-x64"": [ ""linux-x64"", ""unix"" ] - } + ""osx.10.10-x64"": [ ], + ""osx.10.11-x64"": [ ""osx"" ], + ""rhel.7-x64"": [ ""linux-x64"", ""unix"" ] } }"); context.RuntimeGraph.Should().Contain(p => p.Runtime == "osx.10.10-x64").Which From 967fc370a0f560dfe3fbd35786ddfd659f546587 Mon Sep 17 00:00:00 2001 From: Senthil Date: Tue, 15 Mar 2016 13:23:11 -0700 Subject: [PATCH 56/99] Update iterator and merge rid/non-rid assets --- src/corehost/cli/deps_format.cpp | 33 +++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp index c85db98b5..e013ba89f 100644 --- a/src/corehost/cli/deps_format.cpp +++ b/src/corehost/cli/deps_format.cpp @@ -139,9 +139,14 @@ bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, c assert(!matched_rid.empty()); for (auto iter = package.second.begin(); iter != package.second.end(); /* */) { - iter = (iter->first != matched_rid) - ? package.second.erase(iter) - : iter++; + if (iter->first != matched_rid) + { + iter = package.second.erase(iter); + } + else + { + ++iter; + } } } return true; @@ -221,13 +226,27 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar return false; } + std::vector merged; auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool { return rid_assets.count(package) || non_rid_assets.count(package); }; - auto get_relpaths = [&rid_assets, &non_rid_assets](const pal::string_t& package, int type_index) -> const std::vector& { - return (rid_assets.count(package)) - ? rid_assets[package].begin()->second[type_index] - : non_rid_assets[package][type_index]; + auto get_relpaths = [&rid_assets, &non_rid_assets, &merged](const pal::string_t& package, int type_index) -> const std::vector& { + if (rid_assets.count(package) && non_rid_assets.count(package)) + { + const std::vector& rel1 = rid_assets[package].begin()->second[type_index]; + const std::vector& rel2 = non_rid_assets[package][type_index]; + merged.clear(); + merged.reserve(rel1.size() + rel2.size()); + merged.insert(merged.end(), rel1.begin(), rel1.end()); + merged.insert(merged.end(), rel2.begin(), rel2.end()); + return merged; + } + else + { + return rid_assets.count(package) + ? rid_assets[package].begin()->second[type_index] + : non_rid_assets[package][type_index]; + } }; reconcile_libraries_with_targets(json, package_exists, get_relpaths); From 23e024c46320edf10722d54ee8729eacfad44f51 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Tue, 15 Mar 2016 14:06:54 -0700 Subject: [PATCH 57/99] Add a directory-delete helper. This seems to be needed on Windows to delete temporary staging files correctly. --- scripts/dotnet-cli-build/MsiTargets.cs | 6 ++---- scripts/dotnet-cli-build/PackageTargets.cs | 10 +--------- .../dotnet-cli-build/SharedFrameworkTargets.cs | 6 +++--- scripts/dotnet-cli-build/Utils/Utils.cs | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index aa50fcac8..f4f82f695 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -112,9 +112,8 @@ namespace Microsoft.DotNet.Cli.Build if (Directory.Exists(wixObjRoot)) { - Directory.Delete(wixObjRoot, true); + Utils.DeleteDirectory(wixObjRoot); } - Directory.CreateDirectory(wixObjRoot); Cmd("powershell", "-NoProfile", "-NoLogo", @@ -137,9 +136,8 @@ namespace Microsoft.DotNet.Cli.Build if (Directory.Exists(wixObjRoot)) { - Directory.Delete(wixObjRoot, true); + Utils.DeleteDirectory(wixObjRoot); } - Directory.CreateDirectory(wixObjRoot); Cmd("powershell", "-NoProfile", "-NoLogo", diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 4b54013cf..2dc28fd54 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -57,16 +57,8 @@ namespace Microsoft.DotNet.Cli.Build if (Directory.Exists(cliSdkRoot)) { - string[] files = Directory.GetFiles(cliSdkRoot, "*", SearchOption.AllDirectories); - foreach (string file in files) - { - File.SetAttributes(file, FileAttributes.Normal); - File.Delete(file); - } - - Directory.Delete(cliSdkRoot, true); + Utils.DeleteDirectory(cliSdkRoot); } - Directory.CreateDirectory(cliSdk); var binPath = Path.Combine(Dirs.Stage2, "bin"); diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index 2892bc2f2..93ef44ec2 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -37,7 +37,7 @@ namespace Microsoft.DotNet.Cli.Build if (Directory.Exists(SharedFrameworkPublishRoot)) { - Directory.Delete(SharedFrameworkPublishRoot, true); + Utils.DeleteDirectory(SharedFrameworkPublishRoot); } // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. @@ -113,11 +113,11 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult PublishSharedHost(BuildTargetContext c) { string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); + if (Directory.Exists(SharedHostPublishRoot)) { - Directory.Delete(SharedHostPublishRoot); + Utils.DeleteDirectory(SharedHostPublishRoot); } - Directory.CreateDirectory(SharedHostPublishRoot); // corehost will be renamed to dotnet at some point and then this can be removed. diff --git a/scripts/dotnet-cli-build/Utils/Utils.cs b/scripts/dotnet-cli-build/Utils/Utils.cs index 21512a08b..1f255e99e 100644 --- a/scripts/dotnet-cli-build/Utils/Utils.cs +++ b/scripts/dotnet-cli-build/Utils/Utils.cs @@ -85,5 +85,20 @@ namespace Microsoft.DotNet.Cli.Build b[x] = b[y]; b[y] = t; } + + public static void DeleteDirectory(string path) + { + if (Directory.Exists(path)) + { + string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); + foreach (string file in files) + { + File.SetAttributes(file, FileAttributes.Normal); + File.Delete(file); + } + + Directory.Delete(path, true); + } + } } } From a75746cbd8b4deb690489f2403c6dff46436ec62 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Tue, 15 Mar 2016 14:21:20 -0700 Subject: [PATCH 58/99] Fix the VSO signing builds As a part of Package init create all the SharedFx, SharedHost and CLI SDK layouts. This way all other package targets can take a dependency only on InitPackage. --- scripts/dotnet-cli-build/PackageTargets.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 4b54013cf..e3b4ab14c 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -12,7 +12,9 @@ namespace Microsoft.DotNet.Cli.Build { public static class PackageTargets { - [Target] + [Target(nameof(PackageTargets.CopyCLISDKLayout), + nameof(SharedFrameworkTargets.PublishSharedHost), + nameof(SharedFrameworkTargets.PublishSharedFramework))] public static BuildTargetResult InitPackage(BuildTargetContext c) { Directory.CreateDirectory(Dirs.Packages); @@ -22,9 +24,6 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PrepareTargets.Init), nameof(PackageTargets.InitPackage), nameof(PackageTargets.GenerateVersionBadge), - nameof(PackageTargets.CopyCLISDKLayout), - nameof(SharedFrameworkTargets.PublishSharedHost), - nameof(SharedFrameworkTargets.PublishSharedFramework), nameof(PackageTargets.GenerateCompressedFile), nameof(InstallerTargets.GenerateInstaller), nameof(PackageTargets.GenerateNugetPackages))] From f36029d1353e4dc10328dbce15e53bd33b6bd204 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Tue, 15 Mar 2016 14:58:20 -0700 Subject: [PATCH 59/99] Fix a couple build issues on OSX/non-Windows We were downloading the wrong 'latest version' of the CLI, and targets passed into --targets were not split correctly --- scripts/obtain/install.sh | 2 +- scripts/run-build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/obtain/install.sh b/scripts/obtain/install.sh index 198ed6041..706b4c718 100755 --- a/scripts/obtain/install.sh +++ b/scripts/obtain/install.sh @@ -189,7 +189,7 @@ install_dotnet() local localVersion=$(tail -n 1 "$installLocation/cli/.version" 2>/dev/null) if [ "$VERSION" == "Latest" ]; then # Check if we need to bother - local remoteData="$(curl -s https://dotnetcli.blob.core.windows.net/dotnet/$CHANNEL/dnvm/latest.$os.version)" + local remoteData="$(curl -s https://dotnetcli.blob.core.windows.net/dotnet/$CHANNEL/dnvm/latest.$os.x64.version)" [ $? != 0 ] && say_err "Unable to determine latest version." && return 1 local remoteVersion=$(IFS="\n" && echo $remoteData | tail -n 1) diff --git a/scripts/run-build.sh b/scripts/run-build.sh index 076abfdb2..4de0d15a1 100755 --- a/scripts/run-build.sh +++ b/scripts/run-build.sh @@ -114,7 +114,7 @@ echo "Invoking Build Scripts..." echo "Configuration: $CONFIGURATION" if [ -f "$DIR/dotnet-cli-build/bin/dotnet-cli-build" ]; then - $DIR/dotnet-cli-build/bin/dotnet-cli-build "${targets[@]}" + $DIR/dotnet-cli-build/bin/dotnet-cli-build ${targets[@]} exit $? else # We're on an older CLI. This is temporary while Ubuntu and CentOS VSO builds are stalled. From 11e218d341df58d9ca1aac61e8b41d387d445c77 Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Tue, 15 Mar 2016 15:00:54 -0700 Subject: [PATCH 60/99] Updating installer text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad13d40ad..b60817d4a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Installers | |Ubuntu 14.04 |Windows x64 |Windows x86 |Mac OS X |CentOS 7.1 |RHEL 7.2 | |---------|:------:|:------:|:------:|:------:|:------:|:------:| |**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x86_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/RHEL_x64_Release_version_badge.svg)| -|**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Msi](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x86.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A |N/A | +|**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x86.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A |N/A | |**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-rhel-x64.latest.tar.gz) | Interested in .NET Core + ASP.NET Core 1.0 RC1 bits? From 3ec1f4f54b2a4daf01f1871057f9966f3b7340e2 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Tue, 15 Mar 2016 15:07:47 -0700 Subject: [PATCH 61/99] Layout the CLI SDK in the "1.0.0" instead of "1.0.0-beta-001793" dotnet host muxer does not support pre-release CLI SDK when no global.json file is present. So fixing the CLI layout to be in production version layout. THIS IS A TEMP HACK. --- scripts/dotnet-cli-build/PackageTargets.cs | 7 ++++++- scripts/dotnet-cli-build/Utils/BuildVersion.cs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 4b54013cf..d263ec985 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -51,7 +51,12 @@ namespace Microsoft.DotNet.Cli.Build [Target] public static BuildTargetResult CopyCLISDKLayout(BuildTargetContext c) { - var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; + // CLI SDK must be layed out in path which has a Nuget version. + // But the muxer does not currently support the pre-release CLI SDK without a global.json file. + // So we are creating a production version. + // var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; + var nugetVersion = c.BuildContext.Get("BuildVersion").ProductionVersion; + var cliSdkRoot = Path.Combine(Dirs.Output, "obj", "clisdk"); var cliSdk = Path.Combine(cliSdkRoot, "sdk", nugetVersion); diff --git a/scripts/dotnet-cli-build/Utils/BuildVersion.cs b/scripts/dotnet-cli-build/Utils/BuildVersion.cs index df2b32c34..c7e2f50c7 100644 --- a/scripts/dotnet-cli-build/Utils/BuildVersion.cs +++ b/scripts/dotnet-cli-build/Utils/BuildVersion.cs @@ -12,6 +12,7 @@ public string SimpleVersion => $"{Major}.{Minor}.{Patch}.{CommitCountString}"; public string VersionSuffix => $"{ReleaseSuffix}-{CommitCountString}"; public string NuGetVersion => $"{Major}.{Minor}.{Patch}-{VersionSuffix}"; + public string ProductionVersion => $"{Major}.{Minor}.{Patch}"; public string GenerateMsiVersion() { From 8d39adbdbf226fe4802a886277ddb06041822332 Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Tue, 8 Mar 2016 15:53:21 -0800 Subject: [PATCH 62/99] Modifying the reporting channels to make the AdapterChannel a client and leave the TestRunnerChannel a server. This will prevent port conflicts between dotnet test and the Adapter (VS) due to race conditions. Added E2E tests for dotnet test interactions with an adapter (design time). --- Microsoft.DotNet.Cli.sln | 92 +++++---- .../GivenThatIWantSomeFakeTests.cs | 22 +++ .../ProjectWithTests/project.json | 21 +++ scripts/dotnet-cli-build/TestTargets.cs | 3 +- ...estRunnerProcessStartInfoMessageHandler.cs | 2 +- .../TestDiscoveryStartMessageHandler.cs | 2 +- .../MessageHandlers/TestMessageTypes.cs | 1 + src/dotnet/commands/dotnet-test/Program.cs | 2 +- .../AdapterReportingChannel.cs | 43 +++++ .../IReportingChannel.cs | 2 +- .../IReportingChannelFactory.cs | 0 .../ReportingChannel.cs | 57 ++---- .../ReportingChannelFactory.cs | 4 +- .../TestRunnerReportingChannel.cs | 42 +++++ src/dotnet/project.json | 3 +- .../Commands/DotnetTestCommand.cs | 20 ++ test/dotnet-test.Tests/Adapter.cs | 177 ++++++++++++++++++ ...hatWeWantToUseDotnetTestE2EInDesignTime.cs | 72 +++++++ .../dotnet-test.Tests/dotnet-test.Tests.xproj | 18 ++ test/dotnet-test.Tests/project.json | 33 ++++ .../GivenATestDiscoveryStartMessageHandler.cs | 2 +- ...estRunnerProcessStartInfoMessageHandler.cs | 2 +- 22 files changed, 536 insertions(+), 84 deletions(-) create mode 100644 TestAssets/TestProjects/ProjectWithTests/GivenThatIWantSomeFakeTests.cs create mode 100644 TestAssets/TestProjects/ProjectWithTests/project.json create mode 100644 src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs rename src/dotnet/commands/dotnet-test/{ => ReportingChannels}/IReportingChannel.cs (95%) rename src/dotnet/commands/dotnet-test/{ => ReportingChannels}/IReportingChannelFactory.cs (100%) rename src/dotnet/commands/dotnet-test/{ => ReportingChannels}/ReportingChannel.cs (68%) rename src/dotnet/commands/dotnet-test/{ => ReportingChannels}/ReportingChannelFactory.cs (83%) create mode 100644 src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs create mode 100644 test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/DotnetTestCommand.cs create mode 100644 test/dotnet-test.Tests/Adapter.cs create mode 100644 test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTime.cs create mode 100644 test/dotnet-test.Tests/dotnet-test.Tests.xproj create mode 100644 test/dotnet-test.Tests/project.json diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index faa3eb2c8..e2ce9023a 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -1,6 +1,7 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25020.0 +VisualStudioVersion = 14.0.25029.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}" EndProject @@ -76,6 +77,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.TestFramew EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.UnitTests", "test\dotnet-test.UnitTests\dotnet-test.UnitTests.xproj", "{857274AC-E741-4266-A7FD-14DEE0C1CC96}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.Tests", "test\dotnet-test.Tests\dotnet-test.Tests.xproj", "{60C33D0A-A5D8-4AB0-9956-1F804654DF05}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -472,22 +475,6 @@ Global {0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {0745410A-6629-47EB-AAB5-08D6288CAD72}.RelWithDebInfo|x64.Build.0 = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.ActiveCfg = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.Build.0 = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.Build.0 = Debug|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.Build.0 = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.ActiveCfg = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.Build.0 = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU - {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -504,22 +491,22 @@ Global {0B31C336-149D-471A-B7B1-27B0F1E80F83}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {0B31C336-149D-471A-B7B1-27B0F1E80F83}.RelWithDebInfo|x64.Build.0 = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|x64.ActiveCfg = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|x64.Build.0 = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|x64.Build.0 = Debug|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|Any CPU.Build.0 = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|x64.ActiveCfg = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|x64.Build.0 = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU - {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.ActiveCfg = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Debug|x64.Build.0 = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|Any CPU.Build.0 = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.ActiveCfg = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.Release|x64.Build.0 = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {4A4711D8-4312-49FC-87B5-4F183F4C6A51}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {0724ED7C-56E3-4604-9970-25E600611383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0724ED7C-56E3-4604-9970-25E600611383}.Debug|Any CPU.Build.0 = Debug|Any CPU {0724ED7C-56E3-4604-9970-25E600611383}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -536,6 +523,38 @@ Global {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|x64.ActiveCfg = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Debug|x64.Build.0 = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|Any CPU.Build.0 = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|x64.ActiveCfg = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.Release|x64.Build.0 = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {857274AC-E741-4266-A7FD-14DEE0C1CC96}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Debug|x64.ActiveCfg = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Debug|x64.Build.0 = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Release|Any CPU.Build.0 = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Release|x64.ActiveCfg = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.Release|x64.Build.0 = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -565,11 +584,12 @@ Global {DA8E0E9E-A6D6-4583-864C-8F40465E3A48} = {713CBFBB-5392-438D-B766-A9A585EF1BB8} {0138CB8F-4AA9-4029-A21E-C07C30F425BA} = {713CBFBB-5392-438D-B766-A9A585EF1BB8} {BD4F0750-4E81-4AD2-90B5-E470881792C3} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} - {4A4711D8-4312-49FC-87B5-4F183F4C6A51} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {0745410A-6629-47EB-AAB5-08D6288CAD72} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {0E3300A4-DF54-40BF-87D8-E7658330C288} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {0B31C336-149D-471A-B7B1-27B0F1E80F83} = {0E3300A4-DF54-40BF-87D8-E7658330C288} - {857274AC-E741-4266-A7FD-14DEE0C1CC96} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} + {4A4711D8-4312-49FC-87B5-4F183F4C6A51} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {0724ED7C-56E3-4604-9970-25E600611383} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} + {857274AC-E741-4266-A7FD-14DEE0C1CC96} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} + {60C33D0A-A5D8-4AB0-9956-1F804654DF05} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} EndGlobalSection EndGlobal diff --git a/TestAssets/TestProjects/ProjectWithTests/GivenThatIWantSomeFakeTests.cs b/TestAssets/TestProjects/ProjectWithTests/GivenThatIWantSomeFakeTests.cs new file mode 100644 index 000000000..4eca454af --- /dev/null +++ b/TestAssets/TestProjects/ProjectWithTests/GivenThatIWantSomeFakeTests.cs @@ -0,0 +1,22 @@ +// 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 Xunit; + +namespace FakeTests +{ + public class GivenThatIWantSomeFakeTests + { + [Fact] + public void It_succeeds() + { + Assert.True(true); + } + + [Fact] + public void It_fails() + { + Assert.True(false); + } + } +} \ No newline at end of file diff --git a/TestAssets/TestProjects/ProjectWithTests/project.json b/TestAssets/TestProjects/ProjectWithTests/project.json new file mode 100644 index 000000000..db7fc17fa --- /dev/null +++ b/TestAssets/TestProjects/ProjectWithTests/project.json @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-91790-12" + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + + "testRunner": "xunit" +} diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index 8526400a3..5d0e3c31f 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -36,7 +36,8 @@ namespace Microsoft.DotNet.Cli.Build "Microsoft.DotNet.ProjectModel.Tests", "Microsoft.Extensions.DependencyModel.Tests", "ArgumentForwardingTests", - "dotnet-test.UnitTests" + "dotnet-test.UnitTests", + "dotnet-test.Tests" }; [Target(nameof(PrepareTargets.Init), nameof(SetupTests), nameof(RestoreTests), nameof(BuildTests), nameof(RunTests), nameof(ValidateDependencies))] diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs b/src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs index 08898a8f4..95931d9cd 100644 --- a/src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs +++ b/src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs @@ -41,7 +41,7 @@ namespace Microsoft.DotNet.Tools.Test dotnetTest.StartListeningTo(testRunnerChannel); - testRunnerChannel.Accept(); + testRunnerChannel.Connect(); var testRunner = _testRunnerFactory.CreateTestRunner( new RunTestsArgumentsBuilder(dotnetTest.PathToAssemblyUnderTest, testRunnerChannel.Port, message)); diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs b/src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs index 941c48c13..bf3976a27 100644 --- a/src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs +++ b/src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs @@ -55,7 +55,7 @@ namespace Microsoft.DotNet.Cli.Tools.Test dotnetTest.StartListeningTo(testRunnerChannel); - testRunnerChannel.Accept(); + testRunnerChannel.Connect(); var testRunner = _testRunnerFactory.CreateTestRunner( new DiscoverTestsArgumentsBuilder(dotnetTest.PathToAssemblyUnderTest, testRunnerChannel.Port)); diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs b/src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs index a12a62e4f..ce76ccef4 100644 --- a/src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs +++ b/src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs @@ -11,6 +11,7 @@ namespace Microsoft.DotNet.Tools.Test public const string TestRunnerTestStarted = "TestExecution.TestStarted"; public const string TestRunnerTestCompleted = "TestRunner.TestCompleted"; public const string TestRunnerTestFound = "TestDiscovery.TestFound"; + public const string TestSessionConnected = "TestSession.Connected"; public const string TestSessionTerminate = "TestSession.Terminate"; public const string VersionCheck = "ProtocolVersion"; public const string TestDiscoveryStart = "TestDiscovery.Start"; diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs index 24d12c11b..1f327b2c3 100644 --- a/src/dotnet/commands/dotnet-test/Program.cs +++ b/src/dotnet/commands/dotnet-test/Program.cs @@ -183,7 +183,7 @@ namespace Microsoft.DotNet.Tools.Test dotnetTest.StartListeningTo(adapterChannel); - adapterChannel.Accept(); + adapterChannel.Connect(); dotnetTest.StartHandlingMessages(); } diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs new file mode 100644 index 000000000..1bf9ffb21 --- /dev/null +++ b/src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs @@ -0,0 +1,43 @@ +// 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.Extensions.Testing.Abstractions; +using System.Net; +using System.Net.Sockets; + +namespace Microsoft.DotNet.Tools.Test +{ + public class AdapterReportingChannel : ReportingChannel + { + private readonly IPEndPoint _ipEndPoint; + + public static AdapterReportingChannel ConnectTo(int port) + { + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + var ipEndPoint = new IPEndPoint(IPAddress.Loopback, port); + + return new AdapterReportingChannel(socket, ipEndPoint); + } + + private AdapterReportingChannel(Socket connectSocket, IPEndPoint ipEndPoint) + : base(connectSocket, ipEndPoint.Port) + { + _ipEndPoint = ipEndPoint; + } + + public override void Connect() + { + Socket = ConnectSocket; + + Socket.Connect(_ipEndPoint); + + StartReadingMessages(); + + Send(new Message + { + MessageType = TestMessageTypes.TestSessionConnected + }); + } + } +} diff --git a/src/dotnet/commands/dotnet-test/IReportingChannel.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannel.cs similarity index 95% rename from src/dotnet/commands/dotnet-test/IReportingChannel.cs rename to src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannel.cs index f103c61e2..0729b4032 100644 --- a/src/dotnet/commands/dotnet-test/IReportingChannel.cs +++ b/src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannel.cs @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.Tools.Test int Port { get; } - void Accept(); + void Connect(); void Send(Message message); diff --git a/src/dotnet/commands/dotnet-test/IReportingChannelFactory.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannelFactory.cs similarity index 100% rename from src/dotnet/commands/dotnet-test/IReportingChannelFactory.cs rename to src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannelFactory.cs diff --git a/src/dotnet/commands/dotnet-test/ReportingChannel.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannel.cs similarity index 68% rename from src/dotnet/commands/dotnet-test/ReportingChannel.cs rename to src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannel.cs index f6a919ace..624e75c32 100644 --- a/src/dotnet/commands/dotnet-test/ReportingChannel.cs +++ b/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannel.cs @@ -14,52 +14,26 @@ using Newtonsoft.Json.Linq; namespace Microsoft.DotNet.Tools.Test { - public class ReportingChannel : IReportingChannel + public abstract class ReportingChannel : IReportingChannel { - public static ReportingChannel ListenOn(int port) - { - // This fixes the mono incompatibility but ties it to ipv4 connections - var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - - listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, port)); - listenSocket.Listen(10); - - return new ReportingChannel(listenSocket); - } - private BinaryWriter _writer; private BinaryReader _reader; - private Socket _listenSocket; - private ReportingChannel(Socket listenSocket) + protected ReportingChannel(Socket connectSocket, int port) { - _listenSocket = listenSocket; - Port = ((IPEndPoint)listenSocket.LocalEndPoint).Port; + ConnectSocket = connectSocket; + Port = port; } + protected Socket Socket { get; set; } + public event EventHandler MessageReceived; - public Socket Socket { get; private set; } + public Socket ConnectSocket { get; } public int Port { get; } - public void Accept() - { - new Thread(() => - { - using (_listenSocket) - { - Socket = _listenSocket.Accept(); - - var stream = new NetworkStream(Socket); - _writer = new BinaryWriter(stream); - _reader = new BinaryReader(stream); - - // Read incoming messages on the background thread - new Thread(ReadMessages) { IsBackground = true }.Start(); - } - }) { IsBackground = true }.Start(); - } + public abstract void Connect(); public void Send(Message message) { @@ -104,6 +78,16 @@ namespace Microsoft.DotNet.Tools.Test SendError(ex.ToString()); } + protected void StartReadingMessages() + { + var stream = new NetworkStream(Socket); + _writer = new BinaryWriter(stream); + _reader = new BinaryReader(stream); + + // Read incoming messages on the background thread + new Thread(ReadMessages) { IsBackground = true }.Start(); + } + private void ReadMessages() { while (true) @@ -140,10 +124,7 @@ namespace Microsoft.DotNet.Tools.Test public void Dispose() { - if (Socket != null) - { - Socket.Dispose(); - } + Socket?.Dispose(); } } } \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-test/ReportingChannelFactory.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannelFactory.cs similarity index 83% rename from src/dotnet/commands/dotnet-test/ReportingChannelFactory.cs rename to src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannelFactory.cs index f8a5940ea..0ecec58c6 100644 --- a/src/dotnet/commands/dotnet-test/ReportingChannelFactory.cs +++ b/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannelFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.DotNet.Tools.Test public IReportingChannel CreateTestRunnerChannel() { - var testRunnerChannel = ReportingChannel.ListenOn(0); + var testRunnerChannel = TestRunnerReportingChannel.ListenOn(0); TestRunnerChannelCreated?.Invoke(this, testRunnerChannel); @@ -20,7 +20,7 @@ namespace Microsoft.DotNet.Tools.Test public IReportingChannel CreateAdapterChannel(int port) { - return ReportingChannel.ListenOn(port); + return AdapterReportingChannel.ConnectTo(port); } } } diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs b/src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs new file mode 100644 index 000000000..204988441 --- /dev/null +++ b/src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs @@ -0,0 +1,42 @@ +// 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.Net; +using System.Net.Sockets; +using System.Threading; + +namespace Microsoft.DotNet.Tools.Test +{ + public class TestRunnerReportingChannel : ReportingChannel + { + public static ReportingChannel ListenOn(int port) + { + // This fixes the mono incompatibility but ties it to ipv4 connections + var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, port)); + listenSocket.Listen(10); + + return new TestRunnerReportingChannel(listenSocket, ((IPEndPoint)listenSocket.LocalEndPoint)); + } + + private TestRunnerReportingChannel(Socket connectSocket, IPEndPoint ipEndPoint) + : base(connectSocket, ipEndPoint.Port) + { + } + + public override void Connect() + { + new Thread(() => + { + using (ConnectSocket) + { + Socket = ConnectSocket.Accept(); + + StartReadingMessages(); + } + }) + { IsBackground = true }.Start(); + } + } +} diff --git a/src/dotnet/project.json b/src/dotnet/project.json index 7938f0157..ed86374d8 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -58,7 +58,8 @@ "Microsoft.Win32.Registry": { "version": "4.0.0-rc2-23911", "exclude": "Compile" - } + }, + "System.Net.NameResolution": "4.0.0-rc2-23911" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/DotnetTestCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/DotnetTestCommand.cs new file mode 100644 index 000000000..181bdd97b --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/DotnetTestCommand.cs @@ -0,0 +1,20 @@ +// 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.Utils; + +namespace Microsoft.DotNet.Tools.Test.Utilities +{ + public class DotnetTestCommand : TestCommand + { + public DotnetTestCommand() : base("dotnet") + { + } + + public override CommandResult Execute(string args = "") + { + args = $"test {args}"; + return base.Execute(args); + } + } +} diff --git a/test/dotnet-test.Tests/Adapter.cs b/test/dotnet-test.Tests/Adapter.cs new file mode 100644 index 000000000..f4c66fa60 --- /dev/null +++ b/test/dotnet-test.Tests/Adapter.cs @@ -0,0 +1,177 @@ +// 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.Net; +using System.Net.Sockets; +using System.Threading; +using Microsoft.Extensions.Testing.Abstractions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Diagnostics; + +namespace Microsoft.Dotnet.Tools.Test.Tests +{ + public class Adapter : IDisposable + { + private readonly string _startMessage; + private BinaryWriter _writer; + private BinaryReader _reader; + private Socket _socket; + private Socket _listenSocket; + + public IDictionary> Messages { get; } + + public int Port { get; private set; } + + public Adapter(string startMessage) + { + _startMessage = startMessage; + Messages = new Dictionary>(); + + _listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + var endpoint = new IPEndPoint(IPAddress.Loopback, 0); + _listenSocket.Bind(endpoint); + + Port = ((IPEndPoint)_listenSocket.LocalEndPoint).Port; + } + + public void Listen() + { + var listenThread = new Thread(() => + { + using (_listenSocket) + { + _listenSocket.Listen(1); + _socket = _listenSocket.Accept(); + } + + var stream = new NetworkStream(_socket); + _writer = new BinaryWriter(stream); + _reader = new BinaryReader(stream); + + ReadMessages(); + }) + { + IsBackground = true + }; + + listenThread.Start(); + } + + public void Send(string messageType) + { + lock (_writer) + { + _writer.Write(JsonConvert.SerializeObject(new + { + MessageType = messageType, + PayLoad = JToken.FromObject(new + { + }) + })); + } + } + + private void ReadMessages() + { + while (true) + { + try + { + var message = GetMessage(); + + StoreMessage(message); + + if (HandleMessage(message)) + { + break; + } + } + catch (Exception) + { + throw; + } + } + } + + private void StoreMessage(Message message) + { + if (!Messages.ContainsKey(message.MessageType)) + { + Messages.Add(message.MessageType, new List()); + } + + Messages[message.MessageType].Add(message); + } + + private bool HandleMessage(Message message) + { + if (message.MessageType == "TestSession.Connected") + { + Send(_startMessage); + } + + if (message.MessageType == "TestExecution.TestRunnerProcessStartInfo") + { + StartTestRunner(message.Payload.ToObject()); + } + + if (message.MessageType == "TestDiscovery.Completed") + { + Send("TestSession.Terminate"); + return true; + } + + if (message.MessageType == "TestExecution.Completed") + { + Send("TestSession.Terminate"); + return true; + } + + return false; + } + + private static void StartTestRunner(TestStartInfo testPsiInfo) + { + var testPsi = new ProcessStartInfo(testPsiInfo.FileName, testPsiInfo.Arguments); + testPsi.RedirectStandardOutput = true; + testPsi.UseShellExecute = false; + var testProcess = new Process + { + StartInfo = testPsi + }; + + var testProcessThread = new Thread(() => { testProcess.Start(); }) + { + IsBackground = true + }; + testProcessThread.Start(); + } + + private Message GetMessage() + { + var rawMessage = _reader.ReadString(); + Console.WriteLine("\nRECEIVING MESSAGE:"); + Console.WriteLine($"{rawMessage}"); + Console.WriteLine($"==============================\n"); + + var message = JsonConvert.DeserializeObject(rawMessage); + return message; + } + + public void Dispose() + { + _socket?.Dispose(); + } + + private class TestStartInfo + { + public string FileName { get; set; } + + public string Arguments { get; set; } + } + } +} \ No newline at end of file diff --git a/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTime.cs b/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTime.cs new file mode 100644 index 000000000..5c874ac30 --- /dev/null +++ b/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTime.cs @@ -0,0 +1,72 @@ +// 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.ProjectModel; +using Microsoft.DotNet.Tools.Test.Utilities; +using System.IO; +using FluentAssertions; +using Xunit; +using Microsoft.Extensions.PlatformAbstractions; +using System.Linq; + +namespace Microsoft.Dotnet.Tools.Test.Tests +{ + public class GivenThatWeWantToUseDotnetTestE2EInDesignTime : TestBase + { + private string _projectFilePath; + private string _outputPath; + + public GivenThatWeWantToUseDotnetTestE2EInDesignTime() + { + var testInstance = TestAssetsManager.CreateTestInstance("ProjectWithTests").WithLockFiles(); + + _projectFilePath = Path.Combine(testInstance.TestRoot, "project.json"); + var contexts = ProjectContext.CreateContextForEachFramework( + _projectFilePath, + null, + PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers()); + var runtime = contexts.FirstOrDefault(c => !string.IsNullOrEmpty(c.RuntimeIdentifier))?.RuntimeIdentifier; + _outputPath = Path.Combine(testInstance.TestRoot, "bin", "Debug", DefaultFramework, runtime); + var buildCommand = new BuildCommand(_projectFilePath); + var result = buildCommand.Execute(); + + result.Should().Pass(); + } + + [WindowsOnlyFact] + public void It_discovers_two_tests_for_the_ProjectWithTests() + { + using (var adapter = new Adapter("TestDiscovery.Start")) + { + adapter.Listen(); + + var testCommand = new DotnetTestCommand(); + var result = testCommand.Execute($"{_projectFilePath} -o {_outputPath} --port {adapter.Port}"); + result.Should().Pass(); + + adapter.Messages["TestSession.Connected"].Count.Should().Be(1); + adapter.Messages["TestDiscovery.TestFound"].Count.Should().Be(2); + adapter.Messages["TestDiscovery.Completed"].Count.Should().Be(1); + } + } + + [Fact] + public void It_runs_two_tests_for_the_ProjectWithTests() + { + using (var adapter = new Adapter("TestExecution.GetTestRunnerProcessStartInfo")) + { + adapter.Listen(); + + var testCommand = new DotnetTestCommand(); + var result = testCommand.Execute($"{_projectFilePath} -o {_outputPath} --port {adapter.Port}"); + result.Should().Pass(); + + adapter.Messages["TestSession.Connected"].Count.Should().Be(1); + adapter.Messages["TestExecution.TestRunnerProcessStartInfo"].Count.Should().Be(1); + adapter.Messages["TestExecution.TestStarted"].Count.Should().Be(2); + adapter.Messages["TestExecution.TestResult"].Count.Should().Be(2); + adapter.Messages["TestExecution.Completed"].Count.Should().Be(1); + } + } + } +} diff --git a/test/dotnet-test.Tests/dotnet-test.Tests.xproj b/test/dotnet-test.Tests/dotnet-test.Tests.xproj new file mode 100644 index 000000000..19adc5ad5 --- /dev/null +++ b/test/dotnet-test.Tests/dotnet-test.Tests.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 60c33d0a-a5d8-4ab0-9956-1f804654df05 + Microsoft.Dotnet.Tools.Test.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + \ No newline at end of file diff --git a/test/dotnet-test.Tests/project.json b/test/dotnet-test.Tests/project.json new file mode 100644 index 000000000..07eb34c33 --- /dev/null +++ b/test/dotnet-test.Tests/project.json @@ -0,0 +1,33 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "Newtonsoft.Json": "7.0.1", + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "Microsoft.DotNet.TestFramework": { "target": "project" }, + "Microsoft.DotNet.ProjectModel": { "target": "project" }, + "Microsoft.Extensions.Testing.Abstractions": { "target": "project" }, + "System.Net.NameResolution": "4.0.0-rc2-23911", + "System.Net.Sockets": "4.1.0-rc2-23911", + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-23911", + + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-91790-12" + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "content": [ + "../../TestAssets/TestProjects/ProjectWithTests/**/*", + "../../TestAssets/TestProjects/global.json" + ], + + "testRunner": "xunit" +} diff --git a/test/dotnet-test.UnitTests/GivenATestDiscoveryStartMessageHandler.cs b/test/dotnet-test.UnitTests/GivenATestDiscoveryStartMessageHandler.cs index 971ceeb3b..1c6ea4bbf 100644 --- a/test/dotnet-test.UnitTests/GivenATestDiscoveryStartMessageHandler.cs +++ b/test/dotnet-test.UnitTests/GivenATestDiscoveryStartMessageHandler.cs @@ -141,7 +141,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests _dotnetTestMock.Object, _validMessage); - _testRunnerChannelMock.Verify(t => t.Accept(), Times.Once); + _testRunnerChannelMock.Verify(t => t.Connect(), Times.Once); } [Fact] diff --git a/test/dotnet-test.UnitTests/GivenATestExecutionGetTestRunnerProcessStartInfoMessageHandler.cs b/test/dotnet-test.UnitTests/GivenATestExecutionGetTestRunnerProcessStartInfoMessageHandler.cs index 24a9942b7..e99271634 100644 --- a/test/dotnet-test.UnitTests/GivenATestExecutionGetTestRunnerProcessStartInfoMessageHandler.cs +++ b/test/dotnet-test.UnitTests/GivenATestExecutionGetTestRunnerProcessStartInfoMessageHandler.cs @@ -161,7 +161,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests _dotnetTestMock.Object, _validMessage); - _testRunnerChannelMock.Verify(t => t.Accept(), Times.Once); + _testRunnerChannelMock.Verify(t => t.Connect(), Times.Once); } [Fact] From cc00d9d8399f6c7f4593536cefd38c79a56fe418 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Tue, 15 Mar 2016 11:50:14 -0700 Subject: [PATCH 63/99] update project templates for portable app also fix dotnet run --- .../ArgumentEscaper.cs | 4 +- .../RuntimeOutputFiles.cs | 14 +++++-- .../commands/dotnet-build/CompileContext.cs | 14 ++++--- .../CSharp_Console/project.json.template | 6 +-- .../FSharp_Console/project.json.template | 6 +-- src/dotnet/commands/dotnet-run/RunCommand.cs | 20 ++++++++-- test/EndToEnd/EndToEndTest.cs | 28 +++++++------- .../Commands/BuildCommand.cs | 5 +++ .../Commands/PublishCommand.cs | 5 +++ .../Commands/TestCommand.cs | 38 ++++++++++++++----- 10 files changed, 95 insertions(+), 45 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs b/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs index 4a5d0f4fe..c8469a9ac 100644 --- a/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs +++ b/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs @@ -54,7 +54,7 @@ namespace Microsoft.DotNet.Cli.Utils foreach (var arg in args) { - escapedArgs.Add(EscapeArg(arg)); + escapedArgs.Add(EscapeSingleArg(arg)); } return escapedArgs; @@ -82,7 +82,7 @@ namespace Microsoft.DotNet.Cli.Utils return escapedArgs; } - private static string EscapeArg(string arg) + public static string EscapeSingleArg(string arg) { var sb = new StringBuilder(); diff --git a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs index 8e9bdca3b..6368f173b 100644 --- a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs +++ b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs @@ -26,12 +26,18 @@ namespace Microsoft.DotNet.ProjectModel { var extension = FileNameSuffixes.CurrentPlatform.Exe; - // This is the check for mono, if we're not on windows and producing outputs for - // the desktop framework then it's an exe if (Framework.IsDesktop()) { + // This is the check for mono, if we're not on windows and producing outputs for + // the desktop framework then it's an exe extension = FileNameSuffixes.DotNet.Exe; } + else if (string.IsNullOrEmpty(_runtimeIdentifier)) + { + // The executable is a DLL in this case + extension = FileNameSuffixes.DotNet.DynamicLib; + } + return Path.Combine(BasePath, Project.Name + extension); } } @@ -81,9 +87,9 @@ namespace Microsoft.DotNet.ProjectModel yield return RuntimeConfigJson; } - // If the project actually has an entry point AND we're doing a standalone build + // If the project actually has an entry point var hasEntryPoint = Project.GetCompilerOptions(targetFramework: null, configurationName: Configuration).EmitEntryPoint ?? false; - if (hasEntryPoint && !string.IsNullOrEmpty(_runtimeIdentifier)) + if (hasEntryPoint) { // Yield the executable yield return Executable; diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs index b6b5c2adb..4768f12e7 100644 --- a/src/dotnet/commands/dotnet-build/CompileContext.cs +++ b/src/dotnet/commands/dotnet-build/CompileContext.cs @@ -405,6 +405,13 @@ namespace Microsoft.DotNet.Tools.Build { var dest = outputPaths.RuntimeOutputPath; var source = outputPaths.CompilationOutputPath; + + // No need to copy if dest and source are the same + if(string.Equals(dest, source, StringComparison.OrdinalIgnoreCase)) + { + return; + } + foreach (var file in outputPaths.CompilationFiles.All()) { var destFileName = file.Replace(source, dest); @@ -423,12 +430,7 @@ namespace Microsoft.DotNet.Tools.Build var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue); var libraryExporter = runtimeContext.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue); - // If we're building for a specific RID, we need to copy the RID-less compilation output into - // the RID-specific output dir - if (!string.IsNullOrEmpty(runtimeContext.RuntimeIdentifier)) - { - CopyCompilationOutput(outputPaths); - } + CopyCompilationOutput(outputPaths); var options = runtimeContext.ProjectFile.GetCompilerOptions(runtimeContext.TargetFramework, _args.ConfigValue); var executable = new Executable(runtimeContext, outputPaths, libraryExporter, _args.ConfigValue); diff --git a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template index 2e5ebbe30..5f0805e14 100644 --- a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template @@ -4,11 +4,11 @@ "emitEntryPoint": true }, "dependencies": { - "NETStandard.Library": "1.5.0-rc2-23911" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" }, "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" + "netstandard1.5": { + "imports": [ "portable-net45+win8", "dnxcore50" ] } } } diff --git a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template index 84d87f6df..501e3dd6c 100644 --- a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template @@ -9,11 +9,11 @@ ], "dependencies": { "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.5.0-rc2-23911" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" }, "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" + "netstandard1.5": { + "imports": [ "portable-net45+win8", "dnxcore50" ] } } } diff --git a/src/dotnet/commands/dotnet-run/RunCommand.cs b/src/dotnet/commands/dotnet-run/RunCommand.cs index cc8c65e32..db67a4394 100644 --- a/src/dotnet/commands/dotnet-run/RunCommand.cs +++ b/src/dotnet/commands/dotnet-run/RunCommand.cs @@ -84,7 +84,7 @@ namespace Microsoft.DotNet.Tools.Run { throw new InvalidOperationException($"Couldn't find target to run. Possible causes:" + Environment.NewLine + "1. No project.lock.json file or restore failed - run `dotnet restore`" + Environment.NewLine + - $"2. project.lock.json has multiple targets none of which is in default list ({string.Join(", " , defaultFrameworks)})"); + $"2. project.lock.json has multiple targets none of which is in default list ({string.Join(", ", defaultFrameworks)})"); } } @@ -125,7 +125,8 @@ namespace Microsoft.DotNet.Tools.Run } // Now launch the output and give it the results - var outputName = _context.GetOutputPaths(Configuration).RuntimeFiles.Executable; + var outputPaths = _context.GetOutputPaths(Configuration); + var outputName = outputPaths.RuntimeFiles.Executable; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -145,7 +146,18 @@ namespace Microsoft.DotNet.Tools.Run } } - result = Command.Create(outputName, _args) + Command command; + if (outputName.EndsWith(FileNameSuffixes.DotNet.DynamicLib, StringComparison.OrdinalIgnoreCase)) + { + // The executable is a ".dll", we need to call it through dotnet.exe + command = Command.Create("corehost", Enumerable.Concat(new[] { outputName }, _args)); + } + else + { + command = Command.Create(outputName, _args); + } + + result = command .ForwardStdOut() .ForwardStdErr() .Execute() @@ -156,7 +168,7 @@ namespace Microsoft.DotNet.Tools.Run private static int RunInteractive(string scriptName) { - var command = Command.CreateDotNet($"repl-csi", new [] {scriptName}) + var command = Command.CreateDotNet($"repl-csi", new[] { scriptName }) .ForwardStdOut() .ForwardStdErr(); var result = command.Execute(); diff --git a/test/EndToEnd/EndToEndTest.cs b/test/EndToEnd/EndToEndTest.cs index be21d46ca..a07507602 100644 --- a/test/EndToEnd/EndToEndTest.cs +++ b/test/EndToEnd/EndToEndTest.cs @@ -8,11 +8,13 @@ using System.Runtime.InteropServices; using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.Extensions.PlatformAbstractions; using Xunit; +using System.Diagnostics; namespace Microsoft.DotNet.Tests.EndToEnd { public class EndToEndTest : TestBase { + private static readonly string NetStandardTfm = "netstandard1.5"; private static readonly string s_expectedOutput = "Hello World!" + Environment.NewLine; private static readonly string s_testdirName = "e2etestroot"; private static readonly string s_outputdirName = "test space/bin"; @@ -42,20 +44,20 @@ namespace Microsoft.DotNet.Tests.EndToEnd [Fact] public void TestDotnetBuild() { - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); } [Fact] public void TestDotnetIncrementalBuild() { // first build - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false); var latestWriteTimeFirstBuild = GetLastWriteTimeUtcOfDirectoryFiles( @@ -63,7 +65,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd // second build; should get skipped (incremental because no inputs changed) buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var latestWriteTimeUtcSecondBuild = GetLastWriteTimeUtcOfDirectoryFiles( binariesOutputDirectory); @@ -73,14 +75,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd // third build; should get compiled because the source file got touched buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var latestWriteTimeUtcThirdBuild = GetLastWriteTimeUtcOfDirectoryFiles( binariesOutputDirectory); Assert.NotEqual(latestWriteTimeUtcSecondBuild, latestWriteTimeUtcThirdBuild); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetBuildNativeRyuJit() { if (!IsNativeCompilationSupported()) @@ -88,14 +90,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd return; } - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetBuildNativeCpp() { if (!IsNativeCompilationSupported()) @@ -103,14 +105,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd return; } - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetCompileNativeCppIncremental() { if (!IsNativeCompilationSupported()) @@ -119,7 +121,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd } // first build - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetStandardTfm); var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false); buildCommand.Execute().Should().Pass(); @@ -163,7 +165,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd var publishCommand = new PublishCommand(TestProject, output: OutputDirectory); publishCommand.Execute().Should().Pass(); - TestExecutable(OutputDirectory, publishCommand.GetOutputExecutable(), s_expectedOutput); + TestExecutable(OutputDirectory, publishCommand.GetPortableOutputName(), s_expectedOutput); } [Fact] diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs index 4f36ac973..693b32586 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs @@ -254,6 +254,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return base.ExecuteWithCapturedOutput(args); } + public string GetPortableOutputName() + { + return $"{_project.Name}.dll"; + } + public string GetOutputExecutableName() { var result = _project.Name; diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs index ec24eb73a..785a1d386 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs @@ -74,6 +74,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return new DirectoryInfo(output); } + public string GetPortableOutputName() + { + return $"{_project.Name}.dll"; + } + public string GetOutputExecutable() { var result = _project.Name; diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs index 16a677add..ef0f086e2 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs @@ -23,11 +23,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities public virtual CommandResult Execute(string args = "") { var commandPath = _command; - if (!Path.IsPathRooted(_command)) - { - _command = Env.GetCommandPath(_command) ?? - Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command); - } + ResolveCommand(ref commandPath, ref args); Console.WriteLine($"Executing - {_command} {args}"); @@ -44,9 +40,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities { Console.WriteLine($"Executing (Captured Output) - {_command} {args}"); - var commandPath = Env.GetCommandPath(_command, ".exe", ".cmd", "") ?? - Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command, ".exe", ".cmd", ""); - + var command = _command; + ResolveCommand(ref command, ref args); + var commandPath = Env.GetCommandPath(command, ".exe", ".cmd", "") ?? + Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, command, ".exe", ".cmd", ""); + var stdOut = new StreamForwarder(); var stdErr = new StreamForwarder(); @@ -56,6 +54,26 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return RunProcess(commandPath, args, stdOut, stdErr); } + private void ResolveCommand(ref string executable, ref string args) + { + if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + var newArgs = ArgumentEscaper.EscapeSingleArg(executable); + if (!string.IsNullOrEmpty(args)) + { + newArgs += " " + args; + } + args = newArgs; + executable = "corehost"; + } + + if (!Path.IsPathRooted(executable)) + { + executable = Env.GetCommandPath(executable) ?? + Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, executable); + } + } + private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr) { var psi = new ProcessStartInfo @@ -88,8 +106,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities var result = new CommandResult( process.StartInfo, - process.ExitCode, - stdOut.CapturedOutput, + process.ExitCode, + stdOut.CapturedOutput, stdErr.CapturedOutput); return result; From c934d594925e5c6a04d07934b6c4ec4b5b14af89 Mon Sep 17 00:00:00 2001 From: Livar Date: Tue, 15 Mar 2016 13:55:05 -0700 Subject: [PATCH 64/99] Merge pull request #1872 from dotnet/run_individual_tests_documentation Update developer-guide.md by adding instructions on running individual test projects --- Documentation/developer-guide.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/developer-guide.md b/Documentation/developer-guide.md index f68aebd14..ed6dc0a09 100644 --- a/Documentation/developer-guide.md +++ b/Documentation/developer-guide.md @@ -36,6 +36,22 @@ In order to build .NET Command Line Interface, you need the following installed 2. `dotnet restore` 3. `dotnet run` +## Running tests + +All the CLI tests are located under `test`. In order to run them, after doing a restore on the CLI repo just do the following: + +1. Navigate to a test project, for instance: `cd test\dotnet-test.UnitTests` +2. `dotnet test` + +For unit test projects (they have UnitTests at the name), that's all that you need to do, as they take a dependency on the product code directly, which gets rebuilt by dotnet when you run the tests. + +For E2E and functional tests, they all depend on the binaries located under `artifacts\rid\stage2\bin`. So, after changing the code, you will need to re-build the product code and copy the new bits to the folder above. For instance, imagine you changed something in dotnet itself, you would have to do the following: + +1. `cd src\dotnet\` +2. `dotnet build` +3. `cp bin\debug\netstandardapp1.5\dotnet.dll artifacts\rid\stage2\bin` +4. `cd ..\..\test\dotnet-build.Tests` +5. `dotnet test` ##Adding a Command From 4fcabc47cc78dcbb669210f3bd3e78f5b019c790 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Tue, 15 Mar 2016 17:01:50 -0700 Subject: [PATCH 65/99] Create combined zip/tar for framework-host-sdk and framework-host --- scripts/dotnet-cli-build/PackageTargets.cs | 42 ++++++++++++++++++++-- scripts/dotnet-cli-build/PrepareTargets.cs | 2 ++ scripts/dotnet-cli-build/Utils/Utils.cs | 10 ++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index fdce6eedd..0284a5dc6 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -14,7 +14,9 @@ namespace Microsoft.DotNet.Cli.Build { [Target(nameof(PackageTargets.CopyCLISDKLayout), nameof(SharedFrameworkTargets.PublishSharedHost), - nameof(SharedFrameworkTargets.PublishSharedFramework))] + nameof(SharedFrameworkTargets.PublishSharedFramework), + nameof(PackageTargets.CopyCombinedFrameworkSDKHostLayout), + nameof(PackageTargets.CopyCombinedFrameworkHostLayout))] public static BuildTargetResult InitPackage(BuildTargetContext c) { Directory.CreateDirectory(Dirs.Packages); @@ -90,6 +92,39 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + public static BuildTargetResult CopyCombinedFrameworkSDKHostLayout(BuildTargetContext c) + { + var combinedRoot = Path.Combine(Dirs.Output, "obj", "combined-framework-sdk-host"); + + string sdkPublishRoot = c.BuildContext.Get("CLISDKRoot"); + Utils.CopyDirectoryRecursively(sdkPublishRoot, combinedRoot); + + string sharedFrameworkPublishRoot = c.BuildContext.Get("SharedFrameworkPublishRoot"); + Utils.CopyDirectoryRecursively(sharedFrameworkPublishRoot, combinedRoot); + + string sharedHostPublishRoot = c.BuildContext.Get("SharedHostPublishRoot"); + Utils.CopyDirectoryRecursively(sharedHostPublishRoot, combinedRoot); + + c.BuildContext["CombinedFrameworkSDKHostRoot"] = combinedRoot; + return c.Success(); + } + + [Target] + public static BuildTargetResult CopyCombinedFrameworkHostLayout(BuildTargetContext c) + { + var combinedRoot = Path.Combine(Dirs.Output, "obj", "combined-framework-host"); + + string sharedFrameworkPublishRoot = c.BuildContext.Get("SharedFrameworkPublishRoot"); + Utils.CopyDirectoryRecursively(sharedFrameworkPublishRoot, combinedRoot); + + string sharedHostPublishRoot = c.BuildContext.Get("SharedHostPublishRoot"); + Utils.CopyDirectoryRecursively(sharedHostPublishRoot, combinedRoot); + + c.BuildContext["CombinedFrameworkHostRoot"] = combinedRoot; + return c.Success(); + } + [Target(nameof(PackageTargets.GenerateZip), nameof(PackageTargets.GenerateTarBall))] public static BuildTargetResult GenerateCompressedFile(BuildTargetContext c) { @@ -103,6 +138,8 @@ namespace Microsoft.DotNet.Cli.Build CreateZipFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); + CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); + CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); return c.Success(); } @@ -113,7 +150,8 @@ namespace Microsoft.DotNet.Cli.Build { CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); - CreateTarBallFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); + CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); + CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); return c.Success(); } diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 1c87e132f..0dcfa1538 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -115,6 +115,8 @@ namespace Microsoft.DotNet.Cli.Build AddInstallerArtifactToContext(c, "dotnet", "Sdk"); AddInstallerArtifactToContext(c, "dotnet-host", "SharedHost"); AddInstallerArtifactToContext(c, "dotnet-sharedframework", "SharedFramework"); + AddInstallerArtifactToContext(c, "dotnet-combined-framework-sdk-host", "CombinedFrameworkSDKHost"); + AddInstallerArtifactToContext(c, "dotnet-combined-framework-host", "CombinedFrameworkHost"); return c.Success(); } diff --git a/scripts/dotnet-cli-build/Utils/Utils.cs b/scripts/dotnet-cli-build/Utils/Utils.cs index 1f255e99e..d9dd937a0 100644 --- a/scripts/dotnet-cli-build/Utils/Utils.cs +++ b/scripts/dotnet-cli-build/Utils/Utils.cs @@ -100,5 +100,15 @@ namespace Microsoft.DotNet.Cli.Build Directory.Delete(path, true); } } + + public static void CopyDirectoryRecursively(string path, string destination) + { + foreach (var file in Directory.GetFiles(path, "*", SearchOption.AllDirectories)) + { + string destFile = file.Replace(path, destination); + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(file, destFile, true); + } + } } } From d9dfaf1328ad94474d529df15373664fef322936 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Tue, 15 Mar 2016 17:41:42 -0700 Subject: [PATCH 66/99] Publish the combined-zip/tar files to azure --- scripts/dotnet-cli-build/PublishTargets.cs | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index b624656ad..04af2b35c 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -49,6 +49,8 @@ namespace Microsoft.DotNet.Cli.Build nameof(PublishTargets.PublishDebFileToDebianRepo), nameof(PublishTargets.PublishSharedFrameworkCompressedFile), nameof(PublishTargets.PublishSharedHostCompressedFile), + nameof(PublishTargets.PublishCombinedFrameworkSDKHostFile), + nameof(PublishTargets.PublishCombinedFrameworkHostFile), nameof(PublishTargets.PublishLatestVersionTextFile))] public static BuildTargetResult PublishArtifacts(BuildTargetContext c) { @@ -169,6 +171,32 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + public static BuildTargetResult PublishCombinedFrameworkSDKHostFile(BuildTargetContext c) + { + var compressedFile = c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile"); + var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; + var latestCompressedFile = compressedFile.Replace(Version, "latest"); + var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; + + PublishFileAzure(compressedFileBlob, compressedFile); + PublishFileAzure(latestCompressedFileBlob, compressedFile); + return c.Success(); + } + + [Target] + public static BuildTargetResult PublishCombinedFrameworkHostFile(BuildTargetContext c) + { + var compressedFile = c.BuildContext.Get("CombinedFrameworkHostCompressedFile"); + var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; + var latestCompressedFile = compressedFile.Replace(Version, "latest"); + var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; + + PublishFileAzure(compressedFileBlob, compressedFile); + PublishFileAzure(latestCompressedFileBlob, compressedFile); + return c.Success(); + } + private static BuildTargetResult PublishFile(BuildTargetContext c, string file) { var env = PackageTargets.GetCommonEnvVars(c); From 00cb8fa045305a600cd00b39a41918c8fed6dfc6 Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Tue, 15 Mar 2016 20:22:10 -0700 Subject: [PATCH 67/99] Updating the dotnet-test-runner version to 1.0.0-dev-91790-12. Some projects still had the old version, which won't work with VS. --- test/ArgumentForwardingTests/project.json | 2 +- test/Microsoft.DotNet.Cli.Utils.Tests/project.json | 2 +- test/Microsoft.DotNet.Compiler.Common.Tests/project.json | 2 +- test/ScriptExecutorTests/project.json | 2 +- test/dotnet-pack.Tests/project.json | 2 +- test/dotnet-resgen.Tests/project.json | 2 +- test/dotnet-run.Tests/project.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/ArgumentForwardingTests/project.json b/test/ArgumentForwardingTests/project.json index ccf9d856b..70c21b3f1 100644 --- a/test/ArgumentForwardingTests/project.json +++ b/test/ArgumentForwardingTests/project.json @@ -15,7 +15,7 @@ "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json index 02638b27b..03dc29205 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json @@ -16,7 +16,7 @@ }, "moq.netcore": "4.4.0-beta8", "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json index 6bcc81722..e95dacee2 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/project.json +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/project.json @@ -12,7 +12,7 @@ "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/ScriptExecutorTests/project.json b/test/ScriptExecutorTests/project.json index 158d402c7..a7848a2c4 100644 --- a/test/ScriptExecutorTests/project.json +++ b/test/ScriptExecutorTests/project.json @@ -12,7 +12,7 @@ "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/dotnet-pack.Tests/project.json b/test/dotnet-pack.Tests/project.json index 86c244272..18b034060 100644 --- a/test/dotnet-pack.Tests/project.json +++ b/test/dotnet-pack.Tests/project.json @@ -10,7 +10,7 @@ "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/dotnet-resgen.Tests/project.json b/test/dotnet-resgen.Tests/project.json index 270d4e747..346c14af5 100644 --- a/test/dotnet-resgen.Tests/project.json +++ b/test/dotnet-resgen.Tests/project.json @@ -10,7 +10,7 @@ }, "xunit": "2.1.0", "xunit.netcore.extensions": "1.0.0-prerelease-*", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { diff --git a/test/dotnet-run.Tests/project.json b/test/dotnet-run.Tests/project.json index 2380359e2..6731f311f 100644 --- a/test/dotnet-run.Tests/project.json +++ b/test/dotnet-run.Tests/project.json @@ -9,7 +9,7 @@ "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-dev-79755-47" + "dotnet-test-xunit": "1.0.0-dev-91790-12" }, "frameworks": { "netstandardapp1.5": { From 77e511c4d4f0dd9781a6bf0ae7c26b5117537efc Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 15 Mar 2016 16:27:30 -0700 Subject: [PATCH 68/99] Generate runtime graph when building runtime --- .../SharedFrameworkTargets.cs | 37 ++++-- .../RuntimeFallbacks.cs | 14 ++- tools/RuntimeGraphGenerator/Program.cs | 110 ++++++++++++++++++ .../RuntimeGraphGenerator.xproj | 19 +++ .../RuntimeGraphManager.cs | 60 ++++++++++ tools/RuntimeGraphGenerator/project.json | 25 ++++ 6 files changed, 253 insertions(+), 12 deletions(-) create mode 100644 tools/RuntimeGraphGenerator/Program.cs create mode 100644 tools/RuntimeGraphGenerator/RuntimeGraphGenerator.xproj create mode 100644 tools/RuntimeGraphGenerator/RuntimeGraphManager.cs create mode 100644 tools/RuntimeGraphGenerator/project.json diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs index 93ef44ec2..7dffd64c4 100644 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs @@ -74,20 +74,37 @@ namespace Microsoft.DotNet.Cli.Build File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps); - // Merge in the RID fallback graph - var fallbackFileName = PlatformServices.Default.Runtime.OperatingSystemPlatform.ToString().ToLowerInvariant() + ".json"; - var fallbackFile = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "rid-fallbacks", fallbackFileName); - if (File.Exists(fallbackFile)) + // Generate RID fallback graph + string runtimeGraphGeneratorRuntime = null; + switch (PlatformServices.Default.Runtime.OperatingSystemPlatform) { - c.Info($"Merging in RID fallback graph: {fallbackFile}"); - var deps = JObject.Parse(File.ReadAllText(destinationDeps)); - var ridfallback = JObject.Parse(File.ReadAllText(fallbackFile)); - deps["runtimes"] = ridfallback["runtimes"]; - File.WriteAllText(destinationDeps, deps.ToString(Formatting.Indented)); + case Platform.Windows: + runtimeGraphGeneratorRuntime = "win"; + break; + case Platform.Linux: + runtimeGraphGeneratorRuntime = "linux"; + break; + case Platform.Darwin: + runtimeGraphGeneratorRuntime = "osx"; + break; + } + if (!string.IsNullOrEmpty(runtimeGraphGeneratorRuntime)) + { + var runtimeGraphGeneratorName = "RuntimeGraphGenerator"; + var runtimeGraphGeneratorProject = Path.Combine(c.BuildContext.BuildDirectory, "tools", runtimeGraphGeneratorName); + var runtimeGraphGeneratorOutput = Path.Combine(Dirs.Output, "tools", runtimeGraphGeneratorName); + + DotNetCli.Stage2.Publish( + "--output", runtimeGraphGeneratorOutput, + runtimeGraphGeneratorProject).Execute().EnsureSuccessful(); + var runtimeGraphGeneratorExe = Path.Combine(runtimeGraphGeneratorOutput, $"{runtimeGraphGeneratorName}{Constants.ExeSuffix}"); + + Cmd(runtimeGraphGeneratorExe, "--project", SharedFrameworkSourceRoot, "--deps", destinationDeps, runtimeGraphGeneratorRuntime) + .Execute(); } else { - c.Warn($"RID fallback graph file not found: {fallbackFile}"); + c.Error($"Could not determine rid graph generation runtime for platform {PlatformServices.Default.Runtime.OperatingSystemPlatform}"); } // corehost will be renamed to dotnet at some point and then we will not need to rename it here. diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs index d759b1942..62f716ba2 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs @@ -1,19 +1,29 @@ // 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.Linq; namespace Microsoft.Extensions.DependencyModel { public class RuntimeFallbacks { public string Runtime { get; set; } - public IEnumerable Fallbacks { get; set; } + public IReadOnlyList Fallbacks { get; set; } public RuntimeFallbacks(string runtime, IEnumerable fallbacks) { + if (runtime == null) + { + throw new ArgumentNullException(nameof(runtime)); + } + if (fallbacks == null) + { + throw new ArgumentNullException(nameof(fallbacks)); + } Runtime = runtime; - Fallbacks = fallbacks; + Fallbacks = fallbacks.ToArray(); } } } \ No newline at end of file diff --git a/tools/RuntimeGraphGenerator/Program.cs b/tools/RuntimeGraphGenerator/Program.cs new file mode 100644 index 000000000..09253af49 --- /dev/null +++ b/tools/RuntimeGraphGenerator/Program.cs @@ -0,0 +1,110 @@ +// 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.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using System.IO; +using System.Runtime.Versioning; +using Microsoft.DotNet.ProjectModel; +using Microsoft.Extensions.DependencyModel; +using NuGet.Frameworks; +using NuGet.Packaging; +using NuGet.Versioning; +using Microsoft.DotNet.ProjectModel.Graph; + +namespace RuntimeGraphGenerator +{ + public class Program + { + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + string projectDirectory = null; + string depsFile = null; + IReadOnlyList runtimes = null; + try + { + ArgumentSyntax.Parse(args, syntax => + { + syntax.ApplicationName = "Runtime GraphGenerator"; + + syntax.HandleHelp = false; + syntax.HandleErrors = false; + + syntax.DefineOption("p|project", ref projectDirectory, "Project location"); + syntax.DefineOption("d|deps", ref depsFile, "Deps file path"); + + syntax.DefineParameterList("runtimes", ref runtimes, "Runtimes"); + }); + } + catch (ArgumentSyntaxException exception) + { + Console.Error.WriteLine(exception.Message); + return 1; + } + + if (runtimes == null || runtimes.Count == 0) + { + Reporter.Error.WriteLine("No runtimes specified"); + return 1; + } + if (!File.Exists(depsFile)) + { + Reporter.Error.WriteLine($"Deps file not found: {depsFile}"); + return 1; + } + if (!Directory.Exists(projectDirectory)) + { + Reporter.Error.WriteLine($"Project directory not found: {projectDirectory}"); + return 1; + } + + try + { + DependencyContext context; + using (var depsStream = File.OpenRead(depsFile)) + { + context = new DependencyContextJsonReader().Read(depsStream); + } + var framework = NuGetFramework.Parse(context.TargetFramework); + var projectContext = ProjectContext.Create(projectDirectory, framework); + + // Configuration is used only for P2P dependencies so were don't care + var exporter = projectContext.CreateExporter("Debug"); + var manager = new RuntimeGraphManager(); + var graph = manager.Collect(exporter.GetDependencies(LibraryType.Package)); + var expandedGraph = manager.Expand(graph, runtimes); + + context = new DependencyContext( + context.TargetFramework, + context.Runtime, + context.IsPortable, + context.CompilationOptions, + context.CompileLibraries, + context.RuntimeLibraries, + expandedGraph + ); + + using (var depsStream = File.Create(depsFile)) + { + new DependencyContextWriter().Write(context, depsStream); + } + + return 0; + } + catch (Exception ex) + { +#if DEBUG + Reporter.Error.WriteLine(ex.ToString()); +#else + Reporter.Error.WriteLine(ex.Message); +#endif + return 1; + } + } + + } +} diff --git a/tools/RuntimeGraphGenerator/RuntimeGraphGenerator.xproj b/tools/RuntimeGraphGenerator/RuntimeGraphGenerator.xproj new file mode 100644 index 000000000..1126cb59b --- /dev/null +++ b/tools/RuntimeGraphGenerator/RuntimeGraphGenerator.xproj @@ -0,0 +1,19 @@ + + + + 14.0.25029 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + efc4fe68-83eb-40e4-bfa8-61d0b4626f25 + RuntimeGraphGenerator + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/tools/RuntimeGraphGenerator/RuntimeGraphManager.cs b/tools/RuntimeGraphGenerator/RuntimeGraphManager.cs new file mode 100644 index 000000000..f1c0629c1 --- /dev/null +++ b/tools/RuntimeGraphGenerator/RuntimeGraphManager.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.DotNet.ProjectModel.Graph; +using NuGet.RuntimeModel; +using System.IO; +using Microsoft.Extensions.DependencyModel; + +namespace Microsoft.DotNet.ProjectModel +{ + public class RuntimeGraphManager + { + private const string RuntimeJsonFileName = "runtime.json"; + + public NuGet.RuntimeModel.RuntimeGraph Collect(IEnumerable exports) + { + var graph = RuntimeGraph.Empty; + foreach (var export in exports) + { + if (export.Library.Identity.Type == LibraryType.Package) + { + var runtimeJson = ((PackageDescription) export.Library).Library.Files.FirstOrDefault(f => f == RuntimeJsonFileName); + if (runtimeJson != null) + { + var runtimeJsonFullName = Path.Combine(export.Library.Path, runtimeJson); + graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); + } + } + } + return graph; + } + + public IEnumerable Expand(RuntimeGraph runtimeGraph, IEnumerable runtimes) + { + foreach (var runtime in runtimes) + { + var importers = FindImporters(runtimeGraph, runtime); + foreach (var importer in importers) + { + // ExpandRuntime return runtime itself as first item so we are skiping it + yield return new RuntimeFallbacks(importer, runtimeGraph.ExpandRuntime(importer).Skip(1)); + } + } + } + + private IEnumerable FindImporters(RuntimeGraph runtimeGraph, string runtime) + { + foreach (var runtimePair in runtimeGraph.Runtimes) + { + var expanded = runtimeGraph.ExpandRuntime(runtimePair.Key); + if (expanded.Contains(runtime)) + { + yield return runtimePair.Key; + } + } + } + } +} diff --git a/tools/RuntimeGraphGenerator/project.json b/tools/RuntimeGraphGenerator/project.json new file mode 100644 index 000000000..9719346de --- /dev/null +++ b/tools/RuntimeGraphGenerator/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NuGet.RuntimeModel": "3.4.0-rtm-0763", + "NuGet.Versioning": "3.4.0-rtm-0763", + "System.CommandLine": "0.1.0-e160119-1", + "System.Runtime.Serialization.Json": "1.0.0-rc2-23911", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-23911", + "NETStandard.Library": "1.5.0-rc2-23911" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+wp80+win8+wpa81+dnxcore50" + ] + } + }, +} From 964318b291a5b4353ce6a2670feae2811847d309 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 16 Mar 2016 11:44:09 -0500 Subject: [PATCH 69/99] Revert "Update the .xproj files to reference the "DotNet" targets and props instead of "DNX"." This reverts commit 4304ca9848eced94a0f39829fd31b2a3cf601bec. --- TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj | 4 ++-- .../FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj | 4 ++-- .../dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj | 4 ++-- .../dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj | 4 ++-- .../DependencyContextValidator.xproj | 4 ++-- .../OutputStandardOutputAndError.xproj | 4 ++-- .../TestAppCompilationContext/TestLibrary/TestLibrary.xproj | 4 ++-- TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj | 4 ++-- .../TestAppWithContentPackage/TestAppWithContentPackage.xproj | 4 ++-- .../TestAppWithContents/TestAppWithContents.xproj | 4 ++-- .../TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj | 4 ++-- .../TestAppWithLibrary/TestLibrary/TestLibrary.xproj | 4 ++-- TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj | 4 ++-- .../TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj | 4 ++-- .../TestLibrary/TestLibrary.xproj | 4 ++-- .../TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj | 4 ++-- .../TestProjectWithCultureSpecificResource.xproj | 4 ++-- .../TestProjectWithResource/TestProjectWithResource.xproj | 4 ++-- .../TestProjects/TestSimpleIncrementalApp/TestApp.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Build.Framework.xproj | 4 ++-- scripts/dotnet-cli-build/dotnet-cli-build.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Utils.xproj | 4 ++-- .../Microsoft.Dotnet.Compiler.Common.xproj | 4 ++-- src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj | 4 ++-- .../Microsoft.DotNet.InternalAbstractions.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Loader.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Workspaces.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.xproj | 4 ++-- .../Microsoft.DotNet.TestFramework.xproj | 4 ++-- .../Microsoft.Extensions.DependencyModel.xproj | 4 ++-- .../Microsoft.Extensions.Testing.Abstractions.xproj | 4 ++-- src/dotnet/commands/dotnet-test/dotnet-test.xproj | 4 ++-- src/dotnet/dotnet.xproj | 4 ++-- test/ArgumentForwardingTests/ArgumentForwardingTests.xproj | 4 ++-- test/ArgumentsReflector/Reflector.xproj | 4 ++-- test/EndToEnd/EndToEnd.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Msi.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Cli.Utils.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Compiler.Common.Tests.xproj | 4 ++-- .../Microsoft.DotNet.ProjectModel.Tests.xproj | 4 ++-- .../Microsoft.DotNet.Tools.Test.Utilities.xproj | 4 ++-- .../Microsoft.Extensions.DependencyModel.Tests.xproj | 4 ++-- test/ScriptExecutorTests/ScriptExecutorTests.xproj | 4 ++-- test/dotnet-build.Tests/dotnet-build.Tests.xproj | 4 ++-- test/dotnet-compile.Tests/dotnet-compile.Tests.xproj | 4 ++-- test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj | 4 ++-- test/dotnet-pack.Tests/dotnet-pack.Tests.xproj | 4 ++-- .../dotnet-projectmodel-server.Tests.xproj | 4 ++-- test/dotnet-publish.Tests/dotnet-publish.Tests.xproj | 4 ++-- test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj | 4 ++-- test/dotnet-run.Tests/dotnet-run.Tests.xproj | 4 ++-- test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj | 4 ++-- test/dotnet.Tests/dotnet.Tests.xproj | 4 ++-- tools/MultiProjectValidator/MultiProjectValidator.xproj | 4 ++-- 54 files changed, 108 insertions(+), 108 deletions(-) diff --git a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj index e48ab0105..4b792e869 100644 --- a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj +++ b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + a666217d-2aca-4866-b109-ea476e51c7aa FSharpTestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj index de36bbed6..ae10bbff6 100644 --- a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj +++ b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + ec801982-096b-4af3-a42b-7881b1a7380e FSharpTestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj index d49a161f4..635819547 100644 --- a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj +++ b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + b8055234-9a66-4ba0-8b4c-d5e431494fe3 dotnet-hello @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj index 7c2da659a..7011c102d 100644 --- a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj +++ b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 282c5014-d0cd-4dde-af4e-531e4a2e7bcd dotnet-hello @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj index 8a2f395fd..c827617ac 100644 --- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj +++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6d84ef36-a5d5-4eaf-b38b-ced635473785 DependencyContextValidator @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj index 0443b706a..ee6ccb69d 100644 --- a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj +++ b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e OutputStandardOutputAndError @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj index ae7910d0d..eb9f8bc2d 100644 --- a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj index 70d47bf5c..fbd214cbd 100644 --- a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj +++ b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + da8e0e9e-a6d6-4583-864c-8f40465e3a48 TestAppWithArgs @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj index 7cc51e6eb..718199108 100644 --- a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj +++ b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + ea239e10-75e8-4305-966e-fec926a5aee6 TestAppWithContentPackage @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj index 1f1eafbea..00103e020 100644 --- a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj +++ b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0138cb8f-4aa9-4029-a21e-c07c30f425ba TestAppWithContents @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj index 75b98c80d..4cef17daa 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj index ae7910d0d..eb9f8bc2d 100644 --- a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj index 75b98c80d..4cef17daa 100644 --- a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj index 75b98c80d..4cef17daa 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj index ae7910d0d..eb9f8bc2d 100644 --- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj +++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 TestLibrary @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj index 75b98c80d..4cef17daa 100644 --- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145eda4e TestApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj index f09a83c44..d8121765f 100644 --- a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj +++ b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + fea4ab27-d004-4580-8abe-b171e30b68cc TestProjectWithCultureSpecificResource @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj index cc3bb2c74..aee14e286 100644 --- a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj +++ b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4909876ed864 TestProjectWithResource @@ -16,5 +16,5 @@ 2.0 - + diff --git a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj index 518aa7600..088568e54 100644 --- a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj +++ b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 58808bbc-371e-47d6-a3d0-4902145edaaa TestSimpleIncrementalApp @@ -16,5 +16,5 @@ 2.0 - + diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj index 5e45f32ed..d4c58d0e8 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 49beb486-ab5a-4416-91ea-8cd34abb0c9d Microsoft.DotNet.Cli.Build.Framework @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/scripts/dotnet-cli-build/dotnet-cli-build.xproj b/scripts/dotnet-cli-build/dotnet-cli-build.xproj index fdd8f182d..fd8546624 100644 --- a/scripts/dotnet-cli-build/dotnet-cli-build.xproj +++ b/scripts/dotnet-cli-build/dotnet-cli-build.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + d7b9695d-23eb-4ea8-b8ab-707a0092e1d5 Microsoft.DotNet.Cli.Build @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj index e5fda6870..68df775cf 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj +++ b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 61b7c351-c77d-43f7-b56f-bb1440178e10 Microsoft.DotNet.Cli.Utils @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj index 50899a805..e7b0225ee 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj +++ b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + a16958e1-24c7-4f1e-b317-204ad91625dd Microsoft.Dotnet.Cli.Compiler.Common @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj index 15a95077a..0dca981d4 100644 --- a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj +++ b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + d521dd9f-0614-4929-93b4-d8fa5682c174 Microsoft.DotNet.Files @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj index 2a323b565..2f07cc659 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj +++ b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + bd4f0750-4e81-4ad2-90b5-e470881792c3 Microsoft.DotNet.InternalAbstractions @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj index 51615b07a..049c639a2 100644 --- a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj +++ b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + c7af0290-ef0d-44dc-9edc-600803b664f8 Microsoft.DotNet.ProjectModel.Loader @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj index fa941946f..3227dea0a 100644 --- a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj +++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + bd7833f8-3209-4682-bf75-b4bca883e279 Microsoft.DotNet.ProjectModel.Workspaces @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj index d56e4bae5..c33400887 100644 --- a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj +++ b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 303677d5-7312-4c3f-baee-beb1a9bd9fe6 Microsoft.DotNet.ProjectModel @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj index 4fc8570fb..e6f1e6339 100644 --- a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj +++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0724ed7c-56e3-4604-9970-25e600611383 Microsoft.DotNet.TestFramework @@ -16,5 +16,5 @@ 2.0 - + diff --git a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj index 8e2d9aca8..8c6e7884f 100644 --- a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj +++ b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 688870c8-9843-4f9e-8576-d39290ad0f25 Microsoft.Extensions.DependencyModel @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj index 9d149a5c3..a364b40ec 100644 --- a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj +++ b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + dcdfe282-03de-4dbc-b90c-cc3ce3ec8162 Microsoft.Extensions.Testing.Abstractions @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-test/dotnet-test.xproj b/src/dotnet/commands/dotnet-test/dotnet-test.xproj index fcacb1dd3..7f173a43e 100644 --- a/src/dotnet/commands/dotnet-test/dotnet-test.xproj +++ b/src/dotnet/commands/dotnet-test/dotnet-test.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + f003f228-2ae2-4e9d-877b-93eb773b5061 ..\..\artifacts\obj\$(MSBuildProjectName) @@ -13,5 +13,5 @@ 2.0 - + \ No newline at end of file diff --git a/src/dotnet/dotnet.xproj b/src/dotnet/dotnet.xproj index a8a83293d..eb07f538d 100644 --- a/src/dotnet/dotnet.xproj +++ b/src/dotnet/dotnet.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 60cf7e6c-d6c8-439d-b7b7-d8a27e29be2c Microsoft.DotNet.Cli @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj b/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj index 6ccc31090..5b9cd4886 100644 --- a/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj +++ b/test/ArgumentForwardingTests/ArgumentForwardingTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6973e08d-11ec-49dc-82ef-d5effec7c6e9 Microsoft.DotNet.Tests.ArgumentForwarding @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/ArgumentsReflector/Reflector.xproj b/test/ArgumentsReflector/Reflector.xproj index 5c40febb9..06cbe2be6 100644 --- a/test/ArgumentsReflector/Reflector.xproj +++ b/test/ArgumentsReflector/Reflector.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 6f2e6f25-b43b-495d-9ca5-7f207d1dd604 Microsoft.DotNet.Tests.ArgumentForwarding @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/EndToEnd/EndToEnd.xproj b/test/EndToEnd/EndToEnd.xproj index d3dcb255f..cfee5a0ea 100644 --- a/test/EndToEnd/EndToEnd.xproj +++ b/test/EndToEnd/EndToEnd.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 65741cb1-8aee-4c66-8198-10a7ea0e4258 Microsoft.DotNet.Tests.EndToEnd @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj index 989b970a6..64ee27ba4 100644 --- a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj +++ b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0B31C336-149D-471A-B7B1-27B0F1E80F83 Microsoft.DotNet.Cli.Msi.Tests @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj b/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj index 2d287f25f..e7b914485 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/Microsoft.DotNet.Cli.Utils.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 09c52f96-efdd-4448-95ec-6d362dd60baa Microsoft.DotNet.Cli.Utils @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj b/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj index 8d39d9bb5..297d01c2b 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/Microsoft.DotNet.Compiler.Common.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 44e7d1ac-dcf1-4a18-9c22-f09e6bb302b5 Microsoft.DotNet.Cli.Utils @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj b/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj index b2001d9f8..f0b4029a5 100644 --- a/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj +++ b/test/Microsoft.DotNet.ProjectModel.Tests/Microsoft.DotNet.ProjectModel.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 0745410a-6629-47eb-aab5-08d6288cad72 Microsoft.DotNet.ProjectModel.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj index 48a117951..19010ace5 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Test.Utilities.xproj @@ -5,7 +5,7 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + e4f46eab-b5a5-4e60-9b9d-40a1fadbf45c Microsoft.DotNet.Tools.Test.Utilities @@ -16,5 +16,5 @@ 2.0 - + diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj b/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj index 5b7cd1e50..f6f7d2856 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj +++ b/test/Microsoft.Extensions.DependencyModel.Tests/Microsoft.Extensions.DependencyModel.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 4a4711d8-4312-49fc-87b5-4f183f4c6a51 Microsoft.Extensions.DependencyModel.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/ScriptExecutorTests/ScriptExecutorTests.xproj b/test/ScriptExecutorTests/ScriptExecutorTests.xproj index b3c5668f3..e114297b9 100644 --- a/test/ScriptExecutorTests/ScriptExecutorTests.xproj +++ b/test/ScriptExecutorTests/ScriptExecutorTests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48833333 Microsoft.DotNet.Cli.Utils.ScriptExecutorTests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-build.Tests/dotnet-build.Tests.xproj b/test/dotnet-build.Tests/dotnet-build.Tests.xproj index a3aca10c4..b23863bda 100644 --- a/test/dotnet-build.Tests/dotnet-build.Tests.xproj +++ b/test/dotnet-build.Tests/dotnet-build.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48833333 Microsoft.DotNet.Tools.Builder.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj b/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj index 93ffc1f97..109254497 100644 --- a/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj +++ b/test/dotnet-compile.Tests/dotnet-compile.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 833ffee1-7eed-4f51-8dfd-946d48893d6e Microsoft.DotNet.Tools.Compiler.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj b/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj index 87bee84c4..458f8ad82 100644 --- a/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj +++ b/test/dotnet-compile.UnitTests/dotnet-compile.UnitTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 920b71d8-62da-4f5e-8a26-926c113f1d97 dotnet-compile.UnitTests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj b/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj index 0dd8575bb..b0d2ba45f 100644 --- a/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj +++ b/test/dotnet-pack.Tests/dotnet-pack.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 5fda6d37-3a3e-4333-ba5c-f0b28be316f4 dotnet-pack.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj b/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj index cc567f6fd..29f474eb4 100644 --- a/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj +++ b/test/dotnet-projectmodel-server.Tests/dotnet-projectmodel-server.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 11c77123-e4da-499f-8900-80c88c2c69f2 Microsoft.DotNet.ProjectModel.Server.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj b/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj index 55201e8b1..5300386c1 100644 --- a/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj +++ b/test/dotnet-publish.Tests/dotnet-publish.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 386d412c-003c-47b1-8258-0e35865cb7c4 Microsoft.DotNet.Tools.Publish.Tests @@ -18,5 +18,5 @@ - + \ No newline at end of file diff --git a/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj b/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj index 7ca087810..279ade660 100644 --- a/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj +++ b/test/dotnet-resgen.Tests/dotnet-resgen.Tests.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 386d412c-003c-47b1-8258-0e35865cb7c4 Microsoft.DotNet.Tools.Resgen.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-run.Tests/dotnet-run.Tests.xproj b/test/dotnet-run.Tests/dotnet-run.Tests.xproj index 1921817f6..a48fde4f7 100644 --- a/test/dotnet-run.Tests/dotnet-run.Tests.xproj +++ b/test/dotnet-run.Tests/dotnet-run.Tests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 35e3c2dc-9b38-4ec5-8dd7-c32458dc485f dotnet-run.Tests @@ -15,5 +15,5 @@ 2.0 - + \ No newline at end of file diff --git a/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj b/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj index b54973d91..968a14550 100644 --- a/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj +++ b/test/dotnet-test.UnitTests/dotnet-test.UnitTests.xproj @@ -4,7 +4,7 @@ 14.0.24720 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 857274ac-e741-4266-a7fd-14dee0c1cc96 Microsoft.Dotnet.Tools.Test.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/test/dotnet.Tests/dotnet.Tests.xproj b/test/dotnet.Tests/dotnet.Tests.xproj index 5727980e1..35608f3d2 100644 --- a/test/dotnet.Tests/dotnet.Tests.xproj +++ b/test/dotnet.Tests/dotnet.Tests.xproj @@ -4,7 +4,7 @@ 14.0.23107 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + cb710268-4a82-48e4-9531-faf1c8f78f4b Microsoft.DotNet.Tests @@ -17,5 +17,5 @@ - + \ No newline at end of file diff --git a/tools/MultiProjectValidator/MultiProjectValidator.xproj b/tools/MultiProjectValidator/MultiProjectValidator.xproj index a940c18c6..27627c2bb 100644 --- a/tools/MultiProjectValidator/MultiProjectValidator.xproj +++ b/tools/MultiProjectValidator/MultiProjectValidator.xproj @@ -4,7 +4,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - + 08a68c6a-86f6-4ed2-89a7-b166d33e9f85 ProjectSanity @@ -14,5 +14,5 @@ 2.0 - + \ No newline at end of file From 570e348edf74e365fa36cc02b11df7ebe2b17aa2 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 10:59:17 -0700 Subject: [PATCH 70/99] Make corehost pick pre-release SDK version when no production releases. Also fix STL crash. --- src/corehost/cli/args.cpp | 6 ++- src/corehost/cli/fxr/fx_muxer.cpp | 63 ++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/corehost/cli/args.cpp b/src/corehost/cli/args.cpp index 569110857..40ebd24be 100644 --- a/src/corehost/cli/args.cpp +++ b/src/corehost/cli/args.cpp @@ -87,8 +87,10 @@ bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_ args.app_argc -= num_args; args.app_argv += num_args; - pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : deps_path; - pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : probe_dir; + pal::string_t opts_deps_file = _X("--depsfile"); + pal::string_t opts_probe_path = _X("--additionalprobingpath"); + pal::string_t deps_file = opts.count(opts_deps_file) ? opts[opts_deps_file] : deps_path; + pal::string_t probe_path = opts.count(opts_probe_path) ? opts[opts_probe_path] : probe_dir; if (!deps_file.empty()) { diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 84ae55c1b..8012d09c4 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -98,6 +98,42 @@ pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) return retval; } +pal::string_t resolve_sdk_version(pal::string_t sdk_path) +{ + pal::string_t retval; + std::vector versions; + + pal::readdir(sdk_path, &versions); + fx_ver_t max_ver(-1, -1, -1); + fx_ver_t max_pre(-1, -1, -1); + for (const auto& version : versions) + { + fx_ver_t ver(-1, -1, -1); + if (fx_ver_t::parse(version, &ver, true)) + { + max_ver = std::max(ver, max_ver); + } + if (fx_ver_t::parse(version, &ver, false)) + { + max_pre = std::max(ver, max_pre); + } + } + + // No production, use the max pre-release. + if (max_ver == fx_ver_t(-1, -1, -1)) + { + max_ver = max_pre; + } + + pal::string_t max_ver_str = max_ver.as_str(); + append_path(&sdk_path, max_ver_str.c_str()); + if (pal::directory_exists(sdk_path)) + { + retval = sdk_path; + } + return retval; +} + bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk) { pal::string_t cwd; @@ -139,24 +175,7 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri { pal::string_t sdk_path = own_dir; append_path(&sdk_path, _X("sdk")); - - std::vector versions; - pal::readdir(sdk_path, &versions); - fx_ver_t max_ver(-1, -1, -1); - for (const auto& version : versions) - { - fx_ver_t ver(-1, -1, -1); - if (fx_ver_t::parse(version, &ver, true)) - { - max_ver = std::max(ver, max_ver); - } - } - pal::string_t max_ver_str = max_ver.as_str(); - append_path(&sdk_path, max_ver_str.c_str()); - if (pal::directory_exists(sdk_path)) - { - retval = sdk_path; - } + retval = resolve_sdk_version(sdk_path); } cli_sdk->assign(retval); trace::verbose(_X("Found cli sdk in: %s"), cli_sdk->c_str()); @@ -232,8 +251,10 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) memcpy(new_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*)); new_argv[0] = argv[0]; - pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : _X(""); - pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : _X(""); + pal::string_t opts_deps_file = _X("--depsfile"); + pal::string_t opts_probe_path = _X("--additionalprobingpath"); + pal::string_t deps_file = opts.count(opts_deps_file) ? opts[opts_deps_file] : _X(""); + pal::string_t probe_path = opts.count(opts_probe_path) ? opts[opts_probe_path] : _X(""); pal::string_t app_path = argv[cur_i]; runtime_config_t config(get_runtime_config_json(app_path)); @@ -295,4 +316,4 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[]) { trace::setup(); return fx_muxer_t().execute(argc, argv); -} +} \ No newline at end of file From 897f669ec01ed52c85343d5ddaf79e423fa3d79b Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 11:12:45 -0700 Subject: [PATCH 71/99] Remove the hack to layout CLI SDK into a production version path. Go back to using a nuget version path. --- scripts/dotnet-cli-build/PackageTargets.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 0284a5dc6..f58549a1d 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -52,12 +52,7 @@ namespace Microsoft.DotNet.Cli.Build [Target] public static BuildTargetResult CopyCLISDKLayout(BuildTargetContext c) { - // CLI SDK must be layed out in path which has a Nuget version. - // But the muxer does not currently support the pre-release CLI SDK without a global.json file. - // So we are creating a production version. - // var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; - var nugetVersion = c.BuildContext.Get("BuildVersion").ProductionVersion; - + var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; var cliSdkRoot = Path.Combine(Dirs.Output, "obj", "clisdk"); var cliSdk = Path.Combine(cliSdkRoot, "sdk", nugetVersion); From d4bbdaa37a1909d7dab6dcb0bb460af26d0d879b Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 11:30:56 -0700 Subject: [PATCH 72/99] Update PackageTargets.cs Fix to create CLI SDK tarballs on unix. --- scripts/dotnet-cli-build/PackageTargets.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 0284a5dc6..df63a4462 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -150,6 +150,7 @@ namespace Microsoft.DotNet.Cli.Build { CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); + CreateTarBallFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); From 1cbec5a49491f20f933785a5f368ecc57af59d4b Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 16 Mar 2016 11:57:14 -0700 Subject: [PATCH 73/99] Generate embedded deps file that previos versions of DependencyModel can use --- src/dotnet/commands/dotnet-compile/ManagedCompiler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs index 2bff5ba89..46b7d7cb1 100644 --- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs +++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs @@ -114,7 +114,7 @@ namespace Microsoft.DotNet.Tools.Compiler var dependencyContext = new DependencyContextBuilder().Build(compilationOptions, allExports, allExports, - true, // For now, just assume portable mode in the legacy deps file (this is going away soon anyway) + false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway) context.TargetFramework, context.RuntimeIdentifier ?? string.Empty); From 88fc96803ace3ebe583910522d35dc1a41154ea1 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Wed, 16 Mar 2016 14:05:46 -0700 Subject: [PATCH 74/99] update README links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b60817d4a..5f0ff2628 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Installers |---------|:------:|:------:|:------:|:------:|:------:|:------:| |**Version**|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Ubuntu_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/Windows_x86_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/OSX_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/CentOS_x64_Release_version_badge.svg)|![](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/RHEL_x64_Release_version_badge.svg)| |**Installers**|[Download Debian Package](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-ubuntu-x64.latest.deb)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x64.latest.exe)|[Download Installer](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-win-x86.latest.exe)|[Download Pkg](https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-osx-x64.latest.pkg) |N/A |N/A | -|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-rhel-x64.latest.tar.gz) | +|**Binaries**|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-ubuntu-x64.latest.tar.gz)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-win-x64.latest.zip)|[Download zip file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-win-x86.latest.zip)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-osx-x64.latest.tar.gz) |[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-centos-x64.latest.tar.gz)|[Download tar file](https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-combined-framework-sdk-host-rhel-x64.latest.tar.gz) | Interested in .NET Core + ASP.NET Core 1.0 RC1 bits? ---------------------------------------------------- From 0a5d95d2add2f9820db418e01ba32b8f8b5788ec Mon Sep 17 00:00:00 2001 From: Senthil Date: Wed, 16 Mar 2016 14:09:29 -0700 Subject: [PATCH 75/99] Fix casing of shared and add DT_DIR to readdir --- src/corehost/cli/fxr/fx_muxer.cpp | 2 +- src/corehost/common/pal.unix.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 8012d09c4..75a195982 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -29,7 +29,7 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime } auto fx_dir = muxer_dir; - append_path(&fx_dir, _X("Shared")); + append_path(&fx_dir, _X("shared")); append_path(&fx_dir, fx_name.c_str()); // If not roll forward or if pre-release, just return. diff --git a/src/corehost/common/pal.unix.cpp b/src/corehost/common/pal.unix.cpp index a58ad8761..117b07a89 100644 --- a/src/corehost/common/pal.unix.cpp +++ b/src/corehost/common/pal.unix.cpp @@ -202,6 +202,7 @@ void pal::readdir(const pal::string_t& path, std::vector* list) // We are interested in files only switch (entry->d_type) { + case DT_DIR: case DT_REG: break; From cd2b638b18b8db75b79d05d5e4acac4ce96b9a5f Mon Sep 17 00:00:00 2001 From: Nate Amundson Date: Wed, 16 Mar 2016 14:39:02 -0700 Subject: [PATCH 76/99] Trigger automated DockerHub builds This change triggers automated DockerHub builds for successful official Ubuntu builds of rel.1.0.0. The DockerHub repo for this is https://hub.docker.com/r/microsoft/dotnet-preview/. The variables DOCKER_HUB_REPO and DOCKER_HUB_TRIGGER_TOKEN are set in the "DotNet-CLI-CI (Ubuntu) [rel.1.0.0]" VSTS build definition. This change also allows the Environment TargetConditionAttribute to be used to require that an environment variable is set, in addition to the existing functionality of being able to be used to require that an environment variable is equal to one of a set of specified values. --- .../TargetConditions/EnvironmentAttribute.cs | 21 ++++--- scripts/dotnet-cli-build/PublishTargets.cs | 63 +++++++++++++++---- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs index 2a9aea581..0a8455e5c 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/TargetConditions/EnvironmentAttribute.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Linq; namespace Microsoft.DotNet.Cli.Build.Framework { @@ -13,7 +13,11 @@ namespace Microsoft.DotNet.Cli.Build.Framework { if (string.IsNullOrEmpty(envVar)) { - throw new ArgumentNullException("envVar"); + throw new ArgumentNullException(nameof(envVar)); + } + if (expectedVals == null) + { + throw new ArgumentNullException(nameof(expectedVals)); } _envVar = envVar; @@ -24,15 +28,14 @@ namespace Microsoft.DotNet.Cli.Build.Framework { var actualVal = Environment.GetEnvironmentVariable(_envVar); - foreach (var expectedVal in _expectedVals) + if (_expectedVals.Any()) { - if (string.Equals(actualVal, expectedVal, StringComparison.Ordinal)) - { - return true; - } + return _expectedVals.Any(ev => string.Equals(actualVal, ev, StringComparison.Ordinal)); + } + else + { + return !string.IsNullOrEmpty(actualVal); } - - return false; } } } diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 04af2b35c..71051aebf 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -1,12 +1,9 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; +using System.Net.Http; +using System.Text; using Microsoft.DotNet.Cli.Build.Framework; -using Microsoft.Extensions.PlatformAbstractions; -using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; @@ -36,7 +33,8 @@ namespace Microsoft.DotNet.Cli.Build [Target(nameof(PrepareTargets.Init), nameof(PublishTargets.InitPublish), - nameof(PublishTargets.PublishArtifacts))] + nameof(PublishTargets.PublishArtifacts), + nameof(PublishTargets.TriggerDockerHubBuilds))] [Environment("PUBLISH_TO_AZURE_BLOB", "1", "true")] // This is set by CI systems public static BuildTargetResult Publish(BuildTargetContext c) { @@ -113,7 +111,7 @@ namespace Microsoft.DotNet.Cli.Build { var packageName = Monikers.GetDebianPackageName(c); var installerFile = c.BuildContext.Get("SdkInstallerFile"); - var uploadUrl = $"https://dotnetcli.blob.core.windows.net/dotnet/{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; + var uploadUrl = $"https://dotnetcli.blob.core.windows.net/dotnet/{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; var uploadJson = GenerateUploadJsonFile(packageName, Version, uploadUrl); Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "publish", "repoapi_client.sh"), "-addpkg", uploadJson) @@ -123,6 +121,45 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + [Environment("DOCKER_HUB_REPO")] + [Environment("DOCKER_HUB_TRIGGER_TOKEN")] + public static BuildTargetResult TriggerDockerHubBuilds(BuildTargetContext c) + { + string dockerHubRepo = Environment.GetEnvironmentVariable("DOCKER_HUB_REPO"); + string dockerHubTriggerToken = Environment.GetEnvironmentVariable("DOCKER_HUB_TRIGGER_TOKEN"); + + Uri baseDockerHubUri = new Uri("https://registry.hub.docker.com/u/"); + Uri dockerHubTriggerUri; + if (!Uri.TryCreate(baseDockerHubUri, $"{dockerHubRepo}/trigger/{dockerHubTriggerToken}/", out dockerHubTriggerUri)) + { + return c.Failed("Invalid DOCKER_HUB_REPO and/or DOCKER_HUB_TRIGGER_TOKEN"); + } + + c.Info($"Triggering automated DockerHub builds for {dockerHubRepo}"); + using (HttpClient client = new HttpClient()) + { + StringContent requestContent = new StringContent("{\"build\": true}", Encoding.UTF8, "application/json"); + try + { + HttpResponseMessage response = client.PostAsync(dockerHubTriggerUri, requestContent).Result; + if (!response.IsSuccessStatusCode) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"HTTP request to {dockerHubTriggerUri.ToString()} was unsuccessful."); + sb.AppendLine($"Response status code: {response.StatusCode}. Reason phrase: {response.ReasonPhrase}."); + sb.Append($"Respone content: {response.Content.ReadAsStringAsync().Result}"); + return c.Failed(sb.ToString()); + } + } + catch (AggregateException e) + { + return c.Failed($"HTTP request to {dockerHubTriggerUri.ToString()} failed. {e.ToString()}"); + } + } + return c.Success(); + } + private static string GenerateUploadJsonFile(string packageName, string version, string uploadUrl) { var repoID = Environment.GetEnvironmentVariable("REPO_ID"); @@ -133,12 +170,12 @@ namespace Microsoft.DotNet.Cli.Build { using (StreamWriter sw = new StreamWriter(fileStream)) { - sw.WriteLine("{"); - sw.WriteLine($" \"name\":\"{packageName}\","); - sw.WriteLine($" \"version\":\"{version}\","); - sw.WriteLine($" \"repositoryId\":\"{repoID}\","); - sw.WriteLine($" \"sourceUrl\":\"{uploadUrl}\""); - sw.WriteLine("}"); + sw.WriteLine("{"); + sw.WriteLine($" \"name\":\"{packageName}\","); + sw.WriteLine($" \"version\":\"{version}\","); + sw.WriteLine($" \"repositoryId\":\"{repoID}\","); + sw.WriteLine($" \"sourceUrl\":\"{uploadUrl}\""); + sw.WriteLine("}"); } } From 4d19e4d86644fd5cebacd9dbe9213f43996288ad Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 15:54:02 -0700 Subject: [PATCH 77/99] Layout CLI SDK, Shared Fx and Muxer in stage1 and stage2. --- scripts/dotnet-cli-build/CompileTargets.cs | 247 ++++++++++++++++++-- scripts/dotnet-cli-build/Utils/DotNetCli.cs | 6 +- 2 files changed, 225 insertions(+), 28 deletions(-) diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index 7c6c80bb4..f78b0a2a8 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -7,6 +7,8 @@ using Microsoft.Extensions.PlatformAbstractions; using static Microsoft.DotNet.Cli.Build.FS; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; +using System.Text.RegularExpressions; +using System.Reflection.PortableExecutable; namespace Microsoft.DotNet.Cli.Build { @@ -45,6 +47,12 @@ namespace Microsoft.DotNet.Cli.Build "Microsoft.Extensions.Testing.Abstractions" }; + public const string SharedFrameworkName = "Microsoft.NETCore.App"; + + private static string CoreHostBaseName => $"corehost{Constants.ExeSuffix}"; + private static string DotnetHostFxrBaseName => $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"; + private static string HostPolicyBaseName => $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"; + // Updates the stage 2 with recent changes. [Target(nameof(PrepareTargets.Init), nameof(CompileStage2))] public static BuildTargetResult UpdateBuild(BuildTargetContext c) @@ -118,9 +126,9 @@ namespace Microsoft.DotNet.Cli.Build rid); // Copy the output out - File.Copy(Path.Combine(cmakeOut, "cli", "corehost"), Path.Combine(Dirs.Corehost, "corehost"), overwrite: true); - File.Copy(Path.Combine(cmakeOut, "cli", "dll", $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); - File.Copy(Path.Combine(cmakeOut, "cli", "fxr", $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "corehost"), Path.Combine(Dirs.Corehost, CoreHostBaseName), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "dll", DotnetHostFxrBaseName), Path.Combine(Dirs.Corehost, DotnetHostFxrBaseName), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "fxr", HostPolicyBaseName), Path.Combine(Dirs.Corehost, HostPolicyBaseName), overwrite: true); } return c.Success(); @@ -131,7 +139,16 @@ namespace Microsoft.DotNet.Cli.Build { CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src")); CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test")); - return CompileStage(c, + + if (Directory.Exists(Dirs.Stage1)) + { + Utils.DeleteDirectory(Dirs.Stage1); + } + Directory.CreateDirectory(Dirs.Stage1); + + CopySharedHost(Dirs.Stage1); + PackageSharedFramework(c, Dirs.Stage1, DotNetCli.Stage0); + return CompileCliSdk(c, dotnet: DotNetCli.Stage0, outputDir: Dirs.Stage1); } @@ -143,7 +160,16 @@ namespace Microsoft.DotNet.Cli.Build CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src")); CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test")); - var result = CompileStage(c, + + if (Directory.Exists(Dirs.Stage2)) + { + Utils.DeleteDirectory(Dirs.Stage2); + } + Directory.CreateDirectory(Dirs.Stage2); + + PackageSharedFramework(c, Dirs.Stage2, DotNetCli.Stage1); + CopySharedHost(Dirs.Stage2); + var result = CompileCliSdk(c, dotnet: DotNetCli.Stage1, outputDir: Dirs.Stage2); @@ -174,15 +200,134 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - private static BuildTargetResult CompileStage(BuildTargetContext c, DotNetCli dotnet, string outputDir) + private static void CopySharedHost(string outputDir) { - Rmdir(outputDir); + // corehost will be renamed to dotnet at some point and then this can be removed. + File.Copy( + Path.Combine(Dirs.Corehost, CoreHostBaseName), + Path.Combine(outputDir, $"dotnet{Constants.ExeSuffix}"), true); + File.Copy( + Path.Combine(Dirs.Corehost, DotnetHostFxrBaseName), + Path.Combine(outputDir, DotnetHostFxrBaseName), true); + } + public static void PackageSharedFramework(BuildTargetContext c, string outputDir, DotNetCli dotnetCli) + { + string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"); + string SharedFrameworkNugetVersion = GetVersionFromProjectJson(Path.Combine(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"), "project.json")); + + // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. + string SharedFrameworkNameAndVersionRoot = Path.Combine(outputDir, "shared", SharedFrameworkName, SharedFrameworkNugetVersion); + + if (Directory.Exists(SharedFrameworkNameAndVersionRoot)) + { + Utils.DeleteDirectory(SharedFrameworkNameAndVersionRoot); + } + + string publishFramework = "dnxcore50"; // Temporary, use "netcoreapp" when we update nuget. + string publishRuntime; + if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows) + { + publishRuntime = $"win7-{PlatformServices.Default.Runtime.RuntimeArchitecture}"; + } + else + { + publishRuntime = PlatformServices.Default.Runtime.GetRuntimeIdentifier(); + } + + dotnetCli.Publish( + "--output", SharedFrameworkNameAndVersionRoot, + "-r", publishRuntime, + "-f", publishFramework, + SharedFrameworkSourceRoot).Execute().EnsureSuccessful(); + + // Clean up artifacts that dotnet-publish generates which we don't need + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb")); + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.runtimeconfig.json")); + + // Rename the .deps file + var destinationDeps = Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json"); + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); + File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps); + + // Generate RID fallback graph + string runtimeGraphGeneratorRuntime = null; + switch (PlatformServices.Default.Runtime.OperatingSystemPlatform) + { + case Platform.Windows: + runtimeGraphGeneratorRuntime = "win"; + break; + case Platform.Linux: + runtimeGraphGeneratorRuntime = "linux"; + break; + case Platform.Darwin: + runtimeGraphGeneratorRuntime = "osx"; + break; + } + if (!string.IsNullOrEmpty(runtimeGraphGeneratorRuntime)) + { + var runtimeGraphGeneratorName = "RuntimeGraphGenerator"; + var runtimeGraphGeneratorProject = Path.Combine(Dirs.RepoRoot, "tools", runtimeGraphGeneratorName); + var runtimeGraphGeneratorOutput = Path.Combine(Dirs.Output, "tools", runtimeGraphGeneratorName); + + dotnetCli.Publish( + "--output", runtimeGraphGeneratorOutput, + runtimeGraphGeneratorProject).Execute().EnsureSuccessful(); + var runtimeGraphGeneratorExe = Path.Combine(runtimeGraphGeneratorOutput, $"{runtimeGraphGeneratorName}{Constants.ExeSuffix}"); + + Cmd(runtimeGraphGeneratorExe, "--project", SharedFrameworkSourceRoot, "--deps", destinationDeps, runtimeGraphGeneratorRuntime) + .Execute(); + } + else + { + c.Error($"Could not determine rid graph generation runtime for platform {PlatformServices.Default.Runtime.OperatingSystemPlatform}"); + } + + // corehost will be renamed to dotnet at some point and then we will not need to rename it here. + File.Copy( + Path.Combine(Dirs.Corehost, CoreHostBaseName), + Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); + File.Copy( + Path.Combine(Dirs.Corehost, HostPolicyBaseName), + Path.Combine(SharedFrameworkNameAndVersionRoot, HostPolicyBaseName), true); + + if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll"))) + { + // Publish already places the crossgen'd version of mscorlib into the output, so we can + // remove the IL version + File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll")); + } + + CrossgenSharedFx(c, SharedFrameworkNameAndVersionRoot); + } + + private static string GetVersionFromProjectJson(string pathToProjectJson) + { + Regex r = new Regex($"\"{Regex.Escape(SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\""); + + foreach (var line in File.ReadAllLines(pathToProjectJson)) + { + var m = r.Match(line); + + if (m.Success) + { + return m.Groups["version"].Value; + } + } + + throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); + } + + private static BuildTargetResult CompileCliSdk(BuildTargetContext c, DotNetCli dotnet, string outputDir) + { var configuration = c.BuildContext.Get("Configuration"); - var binDir = Path.Combine(outputDir, "bin"); - var buildVesion = c.BuildContext.Get("BuildVersion"); + var buildVersion = c.BuildContext.Get("BuildVersion"); + outputDir = Path.Combine(outputDir, "sdk", buildVersion.NuGetVersion); - Mkdirp(binDir); + Rmdir(outputDir); + Mkdirp(outputDir); foreach (var project in ProjectsToPublish) { @@ -191,11 +336,11 @@ namespace Microsoft.DotNet.Cli.Build dotnet.Publish( "--native-subdirectory", "--output", - binDir, + outputDir, "--configuration", configuration, Path.Combine(c.BuildContext.BuildDirectory, "src", project)) - .Environment("DOTNET_BUILD_VERSION", buildVesion.VersionSuffix) + .Environment("DOTNET_BUILD_VERSION", buildVersion.VersionSuffix) .Execute() .EnsureSuccessful(); } @@ -203,9 +348,9 @@ namespace Microsoft.DotNet.Cli.Build FixModeFlags(outputDir); // Copy corehost - File.Copy(Path.Combine(Dirs.Corehost, $"corehost{Constants.ExeSuffix}"), Path.Combine(binDir, $"corehost{Constants.ExeSuffix}"), overwrite: true); - File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); - File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); + File.Copy(Path.Combine(Dirs.Corehost, $"corehost{Constants.ExeSuffix}"), Path.Combine(outputDir, $"corehost{Constants.ExeSuffix}"), overwrite: true); + File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(outputDir, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); + File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(outputDir, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); // Corehostify binaries foreach (var binaryToCorehostify in BinariesForCoreHost) @@ -213,9 +358,9 @@ namespace Microsoft.DotNet.Cli.Build try { // Yes, it is .exe even on Linux. This is the managed exe we're working with - File.Copy(Path.Combine(binDir, $"{binaryToCorehostify}.exe"), Path.Combine(binDir, $"{binaryToCorehostify}.dll")); - File.Delete(Path.Combine(binDir, $"{binaryToCorehostify}.exe")); - File.Copy(Path.Combine(binDir, $"corehost{Constants.ExeSuffix}"), Path.Combine(binDir, binaryToCorehostify + Constants.ExeSuffix)); + File.Copy(Path.Combine(outputDir, $"{binaryToCorehostify}.exe"), Path.Combine(outputDir, $"{binaryToCorehostify}.dll")); + File.Delete(Path.Combine(outputDir, $"{binaryToCorehostify}.exe")); + File.Copy(Path.Combine(outputDir, $"corehost{Constants.ExeSuffix}"), Path.Combine(outputDir, binaryToCorehostify + Constants.ExeSuffix)); } catch (Exception ex) { @@ -224,25 +369,25 @@ namespace Microsoft.DotNet.Cli.Build } // dotnet.exe is from stage0. But we must be using the newly built corehost in stage1 - File.Delete(Path.Combine(binDir, $"dotnet{Constants.ExeSuffix}")); - File.Copy(Path.Combine(binDir, $"corehost{Constants.ExeSuffix}"), Path.Combine(binDir, $"dotnet{Constants.ExeSuffix}")); + File.Delete(Path.Combine(outputDir, $"dotnet{Constants.ExeSuffix}")); + File.Copy(Path.Combine(outputDir, $"corehost{Constants.ExeSuffix}"), Path.Combine(outputDir, $"dotnet{Constants.ExeSuffix}")); // Crossgen Roslyn - var result = Crossgen(c, binDir); + var result = CrossgenCliSdk(c, outputDir); if (!result.Success) { return result; } // Copy AppDeps - result = CopyAppDeps(c, binDir); + result = CopyAppDeps(c, outputDir); if (!result.Success) { return result; } // Generate .version file - var version = buildVesion.SimpleVersion; + var version = buildVersion.SimpleVersion; var content = $@"{c.BuildContext["CommitHash"]}{Environment.NewLine}{version}{Environment.NewLine}"; File.WriteAllText(Path.Combine(outputDir, ".version"), content); @@ -296,12 +441,12 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - private static BuildTargetResult Crossgen(BuildTargetContext c, string outputDir) + private static BuildTargetResult CrossgenCliSdk(BuildTargetContext c, string outputDir) { // Check if we need to skip crossgen if (string.Equals(Environment.GetEnvironmentVariable("DOTNET_BUILD_SKIP_CROSSGEN"), "1")) { - c.Warn("Skipping crossgen because DOTNET_BUILD_SKIP_CROSSGEN is set"); + c.Warn("Skipping crossgen for Cli Sdk because DOTNET_BUILD_SKIP_CROSSGEN is set"); return c.Success(); } @@ -346,6 +491,58 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + public static BuildTargetResult CrossgenSharedFx(BuildTargetContext c, string pathToAssemblies) + { + // Check if we need to skip crossgen + if (!string.Equals(Environment.GetEnvironmentVariable("CROSSGEN_SHAREDFRAMEWORK"), "1")) + { + c.Warn("Skipping crossgen for SharedFx because CROSSGEN_SHAREDFRAMEWORK is not set to 1"); + return c.Success(); + } + + foreach (var file in Directory.GetFiles(pathToAssemblies)) + { + string fileName = Path.GetFileName(file); + + if (fileName == "mscorlib.dll" || fileName == "mscorlib.ni.dll" || !HasMetadata(file)) + { + continue; + } + + string tempPathName = Path.ChangeExtension(file, "readytorun"); + + // This is not always correct. The version of crossgen we need to pick up is whatever one was restored as part + // of the Microsoft.NETCore.Runtime.CoreCLR package that is part of the shared library. For now, the version hardcoded + // in CompileTargets and the one in the shared library project.json match and are updated in lock step, but long term + // we need to be able to look at the project.lock.json file and figure out what version of Microsoft.NETCore.Runtime.CoreCLR + // was used, and then select that version. + ExecSilent(Crossgen.GetCrossgenPathForVersion(CompileTargets.CoreCLRVersion), + "-readytorun", "-in", file, "-out", tempPathName, "-platform_assemblies_paths", pathToAssemblies); + + File.Delete(file); + File.Move(tempPathName, file); + } + + return c.Success(); + } + + private static bool HasMetadata(string pathToFile) + { + try + { + using (var inStream = File.OpenRead(pathToFile)) + { + using (var peReader = new PEReader(inStream)) + { + return peReader.HasMetadata; + } + } + } + catch (BadImageFormatException) { } + + return false; + } + private static List GetAssembliesToCrossGen() { return new List diff --git a/scripts/dotnet-cli-build/Utils/DotNetCli.cs b/scripts/dotnet-cli-build/Utils/DotNetCli.cs index a84ec89dc..01e618fac 100644 --- a/scripts/dotnet-cli-build/Utils/DotNetCli.cs +++ b/scripts/dotnet-cli-build/Utils/DotNetCli.cs @@ -7,11 +7,11 @@ using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.DotNet.Cli.Build { - internal class DotNetCli + public class DotNetCli { public static readonly DotNetCli Stage0 = new DotNetCli(GetStage0Path()); - public static readonly DotNetCli Stage1 = new DotNetCli(Path.Combine(Dirs.Stage1, "bin")); - public static readonly DotNetCli Stage2 = new DotNetCli(Path.Combine(Dirs.Stage2, "bin")); + public static readonly DotNetCli Stage1 = new DotNetCli(Dirs.Stage1); + public static readonly DotNetCli Stage2 = new DotNetCli(Dirs.Stage2); public string BinPath { get; } From 665dc9bcce360fa8e51c0b20e59f5aca3473bb49 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Wed, 16 Mar 2016 16:31:38 -0700 Subject: [PATCH 78/99] Add null checks everywhere in dependency model --- .../CompilationLibrary.cs | 4 ++++ .../CompilationOptions.cs | 11 +++++++--- .../Dependency.cs | 9 ++++++++ .../DependencyContext.cs | 8 ++----- .../DependencyContextCsvReader.cs | 4 ++++ .../DependencyContextJsonReader.cs | 4 ++++ .../DependencyContextLoader.cs | 4 ++-- .../DependencyContextWriter.cs | 8 +++++++ .../Library.cs | 22 +++++++++++++++++++ .../ResourceAssembly.cs | 10 +++++++++ .../RuntimeAssembly.cs | 8 +++++++ .../RuntimeFallbacks.cs | 4 ++-- .../RuntimeLibrary.cs | 21 ++++++++++++++++-- .../RuntimeTarget.cs | 13 +++++++++++ 14 files changed, 115 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Extensions.DependencyModel/CompilationLibrary.cs b/src/Microsoft.Extensions.DependencyModel/CompilationLibrary.cs index 2a85c2f8e..435068ceb 100644 --- a/src/Microsoft.Extensions.DependencyModel/CompilationLibrary.cs +++ b/src/Microsoft.Extensions.DependencyModel/CompilationLibrary.cs @@ -19,6 +19,10 @@ namespace Microsoft.Extensions.DependencyModel bool serviceable) : base(type, name, version, hash, dependencies, serviceable) { + if (assemblies == null) + { + throw new ArgumentNullException(nameof(assemblies)); + } Assemblies = assemblies.ToArray(); } diff --git a/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs b/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs index d887671cc..f37e553cb 100644 --- a/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs +++ b/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs @@ -1,6 +1,7 @@ // 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.Linq; @@ -8,7 +9,7 @@ namespace Microsoft.Extensions.DependencyModel { public class CompilationOptions { - public IEnumerable Defines { get; } + public IReadOnlyList Defines { get; } public string LanguageVersion { get; } @@ -26,7 +27,7 @@ namespace Microsoft.Extensions.DependencyModel public bool? PublicSign { get; } - public string DebugType { get; } + public string DebugType { get; } public bool? EmitEntryPoint { get; } @@ -59,7 +60,11 @@ namespace Microsoft.Extensions.DependencyModel bool? emitEntryPoint, bool? generateXmlDocumentation) { - Defines = defines; + if (defines == null) + { + throw new ArgumentNullException(nameof(defines)); + } + Defines = defines.ToArray(); LanguageVersion = languageVersion; Platform = platform; AllowUnsafe = allowUnsafe; diff --git a/src/Microsoft.Extensions.DependencyModel/Dependency.cs b/src/Microsoft.Extensions.DependencyModel/Dependency.cs index 8060cb4b1..76a75fa74 100644 --- a/src/Microsoft.Extensions.DependencyModel/Dependency.cs +++ b/src/Microsoft.Extensions.DependencyModel/Dependency.cs @@ -1,6 +1,7 @@ // 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 Microsoft.Extensions.Internal; namespace Microsoft.Extensions.DependencyModel @@ -9,6 +10,14 @@ namespace Microsoft.Extensions.DependencyModel { public Dependency(string name, string version) { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException(nameof(name)); + } + if (string.IsNullOrEmpty(version)) + { + throw new ArgumentException(nameof(version)); + } Name = name; Version = version; } diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs index f4f3e34ba..d955b02e1 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs @@ -21,13 +21,9 @@ namespace Microsoft.Extensions.DependencyModel IEnumerable runtimeLibraries, IEnumerable runtimeGraph) { - if (targetFramework == null) + if (string.IsNullOrEmpty(targetFramework)) { - throw new ArgumentNullException(nameof(targetFramework)); - } - if (runtime == null) - { - throw new ArgumentNullException(nameof(runtime)); + throw new ArgumentException(nameof(targetFramework)); } if (compilationOptions == null) { diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs index 0e1e5e54a..f79199b99 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs @@ -13,6 +13,10 @@ namespace Microsoft.Extensions.DependencyModel { public DependencyContext Read(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } var lines = new List(); using (var reader = new StreamReader(stream)) { diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index 80ee0d8bd..ed8fd17da 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -14,6 +14,10 @@ namespace Microsoft.Extensions.DependencyModel { public DependencyContext Read(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } using (var streamReader = new StreamReader(stream)) { using (var reader = new JsonTextReader(streamReader)) diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs index 4a4256bb1..39e647d70 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.DependencyModel internal virtual bool IsEntryAssembly(Assembly assembly) { - return assembly.GetName() == Assembly.GetEntryAssembly().GetName(); + return assembly.GetName() == Assembly.GetEntryAssembly()?.GetName(); } internal virtual Stream GetResourceStream(Assembly assembly, string name) @@ -166,7 +166,7 @@ namespace Microsoft.Extensions.DependencyModel private static string[] GetHostDepsList() { - // TODO: Were going to replace this with AppContext.GetData + // TODO: We're going to replace this with AppContext.GetData var appDomainType = typeof(object).GetTypeInfo().Assembly?.GetType("System.AppDomain"); var currentDomain = appDomainType?.GetProperty("CurrentDomain")?.GetValue(null); var deps = appDomainType?.GetMethod("GetData")?.Invoke(currentDomain, new[] { "APP_CONTEXT_DEPS_FILES" }); diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs index ecc06a77b..1a6015359 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs @@ -16,6 +16,14 @@ namespace Microsoft.Extensions.DependencyModel { public void Write(DependencyContext context, Stream stream) { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } using (var writer = new StreamWriter(stream)) { using (var jsonWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }) diff --git a/src/Microsoft.Extensions.DependencyModel/Library.cs b/src/Microsoft.Extensions.DependencyModel/Library.cs index a3fefef42..a522a68e2 100644 --- a/src/Microsoft.Extensions.DependencyModel/Library.cs +++ b/src/Microsoft.Extensions.DependencyModel/Library.cs @@ -1,6 +1,7 @@ // 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.Linq; using System.Collections.Generic; @@ -10,6 +11,27 @@ namespace Microsoft.Extensions.DependencyModel { public Library(string type, string name, string version, string hash, IEnumerable dependencies, bool serviceable) { + if (string.IsNullOrEmpty(type)) + { + throw new ArgumentException(nameof(type)); + } + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException(nameof(name)); + } + if (string.IsNullOrEmpty(version)) + { + throw new ArgumentException(nameof(version)); + } + // Hash could be empty for projects + if (hash == null) + { + throw new ArgumentException(nameof(hash)); + } + if (dependencies == null) + { + throw new ArgumentNullException(nameof(dependencies)); + } Type = type; Name = name; Version = version; diff --git a/src/Microsoft.Extensions.DependencyModel/ResourceAssembly.cs b/src/Microsoft.Extensions.DependencyModel/ResourceAssembly.cs index 416ed20b1..4a59c054a 100644 --- a/src/Microsoft.Extensions.DependencyModel/ResourceAssembly.cs +++ b/src/Microsoft.Extensions.DependencyModel/ResourceAssembly.cs @@ -1,12 +1,22 @@ // 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; + namespace Microsoft.Extensions.DependencyModel { public class ResourceAssembly { public ResourceAssembly(string path, string locale) { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentException(nameof(path)); + } + if (string.IsNullOrEmpty(locale)) + { + throw new ArgumentException(nameof(locale)); + } Locale = locale; Path = path; } diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeAssembly.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeAssembly.cs index 4cfc002eb..196a36c17 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeAssembly.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeAssembly.cs @@ -15,6 +15,14 @@ namespace Microsoft.Extensions.DependencyModel public RuntimeAssembly(string assemblyName, string path) { + if (string.IsNullOrEmpty(assemblyName)) + { + throw new ArgumentException(nameof(assemblyName)); + } + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentException(nameof(path)); + } _assemblyName = assemblyName; Path = path; } diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs index 62f716ba2..d5ff52403 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs @@ -14,9 +14,9 @@ namespace Microsoft.Extensions.DependencyModel public RuntimeFallbacks(string runtime, IEnumerable fallbacks) { - if (runtime == null) + if (string.IsNullOrEmpty(runtime)) { - throw new ArgumentNullException(nameof(runtime)); + throw new ArgumentException(nameof(runtime)); } if (fallbacks == null) { diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs index c7858de26..cc7accd3e 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeLibrary.cs @@ -1,6 +1,7 @@ // 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.Linq; @@ -21,6 +22,22 @@ namespace Microsoft.Extensions.DependencyModel bool serviceable) : base(type, name, version, hash, dependencies, serviceable) { + if (assemblies == null) + { + throw new ArgumentNullException(nameof(assemblies)); + } + if (nativeLibraries == null) + { + throw new ArgumentNullException(nameof(nativeLibraries)); + } + if (resourceAssemblies == null) + { + throw new ArgumentNullException(nameof(resourceAssemblies)); + } + if (subTargets == null) + { + throw new ArgumentNullException(nameof(subTargets)); + } Assemblies = assemblies.ToArray(); ResourceAssemblies = resourceAssemblies.ToArray(); RuntimeTargets = subTargets.ToArray(); @@ -28,8 +45,8 @@ namespace Microsoft.Extensions.DependencyModel } public IReadOnlyList Assemblies { get; } - - public IReadOnlyList NativeLibraries { get; } + + public IReadOnlyList NativeLibraries { get; } public IReadOnlyList ResourceAssemblies { get; } diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeTarget.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeTarget.cs index 81771662b..709e1073d 100644 --- a/src/Microsoft.Extensions.DependencyModel/RuntimeTarget.cs +++ b/src/Microsoft.Extensions.DependencyModel/RuntimeTarget.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; @@ -7,6 +8,18 @@ namespace Microsoft.Extensions.DependencyModel { public RuntimeTarget(string runtime, IEnumerable assemblies, IEnumerable nativeLibraries) { + if (string.IsNullOrEmpty(runtime)) + { + throw new ArgumentException(nameof(runtime)); + } + if (assemblies == null) + { + throw new ArgumentNullException(nameof(assemblies)); + } + if (nativeLibraries == null) + { + throw new ArgumentNullException(nameof(nativeLibraries)); + } Runtime = runtime; Assemblies = assemblies.ToArray(); NativeLibraries = nativeLibraries.ToArray(); From 5150bae60c405bcb71d4a97bb13cbb92202233a0 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 17:54:44 -0700 Subject: [PATCH 79/99] Fix Package targets to respect the new CLI SDK layout. --- scripts/dotnet-cli-build/CompileTargets.cs | 31 +-- scripts/dotnet-cli-build/InstallerTargets.cs | 2 +- scripts/dotnet-cli-build/MsiTargets.cs | 4 +- scripts/dotnet-cli-build/PackageTargets.cs | 84 ++++--- scripts/dotnet-cli-build/PkgTargets.cs | 10 +- scripts/dotnet-cli-build/PrepareTargets.cs | 25 +- .../SharedFrameworkTargets.cs | 218 ------------------ scripts/dotnet-cli-build/Utils/Monikers.cs | 6 +- scripts/dotnet-cli-build/Utils/Utils.cs | 9 +- test/Installer/testmsi.ps1 | 2 +- 10 files changed, 100 insertions(+), 291 deletions(-) delete mode 100644 scripts/dotnet-cli-build/SharedFrameworkTargets.cs diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index f78b0a2a8..d05bf4e2c 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -139,7 +139,7 @@ namespace Microsoft.DotNet.Cli.Build { CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src")); CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test")); - + if (Directory.Exists(Dirs.Stage1)) { Utils.DeleteDirectory(Dirs.Stage1); @@ -147,7 +147,7 @@ namespace Microsoft.DotNet.Cli.Build Directory.CreateDirectory(Dirs.Stage1); CopySharedHost(Dirs.Stage1); - PackageSharedFramework(c, Dirs.Stage1, DotNetCli.Stage0); + PublishSharedFramework(c, Dirs.Stage1, DotNetCli.Stage0); return CompileCliSdk(c, dotnet: DotNetCli.Stage0, outputDir: Dirs.Stage1); @@ -160,14 +160,14 @@ namespace Microsoft.DotNet.Cli.Build CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src")); CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test")); - + if (Directory.Exists(Dirs.Stage2)) { Utils.DeleteDirectory(Dirs.Stage2); } Directory.CreateDirectory(Dirs.Stage2); - PackageSharedFramework(c, Dirs.Stage2, DotNetCli.Stage1); + PublishSharedFramework(c, Dirs.Stage2, DotNetCli.Stage1); CopySharedHost(Dirs.Stage2); var result = CompileCliSdk(c, dotnet: DotNetCli.Stage1, @@ -211,10 +211,10 @@ namespace Microsoft.DotNet.Cli.Build Path.Combine(outputDir, DotnetHostFxrBaseName), true); } - public static void PackageSharedFramework(BuildTargetContext c, string outputDir, DotNetCli dotnetCli) + public static void PublishSharedFramework(BuildTargetContext c, string outputDir, DotNetCli dotnetCli) { string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"); - string SharedFrameworkNugetVersion = GetVersionFromProjectJson(Path.Combine(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"), "project.json")); + string SharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. string SharedFrameworkNameAndVersionRoot = Path.Combine(outputDir, "shared", SharedFrameworkName, SharedFrameworkNugetVersion); @@ -303,23 +303,6 @@ namespace Microsoft.DotNet.Cli.Build CrossgenSharedFx(c, SharedFrameworkNameAndVersionRoot); } - private static string GetVersionFromProjectJson(string pathToProjectJson) - { - Regex r = new Regex($"\"{Regex.Escape(SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\""); - - foreach (var line in File.ReadAllLines(pathToProjectJson)) - { - var m = r.Match(line); - - if (m.Success) - { - return m.Groups["version"].Value; - } - } - - throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); - } - private static BuildTargetResult CompileCliSdk(BuildTargetContext c, DotNetCli dotnet, string outputDir) { var configuration = c.BuildContext.Get("Configuration"); @@ -499,7 +482,7 @@ namespace Microsoft.DotNet.Cli.Build c.Warn("Skipping crossgen for SharedFx because CROSSGEN_SHAREDFRAMEWORK is not set to 1"); return c.Success(); } - + foreach (var file in Directory.GetFiles(pathToAssemblies)) { string fileName = Path.GetFileName(file); diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index 097d37f18..ba657769f 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -99,7 +99,7 @@ namespace Microsoft.DotNet.Cli.Build Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "package", "package-sharedframework-debian.sh"), "--input", inputRoot, "--output", debFile, "--package-name", packageName, - "--framework-nuget-name", SharedFrameworkTargets.SharedFrameworkName, + "--framework-nuget-name", Monikers.SharedFrameworkName, "--framework-nuget-version", c.BuildContext.Get("SharedFrameworkNugetVersion"), "--obj-root", objRoot, "--version", version) .Execute() diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs index f4f82f695..5d2adf871 100644 --- a/scripts/dotnet-cli-build/MsiTargets.cs +++ b/scripts/dotnet-cli-build/MsiTargets.cs @@ -64,7 +64,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult InitMsi(BuildTargetContext c) { - SdkBundle = c.BuildContext.Get("SdkInstallerFile"); + SdkBundle = c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile"); SdkMsi = Path.ChangeExtension(SdkBundle, "msi"); Engine = Path.Combine(Path.GetDirectoryName(SdkBundle), ENGINE); @@ -129,7 +129,7 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult GenerateDotnetSharedFrameworkMsi(BuildTargetContext c) { var inputDir = c.BuildContext.Get("SharedFrameworkPublishRoot"); - var sharedFrameworkNuGetName = SharedFrameworkTargets.SharedFrameworkName; + var sharedFrameworkNuGetName = Monikers.SharedFrameworkName; var sharedFrameworkNuGetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); var upgradeCode = Utils.GenerateGuidFromName($"{sharedFrameworkNuGetName}-{sharedFrameworkNuGetVersion}-{Arch}").ToString().ToUpper(); var wixObjRoot = Path.Combine(Dirs.Output, "obj", "wix", "sharedframework"); diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index 0ef59c1f2..2719439e4 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -13,8 +13,8 @@ namespace Microsoft.DotNet.Cli.Build public static class PackageTargets { [Target(nameof(PackageTargets.CopyCLISDKLayout), - nameof(SharedFrameworkTargets.PublishSharedHost), - nameof(SharedFrameworkTargets.PublishSharedFramework), + nameof(PackageTargets.CopySharedHostLayout), + nameof(PackageTargets.CopySharedFxLayout), nameof(PackageTargets.CopyCombinedFrameworkSDKHostLayout), nameof(PackageTargets.CopyCombinedFrameworkHostLayout))] public static BuildTargetResult InitPackage(BuildTargetContext c) @@ -52,45 +52,62 @@ namespace Microsoft.DotNet.Cli.Build [Target] public static BuildTargetResult CopyCLISDKLayout(BuildTargetContext c) { - var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion; var cliSdkRoot = Path.Combine(Dirs.Output, "obj", "clisdk"); - var cliSdk = Path.Combine(cliSdkRoot, "sdk", nugetVersion); - if (Directory.Exists(cliSdkRoot)) { Utils.DeleteDirectory(cliSdkRoot); } - Directory.CreateDirectory(cliSdk); - - var binPath = Path.Combine(Dirs.Stage2, "bin"); - foreach (var file in Directory.GetFiles(binPath, "*", SearchOption.AllDirectories)) - { - string destFile = file.Replace(binPath, cliSdk); - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(file, destFile, true); - } - - File.Copy(Path.Combine(Dirs.Stage2, ".version"), Path.Combine(cliSdk, ".version"), true); - - // copy stage2 to "cliSdkRoot\bin". - // this is a temp hack until we fix the build scripts to use the new shared fx and shared host - // the current build scripts need the CLI sdk to be in the bin folder. - - foreach (var file in Directory.GetFiles(Dirs.Stage2, "*", SearchOption.AllDirectories)) - { - string destFile = file.Replace(Dirs.Stage2, cliSdkRoot); - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(file, destFile, true); - } + Directory.CreateDirectory(cliSdkRoot); + Utils.CopyDirectoryRecursively(Path.Combine(Dirs.Stage2, "sdk"), cliSdkRoot, true); c.BuildContext["CLISDKRoot"] = cliSdkRoot; return c.Success(); } + [Target] + public static BuildTargetResult CopySharedHostLayout(BuildTargetContext c) + { + var sharedHostRoot = Path.Combine(Dirs.Output, "obj", "sharedHost"); + if (Directory.Exists(sharedHostRoot)) + { + Utils.DeleteDirectory(sharedHostRoot); + } + + Directory.CreateDirectory(sharedHostRoot); + + foreach (var file in Directory.GetFiles(Dirs.Stage2, "*", SearchOption.TopDirectoryOnly)) + { + var destFile = file.Replace(Dirs.Stage2, sharedHostRoot); + File.Copy(file, destFile, true); + } + + c.BuildContext["SharedHostPublishRoot"] = sharedHostRoot; + return c.Success(); + } + + [Target] + public static BuildTargetResult CopySharedFxLayout(BuildTargetContext c) + { + var sharedFxRoot = Path.Combine(Dirs.Output, "obj", "sharedFx"); + if (Directory.Exists(sharedFxRoot)) + { + Utils.DeleteDirectory(sharedFxRoot); + } + + Directory.CreateDirectory(sharedFxRoot); + Utils.CopyDirectoryRecursively(Path.Combine(Dirs.Stage2, "shared"), sharedFxRoot, true); + c.BuildContext["SharedFrameworkPublishRoot"] = sharedFxRoot; + return c.Success(); + } + [Target] public static BuildTargetResult CopyCombinedFrameworkSDKHostLayout(BuildTargetContext c) { var combinedRoot = Path.Combine(Dirs.Output, "obj", "combined-framework-sdk-host"); + if (Directory.Exists(combinedRoot)) + { + Utils.DeleteDirectory(combinedRoot); + } string sdkPublishRoot = c.BuildContext.Get("CLISDKRoot"); Utils.CopyDirectoryRecursively(sdkPublishRoot, combinedRoot); @@ -109,6 +126,11 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult CopyCombinedFrameworkHostLayout(BuildTargetContext c) { var combinedRoot = Path.Combine(Dirs.Output, "obj", "combined-framework-host"); + if (Directory.Exists(combinedRoot)) + { + Utils.DeleteDirectory(combinedRoot); + } + string sharedFrameworkPublishRoot = c.BuildContext.Get("SharedFrameworkPublishRoot"); Utils.CopyDirectoryRecursively(sharedFrameworkPublishRoot, combinedRoot); @@ -130,9 +152,6 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateZip(BuildTargetContext c) { - CreateZipFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); - CreateZipFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); - CreateZipFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); CreateZipFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); @@ -143,9 +162,6 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.Unix)] public static BuildTargetResult GenerateTarBall(BuildTargetContext c) { - CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile")); - CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile")); - CreateTarBallFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkSDKHostRoot"), c.BuildContext.Get("CombinedFrameworkSDKHostCompressedFile")); CreateTarBallFromDirectory(c.BuildContext.Get("CombinedFrameworkHostRoot"), c.BuildContext.Get("CombinedFrameworkHostCompressedFile")); @@ -159,7 +175,7 @@ namespace Microsoft.DotNet.Cli.Build var versionSuffix = c.BuildContext.Get("BuildVersion").VersionSuffix; var env = GetCommonEnvVars(c); Cmd("powershell", "-NoProfile", "-NoLogo", - Path.Combine(Dirs.RepoRoot, "packaging", "nuget", "package.ps1"), Path.Combine(Dirs.Stage2, "bin"), versionSuffix) + Path.Combine(Dirs.RepoRoot, "packaging", "nuget", "package.ps1"), Dirs.Stage2, versionSuffix) .Environment(env) .Execute() .EnsureSuccessful(); diff --git a/scripts/dotnet-cli-build/PkgTargets.cs b/scripts/dotnet-cli-build/PkgTargets.cs index 1f082b069..56b37026f 100644 --- a/scripts/dotnet-cli-build/PkgTargets.cs +++ b/scripts/dotnet-cli-build/PkgTargets.cs @@ -37,7 +37,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GenerateSharedFrameworkProductArchive(BuildTargetContext c) { - string sharedFrameworkNugetName = SharedFrameworkTargets.SharedFrameworkName; + string sharedFrameworkNugetName = Monikers.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.osx.x64"; @@ -53,9 +53,9 @@ namespace Microsoft.DotNet.Cli.Build "shared-framework-distribution-template.xml"); string distTemplate = File.ReadAllText(inputDistTemplatePath); string distributionPath = Path.Combine(packageIntermediatesPath, "shared-framework-formatted-distribution.xml"); - string formattedDistContents = + string formattedDistContents = distTemplate.Replace("{SharedFrameworkNugetVersion}", sharedFrameworkNugetVersion) - .Replace("{SharedFrameworkNugetName}", SharedFrameworkTargets.SharedFrameworkName) + .Replace("{SharedFrameworkNugetName}", Monikers.SharedFrameworkName) .Replace("{VERSION}", version); File.WriteAllText(distributionPath, formattedDistContents); @@ -63,7 +63,7 @@ namespace Microsoft.DotNet.Cli.Build "--version", version, "--identifier", id, "--package-path", packageIntermediatesPath, - "--resources", resourcePath, + "--resources", resourcePath, "--distribution", distributionPath, outFilePath) .Execute() @@ -76,7 +76,7 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GenerateSharedFrameworkPkg(BuildTargetContext c) { - string sharedFrameworkNugetName = SharedFrameworkTargets.SharedFrameworkName; + string sharedFrameworkNugetName = Monikers.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 0dcfa1538..33a2eaf43 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -10,6 +10,7 @@ using System.Text; using static Microsoft.DotNet.Cli.Build.FS; using static Microsoft.DotNet.Cli.Build.Utils; using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; +using System.Text.RegularExpressions; namespace Microsoft.DotNet.Cli.Build { @@ -45,6 +46,7 @@ namespace Microsoft.DotNet.Cli.Build c.BuildContext["Configuration"] = configEnv; c.BuildContext["Channel"] = Environment.GetEnvironmentVariable("CHANNEL"); + c.BuildContext["SharedFrameworkNugetVersion"] = GetVersionFromProjectJson(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework", "project.json")); c.Info($"Building {c.BuildContext["Configuration"]} to: {Dirs.Output}"); c.Info("Build Environment:"); @@ -112,11 +114,11 @@ namespace Microsoft.DotNet.Cli.Build var versionBadgeName = $"{CurrentPlatform.Current}_{CurrentArchitecture.Current}_{config}_version_badge.svg"; c.BuildContext["VersionBadge"] = Path.Combine(Dirs.Output, versionBadgeName); - AddInstallerArtifactToContext(c, "dotnet", "Sdk"); + AddInstallerArtifactToContext(c, "dotnet-sdk", "Sdk"); AddInstallerArtifactToContext(c, "dotnet-host", "SharedHost"); AddInstallerArtifactToContext(c, "dotnet-sharedframework", "SharedFramework"); - AddInstallerArtifactToContext(c, "dotnet-combined-framework-sdk-host", "CombinedFrameworkSDKHost"); - AddInstallerArtifactToContext(c, "dotnet-combined-framework-host", "CombinedFrameworkHost"); + AddInstallerArtifactToContext(c, "dotnet-dev", "CombinedFrameworkSDKHost"); + AddInstallerArtifactToContext(c, "dotnet", "CombinedFrameworkHost"); return c.Success(); } @@ -315,6 +317,23 @@ cmake is required to build the native host 'corehost'"; return c.Success(); } + private static string GetVersionFromProjectJson(string pathToProjectJson) + { + Regex r = new Regex($"\"{Regex.Escape(Monikers.SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\""); + + foreach (var line in File.ReadAllLines(pathToProjectJson)) + { + var m = r.Match(line); + + if (m.Success) + { + return m.Groups["version"].Value; + } + } + + throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); + } + private static bool AptPackageIsInstalled(string packageName) { var result = Command.Create("dpkg", "-s", packageName) diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs deleted file mode 100644 index 7dffd64c4..000000000 --- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Text.RegularExpressions; -using System.Reflection.PortableExecutable; -using System.Runtime.InteropServices; -using Microsoft.DotNet.Cli.Build.Framework; -using Microsoft.Extensions.PlatformAbstractions; - -using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; - -namespace Microsoft.DotNet.Cli.Build -{ - public class SharedFrameworkTargets - { - public const string SharedFrameworkName = "Microsoft.NETCore.App"; - - private const string CoreHostBaseName = "corehost"; - private const string DotnetHostFxrBaseName = "hostfxr"; - private const string HostPolicyBaseName = "hostpolicy"; - - [Target(nameof(PackageSharedFramework), nameof(CrossGenAllManagedAssemblies))] - public static BuildTargetResult PublishSharedFramework(BuildTargetContext c) - { - return c.Success(); - } - - [Target] - public static BuildTargetResult PackageSharedFramework(BuildTargetContext c) - { - string SharedFrameworkPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedframework"); - string SharedFrameworkSourceRoot = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"); - string SharedFrameworkNugetVersion = GetVersionFromProjectJson(Path.Combine(Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "framework"), "project.json")); - - if (Directory.Exists(SharedFrameworkPublishRoot)) - { - Utils.DeleteDirectory(SharedFrameworkPublishRoot); - } - - // We publish to a sub folder of the PublishRoot so tools like heat and zip can generate folder structures easier. - string SharedFrameworkNameAndVersionRoot = Path.Combine(SharedFrameworkPublishRoot, "shared", SharedFrameworkName, SharedFrameworkNugetVersion); - - string publishFramework = "dnxcore50"; // Temporary, use "netcoreapp" when we update nuget. - string publishRuntime; - if (PlatformServices.Default.Runtime.OperatingSystemPlatform == Platform.Windows) - { - publishRuntime = $"win7-{PlatformServices.Default.Runtime.RuntimeArchitecture}"; - } - else - { - publishRuntime = PlatformServices.Default.Runtime.GetRuntimeIdentifier(); - } - - DotNetCli.Stage2.Publish( - "--output", SharedFrameworkNameAndVersionRoot, - "-r", publishRuntime, - "-f", publishFramework, - SharedFrameworkSourceRoot).Execute().EnsureSuccessful(); - - c.BuildContext["SharedFrameworkPublishRoot"] = SharedFrameworkPublishRoot; - c.BuildContext["SharedFrameworkNugetVersion"] = SharedFrameworkNugetVersion; - - // Clean up artifacts that dotnet-publish generates which we don't need - File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}")); - File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll")); - File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb")); - File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.runtimeconfig.json")); - - // Rename the .deps file - var destinationDeps = Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json"); - File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps")); - File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps); - - // Generate RID fallback graph - string runtimeGraphGeneratorRuntime = null; - switch (PlatformServices.Default.Runtime.OperatingSystemPlatform) - { - case Platform.Windows: - runtimeGraphGeneratorRuntime = "win"; - break; - case Platform.Linux: - runtimeGraphGeneratorRuntime = "linux"; - break; - case Platform.Darwin: - runtimeGraphGeneratorRuntime = "osx"; - break; - } - if (!string.IsNullOrEmpty(runtimeGraphGeneratorRuntime)) - { - var runtimeGraphGeneratorName = "RuntimeGraphGenerator"; - var runtimeGraphGeneratorProject = Path.Combine(c.BuildContext.BuildDirectory, "tools", runtimeGraphGeneratorName); - var runtimeGraphGeneratorOutput = Path.Combine(Dirs.Output, "tools", runtimeGraphGeneratorName); - - DotNetCli.Stage2.Publish( - "--output", runtimeGraphGeneratorOutput, - runtimeGraphGeneratorProject).Execute().EnsureSuccessful(); - var runtimeGraphGeneratorExe = Path.Combine(runtimeGraphGeneratorOutput, $"{runtimeGraphGeneratorName}{Constants.ExeSuffix}"); - - Cmd(runtimeGraphGeneratorExe, "--project", SharedFrameworkSourceRoot, "--deps", destinationDeps, runtimeGraphGeneratorRuntime) - .Execute(); - } - else - { - c.Error($"Could not determine rid graph generation runtime for platform {PlatformServices.Default.Runtime.OperatingSystemPlatform}"); - } - - // corehost will be renamed to dotnet at some point and then we will not need to rename it here. - File.Copy( - Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), - Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}")); - File.Copy( - Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), - Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), true); - - if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll"))) - { - // Publish already places the crossgen'd version of mscorlib into the output, so we can - // remove the IL version - File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll")); - c.BuildContext["SharedFrameworkNameAndVersionRoot"] = SharedFrameworkNameAndVersionRoot; - } - - return c.Success(); - } - - [Target] - public static BuildTargetResult PublishSharedHost(BuildTargetContext c) - { - string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost"); - - if (Directory.Exists(SharedHostPublishRoot)) - { - Utils.DeleteDirectory(SharedHostPublishRoot); - } - Directory.CreateDirectory(SharedHostPublishRoot); - - // corehost will be renamed to dotnet at some point and then this can be removed. - File.Copy( - Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), - Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}")); - File.Copy( - Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}"), - Path.Combine(SharedHostPublishRoot, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}")); - - c.BuildContext["SharedHostPublishRoot"] = SharedHostPublishRoot; - - return c.Success(); - } - - private static string GetVersionFromProjectJson(string pathToProjectJson) - { - Regex r = new Regex($"\"{Regex.Escape(SharedFrameworkName)}\"\\s*:\\s*\"(?'version'[^\"]*)\""); - - foreach(var line in File.ReadAllLines(pathToProjectJson)) - { - var m = r.Match(line); - - if (m.Success) - { - return m.Groups["version"].Value; - } - } - - throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); - } - - [Target] - [Environment("CROSSGEN_SHAREDFRAMEWORK", "1", "true")] - public static BuildTargetResult CrossGenAllManagedAssemblies(BuildTargetContext c) - { - string pathToAssemblies = c.BuildContext.Get("SharedFrameworkNameAndVersionRoot"); - - foreach (var file in Directory.GetFiles(pathToAssemblies)) - { - string fileName = Path.GetFileName(file); - - if (fileName == "mscorlib.dll" || fileName == "mscorlib.ni.dll" || !HasMetadata(file)) - { - continue; - } - - string tempPathName = Path.ChangeExtension(file, "readytorun"); - - // This is not always correct. The version of crossgen we need to pick up is whatever one was restored as part - // of the Microsoft.NETCore.Runtime.CoreCLR package that is part of the shared library. For now, the version hardcoded - // in CompileTargets and the one in the shared library project.json match and are updated in lock step, but long term - // we need to be able to look at the project.lock.json file and figure out what version of Microsoft.NETCore.Runtime.CoreCLR - // was used, and then select that version. - ExecSilent(Crossgen.GetCrossgenPathForVersion(CompileTargets.CoreCLRVersion), - "-readytorun", "-in", file, "-out", tempPathName, "-platform_assemblies_paths", pathToAssemblies); - - File.Delete(file); - File.Move(tempPathName, file); - } - - return c.Success(); - } - - private static bool HasMetadata(string pathToFile) - { - try - { - using (var inStream = File.OpenRead(pathToFile)) - { - using (var peReader = new PEReader(inStream)) - { - return peReader.HasMetadata; - } - } - } catch (BadImageFormatException) { } - - return false; - } - } -} diff --git a/scripts/dotnet-cli-build/Utils/Monikers.cs b/scripts/dotnet-cli-build/Utils/Monikers.cs index b69c0d05b..7fb3562e4 100644 --- a/scripts/dotnet-cli-build/Utils/Monikers.cs +++ b/scripts/dotnet-cli-build/Utils/Monikers.cs @@ -8,6 +8,8 @@ namespace Microsoft.DotNet.Cli.Build { public class Monikers { + public const string SharedFrameworkName = "Microsoft.NETCore.App"; + public static string GetProductMoniker(BuildTargetContext c, string artifactPrefix) { string osname = GetOSShortName(); @@ -31,7 +33,7 @@ namespace Microsoft.DotNet.Cli.Build case "rtm": packageName = "dotnet"; break; - default: + default: throw new Exception($"Unknown channel - {channel}"); } @@ -42,7 +44,7 @@ namespace Microsoft.DotNet.Cli.Build { var sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); - return $"dotnet-sharedframework-{SharedFrameworkTargets.SharedFrameworkName}-{sharedFrameworkNugetVersion}".ToLower(); + return $"dotnet-sharedframework-{SharedFrameworkName}-{sharedFrameworkNugetVersion}".ToLower(); } public static string GetOSShortName() diff --git a/scripts/dotnet-cli-build/Utils/Utils.cs b/scripts/dotnet-cli-build/Utils/Utils.cs index d9dd937a0..b94343249 100644 --- a/scripts/dotnet-cli-build/Utils/Utils.cs +++ b/scripts/dotnet-cli-build/Utils/Utils.cs @@ -101,8 +101,15 @@ namespace Microsoft.DotNet.Cli.Build } } - public static void CopyDirectoryRecursively(string path, string destination) + public static void CopyDirectoryRecursively(string path, string destination, bool keepParentDir = false) { + if (keepParentDir) + { + path = path.TrimEnd(Path.DirectorySeparatorChar); + destination = Path.Combine(destination, Path.GetFileName(path)); + Directory.CreateDirectory(destination); + } + foreach (var file in Directory.GetFiles(path, "*", SearchOption.AllDirectories)) { string destFile = file.Replace(path, destination); diff --git a/test/Installer/testmsi.ps1 b/test/Installer/testmsi.ps1 index 3f4f0d3cc..d1b82f67b 100644 --- a/test/Installer/testmsi.ps1 +++ b/test/Installer/testmsi.ps1 @@ -38,7 +38,7 @@ $testName = "Microsoft.DotNet.Cli.Msi.Tests" $testDir="$PSScriptRoot\$testName" $testBin="$RepoRoot\artifacts\tests\$testName" -pushd "$Stage2Dir\bin" +pushd "$Stage2Dir" try { .\dotnet restore ` From 9602d926346c6da97dc7301fd2abda93726b4029 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Wed, 16 Mar 2016 18:16:51 -0700 Subject: [PATCH 80/99] Publish and Pkg, Deb fixes - Publish only combined SharedFx,SharedHost and combined SharedFx,SharedHost,CLISDK tarballs and zips. --- scripts/dotnet-cli-build/InstallerTargets.cs | 5 +- scripts/dotnet-cli-build/PkgTargets.cs | 5 +- scripts/dotnet-cli-build/PublishTargets.cs | 58 +++----------------- 3 files changed, 14 insertions(+), 54 deletions(-) diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index ba657769f..feef6e319 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -37,7 +37,8 @@ namespace Microsoft.DotNet.Cli.Build var channel = c.BuildContext.Get("Channel").ToLower(); var packageName = Monikers.GetDebianPackageName(c); var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var debFile = c.BuildContext.Get("SdkInstallerFile"); + var debFile = c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile"); + var input = c.BuildContext.Get("CLISDKRoot"); var manPagesDir = Path.Combine(Dirs.RepoRoot, "Documentation", "manpages"); var previousVersionURL = $"https://dotnetcli.blob.core.windows.net/dotnet/{channel}/Installers/Latest/dotnet-ubuntu-x64.latest.deb"; @@ -51,7 +52,7 @@ namespace Microsoft.DotNet.Cli.Build Directory.CreateDirectory(objRoot); Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "package", "package-debian.sh"), - "-v", version, "-i", Dirs.Stage2, "-o", debFile, "-p", packageName, "-m", manPagesDir, "--previous-version-url", previousVersionURL, "--obj-root", objRoot) + "-v", version, "-i", input, "-o", debFile, "-p", packageName, "-m", manPagesDir, "--previous-version-url", previousVersionURL, "--obj-root", objRoot) .Execute() .EnsureSuccessful(); return c.Success(); diff --git a/scripts/dotnet-cli-build/PkgTargets.cs b/scripts/dotnet-cli-build/PkgTargets.cs index 56b37026f..55b1ebe33 100644 --- a/scripts/dotnet-cli-build/PkgTargets.cs +++ b/scripts/dotnet-cli-build/PkgTargets.cs @@ -24,10 +24,11 @@ namespace Microsoft.DotNet.Cli.Build public static BuildTargetResult GenerateSdkProductArchive(BuildTargetContext c) { var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var pkg = c.BuildContext.Get("SdkInstallerFile"); + var pkg = c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile"); + var input = c.BuildContext.Get("CLISDKRoot"); Cmd(Path.Combine(Dirs.RepoRoot, "packaging", "osx", "package-osx.sh"), - "-v", version, "-i", Dirs.Stage2, "-o", pkg) + "-v", version, "-i", input, "-o", pkg) .Execute() .EnsureSuccessful(); return c.Success(); diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs index 04af2b35c..0894ade05 100644 --- a/scripts/dotnet-cli-build/PublishTargets.cs +++ b/scripts/dotnet-cli-build/PublishTargets.cs @@ -44,11 +44,8 @@ namespace Microsoft.DotNet.Cli.Build } [Target(nameof(PublishTargets.PublishVersionBadge), - nameof(PublishTargets.PublishCompressedFile), nameof(PublishTargets.PublishSdkInstallerFile), nameof(PublishTargets.PublishDebFileToDebianRepo), - nameof(PublishTargets.PublishSharedFrameworkCompressedFile), - nameof(PublishTargets.PublishSharedHostCompressedFile), nameof(PublishTargets.PublishCombinedFrameworkSDKHostFile), nameof(PublishTargets.PublishCombinedFrameworkHostFile), nameof(PublishTargets.PublishLatestVersionTextFile))] @@ -69,24 +66,11 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target] - public static BuildTargetResult PublishCompressedFile(BuildTargetContext c) - { - var compressedFile = c.BuildContext.Get("SdkCompressedFile"); - var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; - var latestCompressedFile = compressedFile.Replace(Version, "latest"); - var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; - - PublishFileAzure(compressedFileBlob, compressedFile); - PublishFileAzure(latestCompressedFileBlob, compressedFile); - return c.Success(); - } - [Target] [BuildPlatforms(BuildPlatform.Windows, BuildPlatform.OSX, BuildPlatform.Ubuntu)] public static BuildTargetResult PublishSdkInstallerFile(BuildTargetContext c) { - var installerFile = c.BuildContext.Get("SdkInstallerFile"); + var installerFile = c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile"); var installerFileBlob = $"{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; var latestInstallerFile = installerFile.Replace(Version, "latest"); var latestInstallerFileBlob = $"{Channel}/Installers/Latest/{Path.GetFileName(latestInstallerFile)}"; @@ -113,7 +97,7 @@ namespace Microsoft.DotNet.Cli.Build { var packageName = Monikers.GetDebianPackageName(c); var installerFile = c.BuildContext.Get("SdkInstallerFile"); - var uploadUrl = $"https://dotnetcli.blob.core.windows.net/dotnet/{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; + var uploadUrl = $"https://dotnetcli.blob.core.windows.net/dotnet/{Channel}/Installers/{Version}/{Path.GetFileName(installerFile)}"; var uploadJson = GenerateUploadJsonFile(packageName, Version, uploadUrl); Cmd(Path.Combine(Dirs.RepoRoot, "scripts", "publish", "repoapi_client.sh"), "-addpkg", uploadJson) @@ -133,44 +117,18 @@ namespace Microsoft.DotNet.Cli.Build { using (StreamWriter sw = new StreamWriter(fileStream)) { - sw.WriteLine("{"); - sw.WriteLine($" \"name\":\"{packageName}\","); - sw.WriteLine($" \"version\":\"{version}\","); - sw.WriteLine($" \"repositoryId\":\"{repoID}\","); - sw.WriteLine($" \"sourceUrl\":\"{uploadUrl}\""); - sw.WriteLine("}"); + sw.WriteLine("{"); + sw.WriteLine($" \"name\":\"{packageName}\","); + sw.WriteLine($" \"version\":\"{version}\","); + sw.WriteLine($" \"repositoryId\":\"{repoID}\","); + sw.WriteLine($" \"sourceUrl\":\"{uploadUrl}\""); + sw.WriteLine("}"); } } return uploadJson; } - [Target] - public static BuildTargetResult PublishSharedFrameworkCompressedFile(BuildTargetContext c) - { - var compressedFile = c.BuildContext.Get("SharedFrameworkCompressedFile"); - var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; - var latestCompressedFile = compressedFile.Replace(Version, "latest"); - var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; - - PublishFileAzure(compressedFileBlob, compressedFile); - PublishFileAzure(latestCompressedFileBlob, compressedFile); - return c.Success(); - } - - [Target] - public static BuildTargetResult PublishSharedHostCompressedFile(BuildTargetContext c) - { - var compressedFile = c.BuildContext.Get("SharedHostCompressedFile"); - var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}"; - var latestCompressedFile = compressedFile.Replace(Version, "latest"); - var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}"; - - PublishFileAzure(compressedFileBlob, compressedFile); - PublishFileAzure(latestCompressedFileBlob, compressedFile); - return c.Success(); - } - [Target] public static BuildTargetResult PublishCombinedFrameworkSDKHostFile(BuildTargetContext c) { From 00905c3faf24880aa0873cd40a5c0b56606c7d19 Mon Sep 17 00:00:00 2001 From: Senthil Chellappan Date: Wed, 16 Mar 2016 15:13:22 -0700 Subject: [PATCH 81/99] Revert merging relpaths and relax erroring --- src/corehost/cli/deps_format.cpp | 48 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp index e013ba89f..0dafed29c 100644 --- a/src/corehost/cli/deps_format.cpp +++ b/src/corehost/cli/deps_format.cpp @@ -129,23 +129,27 @@ bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, c auto iter = std::find_if(fallback_rids.begin(), fallback_rids.end(), [&package](const pal::string_t& rid) { return package.second.count(rid); }); - if (iter == fallback_rids.end() || (*iter).empty()) + if (iter != fallback_rids.end()) { - trace::error(_X("Did not find a matching fallback rid for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str()); - return false; + matched_rid = *iter; } - matched_rid = *iter; } - assert(!matched_rid.empty()); + + if (matched_rid.empty()) + { + package.second.clear(); + } + for (auto iter = package.second.begin(); iter != package.second.end(); /* */) { if (iter->first != matched_rid) { - iter = package.second.erase(iter); + trace::verbose(_X("Chose %s, so removing rid (%s) specific assets for package %s"), matched_rid.c_str(), iter->first.c_str(), package.first.c_str()); + iter = package.second.erase(iter); } else { - ++iter; + ++iter; } } } @@ -194,7 +198,6 @@ bool deps_json_t::process_targets(const json_value& json, const pal::string_t& t for (const auto& package : json.at(_X("targets")).at(target_name).as_object()) { // if (package.second.at(_X("type")).as_string() != _X("package")) continue; - const auto& asset_types = package.second.as_object(); for (int i = 0; i < s_known_asset_types.size(); ++i) { @@ -226,27 +229,24 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar return false; } - std::vector merged; auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool { return rid_assets.count(package) || non_rid_assets.count(package); }; - auto get_relpaths = [&rid_assets, &non_rid_assets, &merged](const pal::string_t& package, int type_index) -> const std::vector& { - if (rid_assets.count(package) && non_rid_assets.count(package)) + auto get_relpaths = [&rid_assets, &non_rid_assets](const pal::string_t& package, int type_index) -> const std::vector& { + + // Is there any rid specific assets for this type ("native" or "runtime" or "resources") + if (rid_assets.count(package) && !rid_assets[package].empty()) { - const std::vector& rel1 = rid_assets[package].begin()->second[type_index]; - const std::vector& rel2 = non_rid_assets[package][type_index]; - merged.clear(); - merged.reserve(rel1.size() + rel2.size()); - merged.insert(merged.end(), rel1.begin(), rel1.end()); - merged.insert(merged.end(), rel2.begin(), rel2.end()); - return merged; - } - else - { - return rid_assets.count(package) - ? rid_assets[package].begin()->second[type_index] - : non_rid_assets[package][type_index]; + const auto& assets_by_type = rid_assets[package].begin()->second[type_index]; + if (!assets_by_type.empty()) + { + return assets_by_type; + } + + trace::verbose(_X("There were no rid specific %s asset for %s"), deps_json_t::s_known_asset_types[type_index], package.c_str()); } + + return non_rid_assets[package][type_index]; }; reconcile_libraries_with_targets(json, package_exists, get_relpaths); From 8ff5f9df6f87bf1d71f9696d3b905cfb57645840 Mon Sep 17 00:00:00 2001 From: Senthil Date: Wed, 16 Mar 2016 20:50:32 -0700 Subject: [PATCH 82/99] Return empty entries instead of creating empty ones --- src/corehost/cli/deps_format.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp index 0dafed29c..f9e02ffa4 100644 --- a/src/corehost/cli/deps_format.cpp +++ b/src/corehost/cli/deps_format.cpp @@ -232,7 +232,9 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool { return rid_assets.count(package) || non_rid_assets.count(package); }; - auto get_relpaths = [&rid_assets, &non_rid_assets](const pal::string_t& package, int type_index) -> const std::vector& { + + std::vector empty; + auto get_relpaths = [&rid_assets, &non_rid_assets, &empty](const pal::string_t& package, int type_index) -> const std::vector& { // Is there any rid specific assets for this type ("native" or "runtime" or "resources") if (rid_assets.count(package) && !rid_assets[package].empty()) @@ -246,7 +248,12 @@ bool deps_json_t::load_portable(const json_value& json, const pal::string_t& tar trace::verbose(_X("There were no rid specific %s asset for %s"), deps_json_t::s_known_asset_types[type_index], package.c_str()); } - return non_rid_assets[package][type_index]; + if (non_rid_assets.count(package)) + { + return non_rid_assets[package][type_index]; + } + + return empty; }; reconcile_libraries_with_targets(json, package_exists, get_relpaths); From ee27b1ff112ecbba96d6a74491103cdc1acff293 Mon Sep 17 00:00:00 2001 From: schellap Date: Thu, 17 Mar 2016 01:37:39 -0700 Subject: [PATCH 83/99] Enable logging and fix xunit runtimeconfig --- src/corehost/cli/fxr/fx_muxer.cpp | 98 ++++++++++++++++++++++++++----- src/corehost/cli/fxr/fx_muxer.h | 2 +- src/corehost/cli/hostpolicy.cpp | 3 +- src/corehost/cli/libhost.cpp | 7 ++- src/corehost/cli/libhost.h | 2 +- src/corehost/common/utils.cpp | 2 +- 6 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 75a195982..4cc2f60fe 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -16,8 +16,9 @@ typedef web::json::value json_value; -pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime, const pal::string_t& app_path) +pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime) { + trace::verbose(_X("--- Resolving FX directory from muxer dir [%s]"), muxer_dir.c_str()); const auto fx_name = runtime->get_fx_name(); const auto fx_ver = runtime->get_fx_version(); const auto roll_fwd = runtime->get_fx_roll_fwd(); @@ -25,6 +26,7 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime fx_ver_t specified(-1, -1, -1); if (!fx_ver_t::parse(fx_ver, &specified, false)) { + trace::error(_X("The specified runtimeconfig.json version [%s] could not be parsed"), fx_ver.c_str()); return pal::string_t(); } @@ -35,15 +37,20 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime // If not roll forward or if pre-release, just return. if (!roll_fwd || specified.is_prerelease()) { + trace::verbose(_X("Did not roll forward because rollfwd=%d and [%s] is prerelease=%d"), + roll_fwd, fx_ver.c_str(), specified.is_prerelease()); append_path(&fx_dir, fx_ver.c_str()); } else { + trace::verbose(_X("Attempting production FX roll forward starting from [%s]"), fx_ver.c_str()); + std::vector list; pal::readdir(fx_dir, &list); fx_ver_t max_specified = specified; for (const auto& version : list) { + trace::verbose(_X("Inspecting version... [%s]"), version.c_str()); fx_ver_t ver(-1, -1, -1); if (fx_ver_t::parse(version, &ver, true) && ver.get_major() == max_specified.get_major() && @@ -55,21 +62,26 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime pal::string_t max_specified_str = max_specified.as_str(); append_path(&fx_dir, max_specified_str.c_str()); } - trace::verbose(_X("Found fx in: %s"), fx_dir.c_str()); + + trace::verbose(_X("Chose FX version [%s]"), fx_dir.c_str()); return pal::directory_exists(fx_dir) ? fx_dir : pal::string_t(); } pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) { + trace::verbose(_X("--- Resolving CLI version from global json [%s]"), global_json.c_str()); + pal::string_t retval; if (!pal::file_exists(global_json)) { + trace::verbose(_X("[%s] does not exist"), global_json.c_str()); return retval; } pal::ifstream_t file(global_json); if (!file.good()) { + trace::verbose(_X("[%s] could not be opened"), global_json.c_str()); return retval; } @@ -80,6 +92,7 @@ pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) const auto sdk_iter = json.find(_X("sdk")); if (sdk_iter == json.end() || sdk_iter->second.is_null()) { + trace::verbose(_X("CLI '/sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } @@ -87,19 +100,23 @@ pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json) const auto ver_iter = sdk_obj.find(_X("version")); if (ver_iter == sdk_obj.end() || ver_iter->second.is_null()) { + trace::verbose(_X("CLI 'sdk/version' field not present/null in [%s]"), global_json.c_str()); return retval; } retval = ver_iter->second.as_string(); } catch (...) { + trace::verbose(_X("A JSON parsing exception occurred")); } - trace::verbose(_X("Found cli in: %s"), retval.c_str()); + trace::verbose(_X("CLI version is [%s] in global json file [%s]"), retval.c_str(), global_json.c_str()); return retval; } pal::string_t resolve_sdk_version(pal::string_t sdk_path) { + trace::verbose(_X("--- Resolving SDK version from SDK dir [%s]"), sdk_path.c_str()); + pal::string_t retval; std::vector versions; @@ -108,6 +125,8 @@ pal::string_t resolve_sdk_version(pal::string_t sdk_path) fx_ver_t max_pre(-1, -1, -1); for (const auto& version : versions) { + trace::verbose(_X("Considering version... [%s]"), version.c_str()); + fx_ver_t ver(-1, -1, -1); if (fx_ver_t::parse(version, &ver, true)) { @@ -122,20 +141,26 @@ pal::string_t resolve_sdk_version(pal::string_t sdk_path) // No production, use the max pre-release. if (max_ver == fx_ver_t(-1, -1, -1)) { + trace::verbose(_X("No production version found, so using latest prerelease")); max_ver = max_pre; } pal::string_t max_ver_str = max_ver.as_str(); append_path(&sdk_path, max_ver_str.c_str()); + + trace::verbose(_X("Checking if resolved SDK dir [%s] exists"), sdk_path.c_str()); if (pal::directory_exists(sdk_path)) { retval = sdk_path; } + + trace::verbose(_X("Resolved SDK dir is [%s]"), retval.c_str()); return retval; } bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk) { + trace::verbose(_X("--- Resolving dotnet from working dir")); pal::string_t cwd; pal::string_t global; if (pal::getcwd(&cwd)) @@ -144,18 +169,27 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri { pal::string_t file = cur_dir; append_path(&file, _X("global.json")); + + trace::verbose(_X("Probing path [%s] for global.json"), file.c_str()); if (pal::file_exists(file)) { global = file; + trace::verbose(_X("Found global.json [%s]"), global.c_str()); break; } parent_dir = get_directory(cur_dir); if (parent_dir.empty() || parent_dir.size() == cur_dir.size()) { + trace::verbose(_X("Terminating global.json search at [%s]"), parent_dir.c_str()); break; } } } + else + { + trace::verbose(_X("Failed to obtain current working dir")); + } + pal::string_t retval; if (!global.empty()) { @@ -165,10 +199,16 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri pal::string_t sdk_path = own_dir; append_path(&sdk_path, _X("sdk")); append_path(&sdk_path, cli_version.c_str()); + if (pal::directory_exists(sdk_path)) { + trace::verbose(_X("CLI directory [%s] from global.json exists"), sdk_path.c_str()); retval = sdk_path; } + else + { + trace::verbose(_X("CLI directory [%s] from global.json doesn't exist"), sdk_path.c_str()); + } } } if (retval.empty()) @@ -178,13 +218,15 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri retval = resolve_sdk_version(sdk_path); } cli_sdk->assign(retval); - trace::verbose(_X("Found cli sdk in: %s"), cli_sdk->c_str()); + trace::verbose(_X("Found CLI SDK in: %s"), cli_sdk->c_str()); return !retval.empty(); } /* static */ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) { + trace::error(_X("--- Executing in muxer mode...")); + pal::string_t own_path; // Get the full name of the application @@ -198,6 +240,7 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) if (argc <= 1) { + trace::error(_X("Usage: dotnet [--help | app.dll]")); return StatusCode::InvalidArgFailure; } if (ends_with(argv[1], _X(".dll"), false)) @@ -206,10 +249,12 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) if (!pal::realpath(&app_path)) { + trace::error(_X("Could not resolve app's full path [%s]"), app_path.c_str()); return StatusCode::LibHostExecModeFailure; } - runtime_config_t config(get_runtime_config_json(app_path)); + auto config_file = get_runtime_config_from_file(app_path); + runtime_config_t config(config_file); if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); @@ -217,12 +262,14 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) } if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config); return policy_load_t::execute_app(fx_dir, &init, argc, argv); } else { + trace::verbose(_X("Executing as a standlone app as per config file [%s]"), config_file.c_str()); corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config); return policy_load_t::execute_app(get_directory(app_path), &init, argc, argv); } @@ -237,11 +284,13 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) std::unordered_map opts; if (!parse_known_args(argc - 2, &argv[2], known_opts, &opts, &num_args)) { + trace::error(_X("Failed to parse known arguments.")); return InvalidArgFailure; } int cur_i = 2 + num_args; if (cur_i >= argc) { + trace::error(_X("Parsed known args, but need more arguments.")); return InvalidArgFailure; } @@ -256,23 +305,31 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) pal::string_t deps_file = opts.count(opts_deps_file) ? opts[opts_deps_file] : _X(""); pal::string_t probe_path = opts.count(opts_probe_path) ? opts[opts_probe_path] : _X(""); - pal::string_t app_path = argv[cur_i]; - runtime_config_t config(get_runtime_config_json(app_path)); + pal::string_t app_or_deps = deps_file.empty() ? argv[cur_i] : deps_file; + auto config_file = get_runtime_config_from_file(app_or_deps); + runtime_config_t config(config_file); if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); return StatusCode::InvalidConfigFile; } + if (!deps_file.empty() && !pal::file_exists(deps_file)) + { + trace::error(_X("Deps file [%s] specified but doesn't exist"), deps_file.c_str()); + return StatusCode::InvalidArgFailure; + } if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path); + trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); corehost_init_t init(deps_file, probe_path, fx_dir, host_mode_t::muxer, &config); return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); } else { + trace::verbose(_X("Executing as a standalone app as per config file [%s]"), config_file.c_str()); corehost_init_t init(deps_file, probe_path, _X(""), host_mode_t::muxer, &config); - pal::string_t impl_dir = get_directory(deps_file.empty() ? app_path : deps_file); + pal::string_t impl_dir = get_directory(app_or_deps); return policy_load_t::execute_app(impl_dir, &init, new_argv.size(), new_argv.data()); } } @@ -281,9 +338,17 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) pal::string_t sdk_dotnet; if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet)) { + trace::error(_X("Could not resolve SDK directory from [%s]"), own_dir.c_str()); return StatusCode::LibHostSdkFindFailure; } append_path(&sdk_dotnet, _X("dotnet.dll")); + + if (!pal::file_exists(_X("dotnet.dll"))) + { + trace::error(_X("Could not find dotnet.dll at [%s]"), sdk_dotnet.c_str()); + return StatusCode::LibHostSdkFindFailure; + } + // Transform dotnet [command] [args] -> dotnet [dotnet.dll] [command] [args] std::vector new_argv(argc + 1); @@ -291,20 +356,21 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) new_argv[0] = argv[0]; new_argv[1] = sdk_dotnet.c_str(); - trace::verbose(_X("Using SDK dll=[%s]"), sdk_dotnet.c_str()); + trace::verbose(_X("Using dotnet SDK dll=[%s]"), sdk_dotnet.c_str()); - assert(ends_with(sdk_dotnet, _X(".dll"), false)); - - runtime_config_t config(get_runtime_config_json(sdk_dotnet)); + auto config_file = get_runtime_config_from_file(sdk_dotnet); + runtime_config_t config(config_file); if (config.get_portable()) { - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, sdk_dotnet); + trace::verbose(_X("Executing dotnet.dll as a portable app as per config file [%s]"), config_file.c_str()); + pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config); return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data()); } else { + trace::verbose(_X("Executing dotnet.dll as a standalone app as per config file [%s]"), config_file.c_str()); corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config); return policy_load_t::execute_app(get_directory(sdk_dotnet), &init, new_argv.size(), new_argv.data()); } @@ -316,4 +382,4 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[]) { trace::setup(); return fx_muxer_t().execute(argc, argv); -} \ No newline at end of file +} diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h index de6518a4c..5ea4cea8b 100644 --- a/src/corehost/cli/fxr/fx_muxer.h +++ b/src/corehost/cli/fxr/fx_muxer.h @@ -9,7 +9,7 @@ class fx_muxer_t public: static int execute(const int argc, const pal::char_t* argv[]); private: - static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime, const pal::string_t& app_path); + static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime); static pal::string_t resolve_cli_version(const pal::string_t& global); static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); }; diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index 32bdb924d..7cf161fba 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -215,7 +215,8 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) } else { - runtime_config_t config(get_runtime_config_json(args.managed_application)); + auto config_path = get_runtime_config_from_file(args.managed_application); + runtime_config_t config(config_path); if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str()); diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp index 56d030505..4537554da 100644 --- a/src/corehost/cli/libhost.cpp +++ b/src/corehost/cli/libhost.cpp @@ -6,11 +6,12 @@ #include "trace.h" #include "libhost.h" -pal::string_t get_runtime_config_json(const pal::string_t& app_path) +pal::string_t get_runtime_config_from_file(const pal::string_t& file) { - auto name = get_filename_without_ext(app_path); + auto name = get_filename_without_ext(file); + name = name.substr(0, name.find(_X('.'))); auto json_name = name + _X(".runtimeconfig.json"); - auto json_path = get_directory(app_path); + auto json_path = get_directory(file); append_path(&json_path, json_name.c_str()); if (pal::file_exists(json_path)) diff --git a/src/corehost/cli/libhost.h b/src/corehost/cli/libhost.h index fa0d60e9c..d4e587e62 100644 --- a/src/corehost/cli/libhost.h +++ b/src/corehost/cli/libhost.h @@ -64,7 +64,7 @@ public: } }; -pal::string_t get_runtime_config_json(const pal::string_t& app_path); +pal::string_t get_runtime_config_from_file(const pal::string_t& file); host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr); #endif // __LIBHOST_H__ diff --git a/src/corehost/common/utils.cpp b/src/corehost/common/utils.cpp index 65f1b8c42..1587e7df5 100644 --- a/src/corehost/common/utils.cpp +++ b/src/corehost/common/utils.cpp @@ -74,7 +74,7 @@ pal::string_t get_filename_without_ext(const pal::string_t& path) size_t name_pos = path.find_last_of(_X("/\\")); size_t dot_pos = path.rfind(_X('.')); size_t start_pos = (name_pos == pal::string_t::npos) ? 0 : (name_pos + 1); - size_t count = (dot_pos == pal::string_t::npos) ? pal::string_t::npos : (dot_pos - start_pos); + size_t count = (dot_pos == pal::string_t::npos || dot_pos < start_pos) ? pal::string_t::npos : (dot_pos - start_pos); return path.substr(start_pos, count); } From eccf44c2004eab9c96e3d1df40f4443ce412eae1 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 7 Mar 2016 14:24:36 -0600 Subject: [PATCH 84/99] Add initial update-dependencies script. This script can be used to automatically update dotnet/cli's dependencies on other repos like CoreFX, NuGet, etc. Currently the script supports updating the CoreFX dependencies. --- Microsoft.DotNet.Cli.sln | 19 ++ .../CommandResult.cs | 17 +- scripts/update-dependencies.ps1 | 51 ++++ scripts/update-dependencies/Config.cs | 74 ++++++ scripts/update-dependencies/Dirs.cs | 12 + scripts/update-dependencies/Program.cs | 25 ++ scripts/update-dependencies/PushPRTargets.cs | 108 ++++++++ .../update-dependencies/UpdateFilesTargets.cs | 233 ++++++++++++++++++ scripts/update-dependencies/project.json | 25 ++ .../update-dependencies.xproj | 18 ++ 10 files changed, 575 insertions(+), 7 deletions(-) create mode 100644 scripts/update-dependencies.ps1 create mode 100644 scripts/update-dependencies/Config.cs create mode 100644 scripts/update-dependencies/Dirs.cs create mode 100644 scripts/update-dependencies/Program.cs create mode 100644 scripts/update-dependencies/PushPRTargets.cs create mode 100644 scripts/update-dependencies/UpdateFilesTargets.cs create mode 100644 scripts/update-dependencies/project.json create mode 100644 scripts/update-dependencies/update-dependencies.xproj diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index e2ce9023a..044847001 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -79,6 +79,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.UnitTests", "te EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test.Tests", "test\dotnet-test.Tests\dotnet-test.Tests.xproj", "{60C33D0A-A5D8-4AB0-9956-1F804654DF05}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "update-dependencies", "scripts\update-dependencies\update-dependencies.xproj", "{A28BD8AC-DF15-4F58-8299-98A9AE2B8726}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -555,6 +557,22 @@ Global {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {60C33D0A-A5D8-4AB0-9956-1F804654DF05}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|x64.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Debug|x64.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|Any CPU.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|x64.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.Release|x64.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -591,5 +609,6 @@ Global {0724ED7C-56E3-4604-9970-25E600611383} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {857274AC-E741-4266-A7FD-14DEE0C1CC96} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {60C33D0A-A5D8-4AB0-9956-1F804654DF05} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} + {A28BD8AC-DF15-4F58-8299-98A9AE2B8726} = {88278B81-7649-45DC-8A6A-D3A645C5AFC3} EndGlobalSection EndGlobal diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs index d6e657e2f..e93320453 100644 --- a/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs +++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/CommandResult.cs @@ -24,20 +24,23 @@ namespace Microsoft.DotNet.Cli.Build.Framework StdErr = stdErr; } - public void EnsureSuccessful() + public void EnsureSuccessful(bool suppressOutput = false) { if(ExitCode != 0) { StringBuilder message = new StringBuilder($"Command failed with exit code {ExitCode}: {StartInfo.FileName} {StartInfo.Arguments}"); - if (!string.IsNullOrEmpty(StdOut)) + if (!suppressOutput) { - message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{StdOut}"); - } + if (!string.IsNullOrEmpty(StdOut)) + { + message.AppendLine($"{Environment.NewLine}Standard Output:{Environment.NewLine}{StdOut}"); + } - if (!string.IsNullOrEmpty(StdErr)) - { - message.AppendLine($"{Environment.NewLine}Standard Error:{Environment.NewLine}{StdErr}"); + if (!string.IsNullOrEmpty(StdErr)) + { + message.AppendLine($"{Environment.NewLine}Standard Error:{Environment.NewLine}{StdErr}"); + } } throw new BuildFailureException(message.ToString()); diff --git a/scripts/update-dependencies.ps1 b/scripts/update-dependencies.ps1 new file mode 100644 index 000000000..e7050cec1 --- /dev/null +++ b/scripts/update-dependencies.ps1 @@ -0,0 +1,51 @@ +# +# 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. +# + +param( + [string[]]$Targets=@("Default"), + [switch]$Help) + +if($Help) +{ + Write-Host "Usage: .\update-dependencies.ps1 [-Targets ]" + Write-Host "" + Write-Host "Options:" + Write-Host " -Targets Comma separated build targets to run (UpdateFiles, PushPR; Default is everything)" + Write-Host " -Help Display this help message" + exit 0 +} + +# Use a repo-local install directory (but not the artifacts directory because that gets cleaned a lot +if (!$env:DOTNET_INSTALL_DIR) +{ + $env:DOTNET_INSTALL_DIR="$PSScriptRoot\..\.dotnet_stage0\Windows\$Architecture" +} + +# Install a stage 0 +Write-Host "Installing .NET Core CLI Stage 0" +& "$PSScriptRoot\obtain\install.ps1" -Architecture x64 + +# Put the stage0 on the path +$env:PATH = "$env:DOTNET_INSTALL_DIR\cli\bin;$env:PATH" + +$appPath = "$PSScriptRoot\update-dependencies" + +# Restore the build scripts +Write-Host "Restoring Build Script projects..." +pushd $PSScriptRoot +dotnet restore +if($LASTEXITCODE -ne 0) { throw "Failed to restore" } +popd + +# Publish the app +Write-Host "Compiling App $appPath..." +dotnet publish "$appPath" -o "$appPath\bin" --framework netstandardapp1.5 +if($LASTEXITCODE -ne 0) { throw "Failed to compile build scripts" } + +# Run the app +Write-Host "Invoking App $appPath..." +Write-Host " Configuration: $env:CONFIGURATION" +& "$appPath\bin\update-dependencies.exe" @Targets +if($LASTEXITCODE -ne 0) { throw "Build failed" } diff --git a/scripts/update-dependencies/Config.cs b/scripts/update-dependencies/Config.cs new file mode 100644 index 000000000..c0e446ec3 --- /dev/null +++ b/scripts/update-dependencies/Config.cs @@ -0,0 +1,74 @@ +// 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 Microsoft.DotNet.Cli.Build.Framework; + +namespace Microsoft.DotNet.Scripts +{ + /// + /// Holds the configuration information for the update-dependencies script. + /// + /// + /// The following Environment Variables are required by this script: + /// + /// GITHUB_USER - The user to commit the changes as. + /// GITHUB_EMAIL - The user's email to commit the changes as. + /// GITHUB_PASSWORD - The password/personal access token of the GitHub user. + /// + /// The following Environment Variables can optionally be specified: + /// + /// COREFX_VERSION_URL - The Url to get the current CoreFx version. (ex. "https://raw.githubusercontent.com/dotnet/versions/master/dotnet/corefx/release/1.0.0-rc2/LKG.txt") + /// GITHUB_ORIGIN_OWNER - The owner of the GitHub fork to push the commit and create the PR from. (ex. "dotnet-bot") + /// GITHUB_UPSTREAM_OWNER - The owner of the GitHub base repo to create the PR to. (ex. "dotnet") + /// GITHUB_PROJECT - The repo name under the ORIGIN and UPSTREAM owners. (ex. "cli") + /// GITHUB_UPSTREAM_BRANCH - The branch in the GitHub base repo to create the PR to. (ex. "rel/1.0.0") + /// + public class Config + { + public static Config Instance { get; } = Read(); + + public string UserName { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public string CoreFxVersionUrl { get; set; } + public string GitHubOriginOwner { get; set; } + public string GitHubUpstreamOwner { get; set; } + public string GitHubProject { get; set; } + public string GitHubUpstreamBranch { get; set; } + + private static Config Read() + { + string userName = GetEnvironmentVariable("GITHUB_USER"); + + return new Config + { + UserName = userName, + Email = GetEnvironmentVariable("GITHUB_EMAIL"), + Password = GetEnvironmentVariable("GITHUB_PASSWORD"), + + CoreFxVersionUrl = GetEnvironmentVariable("COREFX_VERSION_URL", "https://raw.githubusercontent.com/dotnet/versions/master/dotnet/corefx/release/1.0.0-rc2/LKG.txt"), + GitHubOriginOwner = GetEnvironmentVariable("GITHUB_ORIGIN_OWNER", userName), + GitHubUpstreamOwner = GetEnvironmentVariable("GITHUB_UPSTREAM_OWNER", "dotnet"), + GitHubProject = GetEnvironmentVariable("GITHUB_PROJECT", "cli"), + GitHubUpstreamBranch = GetEnvironmentVariable("GITHUB_UPSTREAM_BRANCH", "rel/1.0.0"), + }; + } + + private static string GetEnvironmentVariable(string name, string defaultValue = null) + { + string value = Environment.GetEnvironmentVariable(name); + if (string.IsNullOrEmpty(value)) + { + value = defaultValue; + } + + if (string.IsNullOrEmpty(value)) + { + throw new BuildFailureException($"Can't find environment variable '{name}'."); + } + + return value; + } + } +} diff --git a/scripts/update-dependencies/Dirs.cs b/scripts/update-dependencies/Dirs.cs new file mode 100644 index 000000000..302928f02 --- /dev/null +++ b/scripts/update-dependencies/Dirs.cs @@ -0,0 +1,12 @@ +// 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.IO; + +namespace Microsoft.DotNet.Scripts +{ + public static class Dirs + { + public static readonly string RepoRoot = Directory.GetCurrentDirectory(); + } +} diff --git a/scripts/update-dependencies/Program.cs b/scripts/update-dependencies/Program.cs new file mode 100644 index 000000000..f0fc8f8d1 --- /dev/null +++ b/scripts/update-dependencies/Program.cs @@ -0,0 +1,25 @@ +// 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.Build.Framework; + +namespace Microsoft.DotNet.Scripts +{ + public class Program + { + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + return BuildSetup.Create(".NET CLI Dependency Updater") + .UseTargets(new[] + { + new BuildTarget("Default", "Dependency Updater Goals", new [] { "UpdateFiles", "PushPR" }), + new BuildTarget("UpdateFiles", "Dependency Updater Goals"), + new BuildTarget("PushPR", "Dependency Updater Goals"), + }) + .UseAllTargetsFromAssembly() + .Run(args); + } + } +} diff --git a/scripts/update-dependencies/PushPRTargets.cs b/scripts/update-dependencies/PushPRTargets.cs new file mode 100644 index 000000000..4d9ca44c1 --- /dev/null +++ b/scripts/update-dependencies/PushPRTargets.cs @@ -0,0 +1,108 @@ +// 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 Microsoft.DotNet.Cli.Build.Framework; +using Octokit; + +using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; + +namespace Microsoft.DotNet.Scripts +{ + /// + /// Creates a GitHub Pull Request for the current changes in the repo. + /// + public static class PushPRTargets + { + private const string PullRequestTitle = "Updating dependencies from last known good builds"; + + private static readonly Config s_config = Config.Instance; + + [Target(nameof(CommitChanges), nameof(CreatePR))] + public static BuildTargetResult PushPR(BuildTargetContext c) => c.Success(); + + /// + /// Commits all the current changes in the repo and pushes the commit to a remote + /// so a PR can be created for it. + /// + [Target] + public static BuildTargetResult CommitChanges(BuildTargetContext c) + { + Cmd("git", "add", ".") + .Execute() + .EnsureSuccessful(); + + string userName = s_config.UserName; + string email = s_config.Email; + + Cmd("git", "commit", "-m", PullRequestTitle, "--author", $"{userName} <{email}>") + .EnvironmentVariable("GIT_COMMITTER_NAME", userName) + .EnvironmentVariable("GIT_COMMITTER_EMAIL", email) + .Execute() + .EnsureSuccessful(); + + string remoteUrl = $"github.com/{s_config.GitHubOriginOwner}/{s_config.GitHubProject}.git"; + string remoteBranchName = $"UpdateDependencies{DateTime.UtcNow.ToString("yyyyMMddhhmmss")}"; + string refSpec = $"HEAD:refs/heads/{remoteBranchName}"; + + string logMessage = $"git push https://{remoteUrl} {refSpec}"; + BuildReporter.BeginSection("EXEC", logMessage); + + CommandResult pushResult = + Cmd("git", "push", $"https://{userName}:{s_config.Password}@{remoteUrl}", refSpec) + .QuietBuildReporter() // we don't want secrets showing up in our logs + .CaptureStdErr() // git push will write to StdErr upon success, disable that + .CaptureStdOut() + .Execute(); + + var message = logMessage + $" exited with {pushResult.ExitCode}"; + if (pushResult.ExitCode == 0) + { + BuildReporter.EndSection("EXEC", message.Green(), success: true); + } + else + { + BuildReporter.EndSection("EXEC", message.Red().Bold(), success: false); + } + + pushResult.EnsureSuccessful(suppressOutput: true); + + c.SetRemoteBranchName(remoteBranchName); + + return c.Success(); + } + + /// + /// Creates a GitHub PR for the remote branch created above. + /// + [Target] + public static BuildTargetResult CreatePR(BuildTargetContext c) + { + string remoteBranchName = c.GetRemoteBranchName(); + + NewPullRequest prInfo = new NewPullRequest( + PullRequestTitle, + s_config.GitHubOriginOwner + ":" + remoteBranchName, + s_config.GitHubUpstreamBranch); + + GitHubClient gitHub = new GitHubClient(new ProductHeaderValue("dotnetDependencyUpdater")); + + gitHub.Credentials = new Credentials(s_config.Password); + + PullRequest createdPR = gitHub.PullRequest.Create(s_config.GitHubUpstreamOwner, s_config.GitHubProject, prInfo).Result; + c.Info($"Created Pull Request: {createdPR.HtmlUrl}"); + + return c.Success(); + } + + private static string GetRemoteBranchName(this BuildTargetContext c) + { + return (string)c.BuildContext["RemoteBranchName"]; + } + + private static void SetRemoteBranchName(this BuildTargetContext c, string value) + { + c.BuildContext["RemoteBranchName"] = value; + } + } +} diff --git a/scripts/update-dependencies/UpdateFilesTargets.cs b/scripts/update-dependencies/UpdateFilesTargets.cs new file mode 100644 index 000000000..31527ce59 --- /dev/null +++ b/scripts/update-dependencies/UpdateFilesTargets.cs @@ -0,0 +1,233 @@ +// 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.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.DotNet.Cli.Build.Framework; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Scripts +{ + public static class UpdateFilesTargets + { + private static HttpClient s_client = new HttpClient(); + + [Target(nameof(GetDependencies), nameof(ReplaceVersions))] + public static BuildTargetResult UpdateFiles(BuildTargetContext c) => c.Success(); + + /// + /// Gets all the dependency information and puts it in the build properties. + /// + [Target] + public static BuildTargetResult GetDependencies(BuildTargetContext c) + { + string coreFxLkgVersion = s_client.GetStringAsync(Config.Instance.CoreFxVersionUrl).Result; + coreFxLkgVersion = coreFxLkgVersion.Trim(); + + const string coreFxIdPattern = @"^(?i)((System\..*)|(NETStandard\.Library)|(Microsoft\.CSharp)|(Microsoft\.NETCore.*)|(Microsoft\.TargetingPack\.Private\.(CoreCLR|NETNative))|(Microsoft\.Win32\..*)|(Microsoft\.VisualBasic))$"; + const string coreFxIdExclusionPattern = @"System.CommandLine"; + + List dependencyInfos = c.GetDependencyInfo(); + dependencyInfos.Add(new DependencyInfo() + { + Name = "CoreFx", + IdPattern = coreFxIdPattern, + IdExclusionPattern = coreFxIdExclusionPattern, + NewReleaseVersion = coreFxLkgVersion + }); + + return c.Success(); + } + + private static List GetDependencyInfo(this BuildTargetContext c) + { + const string propertyName = "DependencyInfo"; + + List dependencyInfos; + object dependencyInfosObj; + if (c.BuildContext.Properties.TryGetValue(propertyName, out dependencyInfosObj)) + { + dependencyInfos = (List)dependencyInfosObj; + } + else + { + dependencyInfos = new List(); + c.BuildContext[propertyName] = dependencyInfos; + } + + return dependencyInfos; + } + + [Target(nameof(ReplaceProjectJson), nameof(ReplaceCrossGen))] + public static BuildTargetResult ReplaceVersions(BuildTargetContext c) => c.Success(); + + /// + /// Replaces all the dependency versions in the project.json files. + /// + [Target] + public static BuildTargetResult ReplaceProjectJson(BuildTargetContext c) + { + List dependencyInfos = c.GetDependencyInfo(); + + IEnumerable projectJsonFiles = Enumerable.Union( + Directory.GetFiles(Dirs.RepoRoot, "project.json", SearchOption.AllDirectories), + Directory.GetFiles(Path.Combine(Dirs.RepoRoot, @"src\dotnet\commands\dotnet-new"), "project.json.template", SearchOption.AllDirectories)); + + JObject projectRoot; + foreach (string projectJsonFile in projectJsonFiles) + { + try + { + projectRoot = ReadProject(projectJsonFile); + } + catch (Exception e) + { + c.Warn($"Non-fatal exception occurred reading '{projectJsonFile}'. Skipping file. Exception: {e}. "); + continue; + } + + bool changedAnyPackage = FindAllDependencyProperties(projectRoot) + .Select(dependencyProperty => ReplaceDependencyVersion(dependencyProperty, dependencyInfos)) + .ToArray() + .Any(shouldWrite => shouldWrite); + + if (changedAnyPackage) + { + c.Info($"Writing changes to {projectJsonFile}"); + WriteProject(projectRoot, projectJsonFile); + } + } + + return c.Success(); + } + + /// + /// Replaces the single dependency with the updated version, if it matches any of the dependencies that need to be updated. + /// + private static bool ReplaceDependencyVersion(JProperty dependencyProperty, List dependencyInfos) + { + string id = dependencyProperty.Name; + foreach (DependencyInfo dependencyInfo in dependencyInfos) + { + if (Regex.IsMatch(id, dependencyInfo.IdPattern)) + { + if (string.IsNullOrEmpty(dependencyInfo.IdExclusionPattern) || !Regex.IsMatch(id, dependencyInfo.IdExclusionPattern)) + { + string version; + if (dependencyProperty.Value is JObject) + { + version = dependencyProperty.Value["version"].Value(); + } + else if (dependencyProperty.Value is JValue) + { + version = dependencyProperty.Value.ToString(); + } + else + { + throw new Exception($"Invalid package project.json version {dependencyProperty}"); + } + + VersionRange dependencyVersionRange = VersionRange.Parse(version); + NuGetVersion dependencyVersion = dependencyVersionRange.MinVersion; + + string newReleaseVersion = dependencyInfo.NewReleaseVersion; + + if (!string.IsNullOrEmpty(dependencyVersion.Release) && dependencyVersion.Release != newReleaseVersion) + { + string newVersion = new NuGetVersion( + dependencyVersion.Major, + dependencyVersion.Minor, + dependencyVersion.Patch, + newReleaseVersion, + dependencyVersion.Metadata).ToNormalizedString(); + + if (dependencyProperty.Value is JObject) + { + dependencyProperty.Value["version"] = newVersion; + } + else + { + dependencyProperty.Value = newVersion; + } + + return true; + } + } + } + } + + return false; + } + + private static JObject ReadProject(string projectJsonPath) + { + using (TextReader projectFileReader = File.OpenText(projectJsonPath)) + { + var projectJsonReader = new JsonTextReader(projectFileReader); + + var serializer = new JsonSerializer(); + return serializer.Deserialize(projectJsonReader); + } + } + + private static void WriteProject(JObject projectRoot, string projectJsonPath) + { + string projectJson = JsonConvert.SerializeObject(projectRoot, Formatting.Indented); + + File.WriteAllText(projectJsonPath, projectJson + Environment.NewLine); + } + + private static IEnumerable FindAllDependencyProperties(JObject projectJsonRoot) + { + return projectJsonRoot + .Descendants() + .OfType() + .Where(property => property.Name == "dependencies") + .Select(property => property.Value) + .SelectMany(o => o.Children()); + } + + private class DependencyInfo + { + public string Name { get; set; } + public string IdPattern { get; set; } + public string IdExclusionPattern { get; set; } + public string NewReleaseVersion { get; set; } + } + + /// + /// Replaces version number that is hard-coded in the CrossGen script. + /// + [Target] + public static BuildTargetResult ReplaceCrossGen(BuildTargetContext c) + { + DependencyInfo coreFXInfo = c.GetDependencyInfo().Single(d => d.Name == "CoreFx"); + + string compileTargetsPath = Path.Combine(Dirs.RepoRoot, @"scripts\dotnet-cli-build\CompileTargets.cs"); + string compileTargetsContent = File.ReadAllText(compileTargetsPath); + + Regex regex = new Regex(@"CoreCLRVersion = ""(?\d.\d.\d)-(?.*)"";"); + compileTargetsContent = regex.Replace(compileTargetsContent, m => + { + string replacedValue = m.Value; + Group releaseGroup = m.Groups["release"]; + + replacedValue = replacedValue.Remove(releaseGroup.Index - m.Index, releaseGroup.Length); + replacedValue = replacedValue.Insert(releaseGroup.Index - m.Index, coreFXInfo.NewReleaseVersion); + + return replacedValue; + }); + + File.WriteAllText(compileTargetsPath, compileTargetsContent, Encoding.UTF8); + + return c.Success(); + } + } +} diff --git a/scripts/update-dependencies/project.json b/scripts/update-dependencies/project.json new file mode 100644 index 000000000..d5a24cc82 --- /dev/null +++ b/scripts/update-dependencies/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.0.0-*", + "description": "Updates the repos dependencies", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23911", + "Microsoft.CSharp": "4.0.1-rc2-23911", + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-23911", + "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*", + "NuGet.Versioning": "3.4.0-rtm-0764", + "Newtonsoft.Json": "7.0.1", + "Octokit": "0.18.0", + "Microsoft.Net.Http": "2.2.29" + }, + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win" + ] + } + } +} diff --git a/scripts/update-dependencies/update-dependencies.xproj b/scripts/update-dependencies/update-dependencies.xproj new file mode 100644 index 000000000..07cff1695 --- /dev/null +++ b/scripts/update-dependencies/update-dependencies.xproj @@ -0,0 +1,18 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + a28bd8ac-df15-4f58-8299-98a9ae2b8726 + Microsoft.DotNet.Scripts + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + \ No newline at end of file From 6970a757468ffec08f9a946ad4bf683bccb5d3fb Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 17 Mar 2016 08:36:37 -0700 Subject: [PATCH 85/99] Remove csv reader --- .../DependencyContextCsvReader.cs | 139 ------------------ .../DependencyContextJsonReader.cs | 65 +++++--- .../DependencyContextLoader.cs | 18 +-- .../Library.cs | 5 - .../CompositeResolverTests.cs | 20 +-- .../DependencyContextCsvReaderTests.cs | 94 ------------ .../DependencyContextJsonReaderTest.cs | 18 +-- .../DependencyContextJsonWriterTests.cs | 2 +- 8 files changed, 57 insertions(+), 304 deletions(-) delete mode 100644 src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs delete mode 100644 test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextCsvReaderTests.cs diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs deleted file mode 100644 index f79199b99..000000000 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs +++ /dev/null @@ -1,139 +0,0 @@ -// 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.Text; - -namespace Microsoft.Extensions.DependencyModel -{ - public class DependencyContextCsvReader: IDependencyContextReader - { - public DependencyContext Read(Stream stream) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - var lines = new List(); - using (var reader = new StreamReader(stream)) - { - while (!reader.EndOfStream) - { - var line = new DepsFileLine(); - line.LibraryType = ReadValue(reader); - line.PackageName = ReadValue(reader); - line.PackageVersion = ReadValue(reader); - line.PackageHash = ReadValue(reader); - line.AssetType = ReadValue(reader); - line.AssetName = ReadValue(reader); - line.AssetPath = ReadValue(reader); - - if (line.AssetType == "runtime" && - !line.AssetPath.EndsWith(".ni.dll")) - { - lines.Add(line); - } - SkipWhitespace(reader); - } - } - - var runtimeLibraries = new List(); - var packageGroups = lines.GroupBy(PackageIdentity); - foreach (var packageGroup in packageGroups) - { - var identity = packageGroup.Key; - runtimeLibraries.Add(new RuntimeLibrary( - type: identity.Item1, - name: identity.Item2, - version: identity.Item3, - hash: identity.Item4, - assemblies: packageGroup.Select(l => RuntimeAssembly.Create(l.AssetPath)), - nativeLibraries: Enumerable.Empty(), - resourceAssemblies: Enumerable.Empty(), - subTargets: Enumerable.Empty(), - dependencies: Enumerable.Empty(), - serviceable: false - )); - } - - return new DependencyContext( - targetFramework: string.Empty, - runtime: string.Empty, - isPortable: false, - compilationOptions: CompilationOptions.Default, - compileLibraries: Enumerable.Empty(), - runtimeLibraries: runtimeLibraries.ToArray(), - runtimeGraph: Enumerable.Empty()); - } - - private Tuple PackageIdentity(DepsFileLine line) - { - return Tuple.Create(line.LibraryType, line.PackageName, line.PackageVersion, line.PackageHash); - } - - private void SkipWhitespace(StreamReader reader) - { - // skip all whitespace - while (!reader.EndOfStream && char.IsWhiteSpace((char)reader.Peek())) - { - reader.Read(); - } - } - - private string ReadValue(StreamReader reader) - { - SkipWhitespace(reader); - - var c = ReadSucceed(reader.Read()); - if (c != '"') - { - throw new FormatException("Deps file value should start with '\"'"); - } - - var value = new StringBuilder(); - while (ReadSucceed(reader.Peek()) != '"') - { - c = ReadSucceed(reader.Read()); - if (c == '\\') - { - value.Append(ReadSucceed(reader.Read())); - } - else - { - value.Append(c); - } - } - // Read last " - ReadSucceed(reader.Read()); - // Read comment - if (reader.Peek() == ',') - { - reader.Read(); - } - return value.ToString(); - } - - private char ReadSucceed(int c) - { - if (c == -1) - { - throw new FormatException("Unexpected end of file"); - } - return (char) c; - } - - private struct DepsFileLine - { - public string LibraryType; - public string PackageName; - public string PackageVersion; - public string PackageHash; - public string AssetType; - public string AssetName; - public string AssetPath; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs index ed8fd17da..ceb2f5c2d 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs @@ -43,35 +43,60 @@ namespace Microsoft.Extensions.DependencyModel JObject runtimeTarget = null; JObject compileTarget = null; - if (targetsObject != null) + + if (targetsObject == null) { - var compileTargetProperty = targetsObject.Properties() - .FirstOrDefault(p => !IsRuntimeTarget(p.Name)); + throw new FormatException("Dependency file does not have 'targets' section"); + } - compileTarget = (JObject)compileTargetProperty.Value; - target = compileTargetProperty.Name; - - if (!string.IsNullOrEmpty(runtimeTargetName)) + if (!string.IsNullOrEmpty(runtimeTargetName)) + { + runtimeTarget = (JObject) targetsObject[runtimeTargetName]; + if (runtimeTarget == null) { - runtimeTarget = (JObject) targetsObject[runtimeTargetName]; - if (runtimeTarget == null) - { - throw new FormatException($"Target with name {runtimeTargetName} not found"); - } + throw new FormatException($"Target with name {runtimeTargetName} not found"); + } + } + else + { + var runtimeTargetProperty = targetsObject.Properties() + .FirstOrDefault(p => IsRuntimeTarget(p.Name)); - var seperatorIndex = runtimeTargetName.IndexOf(DependencyContextStrings.VersionSeperator); - if (seperatorIndex > -1 && seperatorIndex < runtimeTargetName.Length) - { - runtime = runtimeTargetName.Substring(seperatorIndex + 1); - isPortable = false; - } + runtimeTarget = (JObject)runtimeTargetProperty?.Value; + runtimeTargetName = runtimeTargetProperty?.Name; + } + + if (runtimeTargetName != null) + { + var seperatorIndex = runtimeTargetName.IndexOf(DependencyContextStrings.VersionSeperator); + if (seperatorIndex > -1 && seperatorIndex < runtimeTargetName.Length) + { + runtime = runtimeTargetName.Substring(seperatorIndex + 1); + target = runtimeTargetName.Substring(0, seperatorIndex); + isPortable = false; } else { - runtimeTarget = compileTarget; + target = runtimeTargetName; } } + var ridlessTargetProperty = targetsObject.Properties().FirstOrDefault(p => !IsRuntimeTarget(p.Name)); + if (ridlessTargetProperty != null) + { + compileTarget = (JObject)ridlessTargetProperty.Value; + if (runtimeTarget == null) + { + runtimeTarget = compileTarget; + target = ridlessTargetProperty.Name; + } + } + + if (runtimeTarget == null) + { + throw new FormatException("No runtime target found"); + } + return new DependencyContext( target, runtime, @@ -104,7 +129,7 @@ namespace Microsoft.Extensions.DependencyModel } return new CompilationOptions( - compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values(), + compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values() ?? Enumerable.Empty(), compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value(), compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value(), compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value(), diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs index 39e647d70..9cc4d5f6c 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs @@ -14,20 +14,17 @@ namespace Microsoft.Extensions.DependencyModel private static Lazy _depsFiles = new Lazy(GetHostDepsList); private const string DepsJsonExtension = ".deps.json"; - private const string DepsExtension = ".deps"; private readonly string _entryPointDepsLocation; private readonly string _runtimeDepsLocation; private readonly IFileSystem _fileSystem; private readonly IDependencyContextReader _jsonReader; - private readonly IDependencyContextReader _csvReader; public DependencyContextLoader() : this( GetDefaultEntrypointDepsLocation(), GetDefaultRuntimeDepsLocation(), FileSystemWrapper.Default, - new DependencyContextJsonReader(), - new DependencyContextCsvReader()) + new DependencyContextJsonReader()) { } @@ -35,14 +32,12 @@ namespace Microsoft.Extensions.DependencyModel string entryPointDepsLocation, string runtimeDepsLocation, IFileSystem fileSystem, - IDependencyContextReader jsonReader, - IDependencyContextReader csvReader) + IDependencyContextReader jsonReader) { _entryPointDepsLocation = entryPointDepsLocation; _runtimeDepsLocation = runtimeDepsLocation; _fileSystem = fileSystem; _jsonReader = jsonReader; - _csvReader = csvReader; } public static DependencyContextLoader Default { get; } = new DependencyContextLoader(); @@ -132,15 +127,6 @@ namespace Microsoft.Extensions.DependencyModel } } - var depsFile = Path.ChangeExtension(assembly.Location, DepsExtension); - if (_fileSystem.File.Exists(depsFile)) - { - using (var stream = _fileSystem.File.OpenRead(depsFile)) - { - return _csvReader.Read(stream); - } - } - return null; } diff --git a/src/Microsoft.Extensions.DependencyModel/Library.cs b/src/Microsoft.Extensions.DependencyModel/Library.cs index a522a68e2..5e9b074e5 100644 --- a/src/Microsoft.Extensions.DependencyModel/Library.cs +++ b/src/Microsoft.Extensions.DependencyModel/Library.cs @@ -23,11 +23,6 @@ namespace Microsoft.Extensions.DependencyModel { throw new ArgumentException(nameof(version)); } - // Hash could be empty for projects - if (hash == null) - { - throw new ArgumentException(nameof(hash)); - } if (dependencies == null) { throw new ArgumentNullException(nameof(dependencies)); diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/CompositeResolverTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/CompositeResolverTests.cs index c78bf7d4a..eb407f548 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/CompositeResolverTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/CompositeResolverTests.cs @@ -10,7 +10,7 @@ using Moq; using Xunit; using FluentAssertions; -namespace StreamForwarderTests +namespace Microsoft.Extensions.DependencyModel.Tests { public class CompositeResolverTests { @@ -55,14 +55,7 @@ namespace StreamForwarderTests failTwo.Object }; - var library = new CompilationLibrary( - string.Empty, - string.Empty, - string.Empty, - string.Empty, - Enumerable.Empty(), - Enumerable.Empty(), - false); + var library = TestLibraryFactory.Create(); var resolver = new CompositeCompilationAssemblyResolver(resolvers); var result = resolver.TryResolveAssemblyPaths(library, null); @@ -90,14 +83,7 @@ namespace StreamForwarderTests }; var assemblies = new List(); - var library = new CompilationLibrary( - string.Empty, - string.Empty, - string.Empty, - string.Empty, - Enumerable.Empty(), - Enumerable.Empty(), - false); + var library = TestLibraryFactory.Create(); var resolver = new CompositeCompilationAssemblyResolver(resolvers); var result = resolver.TryResolveAssemblyPaths(library, assemblies); diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextCsvReaderTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextCsvReaderTests.cs deleted file mode 100644 index 7c19c1c69..000000000 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextCsvReaderTests.cs +++ /dev/null @@ -1,94 +0,0 @@ -// 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.Threading.Tasks; -using System.Text; -using Microsoft.Extensions.DependencyModel; -using FluentAssertions; -using Xunit; - -namespace Microsoft.Extensions.DependencyModel.Tests -{ - public class DependencyContextCsvReaderTests - { - private DependencyContext Read(string text) - { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(text))) - { - return new DependencyContextCsvReader().Read(stream); - } - } - - [Fact] - public void GroupsAssetsCorrectlyIntoLibraries() - { - var context = Read(@" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.Runtime.dll"" -"); - context.RuntimeLibraries.Should().HaveCount(1); - var library = context.RuntimeLibraries.Single(); - library.Type.Should().Be("Package"); - library.Name.Should().Be("runtime.any.System.AppContext"); - library.Version.Should().Be("4.1.0-rc2-23811"); - library.Hash.Should().Be("sha512-1"); - library.Assemblies.Should().HaveCount(2).And - .Contain(a => a.Path == "lib\\dnxcore50\\System.AppContext.dll").And - .Contain(a => a.Path == "lib\\dnxcore50\\System.Runtime.dll"); - } - - [Fact] - public void IgnoresAllButRuntimeAssets() - { - var context = Read(@" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""native"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext2.so"" -"); - context.RuntimeLibraries.Should().HaveCount(1); - var library = context.RuntimeLibraries.Single(); - library.Assemblies.Should().HaveCount(1).And - .Contain(a => a.Path == "lib\\dnxcore50\\System.AppContext.dll"); - } - - [Fact] - public void IgnoresNiDllAssemblies() - { - var context = Read(@" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.ni.dll"" -"); - context.RuntimeLibraries.Should().HaveCount(1); - var library = context.RuntimeLibraries.Single(); - library.Assemblies.Should().HaveCount(1).And - .Contain(a => a.Path == "lib\\dnxcore50\\System.AppContext.dll"); - } - - [Fact] - public void UsesTypeNameVersionAndHashToGroup() - { - var context = Read(@" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23812"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-2"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Package"",""runtime.any.System.AppContext2"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -""Project"",""runtime.any.System.AppContext"",""4.1.0-rc2-23811"",""sha512-1"",""runtime"",""System.AppContext"",""lib\\dnxcore50\\System.AppContext.dll"" -"); - context.RuntimeLibraries.Should().HaveCount(5); - } - - [Theory] - [InlineData("text")] - [InlineData(" ")] - [InlineData("\"")] - [InlineData(@""",""")] - [InlineData(@"\\")] - public void ThrowsFormatException(string intput) - { - Assert.Throws(() => Read(intput)); - } - } -} diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs index e3cae30e5..b611ebd69 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonReaderTest.cs @@ -26,7 +26,6 @@ namespace Microsoft.Extensions.DependencyModel.Tests @"{ ""runtimeTarget"": "".NETStandardApp,Version=v1.5/osx.10.10-x64"", ""targets"": { - "".NETStandardApp,Version=v1.5"": {}, "".NETStandardApp,Version=v1.5/osx.10.10-x64"": {}, } }"); @@ -35,21 +34,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests context.Runtime.Should().Be("osx.10.10-x64"); } - [Fact] - public void DefaultsToPortable() - { - var context = Read( -@"{ -}"); - context.IsPortable.Should().BeTrue(); - } - [Fact] public void SetsPortableIfRuntimeTargetHasNoRid() { var context = Read( @"{ - ""runtimeTarget"": "".NETStandardApp,Version=v1.5"", ""targets"": { "".NETStandardApp,Version=v1.5"": {} } @@ -64,7 +53,6 @@ namespace Microsoft.Extensions.DependencyModel.Tests @"{ ""runtimeTarget"": "".NETStandardApp,Version=v1.5/osx.10.10-x64"", ""targets"": { - "".NETStandardApp,Version=v1.5"": {}, "".NETStandardApp,Version=v1.5/osx.10.10-x64"": {} } }"); @@ -88,6 +76,9 @@ namespace Microsoft.Extensions.DependencyModel.Tests { var context = Read( @"{ + ""targets"": { + "".NETStandardApp,Version=v1.5/osx.10.10-x64"": {}, + }, ""runtimes"": { ""osx.10.10-x64"": [ ], ""osx.10.11-x64"": [ ""osx"" ], @@ -237,6 +228,9 @@ namespace Microsoft.Extensions.DependencyModel.Tests ""publicSign"": true, ""warningsAsErrors"": true, ""optimize"": true + }, + ""targets"": { + "".NETStandardApp,Version=v1.5/osx.10.10-x64"": {}, } }"); context.CompilationOptions.AllowUnsafe.Should().Be(true); diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs index f4d4ad721..ec7ca1a8c 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/DependencyContextJsonWriterTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.Extensions.DependencyModel.Tests IReadOnlyList runtimeGraph = null) { return new DependencyContext( - target ?? string.Empty, + target ?? "DefaultTarget", runtime ?? string.Empty, isPortable ?? false, compilationOptions ?? CompilationOptions.Default, From 75d49d99f3e722dbe361e718106124c5e3fc2087 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Thu, 17 Mar 2016 10:07:03 -0700 Subject: [PATCH 86/99] Bug fix to copy the hostpolicy and hostfxr binaries from the correct location. --- scripts/dotnet-cli-build/CompileTargets.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index d05bf4e2c..13f0a53c0 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -127,8 +127,8 @@ namespace Microsoft.DotNet.Cli.Build // Copy the output out File.Copy(Path.Combine(cmakeOut, "cli", "corehost"), Path.Combine(Dirs.Corehost, CoreHostBaseName), overwrite: true); - File.Copy(Path.Combine(cmakeOut, "cli", "dll", DotnetHostFxrBaseName), Path.Combine(Dirs.Corehost, DotnetHostFxrBaseName), overwrite: true); - File.Copy(Path.Combine(cmakeOut, "cli", "fxr", HostPolicyBaseName), Path.Combine(Dirs.Corehost, HostPolicyBaseName), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "dll", HostPolicyBaseName), Path.Combine(Dirs.Corehost, HostPolicyBaseName), overwrite: true); + File.Copy(Path.Combine(cmakeOut, "cli", "fxr", DotnetHostFxrBaseName), Path.Combine(Dirs.Corehost, DotnetHostFxrBaseName), overwrite: true); } return c.Success(); From b93b915cc652e35bcf604fb9b4b244bc84e5527c Mon Sep 17 00:00:00 2001 From: Senthil Date: Thu, 17 Mar 2016 11:05:49 -0700 Subject: [PATCH 87/99] Fix error check and verbose --- src/corehost/cli/fxr/fx_muxer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 4cc2f60fe..b371832bc 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -225,7 +225,7 @@ bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::stri /* static */ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) { - trace::error(_X("--- Executing in muxer mode...")); + trace::verbose(_X("--- Executing in muxer mode...")); pal::string_t own_path; @@ -343,7 +343,7 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) } append_path(&sdk_dotnet, _X("dotnet.dll")); - if (!pal::file_exists(_X("dotnet.dll"))) + if (!pal::file_exists(sdk_dotnet)) { trace::error(_X("Could not find dotnet.dll at [%s]"), sdk_dotnet.c_str()); return StatusCode::LibHostSdkFindFailure; From a766bc173eabeb53d6cd35bb5bec485acfa12bb5 Mon Sep 17 00:00:00 2001 From: Senthil Date: Thu, 17 Mar 2016 11:31:14 -0700 Subject: [PATCH 88/99] Relax error case if runtime config is not present --- src/corehost/cli/fxr/fx_muxer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index b371832bc..5638043a7 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -26,7 +26,7 @@ pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime fx_ver_t specified(-1, -1, -1); if (!fx_ver_t::parse(fx_ver, &specified, false)) { - trace::error(_X("The specified runtimeconfig.json version [%s] could not be parsed"), fx_ver.c_str()); + trace::info(_X("The specified runtimeconfig.json version [%s] could not be parsed"), fx_ver.c_str()); return pal::string_t(); } From ae83a73e3507fc090f2b91755fcef07dc16ec570 Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Thu, 17 Mar 2016 13:19:27 -0700 Subject: [PATCH 89/99] Create 'dotnet-dev' and 'dotnet' pkg. - 'dotnet-dev' contains the sharedfx, shared host and CLI SDK. - 'dotnet' contains the sharedfx and the shared host. --- packaging/osx/Distribution-Template | 22 ----- packaging/osx/clisdk/Distribution-Template | 33 +++++++ .../osx/{ => clisdk}/scripts/postinstall | 2 +- packaging/osx/package-osx.sh | 86 ------------------ scripts/dotnet-cli-build/PkgTargets.cs | 90 +++++++++++++++---- 5 files changed, 105 insertions(+), 128 deletions(-) delete mode 100644 packaging/osx/Distribution-Template create mode 100644 packaging/osx/clisdk/Distribution-Template rename packaging/osx/{ => clisdk}/scripts/postinstall (86%) delete mode 100755 packaging/osx/package-osx.sh diff --git a/packaging/osx/Distribution-Template b/packaging/osx/Distribution-Template deleted file mode 100644 index c220fa5ac..000000000 --- a/packaging/osx/Distribution-Template +++ /dev/null @@ -1,22 +0,0 @@ - - - .NET CLI {VERSION} - - - - - - - - - - - - - - - - - - dotnet-osx-x64.{VERSION}.pkg - diff --git a/packaging/osx/clisdk/Distribution-Template b/packaging/osx/clisdk/Distribution-Template new file mode 100644 index 000000000..7e3f3b7ad --- /dev/null +++ b/packaging/osx/clisdk/Distribution-Template @@ -0,0 +1,33 @@ + + + .NET CLI {VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + com.microsoft.dotnet.sharedframework.{SharedFrameworkNugetName}.{SharedFrameworkNugetVersion}.component.osx.x64.pkg + com.microsoft.dotnet.sharedhost.osx.x64.pkg + com.microsoft.dotnet.sdk.osx.x64.pkg + diff --git a/packaging/osx/scripts/postinstall b/packaging/osx/clisdk/scripts/postinstall similarity index 86% rename from packaging/osx/scripts/postinstall rename to packaging/osx/clisdk/scripts/postinstall index 0a649953a..428b79064 100755 --- a/packaging/osx/scripts/postinstall +++ b/packaging/osx/clisdk/scripts/postinstall @@ -12,7 +12,7 @@ INSTALL_DESTINATION=$2 chmod -R 755 $INSTALL_DESTINATION # Add the installation bin directory to the system-wide paths -echo $INSTALL_DESTINATION/bin | tee -a /etc/paths.d/dotnet +echo $INSTALL_DESTINATION | tee -a /etc/paths.d/dotnet exit 0 diff --git a/packaging/osx/package-osx.sh b/packaging/osx/package-osx.sh deleted file mode 100755 index 819a7e1f6..000000000 --- a/packaging/osx/package-osx.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# 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. -# - -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - -help(){ - echo "Usage: $0 [--version ] [--input ] [--output ] [--help]" - echo "" - echo "Options:" - echo " --version Specify a version for the package. Version format is 4 '.' separated numbers - ..." - echo " --input Package the entire contents of the directory tree." - echo " --output The path to where the package will be written." - exit 1 -} - -while [[ $# > 0 ]]; do - lowerI="$(echo $1 | awk '{print tolower($0)}')" - case $lowerI in - -v|--version) - DOTNET_CLI_VERSION=$2 - shift - ;; - -o|--output) - OUTPUT_PKG=$2 - shift - ;; - -i|--input) - INPUT_DIR=$2 - shift - ;; - --help) - help - ;; - *) - break - ;; - esac - shift -done - -if [ -z "$DOTNET_CLI_VERSION" ]; then - echo "Provide a version number. Missing option '--version'" && help -fi - -if [ -z "$OUTPUT_PKG" ]; then - echo "Provide an output pkg. Missing option '--output'" && help -fi - -if [ -z "$INPUT_DIR" ]; then - echo "Provide an input directory. Missing option '--input'" && help -fi - -if [ ! -d "$INPUT_DIR" ]; then - echo "'$INPUT_DIR' - is either missing or not a directory" 1>&2 - exit 1 -fi - -PACKAGE_DIR=$(dirname "${OUTPUT_PKG}") -[ -d "$PACKAGE_DIR" ] || mkdir -p $PACKAGE_DIR - -PACKAGE_ID=$(basename "${OUTPUT_PKG}") - -#chmod -R 755 $INPUT_DIR -pkgbuild --root $INPUT_DIR \ - --version $DOTNET_CLI_VERSION \ - --scripts $DIR/scripts \ - --identifier com.microsoft.dotnet.cli.pkg.dotnet-osx-x64 \ - --install-location /usr/local/share/dotnet \ - $DIR/$PACKAGE_ID - -cat $DIR/Distribution-Template | sed "/{VERSION}/s//$DOTNET_CLI_VERSION/g" > $DIR/Dist - -productbuild --version $DOTNET_CLI_VERSION --identifier com.microsoft.dotnet.cli --package-path $DIR --resources $DIR/resources --distribution $DIR/Dist $OUTPUT_PKG - -#Clean temp files -rm $DIR/$PACKAGE_ID -rm $DIR/Dist diff --git a/scripts/dotnet-cli-build/PkgTargets.cs b/scripts/dotnet-cli-build/PkgTargets.cs index 55b1ebe33..34220aac1 100644 --- a/scripts/dotnet-cli-build/PkgTargets.cs +++ b/scripts/dotnet-cli-build/PkgTargets.cs @@ -12,25 +12,80 @@ namespace Microsoft.DotNet.Cli.Build { public class PkgTargets { - [Target(nameof(GenerateSdkProductArchive), nameof(GenerateSharedFrameworkProductArchive))] + public static string PkgsIntermediateDir { get; set; } + [Target] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult InitPkg(BuildTargetContext c) + { + PkgsIntermediateDir = Path.Combine(Dirs.Packages, "intermediate"); + Directory.CreateDirectory(PkgsIntermediateDir); + return c.Success(); + } + + [Target(nameof(InitPkg), nameof(GenerateSharedFrameworkProductArchive), nameof(GenerateCLISdkProductArchive))] [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GeneratePkgs(BuildTargetContext c) { return c.Success(); } + [Target(nameof(GenerateCLISdkPkg))] + [BuildPlatforms(BuildPlatform.OSX)] + public static BuildTargetResult GenerateCLISdkProductArchive(BuildTargetContext c) + { + string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); + string version = c.BuildContext.Get("BuildVersion").SimpleVersion; + string id = $"com.microsoft.dotnet.dev.{version}.osx.x64"; + string resourcePath = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "resources"); + string outFilePath = Path.Combine(Dirs.Packages, c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile")); + + string inputDistTemplatePath = Path.Combine( + Dirs.RepoRoot, + "packaging", + "osx", + "clisdk", + "Distribution-Template"); + string distTemplate = File.ReadAllText(inputDistTemplatePath); + string distributionPath = Path.Combine(PkgsIntermediateDir, "CLI-SDK-Formatted-Distribution-Template.xml"); + string formattedDistContents = + distTemplate.Replace("{SharedFrameworkNugetVersion}", sharedFrameworkNugetVersion) + .Replace("{SharedFrameworkNugetName}", Monikers.SharedFrameworkName) + .Replace("{VERSION}", version); + File.WriteAllText(distributionPath, formattedDistContents); + + Cmd("productbuild", + "--version", version, + "--identifier", id, + "--package-path", PkgsIntermediateDir, + "--resources", resourcePath, + "--distribution", distributionPath, + outFilePath) + .Execute() + .EnsureSuccessful(); + + return c.Success(); + } + [Target] [BuildPlatforms(BuildPlatform.OSX)] - public static BuildTargetResult GenerateSdkProductArchive(BuildTargetContext c) + public static BuildTargetResult GenerateCLISdkPkg(BuildTargetContext c) { - var version = c.BuildContext.Get("BuildVersion").SimpleVersion; - var pkg = c.BuildContext.Get("CombinedFrameworkSDKHostInstallerFile"); - var input = c.BuildContext.Get("CLISDKRoot"); + string version = c.BuildContext.Get("BuildVersion").SimpleVersion; + string id = $"com.microsoft.dotnet.sdk.osx.x64"; + string outFilePath = Path.Combine(PkgsIntermediateDir, id + ".pkg"); + string installLocation = "/usr/local/share/dotnet"; + string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "clisdk", "scripts"); + + Cmd("pkgbuild", + "--root", c.BuildContext.Get("CLISDKRoot"), + "--identifier", id, + "--version", version, + "--install-location", installLocation, + "--scripts", scriptsLocation, + outFilePath) + .Execute() + .EnsureSuccessful(); - Cmd(Path.Combine(Dirs.RepoRoot, "packaging", "osx", "package-osx.sh"), - "-v", version, "-i", input, "-o", pkg) - .Execute() - .EnsureSuccessful(); return c.Success(); } @@ -41,10 +96,9 @@ namespace Microsoft.DotNet.Cli.Build string sharedFrameworkNugetName = Monikers.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; - string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.osx.x64"; - string packageIntermediatesPath = Path.Combine(Dirs.Output, "obj", "pkg"); + string id = $"com.microsoft.dotnet.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.osx.x64"; string resourcePath = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "resources"); - string outFilePath = Path.Combine(packageIntermediatesPath, id + ".pkg"); + string outFilePath = Path.Combine(PkgsIntermediateDir, c.BuildContext.Get("CombinedFrameworkHostInstallerFile")); string inputDistTemplatePath = Path.Combine( Dirs.RepoRoot, @@ -53,7 +107,7 @@ namespace Microsoft.DotNet.Cli.Build "sharedframework", "shared-framework-distribution-template.xml"); string distTemplate = File.ReadAllText(inputDistTemplatePath); - string distributionPath = Path.Combine(packageIntermediatesPath, "shared-framework-formatted-distribution.xml"); + string distributionPath = Path.Combine(PkgsIntermediateDir, "shared-framework-formatted-distribution.xml"); string formattedDistContents = distTemplate.Replace("{SharedFrameworkNugetVersion}", sharedFrameworkNugetVersion) .Replace("{SharedFrameworkNugetName}", Monikers.SharedFrameworkName) @@ -63,7 +117,7 @@ namespace Microsoft.DotNet.Cli.Build Cmd("productbuild", "--version", version, "--identifier", id, - "--package-path", packageIntermediatesPath, + "--package-path", PkgsIntermediateDir, "--resources", resourcePath, "--distribution", distributionPath, outFilePath) @@ -79,10 +133,9 @@ namespace Microsoft.DotNet.Cli.Build { string sharedFrameworkNugetName = Monikers.SharedFrameworkName; string sharedFrameworkNugetVersion = c.BuildContext.Get("SharedFrameworkNugetVersion"); - Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; string id = $"com.microsoft.dotnet.sharedframework.{sharedFrameworkNugetName}.{sharedFrameworkNugetVersion}.component.osx.x64"; - string outFilePath = Path.Combine(Dirs.Output, "obj", "pkg", id + ".pkg"); + string outFilePath = Path.Combine(PkgsIntermediateDir, id + ".pkg"); string installLocation = "/usr/local/share/dotnet"; string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "sharedframework", "scripts"); @@ -103,10 +156,9 @@ namespace Microsoft.DotNet.Cli.Build [BuildPlatforms(BuildPlatform.OSX)] public static BuildTargetResult GenerateSharedHostPkg(BuildTargetContext c) { - Directory.CreateDirectory(Path.Combine(Dirs.Output, "obj", "pkg")); string version = c.BuildContext.Get("BuildVersion").SimpleVersion; string id = $"com.microsoft.dotnet.sharedhost.osx.x64"; - string outFilePath = Path.Combine(Dirs.Output, "obj", "pkg", id + ".pkg"); + string outFilePath = Path.Combine(PkgsIntermediateDir, id + ".pkg"); string installLocation = "/usr/local/share/dotnet"; string scriptsLocation = Path.Combine(Dirs.RepoRoot, "packaging", "osx", "sharedhost", "scripts"); @@ -123,4 +175,4 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } } -} \ No newline at end of file +} From 51dcb6063f5142dd3269813a1fcb6af313fe3a4e Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 11:43:01 -0700 Subject: [PATCH 90/99] Add Portable Test Package Asset --- .../TestPackages/dotnet-portable/Program.cs | 12 ++++++++++++ .../TestPackages/dotnet-portable/project.json | 18 ++++++++++++++++++ .../project.json | 4 ++-- .../AppWithToolDependency/project.json | 4 ++-- scripts/dotnet-cli-build/TestTargets.cs | 3 ++- 5 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 TestAssets/TestPackages/dotnet-portable/Program.cs create mode 100644 TestAssets/TestPackages/dotnet-portable/project.json diff --git a/TestAssets/TestPackages/dotnet-portable/Program.cs b/TestAssets/TestPackages/dotnet-portable/Program.cs new file mode 100644 index 000000000..58d61b1bc --- /dev/null +++ b/TestAssets/TestPackages/dotnet-portable/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello Portable World!"); + } + } +} diff --git a/TestAssets/TestPackages/dotnet-portable/project.json b/TestAssets/TestPackages/dotnet-portable/project.json new file mode 100644 index 000000000..0f9d20ba9 --- /dev/null +++ b/TestAssets/TestPackages/dotnet-portable/project.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "compilationOptions": { + "emitEntryPoint": true + }, + + "frameworks": { + "netstandard1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win8" + ], + "dependencies": { + "Microsoft.NETCore.App": "1.0.0-rc2-23911" + } + } + } +} diff --git a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json index 7bcb08e63..c888180eb 100644 --- a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json +++ b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json @@ -17,8 +17,8 @@ }, "testRunner": "must-be-specified-to-generate-deps", "tools": { - "dotnet-hello": { - "version": "2.0.0", + "dotnet-portable": { + "version": "1.0.0", "target": "package" } } diff --git a/TestAssets/TestProjects/AppWithToolDependency/project.json b/TestAssets/TestProjects/AppWithToolDependency/project.json index 4628c7718..b25c0b2a3 100644 --- a/TestAssets/TestProjects/AppWithToolDependency/project.json +++ b/TestAssets/TestProjects/AppWithToolDependency/project.json @@ -12,8 +12,8 @@ } }, "tools": { - "dotnet-hello": { - "version": "2.0.0", + "dotnet-portable": { + "version": "1.0.0", "target": "package" } } diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index 5d0e3c31f..abedc6663 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -16,7 +16,8 @@ namespace Microsoft.DotNet.Cli.Build public static readonly string[] TestPackageProjects = new[] { "dotnet-hello/v1/dotnet-hello", - "dotnet-hello/v2/dotnet-hello" + "dotnet-hello/v2/dotnet-hello", + "dotnet-portable" }; public static readonly string[] TestProjects = new[] From bd3ba0bd41149ffea5d8fe1504e22fd3795a03a4 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 11:43:17 -0700 Subject: [PATCH 91/99] Update tests to reflect portable tools --- .../GivenAProjectToolsCommandResolver.cs | 57 +++++++++++++++++-- .../project.json | 5 ++ test/dotnet.Tests/PackagedCommandTests.cs | 24 +++++++- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs index c414b1345..9ad2c8b66 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs @@ -16,11 +16,14 @@ using Microsoft.Extensions.PlatformAbstractions; using System.Threading; using FluentAssertions; using NuGet.Frameworks; +using NuGet.Versioning; +using NuGet.ProjectModel; namespace Microsoft.DotNet.Cli.Utils.Tests { public class GivenAProjectToolsCommandResolver { + private static readonly NuGetFramework s_toolPackageFramework = FrameworkConstants.CommonFrameworks.NetStandardApp15; private static readonly string s_liveProjectDirectory = Path.Combine(AppContext.BaseDirectory, "TestAssets/TestProjects/AppWithToolDependency"); @@ -83,7 +86,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests var commandResolverArguments = new CommandResolverArguments() { - CommandName = "dotnet-hello", + CommandName = "dotnet-portable", CommandArguments = null, ProjectDirectory = s_liveProjectDirectory }; @@ -106,7 +109,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests var commandResolverArguments = new CommandResolverArguments() { - CommandName = "dotnet-hello", + CommandName = "dotnet-portable", CommandArguments = new [] { "arg with space"}, ProjectDirectory = s_liveProjectDirectory }; @@ -118,13 +121,13 @@ namespace Microsoft.DotNet.Cli.Utils.Tests } [Fact] - public void It_returns_a_CommandSpec_with_Args_as_CommandPath_when_returning_a_CommandSpec_and_CommandArguments_are_null() + public void It_returns_a_CommandSpec_with_Args_containing_CommandPath_when_returning_a_CommandSpec_and_CommandArguments_are_null() { var projectToolsCommandResolver = SetupProjectToolsCommandResolver(); var commandResolverArguments = new CommandResolverArguments() { - CommandName = "dotnet-hello", + CommandName = "dotnet-portable", CommandArguments = null, ProjectDirectory = s_liveProjectDirectory }; @@ -134,9 +137,51 @@ namespace Microsoft.DotNet.Cli.Utils.Tests result.Should().NotBeNull(); var commandPath = result.Args.Trim('"'); - commandPath.Should().Contain("dotnet-hello"); + commandPath.Should().Contain("dotnet-portable.dll"); + } - File.Exists(commandPath).Should().BeTrue(); + [Fact] + public void It_writes_a_deps_json_file_next_to_the_lockfile() + { + var projectToolsCommandResolver = SetupProjectToolsCommandResolver(); + + var commandResolverArguments = new CommandResolverArguments() + { + CommandName = "dotnet-portable", + CommandArguments = null, + ProjectDirectory = s_liveProjectDirectory + }; + + var context = ProjectContext.Create(Path.Combine(s_liveProjectDirectory, "project.json"), s_toolPackageFramework); + + var nugetPackagesRoot = context.PackagesDirectory; + var toolPathCalculator = new ToolPathCalculator(nugetPackagesRoot); + + var lockFilePath = toolPathCalculator.GetLockFilePath( + "dotnet-portable", + new NuGetVersion("1.0.0"), + s_toolPackageFramework); + + var directory = Path.GetDirectoryName(lockFilePath); + + var depsJsonFile = Directory + .EnumerateFiles(directory) + .FirstOrDefault(p => Path.GetFileName(p).EndsWith(FileNameSuffixes.DepsJson)); + + if (depsJsonFile != null) + { + File.Delete(depsJsonFile); + } + + var result = projectToolsCommandResolver.Resolve(commandResolverArguments); + result.Should().NotBeNull(); + + + depsJsonFile = Directory + .EnumerateFiles(directory) + .FirstOrDefault(p => Path.GetFileName(p).EndsWith(FileNameSuffixes.DepsJson)); + + depsJsonFile.Should().NotBeNull(); } private ProjectToolsCommandResolver SetupProjectToolsCommandResolver( diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json index 03dc29205..7be15c9ff 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/project.json +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/project.json @@ -5,6 +5,11 @@ }, "dependencies": { "NETStandard.Library": "1.5.0-rc2-23911", + "NuGet.Versioning": "3.4.0-rtm-0763", + "NuGet.Packaging": "3.4.0-rtm-0763", + "NuGet.Frameworks": "3.4.0-rtm-0763", + "NuGet.ProjectModel": "3.4.0-rtm-0763", + "Microsoft.DotNet.ProjectModel": { "target": "project" }, diff --git a/test/dotnet.Tests/PackagedCommandTests.cs b/test/dotnet.Tests/PackagedCommandTests.cs index 941d3f258..7b4a91b28 100644 --- a/test/dotnet.Tests/PackagedCommandTests.cs +++ b/test/dotnet.Tests/PackagedCommandTests.cs @@ -36,9 +36,9 @@ namespace Microsoft.DotNet.Tests try { - CommandResult result = new HelloCommand().ExecuteWithCapturedOutput(); + CommandResult result = new PortableCommand().ExecuteWithCapturedOutput(); - result.Should().HaveStdOut("Hello World!" + Environment.NewLine); + result.Should().HaveStdOut("Hello Portable World!" + Environment.NewLine); result.Should().NotHaveStdErr(); result.Should().Pass(); } @@ -94,5 +94,25 @@ namespace Microsoft.DotNet.Tests return base.ExecuteWithCapturedOutput(args); } } + + class PortableCommand : TestCommand + { + public PortableCommand() + : base("dotnet") + { + } + + public override CommandResult Execute(string args = "") + { + args = $"portable {args}"; + return base.Execute(args); + } + + public override CommandResult ExecuteWithCapturedOutput(string args = "") + { + args = $"portable {args}"; + return base.ExecuteWithCapturedOutput(args); + } + } } } From b59c4333eaca5bb7a175bc059d9bab31d8bf3c7b Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 11:44:18 -0700 Subject: [PATCH 92/99] Remove tool restore from dotnet restore, use nuget tool restore --- src/dotnet/commands/dotnet-restore/Program.cs | 155 +----------------- .../commands/dotnet-restore/RestoreTask.cs | 18 -- 2 files changed, 1 insertion(+), 172 deletions(-) delete mode 100644 src/dotnet/commands/dotnet-restore/RestoreTask.cs diff --git a/src/dotnet/commands/dotnet-restore/Program.cs b/src/dotnet/commands/dotnet-restore/Program.cs index 806604cf6..7cf615663 100644 --- a/src/dotnet/commands/dotnet-restore/Program.cs +++ b/src/dotnet/commands/dotnet-restore/Program.cs @@ -40,18 +40,7 @@ namespace Microsoft.DotNet.Tools.Restore { try { - var projectRestoreResult = NuGet3.Restore(args, quiet); - - var restoreTasks = GetRestoreTasks(args); - - foreach (var restoreTask in restoreTasks) - { - var project = ProjectReader.GetProject(restoreTask.ProjectPath); - - RestoreTools(project, restoreTask, quiet); - } - - return projectRestoreResult; + return NuGet3.Restore(args, quiet); } catch (InvalidOperationException e) { @@ -69,147 +58,5 @@ namespace Microsoft.DotNet.Tools.Restore return app.Execute(args); } - - private static IEnumerable GetRestoreTasks(IEnumerable args) - { - var directory = Directory.GetCurrentDirectory(); - - if (args.Any()) - { - var firstArg = args.First(); - - if (IsProjectFile(firstArg)) - { - return new [] {new RestoreTask { ProjectPath = firstArg, Arguments = args.Skip(1)} }; - } - - if (Directory.Exists(firstArg)) - { - directory = firstArg; - - args = args.Skip(1); - } - } - - return GetAllProjectFiles(directory) - .Select(p => new RestoreTask {ProjectPath = p, Arguments = args}); - } - - private static string[] GetAllProjectFiles(string directory) - { - return Directory.GetFiles(directory, Project.FileName, SearchOption.AllDirectories); - } - - private static bool IsProjectFile(string firstArg) - { - return firstArg.EndsWith(Project.FileName) && File.Exists(firstArg); - } - - private static void RestoreTools(Project project, RestoreTask restoreTask, bool quiet) - { - foreach (var tooldep in project.Tools) - { - RestoreTool(tooldep, restoreTask, quiet); - } - } - - private static void RestoreTool(LibraryRange tooldep, RestoreTask restoreTask, bool quiet) - { - var tempRoot = Path.Combine(restoreTask.ProjectDirectory, "obj"); - try - { - var tempPath = Path.Combine(tempRoot, Guid.NewGuid().ToString(), "bin"); - - var restoreSucceded = RestoreToolToPath(tooldep, restoreTask.Arguments, tempPath, quiet); - if (restoreSucceded) - { - CreateDepsInPackageCache(tooldep, tempPath); - PersistLockFile(tooldep, tempPath, restoreTask.ProjectDirectory); - } - } - finally - { - Directory.Delete(tempRoot, true); - } - } - - private static void PersistLockFile(LibraryRange tooldep, string tempPath, string projectPath) - { - var sourcePath = Path.Combine(tempPath, "project.lock.json"); - var targetDir = Path.Combine(projectPath, "artifacts", "Tools", tooldep.Name); - var targetPath = Path.Combine(targetDir, "project.lock.json"); - - if (Directory.Exists(targetDir)) Directory.Delete(targetDir, true); - Directory.CreateDirectory(targetDir); - - Console.WriteLine($"Writing '{sourcePath}' to '{targetPath}'"); - - File.Move(sourcePath, targetPath); - } - - private static void CreateDepsInPackageCache(LibraryRange toolLibrary, string projectPath) - { - var context = ProjectContext.Create(projectPath, - FrameworkConstants.CommonFrameworks.NetStandardApp15, new[] { DefaultRid }); - - var toolDescription = context.LibraryManager.GetLibraries() - .Select(l => l as PackageDescription) - .Where(l => l != null) - .FirstOrDefault(l => l.Identity.Name == toolLibrary.Name); - - var depsPath = Path.Combine( - toolDescription.Path, - Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path), - toolDescription.Identity.Name + FileNameSuffixes.Deps); - - var depsJsonPath = Path.Combine( - toolDescription.Path, - Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path), - toolDescription.Identity.Name + FileNameSuffixes.DepsJson); - - var calculator = context.GetOutputPaths(Constants.DefaultConfiguration, buidBasePath: null, outputPath: context.ProjectDirectory); - var executable = new Executable(context, calculator, context.CreateExporter(Constants.DefaultConfiguration), null); - - executable.MakeCompilationOutputRunnable(); - - if (File.Exists(depsPath)) File.Delete(depsPath); - if (File.Exists(depsJsonPath)) File.Delete(depsJsonPath); - - File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.Deps), depsPath); - File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.DepsJson), depsJsonPath); - } - - private static bool RestoreToolToPath(LibraryRange tooldep, IEnumerable args, string tempPath, bool quiet) - { - Directory.CreateDirectory(tempPath); - var projectPath = Path.Combine(tempPath, Project.FileName); - - Console.WriteLine($"Restoring Tool '{tooldep.Name}' for '{projectPath}' in '{tempPath}'"); - - File.WriteAllText(projectPath, GenerateProjectJsonContents(new[] {"netstandardapp1.5"}, tooldep)); - return NuGet3.Restore(new[] { $"{projectPath}" }.Concat(args), quiet) == 0; - } - - private static string GenerateProjectJsonContents(IEnumerable frameworks, LibraryRange tooldep) - { - var sb = new StringBuilder(); - sb.AppendLine("{"); - sb.AppendLine(" \"dependencies\": {"); - sb.AppendLine($" \"{tooldep.Name}\": \"{tooldep.VersionRange.OriginalString}\""); - sb.AppendLine(" },"); - sb.AppendLine(" \"frameworks\": {"); - foreach (var framework in frameworks) - { - var importsStatement = "\"imports\": [ \"dnxcore50\", \"portable-net452+win81\" ]"; - sb.AppendLine($" \"{framework}\": {{ {importsStatement} }}"); - } - sb.AppendLine(" },"); - sb.AppendLine(" \"runtimes\": { "); - sb.AppendLine($" \"{DefaultRid}\": {{}}"); - sb.AppendLine(" }"); - sb.AppendLine("}"); - var pjContents = sb.ToString(); - return pjContents; - } } } diff --git a/src/dotnet/commands/dotnet-restore/RestoreTask.cs b/src/dotnet/commands/dotnet-restore/RestoreTask.cs deleted file mode 100644 index 04de31d79..000000000 --- a/src/dotnet/commands/dotnet-restore/RestoreTask.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.DotNet.ProjectModel; - -namespace Microsoft.DotNet.Tools.Restore -{ - public struct RestoreTask - { - public string ProjectPath { get; set; } - - public IEnumerable Arguments { get; set; } - - public string ProjectDirectory => ProjectPath.EndsWith(Project.FileName, StringComparison.OrdinalIgnoreCase) - ? Path.GetDirectoryName(ProjectPath) - : ProjectPath; - } -} \ No newline at end of file From f0c2cb2c1806b8c699352d0a15fbdf45672dbf07 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 11:45:13 -0700 Subject: [PATCH 93/99] product changes to support portable tools --- .../IPackagedCommandSpecFactory.cs | 6 +- .../PackagedCommandSpecFactory.cs | 61 +++++++-- .../ProjectToolsCommandResolver.cs | 122 +++++++++++++++--- .../CommandResolution/ToolPathCalculator.cs | 70 ++++++++++ src/Microsoft.DotNet.Cli.Utils/Muxer.cs | 34 +++++ .../RuntimeConfigGenerator.cs | 53 ++++++++ src/Microsoft.DotNet.Cli.Utils/project.json | 6 +- .../Executable.cs | 26 +--- .../ProjectContext.cs | 2 +- .../ProjectContextBuilder.cs | 26 ++-- .../commands/dotnet-build/CompileContext.cs | 32 +++-- .../commands/dotnet-compile/CompilerUtil.cs | 2 +- .../commands/dotnet-pack/PackageGenerator.cs | 1 + 13 files changed, 363 insertions(+), 78 deletions(-) create mode 100644 src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/Muxer.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs index 34c14e56c..c285654da 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; namespace Microsoft.DotNet.Cli.Utils { @@ -15,7 +17,9 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath); + string depsFilePath, + LibraryExporter exporter = null, + bool generateRuntimeConfig = false); } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index 8129fa2e5..9302d05d0 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Runtime.InteropServices; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.Extensions.PlatformAbstractions; using NuGet.Frameworks; using NuGet.Packaging; @@ -20,7 +21,9 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath) + string depsFilePath, + LibraryExporter exporter = null, + bool generateRuntimeConfig = false) { var packageDirectory = GetPackageDirectoryFullPath(library, nugetPackagesRoot); @@ -38,11 +41,15 @@ namespace Microsoft.DotNet.Cli.Utils var commandPath = Path.Combine(packageDirectory, commandFile); + var isPortable = DetermineIfPortableApp(commandPath); + return CreateCommandSpecWrappingWithCorehostfDll( commandPath, commandArguments, depsFilePath, - commandResolutionStrategy); + commandResolutionStrategy, + nugetPackagesRoot, + isPortable); } private string GetPackageDirectoryFullPath(LockFilePackageLibrary library, string nugetPackagesRoot) @@ -69,7 +76,9 @@ namespace Microsoft.DotNet.Cli.Utils string commandPath, IEnumerable commandArguments, string depsFilePath, - CommandResolutionStrategy commandResolutionStrategy) + CommandResolutionStrategy commandResolutionStrategy, + string nugetPackagesRoot, + bool isPortable) { var commandExtension = Path.GetExtension(commandPath); @@ -79,7 +88,9 @@ namespace Microsoft.DotNet.Cli.Utils commandPath, commandArguments, depsFilePath, - commandResolutionStrategy); + commandResolutionStrategy, + nugetPackagesRoot, + isPortable); } return CreateCommandSpec(commandPath, commandArguments, commandResolutionStrategy); @@ -89,11 +100,30 @@ namespace Microsoft.DotNet.Cli.Utils string commandPath, IEnumerable commandArguments, string depsFilePath, - CommandResolutionStrategy commandResolutionStrategy) + CommandResolutionStrategy commandResolutionStrategy, + string nugetPackagesRoot, + bool isPortable) { - var corehost = CoreHost.HostExePath; - + string host = string.Empty; var arguments = new List(); + + if (isPortable) + { + var muxer = new Muxer(); + + host = muxer.MuxerPath; + if (host == null) + { + throw new Exception("Unable to locate dotnet multiplexer"); + } + + arguments.Add("exec"); + } + else + { + host = CoreHost.LocalHostExePath; + } + arguments.Add(commandPath); if (depsFilePath != null) @@ -102,9 +132,12 @@ namespace Microsoft.DotNet.Cli.Utils arguments.Add(depsFilePath); } + arguments.Add("--additionalprobingpath"); + arguments.Add(nugetPackagesRoot); + arguments.AddRange(commandArguments); - return CreateCommandSpec(corehost, arguments, commandResolutionStrategy); + return CreateCommandSpec(host, arguments, commandResolutionStrategy); } private CommandSpec CreateCommandSpec( @@ -115,6 +148,16 @@ namespace Microsoft.DotNet.Cli.Utils var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(commandArguments); return new CommandSpec(commandPath, escapedArgs, commandResolutionStrategy); - } + } + + private bool DetermineIfPortableApp(string commandPath) + { + var commandDir = Path.GetDirectoryName(commandPath); + + var runtimeConfig = Directory.EnumerateFiles(commandDir) + .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); + + return runtimeConfig != null; + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs index 906d660e9..e49c4192e 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs @@ -5,18 +5,28 @@ using System.Linq; using System.Runtime.InteropServices; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.PlatformAbstractions; using NuGet.Frameworks; using NuGet.Packaging; +using NuGet.ProjectModel; + +using LockFile = Microsoft.DotNet.ProjectModel.Graph.LockFile; +using FileFormatException = Microsoft.DotNet.ProjectModel.FileFormatException; namespace Microsoft.DotNet.Cli.Utils { public class ProjectToolsCommandResolver : ICommandResolver { private static readonly NuGetFramework s_toolPackageFramework = FrameworkConstants.CommonFrameworks.NetStandardApp15; + private static readonly CommandResolutionStrategy s_commandResolutionStrategy = CommandResolutionStrategy.ProjectToolsPackage; + private static readonly string s_currentRuntimeIdentifier = PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier(); + + private List _allowedCommandExtensions; private IPackagedCommandSpecFactory _packagedCommandSpecFactory; @@ -90,23 +100,21 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable args, ProjectContext projectContext) { - //todo: change this for new resolution strategy - var lockFilePath = Path.Combine( - projectContext.ProjectDirectory, - "artifacts", "Tools", toolLibrary.Name, - "project.lock.json"); - - if (!File.Exists(lockFilePath)) - { - return null; - } - - var lockFile = LockFileReader.Read(lockFilePath); - - var lockFilePackageLibrary = lockFile.PackageLibraries.FirstOrDefault(l => l.Name == toolLibrary.Name); - var nugetPackagesRoot = projectContext.PackagesDirectory; + var lockFile = GetToolLockFile(toolLibrary, nugetPackagesRoot); + var lockFilePackageLibrary = lockFile.PackageLibraries.FirstOrDefault(l => l.Name == toolLibrary.Name); + + var depsFileRoot = Path.GetDirectoryName(lockFile.LockFilePath); + var depsFilePath = GetToolDepsFilePath(toolLibrary, lockFile, depsFileRoot); + + var toolProjectContext = new ProjectContextBuilder() + .WithLockFile(lockFile) + .WithTargetFramework(s_toolPackageFramework.ToString()) + .Build(); + + var exporter = toolProjectContext.CreateExporter(Constants.DefaultConfiguration); + return _packagedCommandSpecFactory.CreateCommandSpecFromLibrary( lockFilePackageLibrary, commandName, @@ -114,7 +122,44 @@ namespace Microsoft.DotNet.Cli.Utils _allowedCommandExtensions, projectContext.PackagesDirectory, s_commandResolutionStrategy, - null); + depsFilePath); + } + + private LockFile GetToolLockFile( + LibraryRange toolLibrary, + string nugetPackagesRoot) + { + var lockFilePath = GetToolLockFilePath(toolLibrary, nugetPackagesRoot); + + if (!File.Exists(lockFilePath)) + { + return null; + } + + LockFile lockFile = null; + + try + { + lockFile = LockFileReader.Read(lockFilePath); + } + catch (FileFormatException ex) + { + throw ex; + } + + return lockFile; + } + + private string GetToolLockFilePath( + LibraryRange toolLibrary, + string nugetPackagesRoot) + { + var toolPathCalculator = new ToolPathCalculator(nugetPackagesRoot); + + return toolPathCalculator.GetBestLockFilePath( + toolLibrary.Name, + toolLibrary.VersionRange, + s_toolPackageFramework); } private ProjectContext GetProjectContextFromDirectory(string directory, NuGetFramework framework) @@ -143,5 +188,50 @@ namespace Microsoft.DotNet.Cli.Utils return projectContext; } + + private string GetToolDepsFilePath( + LibraryRange toolLibrary, + LockFile toolLockFile, + string depsPathRoot) + { + var depsJsonPath = Path.Combine( + depsPathRoot, + toolLibrary.Name + FileNameSuffixes.DepsJson); + + EnsureToolJsonDepsFileExists(toolLibrary, toolLockFile, depsJsonPath); + + return depsJsonPath; + } + + private void EnsureToolJsonDepsFileExists( + LibraryRange toolLibrary, + LockFile toolLockFile, + string depsPath) + { + if (!File.Exists(depsPath)) + { + var projectContext = new ProjectContextBuilder() + .WithLockFile(toolLockFile) + .WithTargetFramework(s_toolPackageFramework.ToString()) + .Build(); + + var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration); + + var dependencyContext = new DependencyContextBuilder() + .Build(null, + null, + exporter.GetAllExports(), + true, + s_toolPackageFramework, + string.Empty); + + using (var fileStream = File.Create(depsPath)) + { + var dependencyContextWriter = new DependencyContextWriter(); + + dependencyContextWriter.Write(dependencyContext, fileStream); + } + } + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs new file mode 100644 index 000000000..5dd24c0c5 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs @@ -0,0 +1,70 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Collections.Generic; +using NuGet.Frameworks; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class ToolPathCalculator + { + private readonly string _packagesDirectory; + + public ToolPathCalculator(string packagesDirectory) + { + _packagesDirectory = packagesDirectory; + } + + public string GetBestLockFilePath(string packageId, VersionRange versionRange, NuGetFramework framework) + { + var availableToolVersions = GetAvailableToolVersions(packageId); + + var bestVersion = versionRange.FindBestMatch(availableToolVersions); + + return GetLockFilePath(packageId, bestVersion, framework); + } + + public string GetLockFilePath(string packageId, NuGetVersion version, NuGetFramework framework) + { + return Path.Combine( + GetBaseToolPath(packageId), + version.ToNormalizedString(), + framework.GetShortFolderName(), + "project.lock.json"); + } + + private string GetBaseToolPath(string packageId) + { + return Path.Combine( + _packagesDirectory, + ".tools", + packageId); + } + + private IEnumerable GetAvailableToolVersions(string packageId) + { + var availableVersions = new List(); + + var toolBase = GetBaseToolPath(packageId); + var versionDirectories = Directory.EnumerateDirectories(toolBase); + + foreach (var versionDirectory in versionDirectories) + { + var version = Path.GetFileName(versionDirectory); + + NuGetVersion nugetVersion = null; + NuGetVersion.TryParse(version, out nugetVersion); + + if (nugetVersion != null) + { + availableVersions.Add(nugetVersion); + } + } + + return availableVersions; + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/Muxer.cs b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs new file mode 100644 index 000000000..516e0fdd8 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class Muxer + { + private static readonly string s_muxerFileName = "dotnet" + Constants.ExeSuffix; + + private string _muxerPath; + + public string MuxerPath + { + get + { + return _muxerPath; + } + } + + public Muxer() + { + var appBase = new DirectoryInfo(PlatformServices.Default.Application.ApplicationBasePath); + var muxerDir = appBase.Parent.Parent; + + var muxerCandidate = Path.Combine(muxerDir.FullName, s_muxerFileName); + + if (File.Exists(muxerCandidate)) + { + _muxerPath = muxerCandidate; + } + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs b/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs new file mode 100644 index 000000000..92ba1728d --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs @@ -0,0 +1,53 @@ +// 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.Xml.Linq; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.Extensions.DependencyModel; +using NuGet.Frameworks; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; + +namespace Microsoft.DotNet.Cli.Utils +{ + public static class RuntimeConfigGenerator + { + // GROOOOOSS + private static readonly string RedistPackageName = "Microsoft.NETCore.App"; + + public static void WriteRuntimeConfigToFile(LibraryExporter exporter, string runtimeConfigJsonFile) + { + // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated + // in order to prevent breaking incremental compilation... + + var json = new JObject(); + var runtimeOptions = new JObject(); + json.Add("runtimeOptions", runtimeOptions); + + var redistExport = exporter + .GetAllExports() + .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); + if (redistExport != null) + { + var framework = new JObject( + new JProperty("name", redistExport.Library.Identity.Name), + new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); + runtimeOptions.Add("framework", framework); + } + + using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) + { + writer.Formatting = Formatting.Indented; + json.WriteTo(writer); + } + + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json index 3e97e0621..e6cdae2f9 100644 --- a/src/Microsoft.DotNet.Cli.Utils/project.json +++ b/src/Microsoft.DotNet.Cli.Utils/project.json @@ -6,7 +6,11 @@ }, "dependencies": { "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "NuGet.Versioning": "3.4.0-rtm-0763", + "NuGet.Packaging": "3.4.0-rtm-0763", + "NuGet.Frameworks": "3.4.0-rtm-0763", + "NuGet.ProjectModel": "3.4.0-rtm-0763" }, "frameworks": { "net451": { diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs index 3fa63b148..431fc76fe 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs +++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs @@ -126,30 +126,9 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common { if (!_context.TargetFramework.IsDesktop()) { - // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated - // in order to prevent breaking incremental compilation... - - var json = new JObject(); - var runtimeOptions = new JObject(); - json.Add("runtimeOptions", runtimeOptions); - - var redistExport = exporter - .GetAllExports() - .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); - if (redistExport != null) - { - var framework = new JObject( - new JProperty("name", redistExport.Library.Identity.Name), - new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); - runtimeOptions.Add("framework", framework); - } - var runtimeConfigJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.RuntimeConfigJson); - using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) - { - writer.Formatting = Formatting.Indented; - json.WriteTo(writer); - } + + RuntimeConfigGenerator.WriteRuntimeConfigToFile(exporter, runtimeConfigJsonFile); } } @@ -210,7 +189,6 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common } } - private static void CreateDirectoryIfNotExists(string path) { var depsFile = new FileInfo(path); diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index c82e3927f..b920e857c 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -22,7 +22,7 @@ namespace Microsoft.DotNet.ProjectModel public string RuntimeIdentifier { get; } - public Project ProjectFile => RootProject.Project; + public Project ProjectFile => RootProject?.Project; public LockFile LockFile { get; } diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs index 8d617df63..6e2d6b58f 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs @@ -140,7 +140,7 @@ namespace Microsoft.DotNet.ProjectModel { ProjectDirectory = Project?.ProjectDirectory ?? ProjectDirectory; - if (GlobalSettings == null) + if (GlobalSettings == null && ProjectDirectory != null) { RootDirectory = ProjectRootResolver.ResolveRootDirectory(ProjectDirectory); @@ -157,7 +157,6 @@ namespace Microsoft.DotNet.ProjectModel var frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath); LockFileLookup lockFileLookup = null; - EnsureProjectLoaded(); LockFile = LockFile ?? LockFileResolver(ProjectDirectory); @@ -167,7 +166,10 @@ namespace Microsoft.DotNet.ProjectModel if (LockFile != null) { - validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage); + if (Project != null) + { + validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage); + } lockFileLookup = new LockFileLookup(LockFile); } @@ -175,10 +177,14 @@ namespace Microsoft.DotNet.ProjectModel var libraries = new Dictionary(); var projectResolver = new ProjectDependencyProvider(ProjectResolver); - var mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null); + ProjectDescription mainProject = null; + if (Project != null) + { + mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null); - // Add the main project - libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject); + // Add the main project + libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject); + } LockFileTarget target = null; if (lockFileLookup != null) @@ -251,7 +257,7 @@ namespace Microsoft.DotNet.ProjectModel } // Create a library manager - var libraryManager = new LibraryManager(libraries.Values.ToList(), diagnostics, Project.ProjectFilePath); + var libraryManager = new LibraryManager(libraries.Values.ToList(), diagnostics, Project?.ProjectFilePath); return new ProjectContext( GlobalSettings, @@ -375,13 +381,9 @@ namespace Microsoft.DotNet.ProjectModel private void EnsureProjectLoaded() { - if (Project == null) + if (Project == null && ProjectDirectory != null) { Project = ProjectResolver(ProjectDirectory); - if (Project == null) - { - throw new InvalidOperationException($"Unable to resolve project from {ProjectDirectory}"); - } } } diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs index 4768f12e7..229c5af15 100644 --- a/src/dotnet/commands/dotnet-build/CompileContext.cs +++ b/src/dotnet/commands/dotnet-build/CompileContext.cs @@ -255,27 +255,33 @@ namespace Microsoft.DotNet.Tools.Build private void CollectCompilerNamePreconditions(ProjectContext project, IncrementalPreconditions preconditions) { - var projectCompiler = project.ProjectFile.CompilerName; - - if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) + if (project.ProjectFile != null) { - preconditions.AddUnknownCompilerPrecondition(project.ProjectName(), projectCompiler); + var projectCompiler = project.ProjectFile.CompilerName; + + if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) + { + preconditions.AddUnknownCompilerPrecondition(project.ProjectName(), projectCompiler); + } } } private void CollectScriptPreconditions(ProjectContext project, IncrementalPreconditions preconditions) { - var preCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PreCompile); - var postCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PostCompile); - - if (preCompileScripts.Any()) + if (project.ProjectFile != null) { - preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PreCompile); - } + var preCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PreCompile); + var postCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PostCompile); - if (postCompileScripts.Any()) - { - preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PostCompile); + if (preCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PreCompile); + } + + if (postCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PostCompile); + } } } diff --git a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs index 739e46dfe..f258dc43c 100644 --- a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs +++ b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs @@ -122,7 +122,7 @@ namespace Microsoft.DotNet.Tools.Compiler //used in incremental precondition checks public static IEnumerable GetCommandsInvokedByCompile(ProjectContext project) { - return new List {project.ProjectFile.CompilerName, "compile"}; + return new List {project.ProjectFile?.CompilerName, "compile"}; } } } \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-pack/PackageGenerator.cs b/src/dotnet/commands/dotnet-pack/PackageGenerator.cs index 8995e2025..44a793b6f 100644 --- a/src/dotnet/commands/dotnet-pack/PackageGenerator.cs +++ b/src/dotnet/commands/dotnet-pack/PackageGenerator.cs @@ -94,6 +94,7 @@ namespace Microsoft.DotNet.Tools.Compiler TryAddOutputFile(context, inputFolder, outputName); TryAddOutputFile(context, inputFolder, $"{Project.Name}.xml"); + TryAddOutputFile(context, inputFolder, $"{Project.Name}.runtimeconfig.json"); } protected virtual bool GeneratePackage(string nupkg, List packDiagnostics) From 937141c6a5e4c1f67f5c490550004a14a9f427d7 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 13:43:53 -0700 Subject: [PATCH 94/99] Cleanup --- .../IPackagedCommandSpecFactory.cs | 4 +- .../PackagedCommandSpecFactory.cs | 8 ++- src/Microsoft.DotNet.Cli.Utils/Muxer.cs | 39 ++++++++++++-- .../RuntimeConfigGenerator.cs | 53 ------------------- .../Executable.cs | 26 ++++++++- 5 files changed, 63 insertions(+), 67 deletions(-) delete mode 100644 src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs index c285654da..626dcf9cc 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs @@ -17,9 +17,7 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath, - LibraryExporter exporter = null, - bool generateRuntimeConfig = false); + string depsFilePath); } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index 9302d05d0..1d95c8ddd 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -21,9 +21,7 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath, - LibraryExporter exporter = null, - bool generateRuntimeConfig = false) + string depsFilePath) { var packageDirectory = GetPackageDirectoryFullPath(library, nugetPackagesRoot); @@ -124,8 +122,6 @@ namespace Microsoft.DotNet.Cli.Utils host = CoreHost.LocalHostExePath; } - arguments.Add(commandPath); - if (depsFilePath != null) { arguments.Add("--depsfile"); @@ -135,6 +131,8 @@ namespace Microsoft.DotNet.Cli.Utils arguments.Add("--additionalprobingpath"); arguments.Add(nugetPackagesRoot); + arguments.Add(commandPath); + arguments.AddRange(commandArguments); return CreateCommandSpec(host, arguments, commandResolutionStrategy); diff --git a/src/Microsoft.DotNet.Cli.Utils/Muxer.cs b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs index 516e0fdd8..c279f3e5a 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Muxer.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs @@ -6,7 +6,8 @@ namespace Microsoft.DotNet.Cli.Utils { public class Muxer { - private static readonly string s_muxerFileName = "dotnet" + Constants.ExeSuffix; + private static readonly string s_muxerName = "dotnet"; + private static readonly string s_muxerFileName = s_muxerName + Constants.ExeSuffix; private string _muxerPath; @@ -19,16 +20,46 @@ namespace Microsoft.DotNet.Cli.Utils } public Muxer() + { + if (!TryResolveMuxerFromParentDirectories()) + { + TryResolverMuxerFromPath(); + } + } + + private bool TryResolveMuxerFromParentDirectories() { var appBase = new DirectoryInfo(PlatformServices.Default.Application.ApplicationBasePath); - var muxerDir = appBase.Parent.Parent; + var muxerDir = appBase.Parent?.Parent; + + if (muxerDir == null) + { + return false; + } var muxerCandidate = Path.Combine(muxerDir.FullName, s_muxerFileName); - if (File.Exists(muxerCandidate)) + if (!File.Exists(muxerCandidate)) { - _muxerPath = muxerCandidate; + return false; } + + _muxerPath = muxerCandidate; + return true; + } + + private bool TryResolverMuxerFromPath() + { + var muxerPath = Env.GetCommandPath(s_muxerName, Constants.ExeSuffix); + + if (muxerPath == null || !File.Exists(muxerPath)) + { + return false; + } + + _muxerPath = muxerPath; + + return true; } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs b/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs deleted file mode 100644 index 92ba1728d..000000000 --- a/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs +++ /dev/null @@ -1,53 +0,0 @@ -// 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.Xml.Linq; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.ProjectModel; -using Microsoft.DotNet.ProjectModel.Compilation; -using Microsoft.DotNet.ProjectModel.Graph; -using Microsoft.Extensions.DependencyModel; -using NuGet.Frameworks; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; - -namespace Microsoft.DotNet.Cli.Utils -{ - public static class RuntimeConfigGenerator - { - // GROOOOOSS - private static readonly string RedistPackageName = "Microsoft.NETCore.App"; - - public static void WriteRuntimeConfigToFile(LibraryExporter exporter, string runtimeConfigJsonFile) - { - // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated - // in order to prevent breaking incremental compilation... - - var json = new JObject(); - var runtimeOptions = new JObject(); - json.Add("runtimeOptions", runtimeOptions); - - var redistExport = exporter - .GetAllExports() - .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); - if (redistExport != null) - { - var framework = new JObject( - new JProperty("name", redistExport.Library.Identity.Name), - new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); - runtimeOptions.Add("framework", framework); - } - - using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) - { - writer.Formatting = Formatting.Indented; - json.WriteTo(writer); - } - - } - } -} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs index 431fc76fe..3fa63b148 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs +++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs @@ -126,9 +126,30 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common { if (!_context.TargetFramework.IsDesktop()) { - var runtimeConfigJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.RuntimeConfigJson); + // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated + // in order to prevent breaking incremental compilation... - RuntimeConfigGenerator.WriteRuntimeConfigToFile(exporter, runtimeConfigJsonFile); + var json = new JObject(); + var runtimeOptions = new JObject(); + json.Add("runtimeOptions", runtimeOptions); + + var redistExport = exporter + .GetAllExports() + .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); + if (redistExport != null) + { + var framework = new JObject( + new JProperty("name", redistExport.Library.Identity.Name), + new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); + runtimeOptions.Add("framework", framework); + } + + var runtimeConfigJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.RuntimeConfigJson); + using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) + { + writer.Formatting = Formatting.Indented; + json.WriteTo(writer); + } } } @@ -189,6 +210,7 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common } } + private static void CreateDirectoryIfNotExists(string path) { var depsFile = new FileInfo(path); From 873310f8f463c1c04e6fca80f94f39000516077a Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 14:06:15 -0700 Subject: [PATCH 95/99] fix commandPath ordering for corehost --- .../CommandResolution/PackagedCommandSpecFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index 1d95c8ddd..dc2cfed2a 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -122,6 +122,8 @@ namespace Microsoft.DotNet.Cli.Utils host = CoreHost.LocalHostExePath; } + arguments.Add(commandPath); + if (depsFilePath != null) { arguments.Add("--depsfile"); @@ -131,8 +133,6 @@ namespace Microsoft.DotNet.Cli.Utils arguments.Add("--additionalprobingpath"); arguments.Add(nugetPackagesRoot); - arguments.Add(commandPath); - arguments.AddRange(commandArguments); return CreateCommandSpec(host, arguments, commandResolutionStrategy); From 6c17d0e29ce0c0153defa440b0acff7845f7b639 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 14:41:56 -0700 Subject: [PATCH 96/99] fix test --- .../GivenAProjectToolsCommandResolver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs index 9ad2c8b66..63a85bfc7 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectToolsCommandResolver.cs @@ -80,7 +80,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests } [Fact] - public void It_returns_a_CommandSpec_with_CoreHost_as_FileName_and_CommandName_in_Args_when_CommandName_exists_in_ProjectTools() + public void It_returns_a_CommandSpec_with_DOTNET_as_FileName_and_CommandName_in_Args_when_CommandName_exists_in_ProjectTools() { var projectToolsCommandResolver = SetupProjectToolsCommandResolver(); @@ -97,7 +97,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests var commandFile = Path.GetFileNameWithoutExtension(result.Path); - commandFile.Should().Be("corehost"); + commandFile.Should().Be("dotnet"); result.Args.Should().Contain(commandResolverArguments.CommandName); } From d878331a5e1c96f6527d09c11caefe4cc0bae103 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 15:24:36 -0700 Subject: [PATCH 97/99] Fix EndToEnd Tests for portable build and publish --- .../TestBase.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs index 2db36724b..bb016d900 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs @@ -107,10 +107,19 @@ namespace Microsoft.DotNet.Tools.Test.Utilities string expectedOutput) { var executablePath = Path.Combine(outputDir, executableName); + var args = new List(); + + if (IsPortable(executablePath)) + { + args.Add(ArgumentEscaper.EscapeSingleArg(executablePath)); + + var muxer = new Muxer(); + executablePath = muxer.MuxerPath; + } var executableCommand = new TestCommand(executablePath); - var result = executableCommand.ExecuteWithCapturedOutput(""); + var result = executableCommand.ExecuteWithCapturedOutput(string.Join(" ", args)); result.Should().HaveStdOut(expectedOutput); result.Should().NotHaveStdErr(); @@ -141,5 +150,15 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return executablePath; } + + private bool IsPortable(string executablePath) + { + var executableDir = Path.GetDirectoryName(executablePath); + + var runtimeConfig = Directory.EnumerateFiles(executableDir) + .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); + + return runtimeConfig != null; + } } } From 861b7494d3994b9f5be4b4f40c384cca61937758 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 16:39:48 -0700 Subject: [PATCH 98/99] Add hacky abstraction for quickly parsing RuntimeConfig.json and determining if it's a portable app --- .../PackagedCommandSpecFactory.cs | 11 ++++- .../RuntimeConfig/RuntimeConfig.cs | 49 +++++++++++++++++++ .../RuntimeConfig/RuntimeConfigFramework.cs | 36 ++++++++++++++ .../TestBase.cs | 15 ++++-- .../project.json | 1 + 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfig.cs create mode 100644 src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfigFramework.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index dc2cfed2a..8b3ff0ca3 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -152,10 +152,17 @@ namespace Microsoft.DotNet.Cli.Utils { var commandDir = Path.GetDirectoryName(commandPath); - var runtimeConfig = Directory.EnumerateFiles(commandDir) + var runtimeConfigPath = Directory.EnumerateFiles(commandDir) .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); - return runtimeConfig != null; + if (runtimeConfigPath == null) + { + return false; + } + + var runtimeConfig = new RuntimeConfig(runtimeConfigPath); + + return runtimeConfig.IsPortable; } } } diff --git a/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfig.cs b/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfig.cs new file mode 100644 index 000000000..0d2d7431d --- /dev/null +++ b/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfig.cs @@ -0,0 +1,49 @@ +// 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.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.IO; + +namespace Microsoft.DotNet.ProjectModel +{ + public class RuntimeConfig + { + public bool IsPortable { get; } + public RuntimeConfigFramework Framework { get; } + + public RuntimeConfig(string runtimeConfigPath) + { + var runtimeConfigJson = OpenRuntimeConfig(runtimeConfigPath); + + Framework = ParseFramework(runtimeConfigJson); + + IsPortable = Framework != null; + } + + private JObject OpenRuntimeConfig(string runtimeConfigPath) + { + return JObject.Parse(File.ReadAllText(runtimeConfigPath)); + } + + private RuntimeConfigFramework ParseFramework(JObject runtimeConfigRoot) + { + var runtimeOptionsRoot = runtimeConfigRoot["runtimeOptions"]; + if (runtimeOptionsRoot == null) + { + return null; + } + + var framework = (JObject) runtimeOptionsRoot["framework"]; + if (framework == null) + { + return null; + } + + return RuntimeConfigFramework.ParseFromFrameworkRoot(framework); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfigFramework.cs b/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfigFramework.cs new file mode 100644 index 000000000..d6a0c6f63 --- /dev/null +++ b/src/Microsoft.DotNet.ProjectModel/RuntimeConfig/RuntimeConfigFramework.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 System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Microsoft.DotNet.ProjectModel +{ + public class RuntimeConfigFramework + { + public string Name { get; set; } + public string Version { get; set; } + + public static RuntimeConfigFramework ParseFromFrameworkRoot(JObject framework) + { + var properties = framework.Properties(); + + var name = properties.FirstOrDefault(p => p.Name.Equals("name", StringComparison.OrdinalIgnoreCase)); + var version = properties.FirstOrDefault(p => p.Name.Equals("version", StringComparison.OrdinalIgnoreCase)); + + if (name == null || version == null) + { + return null; + } + + return new RuntimeConfigFramework + { + Name = name.Value.ToString(), + Version = version.Value.ToString() + }; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs index bb016d900..0d5f4a0a0 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/TestBase.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.ProjectModel; namespace Microsoft.DotNet.Tools.Test.Utilities { @@ -111,6 +112,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities if (IsPortable(executablePath)) { + args.Add("exec"); args.Add(ArgumentEscaper.EscapeSingleArg(executablePath)); var muxer = new Muxer(); @@ -153,12 +155,19 @@ namespace Microsoft.DotNet.Tools.Test.Utilities private bool IsPortable(string executablePath) { - var executableDir = Path.GetDirectoryName(executablePath); + var commandDir = Path.GetDirectoryName(executablePath); - var runtimeConfig = Directory.EnumerateFiles(executableDir) + var runtimeConfigPath = Directory.EnumerateFiles(commandDir) .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); - return runtimeConfig != null; + if (runtimeConfigPath == null) + { + return false; + } + + var runtimeConfig = new RuntimeConfig(runtimeConfigPath); + Console.WriteLine(runtimeConfig.Framework); + return runtimeConfig.IsPortable; } } } diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json index ac4cff52e..2463caa8f 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/project.json @@ -12,6 +12,7 @@ "dotnet-test-xunit": "1.0.0-dev-91790-12", "Microsoft.DotNet.TestFramework": "1.0.0-*", "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", "Microsoft.DotNet.InternalAbstractions": { "target": "project", From 4890814176aa457ad106fffbe13ee0807497e310 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 17:09:25 -0700 Subject: [PATCH 99/99] disable parallel in run-build --- scripts/run-build.ps1 | 2 +- scripts/run-build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run-build.ps1 b/scripts/run-build.ps1 index 79809e4c6..125a63aa9 100644 --- a/scripts/run-build.ps1 +++ b/scripts/run-build.ps1 @@ -72,7 +72,7 @@ $env:PATH = "$env:DOTNET_INSTALL_DIR\cli\bin;$env:PATH" # Restore the build scripts Write-Host "Restoring Build Script projects..." pushd $PSScriptRoot -dotnet restore +dotnet restore --disable-parallel if($LASTEXITCODE -ne 0) { throw "Failed to restore" } popd diff --git a/scripts/run-build.sh b/scripts/run-build.sh index 4de0d15a1..63f28ea7a 100755 --- a/scripts/run-build.sh +++ b/scripts/run-build.sh @@ -102,7 +102,7 @@ fi echo "Restoring Build Script projects..." ( cd $DIR - dotnet restore + dotnet restore --disable-parallel ) # Build the builder