diff --git a/TestAssets/DesktopTestProjects/AppWithDirectDependencyDesktopAndPortable/project.json b/TestAssets/DesktopTestProjects/AppWithDirectDependencyDesktopAndPortable/project.json index f4799dbc9..1dbf645ce 100644 --- a/TestAssets/DesktopTestProjects/AppWithDirectDependencyDesktopAndPortable/project.json +++ b/TestAssets/DesktopTestProjects/AppWithDirectDependencyDesktopAndPortable/project.json @@ -4,7 +4,7 @@ "emitEntryPoint": true }, "dependencies": { - "dotnet-desktop-and-portable": "1.0.0" + "dotnet-desktop-and-portable": "1.0.0-*" }, "frameworks": { "netstandardapp1.5": { diff --git a/TestAssets/FSharpTestProjects/CompileFail/project.json b/TestAssets/FSharpTestProjects/CompileFail/project.json deleted file mode 100644 index 1409f11f4..000000000 --- a/TestAssets/FSharpTestProjects/CompileFail/project.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "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-23931" - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - } -} diff --git a/TestAssets/FSharpTestProjects/TestApp/project.json b/TestAssets/FSharpTestProjects/TestApp/project.json deleted file mode 100644 index ae811983a..000000000 --- a/TestAssets/FSharpTestProjects/TestApp/project.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "1.0.0-*", - "compilationOptions": { - "emitEntryPoint": true - }, - "compilerName": "fsc", - "compileFiles": [ - "Program.fs" - ], - "dependencies": { - "TestLibrary": "1.0.0-*", - "NETStandard.Library": "1.5.0-rc2-23931", - "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 deleted file mode 100644 index 1409f11f4..000000000 --- a/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "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-23931" - }, - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - } -} diff --git a/TestAssets/FSharpTestProjects/TestLibrary/project.json b/TestAssets/FSharpTestProjects/TestLibrary/project.json deleted file mode 100644 index c2c6d67fb..000000000 --- a/TestAssets/FSharpTestProjects/TestLibrary/project.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "1.0.0-*", - "dependencies": { - "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.5.0-rc2-23931" - }, - "compilerName": "fsc", - "compileFiles": [ - "Helper2.fs", - "Helper.fs" - ], - "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" - } - } -} diff --git a/TestAssets/FSharpTestProjects/global.json b/TestAssets/FSharpTestProjects/global.json deleted file mode 100644 index 98b00dc4e..000000000 --- a/TestAssets/FSharpTestProjects/global.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "projects": [ ".", "../../src" ] -} diff --git a/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/.noautobuild b/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/FSharpTestProjects/CompileFail/Program.fs b/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/Program.fs similarity index 100% rename from TestAssets/FSharpTestProjects/CompileFail/Program.fs rename to TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/Program.fs diff --git a/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/project.json b/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/project.json new file mode 100644 index 000000000..e9c499f79 --- /dev/null +++ b/TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/project.json @@ -0,0 +1,31 @@ +{ + "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-23931" + }, + + "tools": { + "dotnet-compile-fsc": { + "version": "1.0.0-*", + "imports": [ + "dnxcore50", + "portable-net45+win81", + "netstandard1.3" + ] + } + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": ["dnxcore50", "netstandard1.3"] + } + } +} diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestApp/.noautobuild b/TestAssets/TestProjects/FSharpTestProjects/TestApp/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj b/TestAssets/TestProjects/FSharpTestProjects/TestApp/FSharpTestApp.xproj similarity index 100% rename from TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj rename to TestAssets/TestProjects/FSharpTestProjects/TestApp/FSharpTestApp.xproj diff --git a/TestAssets/FSharpTestProjects/TestApp/Program.fs b/TestAssets/TestProjects/FSharpTestProjects/TestApp/Program.fs similarity index 100% rename from TestAssets/FSharpTestProjects/TestApp/Program.fs rename to TestAssets/TestProjects/FSharpTestProjects/TestApp/Program.fs diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestApp/project.json b/TestAssets/TestProjects/FSharpTestProjects/TestApp/project.json new file mode 100644 index 000000000..60b0f771a --- /dev/null +++ b/TestAssets/TestProjects/FSharpTestProjects/TestApp/project.json @@ -0,0 +1,39 @@ +{ + "version": "1.0.0-*", + + "compilationOptions": { + "emitEntryPoint": true + }, + + "compilerName": "fsc", + + "compileFiles": [ + "Program.fs" + ], + "dependencies": { + "TestLibrary": { + "version": "1.0.0-*", + "target": "project" + }, + "NETStandard.Library": "1.5.0-rc2-23931", + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221" + }, + + "tools": { + "dotnet-compile-fsc": { + "version": "1.0.0-*", + "imports": [ + "dnxcore50", + "portable-net45+win81", + "netstandard1.3" + ] + } + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } + +} diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/.noautobuild b/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/FSharpTestProjects/TestAppWithArgs/Program.fs b/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/Program.fs similarity index 100% rename from TestAssets/FSharpTestProjects/TestAppWithArgs/Program.fs rename to TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/Program.fs diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/project.json b/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/project.json new file mode 100644 index 000000000..ff70fb64f --- /dev/null +++ b/TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/project.json @@ -0,0 +1,31 @@ +{ + "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-23931" + }, + + "tools": { + "dotnet-compile-fsc": { + "version": "1.0.0-*", + "imports": [ + "dnxcore50", + "portable-net45+win81", + "netstandard1.3" + ] + } + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } +} diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/.noautobuild b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj similarity index 100% rename from TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj rename to TestAssets/TestProjects/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj diff --git a/TestAssets/FSharpTestProjects/TestLibrary/Helper.fs b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/Helper.fs similarity index 100% rename from TestAssets/FSharpTestProjects/TestLibrary/Helper.fs rename to TestAssets/TestProjects/FSharpTestProjects/TestLibrary/Helper.fs diff --git a/TestAssets/FSharpTestProjects/TestLibrary/Helper2.fs b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/Helper2.fs similarity index 100% rename from TestAssets/FSharpTestProjects/TestLibrary/Helper2.fs rename to TestAssets/TestProjects/FSharpTestProjects/TestLibrary/Helper2.fs diff --git a/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/project.json b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/project.json new file mode 100644 index 000000000..265e2d41e --- /dev/null +++ b/TestAssets/TestProjects/FSharpTestProjects/TestLibrary/project.json @@ -0,0 +1,31 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", + "NETStandard.Library": "1.5.0-rc2-23931" + }, + + "compilerName": "fsc", + + "compileFiles": [ + "Helper2.fs", + "Helper.fs" + ], + + "tools": { + "dotnet-compile-fsc": { + "version": "1.0.0-*", + "imports": [ + "dnxcore50", + "portable-net45+win81", + "netstandard1.3" + ] + } + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": "dnxcore50" + } + } +} diff --git a/TestAssets/TestProjects/FSharpTestProjects/global.json b/TestAssets/TestProjects/FSharpTestProjects/global.json new file mode 100644 index 000000000..9e455db71 --- /dev/null +++ b/TestAssets/TestProjects/FSharpTestProjects/global.json @@ -0,0 +1,3 @@ +{ + "projects": [ ".", "../../../src" ] +} diff --git a/packaging/nuget/package.ps1 b/packaging/nuget/package.ps1 deleted file mode 100644 index b08fd21f3..000000000 --- a/packaging/nuget/package.ps1 +++ /dev/null @@ -1,36 +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. - -param( - [Parameter(Mandatory=$true)][string]$toolsDir, - [string]$versionSuffix = "" -) - -# unify trailing backslash -$toolsDir = $toolsDir.TrimEnd('\') -$versionArg = "" -if ($versionSuffix -ne "") { - $versionArg = "--version-suffix" -} - -$RepoRoot = Convert-Path "$PSScriptRoot\..\.." - -. "$RepoRoot\scripts\common\_common.ps1" -. "$RepoRoot\scripts\package\projectsToPack.ps1" - -$IntermediatePackagesDir = "$RepoRoot\artifacts\packages\intermediate" -$PackagesDir = "$RepoRoot\artifacts\packages" - -New-Item -ItemType Directory -Force -Path $IntermediatePackagesDir - -foreach ($ProjectName in $ProjectsToPack) { - $ProjectFile = "$RepoRoot\src\$ProjectName\project.json" - - & $toolsDir\dotnet pack "$ProjectFile" --no-build --build-base-path "$Stage2CompilationDir\forPackaging" --output "$IntermediatePackagesDir" --configuration "$env:CONFIGURATION" $versionArg $versionSuffix - if (!$?) { - Write-Host "$toolsDir\dotnet pack failed for: $ProjectFile" - Exit 1 - } -} - -Get-ChildItem $IntermediatePackagesDir -Filter *.nupkg | ? {$_.Name -NotLike "*.symbols.nupkg"} | Copy-Item -Destination $PackagesDir diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs index ff4d85168..79fccf0b3 100644 --- a/scripts/dotnet-cli-build/CompileTargets.cs +++ b/scripts/dotnet-cli-build/CompileTargets.cs @@ -33,16 +33,6 @@ namespace Microsoft.DotNet.Cli.Build "vbc.exe" }; - public static readonly string[] ProjectsToPack = new[] - { - "Microsoft.DotNet.Cli.Utils", - "Microsoft.DotNet.ProjectModel", - "Microsoft.DotNet.ProjectModel.Loader", - "Microsoft.DotNet.ProjectModel.Workspaces", - "Microsoft.Extensions.DependencyModel", - "Microsoft.Extensions.Testing.Abstractions" - }; - public const string SharedFrameworkName = "Microsoft.NETCore.App"; private static string CoreHostBaseName => $"corehost{Constants.ExeSuffix}"; @@ -282,22 +272,23 @@ namespace Microsoft.DotNet.Cli.Build return result; } - // Build projects that are packed in NuGet packages, but only on Windows - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (CurrentPlatform.IsWindows) { + // build projects for nuget packages var packagingOutputDir = Path.Combine(Dirs.Stage2Compilation, "forPackaging"); Mkdirp(packagingOutputDir); - foreach (var project in ProjectsToPack) + foreach (var project in PackageTargets.ProjectsToPack) { // Just build them, we'll pack later - DotNetCli.Stage1.Build( + var packBuildResult = DotNetCli.Stage1.Build( "--build-base-path", packagingOutputDir, "--configuration", configuration, Path.Combine(c.BuildContext.BuildDirectory, "src", project)) - .Execute() - .EnsureSuccessful(); + .Execute(); + + packBuildResult.EnsureSuccessful(); } } diff --git a/scripts/dotnet-cli-build/DebTargets.cs b/scripts/dotnet-cli-build/DebTargets.cs index 532c53429..685e0d4f0 100644 --- a/scripts/dotnet-cli-build/DebTargets.cs +++ b/scripts/dotnet-cli-build/DebTargets.cs @@ -128,7 +128,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target] + [Target(nameof(InstallSharedHost))] public static BuildTargetResult InstallSharedFramework(BuildTargetContext c) { InstallPackage(c.BuildContext.Get("SharedFrameworkInstallerFile")); @@ -136,7 +136,7 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } - [Target] + [Target(nameof(InstallSharedFramework))] public static BuildTargetResult InstallSDK(BuildTargetContext c) { InstallPackage(c.BuildContext.Get("SdkInstallerFile")); diff --git a/scripts/dotnet-cli-build/InstallerTargets.cs b/scripts/dotnet-cli-build/InstallerTargets.cs index d90bd4fb6..fcea28e86 100644 --- a/scripts/dotnet-cli-build/InstallerTargets.cs +++ b/scripts/dotnet-cli-build/InstallerTargets.cs @@ -20,7 +20,7 @@ namespace Microsoft.DotNet.Cli.Build { return c.Success(); } - + [Target(nameof(DebTargets.TestDebInstaller))] public static BuildTargetResult TestInstaller(BuildTargetContext c) diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs index d4e532da4..40bc5e3bc 100644 --- a/scripts/dotnet-cli-build/PackageTargets.cs +++ b/scripts/dotnet-cli-build/PackageTargets.cs @@ -12,6 +12,20 @@ namespace Microsoft.DotNet.Cli.Build { public static class PackageTargets { + public static readonly string[] ProjectsToPack = new string[] + { + "Microsoft.DotNet.Cli.Utils", + "Microsoft.DotNet.ProjectModel", + "Microsoft.DotNet.ProjectModel.Loader", + "Microsoft.DotNet.ProjectModel.Workspaces", + "Microsoft.DotNet.InternalAbstractions", + "Microsoft.Extensions.DependencyModel", + "Microsoft.Extensions.Testing.Abstractions", + "Microsoft.DotNet.Compiler.Common", + "Microsoft.DotNet.Files", + "dotnet-compile-fsc" + }; + [Target(nameof(PackageTargets.CopyCLISDKLayout), nameof(PackageTargets.CopySharedHostLayout), nameof(PackageTargets.CopySharedFxLayout), @@ -28,8 +42,8 @@ namespace Microsoft.DotNet.Cli.Build nameof(PackageTargets.GenerateVersionBadge), nameof(PackageTargets.GenerateCompressedFile), nameof(InstallerTargets.GenerateInstaller), - nameof(InstallerTargets.TestInstaller), - nameof(PackageTargets.GenerateNugetPackages))] + nameof(PackageTargets.GenerateNugetPackages), + nameof(InstallerTargets.TestInstaller))] [Environment("DOTNET_BUILD_SKIP_PACKAGING", null, "0", "false")] public static BuildTargetResult Package(BuildTargetContext c) { @@ -175,16 +189,45 @@ namespace Microsoft.DotNet.Cli.Build } [Target] - [BuildPlatforms(BuildPlatform.Windows)] public static BuildTargetResult GenerateNugetPackages(BuildTargetContext c) { var versionSuffix = c.BuildContext.Get("BuildVersion").VersionSuffix; + var configuration = c.BuildContext.Get("Configuration"); + var env = GetCommonEnvVars(c); - Cmd("powershell", "-NoProfile", "-NoLogo", - Path.Combine(Dirs.RepoRoot, "packaging", "nuget", "package.ps1"), Dirs.Stage2, versionSuffix) - .Environment(env) + var dotnet = DotNetCli.Stage2; + + var packagingBuildBasePath = Path.Combine(Dirs.Stage2Compilation, "forPackaging"); + + FS.Mkdirp(Dirs.PackagesIntermediate); + FS.Mkdirp(Dirs.Packages); + + foreach (var projectName in ProjectsToPack) + { + var projectFile = Path.Combine(Dirs.RepoRoot, "src", projectName, "project.json"); + + dotnet.Pack( + projectFile, + "--no-build", + "--build-base-path", packagingBuildBasePath, + "--output", Dirs.PackagesIntermediate, + "--configuration", configuration, + "--version-suffix", versionSuffix) .Execute() .EnsureSuccessful(); + } + + var packageFiles = Directory.EnumerateFiles(Dirs.PackagesIntermediate, "*.nupkg"); + + foreach (var packageFile in packageFiles) + { + if (!packageFile.EndsWith(".symbols.nupkg")) + { + var destinationPath = Path.Combine(Dirs.Packages, Path.GetFileName(packageFile)); + File.Copy(packageFile, destinationPath, overwrite: true); + } + } + return c.Success(); } diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs index 2faad973b..d65df0094 100644 --- a/scripts/dotnet-cli-build/PrepareTargets.cs +++ b/scripts/dotnet-cli-build/PrepareTargets.cs @@ -345,17 +345,6 @@ cmake is required to build the native host 'corehost'"; throw new InvalidOperationException("Unable to match the version name from " + pathToProjectJson); } - private static bool AptPackageIsInstalled(string packageName) - { - var result = Command.Create("dpkg", "-s", packageName) - .CaptureStdOut() - .CaptureStdErr() - .QuietBuildReporter() - .Execute(); - - return result.ExitCode == 0; - } - private static IDictionary ReadBranchInfo(BuildTargetContext c, string path) { var lines = File.ReadAllLines(path); diff --git a/scripts/dotnet-cli-build/TestPackageProjects.cs b/scripts/dotnet-cli-build/TestPackageProjects.cs new file mode 100644 index 000000000..b15db4705 --- /dev/null +++ b/scripts/dotnet-cli-build/TestPackageProjects.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli.Build.Framework; + +using static Microsoft.DotNet.Cli.Build.FS; +using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers; +using static Microsoft.DotNet.Cli.Build.Utils; + +namespace Microsoft.DotNet.Cli.Build +{ + public static class TestPackageProjects + { + private static string s_testPackageBuildVersionSuffix = ""; + + public static string TestPackageBuildVersionSuffix + { + get + { + return s_testPackageBuildVersionSuffix; + } + } + + public static readonly dynamic[] Projects = new[] + { + new + { + Name = "dotnet-dependency-tool-invoker", + IsTool = true, + Path = "TestAssets/TestPackages/dotnet-dependency-tool-invoker", + IsApplicable = new Func(() => CurrentPlatform.IsWindows), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = true + }, + new + { + Name = "dotnet-desktop-and-portable", + IsTool = true, + Path = "TestAssets/TestPackages/dotnet-desktop-and-portable", + IsApplicable = new Func(() => CurrentPlatform.IsWindows), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = true + }, + new + { + Name = "dotnet-hello", + IsTool = true, + Path = "TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello", + IsApplicable = new Func(() => true), + VersionSuffix = string.Empty, + Clean = true + }, + new + { + Name = "dotnet-hello", + IsTool = true, + Path = "TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello", + IsApplicable = new Func(() => true), + VersionSuffix = string.Empty, + Clean = true + }, + new + { + Name = "dotnet-portable", + IsTool = true, + Path = "TestAssets/TestPackages/dotnet-portable", + IsApplicable = new Func(() => true), + VersionSuffix = string.Empty, + Clean = true + }, + new + { + Name = "Microsoft.DotNet.Cli.Utils", + IsTool = true, + Path = "src/Microsoft.DotNet.Cli.Utils", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.ProjectModel", + IsTool = true, + Path = "src/Microsoft.DotNet.ProjectModel", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.ProjectModel.Loader", + IsTool = true, + Path = "src/Microsoft.DotNet.ProjectModel.Loader", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.ProjectModel.Workspaces", + IsTool = true, + Path = "src/Microsoft.DotNet.ProjectModel.Workspaces", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.InternalAbstractions", + IsTool = true, + Path = "src/Microsoft.DotNet.InternalAbstractions", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.Extensions.DependencyModel", + IsTool = true, + Path = "src/Microsoft.Extensions.DependencyModel", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.Extensions.Testing.Abstractions", + IsTool = true, + Path = "src/Microsoft.Extensions.Testing.Abstractions", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.Compiler.Common", + IsTool = true, + Path = "src/Microsoft.DotNet.Compiler.Common", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "Microsoft.DotNet.Files", + IsTool = true, + Path = "src/Microsoft.DotNet.Files", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = false + }, + new + { + Name = "dotnet-compile-fsc", + IsTool = true, + Path = "src/dotnet-compile-fsc", + IsApplicable = new Func(() => true), + VersionSuffix = s_testPackageBuildVersionSuffix, + Clean = true + } + }; + } +} \ No newline at end of file diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index 32c31aea2..13c197f0b 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -13,20 +13,7 @@ namespace Microsoft.DotNet.Cli.Build { public class TestTargets { - public static readonly dynamic[] TestPackageProjects = new[] - { - new { Name = "Microsoft.DotNet.Cli.Utils", IsTool = false, Path = "src/Microsoft.DotNet.Cli.Utils", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "Microsoft.DotNet.ProjectModel", IsTool = false, Path = "src/Microsoft.DotNet.ProjectModel", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "Microsoft.DotNet.Compiler.Common", IsTool = false, Path = "src/Microsoft.DotNet.Compiler.Common", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "Microsoft.Extensions.DependencyModel", IsTool = false, Path = "src/Microsoft.Extensions.DependencyModel", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "Microsoft.DotNet.Files", IsTool = false, Path = "src/Microsoft.DotNet.Files", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "Microsoft.DotNet.InternalAbstractions", IsTool = false, Path = "src/Microsoft.DotNet.InternalAbstractions", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "dotnet-dependency-tool-invoker", IsTool = true, Path = "TestAssets/TestPackages/dotnet-dependency-tool-invoker", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "dotnet-desktop-and-portable", IsTool = true, Path = "TestAssets/TestPackages/dotnet-desktop-and-portable", IsApplicable = new Func(() => CurrentPlatform.IsWindows) }, - new { Name = "dotnet-hello", IsTool = true, Path = "TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello", IsApplicable = new Func(() => true) }, - new { Name = "dotnet-hello", IsTool = true, Path = "TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello", IsApplicable = new Func(() => true) }, - new { Name = "dotnet-portable", IsTool = true, Path = "TestAssets/TestPackages/dotnet-portable", IsApplicable = new Func(() => true) } - }; + private static string s_testPackageBuildVersionSuffix = ""; public static readonly string[] TestProjects = new[] { @@ -35,6 +22,7 @@ namespace Microsoft.DotNet.Cli.Build "dotnet-publish.Tests", "dotnet-compile.Tests", "dotnet-compile.UnitTests", + "dotnet-compile-fsc.Tests", "dotnet-build.Tests", "dotnet-pack.Tests", "dotnet-projectmodel-server.Tests", @@ -54,7 +42,13 @@ namespace Microsoft.DotNet.Cli.Build new { Path = "AppWithDirectDependencyDesktopAndPortable", Skip = new Func(() => !CurrentPlatform.IsWindows) } }; - [Target(nameof(PrepareTargets.Init), nameof(SetupTests), nameof(RestoreTests), nameof(BuildTests), nameof(RunTests), nameof(ValidateDependencies))] + [Target( + nameof(PrepareTargets.Init), + nameof(SetupTests), + nameof(RestoreTests), + nameof(BuildTests), + nameof(RunTests), + nameof(ValidateDependencies))] public static BuildTargetResult Test(BuildTargetContext c) => c.Success(); [Target(nameof(SetupTestPackages), nameof(SetupTestProjects))] @@ -75,7 +69,10 @@ namespace Microsoft.DotNet.Cli.Build CleanNuGetTempCache(); var dotnet = DotNetCli.Stage2; - dotnet.Restore("--verbosity", "verbose", "--infer-runtimes", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")).Execute().EnsureSuccessful(); + dotnet.Restore("--verbosity", "verbose", "--infer-runtimes", "--disable-parallel") + .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")) + .Execute() + .EnsureSuccessful(); return c.Success(); } @@ -89,17 +86,26 @@ namespace Microsoft.DotNet.Cli.Build CleanNuGetTempCache(); var dotnet = DotNetCli.Stage2; - - dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes", "--fallbacksource", Dirs.TestPackages) + dotnet.Restore( + "--verbosity", "verbose", + "--disable-parallel", + "--infer-runtimes", + "--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("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes") + dotnet.Restore( + "--verbosity", "verbose", + "--disable-parallel", + "--infer-runtimes") .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthTestProjects")) .Execute(); - dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes") + dotnet.Restore( + "--verbosity", "verbose", + "--disable-parallel", + "--infer-runtimes") .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthUpdateSearchPathSample")) .Execute(); @@ -112,14 +118,16 @@ namespace Microsoft.DotNet.Cli.Build { var dotnet = DotNetCli.Stage2; - dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes", "--fallbacksource", Dirs.TestPackages) + dotnet.Restore("--verbosity", "verbose", + "--disable-parallel", "--infer-runtimes", + "--fallbacksource", Dirs.TestPackages) .WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "DesktopTestProjects")) .Execute().EnsureSuccessful(); return c.Success(); } - [Target(nameof(CleanTestPackages))] + [Target(nameof(CleanTestPackages), nameof(CleanProductPackages))] public static BuildTargetResult BuildTestAssetPackages(BuildTargetContext c) { CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")); @@ -129,12 +137,62 @@ namespace Microsoft.DotNet.Cli.Build Rmdir(Dirs.TestPackages); Mkdirp(Dirs.TestPackages); - foreach (var relativePath in TestPackageProjects.Where(p => p.IsApplicable()).Select(p => p.Path)) + foreach (var testPackageProject in TestPackageProjects.Projects.Where(p => p.IsApplicable())) { + var relativePath = testPackageProject.Path; + + var versionSuffix = testPackageProject.VersionSuffix; + if (versionSuffix.Equals(s_testPackageBuildVersionSuffix)) + { + versionSuffix = c.BuildContext.Get("BuildVersion").VersionSuffix; + } + var fullPath = Path.Combine(c.BuildContext.BuildDirectory, relativePath.Replace('/', Path.DirectorySeparatorChar)); c.Info($"Packing: {fullPath}"); - dotnet.Pack("--output", Dirs.TestPackages) - .WorkingDirectory(fullPath) + + // build and ignore failure, so net451 fail on non-windows doesn't crash the build + var packageBuildFrameworks = new List() + { + "netstandard1.5", + "netstandard1.3", + "netstandardapp1.5" + }; + + if (CurrentPlatform.IsWindows) + { + packageBuildFrameworks.Add("net451"); + } + + foreach (var packageBuildFramework in packageBuildFrameworks) + { + var buildArgs = new List(); + buildArgs.Add("-f"); + buildArgs.Add(packageBuildFramework); + buildArgs.Add("--build-base-path"); + buildArgs.Add(Dirs.TestPackagesBuild); + buildArgs.Add(fullPath); + + Mkdirp(Dirs.TestPackagesBuild); + var packBuildResult = DotNetCli.Stage1.Build(buildArgs.ToArray()) + .Execute(); + } + + + var projectJson = Path.Combine(fullPath, "project.json"); + var dotnetPackArgs = new List { + projectJson, + "--no-build", + "--build-base-path", Dirs.TestPackagesBuild, + "--output", Dirs.TestPackages + }; + + if (!string.IsNullOrEmpty(versionSuffix)) + { + dotnetPackArgs.Add("--version-suffix"); + dotnetPackArgs.Add(versionSuffix); + } + + dotnet.Pack(dotnetPackArgs.ToArray()) .Execute() .EnsureSuccessful(); } @@ -142,10 +200,21 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + [Target] + public static BuildTargetResult CleanProductPackages(BuildTargetContext c) + { + foreach (var packageName in PackageTargets.ProjectsToPack) + { + Rmdir(Path.Combine(Dirs.NuGetPackages, packageName)); + } + + return c.Success(); + } + [Target] public static BuildTargetResult CleanTestPackages(BuildTargetContext c) { - foreach (var packageProject in TestPackageProjects.Where(p => p.IsApplicable())) + foreach (var packageProject in TestPackageProjects.Projects.Where(p => p.IsApplicable() && p.Clean)) { Rmdir(Path.Combine(Dirs.NuGetPackages, packageProject.Name)); if(packageProject.IsTool) diff --git a/scripts/dotnet-cli-build/Utils/Dirs.cs b/scripts/dotnet-cli-build/Utils/Dirs.cs index eea866d9b..62ebe8f73 100644 --- a/scripts/dotnet-cli-build/Utils/Dirs.cs +++ b/scripts/dotnet-cli-build/Utils/Dirs.cs @@ -12,6 +12,8 @@ namespace Microsoft.DotNet.Cli.Build RepoRoot, "artifacts", PlatformServices.Default.Runtime.GetRuntimeIdentifier()); + + public static readonly string PackagesIntermediate = Path.Combine(Output, "packages/intermediate"); public static readonly string Packages = Path.Combine(Output, "packages"); public static readonly string Stage1 = Path.Combine(Output, "stage1"); public static readonly string Stage1Compilation = Path.Combine(Output, "stage1compilation"); @@ -21,11 +23,14 @@ namespace Microsoft.DotNet.Cli.Build public static readonly string TestOutput = Path.Combine(Output, "tests"); public static readonly string TestArtifacts = Path.Combine(TestOutput, "artifacts"); public static readonly string TestPackages = Path.Combine(TestOutput, "packages"); + public static readonly string TestPackagesBuild = Path.Combine(TestOutput, "packagesBuild"); + public static readonly string OSXReferenceAssembliesPath = "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"; public static readonly string UsrLocalReferenceAssembliesPath = "/usr/local/lib/mono/xbuild-frameworks"; public static readonly string UsrReferenceAssembliesPath = "/usr/lib/mono/xbuild-frameworks"; + public static string NuGetPackages = Environment.GetEnvironmentVariable("NUGET_PACKAGES") ?? GetNuGetPackagesDir(); private static string GetNuGetPackagesDir() diff --git a/scripts/package/projectsToPack.ps1 b/scripts/package/projectsToPack.ps1 index 5c08c9573..e69de29bb 100644 --- a/scripts/package/projectsToPack.ps1 +++ b/scripts/package/projectsToPack.ps1 @@ -1,15 +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. - -$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.TestFramework", - "Microsoft.Extensions.DependencyModel", - "Microsoft.Extensions.Testing.Abstractions" -) \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolutionStrategy.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolutionStrategy.cs index c3059c8a0..a819e9143 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolutionStrategy.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolutionStrategy.cs @@ -2,6 +2,9 @@ { public enum CommandResolutionStrategy { + // command loaded from a deps file + DepsFile, + // command loaded from project dependencies nuget package ProjectDependenciesPackage, diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs index f5ce255ba..e43b377b5 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs @@ -24,5 +24,7 @@ namespace Microsoft.DotNet.Cli.Utils public IEnumerable InferredExtensions { get; set; } public string BuildBasePath { get; set; } + + public string DepsJsonFile { get; set; } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonCommandResolver.cs new file mode 100644 index 000000000..f4b54347c --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DepsJsonCommandResolver.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.IO; +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 Microsoft.DotNet.ProjectModel.Resolution; +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 DepsJsonCommandResolver : ICommandResolver + { + private static readonly string[] s_extensionPreferenceOrder = new [] + { + "", + ".exe", + ".dll" + }; + + private string _nugetPackageRoot; + private Muxer _muxer; + + public DepsJsonCommandResolver(string nugetPackageRoot) + : this(new Muxer(), nugetPackageRoot) { } + + public DepsJsonCommandResolver(Muxer muxer, string nugetPackageRoot) + { + _muxer = muxer; + _nugetPackageRoot = nugetPackageRoot; + } + + public CommandSpec Resolve(CommandResolverArguments commandResolverArguments) + { + if (commandResolverArguments.CommandName == null + || commandResolverArguments.DepsJsonFile == null) + { + return null; + } + + return ResolveFromDepsJsonFile( + commandResolverArguments.CommandName, + commandResolverArguments.CommandArguments.OrEmptyIfNull(), + commandResolverArguments.DepsJsonFile); + } + + private CommandSpec ResolveFromDepsJsonFile( + string commandName, + IEnumerable commandArgs, + string depsJsonFile) + { + var dependencyContext = LoadDependencyContextFromFile(depsJsonFile); + + var commandPath = GetCommandPathFromDependencyContext(commandName, dependencyContext); + if (commandPath == null) + { + return null; + } + + return CreateCommandSpecUsingMuxerIfPortable( + commandPath, + commandArgs, + depsJsonFile, + CommandResolutionStrategy.DepsFile, + _nugetPackageRoot, + IsPortableApp(commandPath)); + } + + public DependencyContext LoadDependencyContextFromFile(string depsJsonFile) + { + DependencyContext dependencyContext = null; + DependencyContextJsonReader contextReader = new DependencyContextJsonReader(); + + using (var contextStream = File.OpenRead(depsJsonFile)) + { + dependencyContext = contextReader.Read(contextStream); + } + + return dependencyContext; + } + + public string GetCommandPathFromDependencyContext(string commandName, DependencyContext dependencyContext) + { + var commandCandidates = new List(); + + var assemblyCommandCandidates = GetCommandCandidates( + commandName, + dependencyContext, + CommandCandidateType.RuntimeCommandCandidate); + var nativeCommandCandidates = GetCommandCandidates( + commandName, + dependencyContext, + CommandCandidateType.NativeCommandCandidate); + + commandCandidates.AddRange(assemblyCommandCandidates); + commandCandidates.AddRange(nativeCommandCandidates); + + var command = ChooseCommandCandidate(commandCandidates); + + return command?.GetAbsoluteCommandPath(_nugetPackageRoot); + } + + private IEnumerable GetCommandCandidates( + string commandName, + DependencyContext dependencyContext, + CommandCandidateType commandCandidateType) + { + var commandCandidates = new List(); + + foreach (var runtimeLibrary in dependencyContext.RuntimeLibraries) + { + IEnumerable runtimeAssetGroups = null; + + if (commandCandidateType == CommandCandidateType.NativeCommandCandidate) + { + runtimeAssetGroups = runtimeLibrary.NativeLibraryGroups; + } + else if (commandCandidateType == CommandCandidateType.RuntimeCommandCandidate) + { + runtimeAssetGroups = runtimeLibrary.RuntimeAssemblyGroups; + } + + commandCandidates.AddRange(GetCommandCandidatesFromRuntimeAssetGroups( + commandName, + runtimeAssetGroups, + runtimeLibrary.Name, + runtimeLibrary.Version)); + } + + return commandCandidates; + } + + private IEnumerable GetCommandCandidatesFromRuntimeAssetGroups( + string commandName, + IEnumerable runtimeAssetGroups, + string PackageName, + string PackageVersion) + { + var candidateAssetGroups = runtimeAssetGroups + .Where(r => r.Runtime == string.Empty) + .Where(a => + a.AssetPaths.Any(p => + Path.GetFileNameWithoutExtension(p).Equals(commandName, StringComparison.OrdinalIgnoreCase))); + + var commandCandidates = new List(); + foreach (var candidateAssetGroup in candidateAssetGroups) + { + var candidateAssetPaths = candidateAssetGroup.AssetPaths.Where( + p => Path.GetFileNameWithoutExtension(p) + .Equals(commandName, StringComparison.OrdinalIgnoreCase)); + + foreach (var candidateAssetPath in candidateAssetPaths) + { + commandCandidates.Add(new CommandCandidate + { + PackageName = PackageName, + PackageVersion = PackageVersion, + RelativeCommandPath = candidateAssetPath + }); + } + } + + return commandCandidates; + } + + private CommandCandidate ChooseCommandCandidate(IEnumerable commandCandidates) + { + foreach (var extension in s_extensionPreferenceOrder) + { + var candidate = commandCandidates + .FirstOrDefault(p => Path.GetExtension(p.RelativeCommandPath) + .Equals(extension, StringComparison.OrdinalIgnoreCase)); + + if (candidate != null) + { + return candidate; + } + } + + return null; + } + + private CommandSpec CreateCommandSpecUsingMuxerIfPortable( + string commandPath, + IEnumerable commandArgs, + string depsJsonFile, + CommandResolutionStrategy commandResolutionStrategy, + string nugetPackagesRoot, + bool isPortable) + { + var depsFileArguments = GetDepsFileArguments(depsJsonFile); + var additionalProbingPathArguments = GetAdditionalProbingPathArguments(); + + var muxerArgs = new List(); + muxerArgs.Add("exec"); + muxerArgs.AddRange(depsFileArguments); + muxerArgs.AddRange(additionalProbingPathArguments); + muxerArgs.Add(commandPath); + muxerArgs.AddRange(commandArgs); + + var escapedArgString = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(muxerArgs); + + return new CommandSpec(_muxer.MuxerPath, escapedArgString, commandResolutionStrategy); + } + + private bool IsPortableApp(string commandPath) + { + var commandDir = Path.GetDirectoryName(commandPath); + + var runtimeConfigPath = Directory.EnumerateFiles(commandDir) + .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); + + if (runtimeConfigPath == null) + { + return false; + } + + var runtimeConfig = new RuntimeConfig(runtimeConfigPath); + + return runtimeConfig.IsPortable; + } + + private IEnumerable GetDepsFileArguments(string depsJsonFile) + { + return new[] { "--depsfile", depsJsonFile }; + } + + private IEnumerable GetAdditionalProbingPathArguments() + { + return new[] { "--additionalProbingPath", _nugetPackageRoot }; + } + + private class CommandCandidate + { + public string PackageName { get; set; } + public string PackageVersion { get; set; } + public string RelativeCommandPath { get; set; } + + public string GetAbsoluteCommandPath(string nugetPackageRoot) + { + return Path.Combine( + nugetPackageRoot.Replace('/', Path.DirectorySeparatorChar), + PackageName.Replace('/', Path.DirectorySeparatorChar), + PackageVersion.Replace('/', Path.DirectorySeparatorChar), + RelativeCommandPath.Replace('/', Path.DirectorySeparatorChar)); + } + } + + private enum CommandCandidateType + { + NativeCommandCandidate, + RuntimeCommandCandidate + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/DepsJsonCommandFactory.cs b/src/Microsoft.DotNet.Cli.Utils/DepsJsonCommandFactory.cs new file mode 100644 index 000000000..55108f4f8 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/DepsJsonCommandFactory.cs @@ -0,0 +1,50 @@ +// 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; +using NuGet.Frameworks; +using System.IO; +using System; +using Microsoft.DotNet.ProjectModel; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class DepsJsonCommandFactory : ICommandFactory + { + private DepsJsonCommandResolver _depsJsonCommandResolver; + private string _temporaryDirectory; + private string _depsJsonFile; + private string _runtimeConfigFile; + + public DepsJsonCommandFactory( + string depsJsonFile, + string runtimeConfigFile, + string nugetPackagesRoot, + string temporaryDirectory) + { + _depsJsonCommandResolver = new DepsJsonCommandResolver(nugetPackagesRoot); + + _temporaryDirectory = temporaryDirectory; + _depsJsonFile = depsJsonFile; + _runtimeConfigFile = runtimeConfigFile; + } + + public ICommand Create( + string commandName, + IEnumerable args, + NuGetFramework framework = null, + string configuration = Constants.DefaultConfiguration) + { + var commandResolverArgs = new CommandResolverArguments() + { + CommandName = commandName, + CommandArguments = args, + DepsJsonFile = _depsJsonFile + }; + + var commandSpec = _depsJsonCommandResolver.Resolve(commandResolverArgs); + + return Command.Create(commandSpec); + } + } +} diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 3a0ed9d51..d798f43d3 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -308,7 +308,7 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) trace::verbose(_X("Current argv is %s"), argv[cur_i]); pal::string_t app_or_deps = deps_file.empty() ? argv[cur_i] : deps_file; - pal::string_t no_json = deps_file.empty() ? app_or_deps : strip_file_ext(app_or_deps); + pal::string_t no_json = argv[cur_i]; auto config_file = get_runtime_config_from_file(no_json); runtime_config_t config(config_file); if (!config.is_valid()) diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp index c68253f23..e238303ca 100644 --- a/src/corehost/cli/libhost.cpp +++ b/src/corehost/cli/libhost.cpp @@ -13,11 +13,8 @@ pal::string_t get_runtime_config_from_file(const pal::string_t& file) auto json_path = get_directory(file); append_path(&json_path, json_name.c_str()); - if (pal::file_exists(json_path)) - { - return json_path; - } - return pal::string_t(); + trace::verbose(_X("Runtime config is %s"), json_path.c_str()); + return json_path; } host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* p_own_dir) diff --git a/src/dotnet/commands/dotnet-compile-fsc/Program.cs b/src/dotnet-compile-fsc/Program.cs similarity index 70% rename from src/dotnet/commands/dotnet-compile-fsc/Program.cs rename to src/dotnet-compile-fsc/Program.cs index 6eb454330..070846b7a 100644 --- a/src/dotnet/commands/dotnet-compile-fsc/Program.cs +++ b/src/dotnet-compile-fsc/Program.cs @@ -12,15 +12,16 @@ using System.Text; using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Resolution; using NuGet.Frameworks; +using System.Reflection; namespace Microsoft.DotNet.Tools.Compiler.Fsc { public class CompileFscCommand { private const int ExitFailed = 1; - - public static int Run(string[] args) + public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); @@ -80,19 +81,24 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc return returnCode; } - // TODO less hacky bool targetNetCore = commonOptions.Defines.Contains("DNXCORE50") || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() || commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any(); + // Get FSC Path upfront to use it for win32manifest path + var fscCommandSpec = ResolveFsc(null, tempOutDir); + var fscExeFile = fscCommandSpec.FscExeFile; + var fscExeDir = fscCommandSpec.FscExeDir; + // FSC arguments var allArgs = new List(); //HACK fsc raise error FS0208 if target exe doesnt have extension .exe bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true; - string originalOutputName = outputName; + + var originalOutputName = outputName; if (outputName != null) { @@ -168,11 +174,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc allArgs.Add("--target:exe"); //HACK we need default.win32manifest for exe - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var win32manifestPath = Path.Combine(AppContext.BaseDirectory, "default.win32manifest"); - allArgs.Add($"--win32manifest:{win32manifestPath}"); - } + var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "default.win32manifest"); + allArgs.Add($"--win32manifest:{win32manifestPath}"); } if (commonOptions.SuppressWarnings != null) @@ -227,13 +230,13 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc //source files + assemblyInfo allArgs.AddRange(GetSourceFiles(sources, assemblyInfo).ToArray()); - //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration + //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); File.WriteAllLines(rsp, allArgs, Encoding.UTF8); // Execute FSC! - var result = RunFsc(new List { $"@{rsp}" }) + var result = RunFsc(new List { $"@{rsp}" }, tempOutDir) .ForwardStdErr() .ForwardStdOut() .Execute(); @@ -257,26 +260,6 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc return result.ExitCode; } - private static Command RunFsc(List fscArgs) - { - var fscExe = Environment.GetEnvironmentVariable("DOTNET_FSC_PATH") - ?? Path.Combine(AppContext.BaseDirectory, "fsc.exe"); - - var exec = Environment.GetEnvironmentVariable("DOTNET_FSC_EXEC")?.ToUpper() ?? "COREHOST"; - - switch (exec) - { - case "RUN": - return Command.Create(fscExe, fscArgs.ToArray()); - - case "COREHOST": - default: - var corehost = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName); - return Command.Create(corehost, new[] { fscExe }.Concat(fscArgs).ToArray()); - } - - } - // The assembly info must be in the last minus 1 position because: // - assemblyInfo should be in the end to override attributes // - assemblyInfo cannot be in the last position, because last file contains the main @@ -295,5 +278,97 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc yield return sourceFiles.Last(); } + + private static Command RunFsc(List fscArgs, string temp) + { + var fscEnvExe = Environment.GetEnvironmentVariable("DOTNET_FSC_PATH"); + var exec = Environment.GetEnvironmentVariable("DOTNET_FSC_EXEC")?.ToUpper() ?? "COREHOST"; + + var muxer = new Muxer(); + + if (fscEnvExe != null) + { + switch (exec) + { + case "RUN": + return Command.Create(fscEnvExe, fscArgs.ToArray()); + + case "COREHOST": + default: + var host = muxer.MuxerPath; + return Command.Create(host, new[] { fscEnvExe }.Concat(fscArgs).ToArray()); + } + } + else + { + var fscCommandSpec = ResolveFsc(fscArgs, temp)?.Spec; + return Command.Create(fscCommandSpec); + } + } + + private static FscCommandSpec ResolveFsc(List fscArgs, string temp) + { + var nugetPackagesRoot = PackageDependencyProvider.ResolvePackagesPath(null, null); + var depsFile = Path.Combine(AppContext.BaseDirectory, "dotnet-compile-fsc" + FileNameSuffixes.DepsJson); + + var depsJsonCommandResolver = new DepsJsonCommandResolver(nugetPackagesRoot); + var dependencyContext = depsJsonCommandResolver.LoadDependencyContextFromFile(depsFile); + var fscPath = depsJsonCommandResolver.GetCommandPathFromDependencyContext("fsc", dependencyContext); + + + var commandResolverArgs = new CommandResolverArguments() + { + CommandName = "fsc", + CommandArguments = fscArgs, + DepsJsonFile = depsFile + }; + + var fscCommandSpec = depsJsonCommandResolver.Resolve(commandResolverArgs); + + var runtimeConfigFile = Path.Combine( + Path.GetDirectoryName(typeof(CompileFscCommand).GetTypeInfo().Assembly.Location) + , "dotnet-compile-fsc" + FileNameSuffixes.RuntimeConfigJson); + + + CopyRuntimeConfigForFscExe(runtimeConfigFile, "fsc", depsFile, nugetPackagesRoot, fscPath); + + return new FscCommandSpec + { + Spec = fscCommandSpec, + FscExeDir = Path.GetDirectoryName(fscPath), + FscExeFile = fscPath + }; + } + + private static void CopyRuntimeConfigForFscExe( + string runtimeConfigFile, + string commandName, + string depsJsonFile, + string nugetPackagesRoot, + string fscPath) + { + var newFscRuntimeConfigDir = Path.GetDirectoryName(fscPath); + var newFscRuntimeConfigFile = Path.Combine( + newFscRuntimeConfigDir, + Path.GetFileNameWithoutExtension(fscPath) + FileNameSuffixes.RuntimeConfigJson); + + try + { + File.Copy(runtimeConfigFile, newFscRuntimeConfigFile, true); + } + catch(Exception e) + { + Reporter.Error.WriteLine("Failed to copy fsc runtimeconfig.json"); + throw e; + } + } + + private class FscCommandSpec + { + public CommandSpec Spec { get; set; } + public string FscExeDir { get; set; } + public string FscExeFile { get; set; } + } } } + diff --git a/src/dotnet-compile-fsc/dotnet-compile-fsc.xproj b/src/dotnet-compile-fsc/dotnet-compile-fsc.xproj new file mode 100644 index 000000000..186b3d19a --- /dev/null +++ b/src/dotnet-compile-fsc/dotnet-compile-fsc.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 60cf7e6c-d6c8-439d-b7b7-d8a27e29be2c + Microsoft.DotNet.Tools.Compiler.Fsc + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + + 2.0 + + + \ No newline at end of file diff --git a/src/dotnet-compile-fsc/project.json b/src/dotnet-compile-fsc/project.json new file mode 100644 index 000000000..59c39edee --- /dev/null +++ b/src/dotnet-compile-fsc/project.json @@ -0,0 +1,29 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "Microsoft.FSharp.Compiler.netcore": "1.0.0-alpha-160318", + "System.CommandLine": "0.1.0-e160323-1", + + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Compiler.Common": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": "1.0.0-*", + + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-23931" + } + }, + "frameworks": { + "netstandard1.5": { + "imports": [ + "dnxcore50", + "portable-net45+win81", + "netstandard1.3" + ] + } + } +} diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 73f75b217..7d8e02cb3 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -13,7 +13,6 @@ using Microsoft.DotNet.ProjectModel.Server; using Microsoft.DotNet.Tools.Build; using Microsoft.DotNet.Tools.Compiler; using Microsoft.DotNet.Tools.Compiler.Csc; -using Microsoft.DotNet.Tools.Compiler.Fsc; using Microsoft.DotNet.Tools.Compiler.Native; using Microsoft.DotNet.Tools.Help; using Microsoft.DotNet.Tools.New; diff --git a/src/dotnet/commands/dotnet-new/FSharp_Console/NuGet.Config b/src/dotnet/commands/dotnet-new/FSharp_Console/NuGet.Config index 3f788a5d7..f1c321599 100644 --- a/src/dotnet/commands/dotnet-new/FSharp_Console/NuGet.Config +++ b/src/dotnet/commands/dotnet-new/FSharp_Console/NuGet.Config @@ -6,5 +6,8 @@ + + + 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 7f2fc80c4..745dc0243 100644 --- a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template @@ -14,6 +14,11 @@ "version": "1.0.0-rc2-23931" } }, + + "tools": { + "dotnet-compile-fsc": "1.0.0-*" + }, + "frameworks": { "netstandard1.5": { "imports": [ diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs index 3fab175b5..c763ae5f3 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Assertions/CommandResultAssertions.cs @@ -32,13 +32,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return new AndConstraint(this); } - public AndConstraint NotPass() - { - Execute.Assertion.ForCondition(_commandResult.ExitCode != 0) - .FailWith(AppendDiagnosticsTo($"Expected command to fail but it did not.")); - return new AndConstraint(this); - } - public AndConstraint Fail() { Execute.Assertion.ForCondition(_commandResult.ExitCode != 0) diff --git a/test/dotnet-compile-fsc.Tests/GivenThatIWantToCompileFSharpPrograms.cs b/test/dotnet-compile-fsc.Tests/GivenThatIWantToCompileFSharpPrograms.cs new file mode 100644 index 000000000..a37b47064 --- /dev/null +++ b/test/dotnet-compile-fsc.Tests/GivenThatIWantToCompileFSharpPrograms.cs @@ -0,0 +1,66 @@ +// 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.DotNet.Cli.Utils; +using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Tools.Test.Utilities; +using FluentAssertions; +using Xunit; + +namespace Microsoft.DotNet.Tools.Compiler.Tests +{ + public class GivenThatIWantToCompileFSharpPrograms + { + private readonly static string s_testProjectsRoot = Path.Combine( + AppContext.BaseDirectory, + "TestAssets", + "TestProjects", + "FSharpTestProjects"); + + [Fact] + public void Compilation_of_app_with_invalid_source_should_fail() + { + var testProject = Path.Combine(s_testProjectsRoot, "CompileFailApp", "project.json"); + var buildCommand = new BuildCommand(testProject); + + var oldDirectory = Directory.GetCurrentDirectory(); + Directory.SetCurrentDirectory(Path.GetDirectoryName(testProject)); + + buildCommand.Execute().Should().Fail(); + + Directory.SetCurrentDirectory(oldDirectory); + } + + [Fact] + public void Compilation_of_valid_app_should_succeed() + { + var testProject = Path.Combine(s_testProjectsRoot, "TestAppWithArgs", "project.json"); + var buildCommand = new BuildCommand(testProject); + + var oldDirectory = Directory.GetCurrentDirectory(); + Directory.SetCurrentDirectory(Path.GetDirectoryName(testProject)); + + buildCommand.Execute().Should().Pass(); + + Directory.SetCurrentDirectory(oldDirectory); + } + + [Fact] + public void Compilation_of_app_with_P2P_reference_to_fsharp_library_should_be_runnable() + { + var testProject = Path.Combine(s_testProjectsRoot, "TestApp", "project.json"); + var runCommand = new RunCommand(testProject); + + var oldDirectory = Directory.GetCurrentDirectory(); + Directory.SetCurrentDirectory(Path.GetDirectoryName(testProject)); + + var result = runCommand.Execute(); + + result.Should().Pass(); + + Directory.SetCurrentDirectory(oldDirectory); + } + } +} diff --git a/test/dotnet-compile-fsc.Tests/dotnet-compile-fsc.Tests.xproj b/test/dotnet-compile-fsc.Tests/dotnet-compile-fsc.Tests.xproj new file mode 100644 index 000000000..109254497 --- /dev/null +++ b/test/dotnet-compile-fsc.Tests/dotnet-compile-fsc.Tests.xproj @@ -0,0 +1,21 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 833ffee1-7eed-4f51-8dfd-946d48893d6e + Microsoft.DotNet.Tools.Compiler.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/dotnet-compile-fsc.Tests/project.json b/test/dotnet-compile-fsc.Tests/project.json new file mode 100644 index 000000000..268f178df --- /dev/null +++ b/test/dotnet-compile-fsc.Tests/project.json @@ -0,0 +1,34 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.5.0-rc2-23931", + + "Microsoft.DotNet.Tools.Tests.Utilities": { "target": "project" }, + "Microsoft.DotNet.Cli.Utils": { + "target": "project" + }, + + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-dev-128011-22" + }, + + "frameworks": { + "netstandardapp1.5": { + "imports": [ + "dnxcore50", + "portable-net451+win8" + ] + } + }, + + "content": [ + "../../TestAssets/TestProjects/FSharpTestProjects/CompileFailApp/**/*", + "../../TestAssets/TestProjects/FSharpTestProjects/TestApp/**/*", + "../../TestAssets/TestProjects/FSharpTestProjects/TestAppWithArgs/**/*", + "../../TestAssets/TestProjects/FSharpTestProjects/TestLibrary/**/*", + "../../TestAssets/TestProjects/FSharpTestProjects/global.json" + ], + + "testRunner": "xunit" +} diff --git a/test/dotnet.Tests/PackagedCommandTests.cs b/test/dotnet.Tests/PackagedCommandTests.cs index 3fee9f023..cdda94343 100644 --- a/test/dotnet.Tests/PackagedCommandTests.cs +++ b/test/dotnet.Tests/PackagedCommandTests.cs @@ -88,7 +88,7 @@ namespace Microsoft.DotNet.Tests CommandResult result = new HelloCommand().ExecuteWithCapturedOutput(); result.StdOut.Should().Contain("No executable found matching command"); - result.Should().NotPass(); + result.Should().Fail(); } finally {