diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenADependencyContextBuilder.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenADependencyContextBuilder.cs index a6ccd3ef9009..e6860b12e721 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenADependencyContextBuilder.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenADependencyContextBuilder.cs @@ -49,7 +49,8 @@ public void ItBuildsDependencyContextsFromProjectLockFiles( ProjectContext projectContext = lockFile.CreateProjectContext( FrameworkConstants.CommonFrameworks.NetCoreApp10, runtime, - Constants.DefaultPlatformLibrary); + Constants.DefaultPlatformLibrary, + isSelfContained: !string.IsNullOrEmpty(runtime)); DependencyContext dependencyContext = new DependencyContextBuilder(mainProject, projectContext) .WithDirectReferences(directReferences) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAProjectContext.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAProjectContext.cs index 978e7a4d3374..44a6503fae3f 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAProjectContext.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAProjectContext.cs @@ -21,7 +21,8 @@ public void ItComputesPrivateAssetsExclusionList() ProjectContext projectContext = lockFile.CreateProjectContext( FrameworkConstants.CommonFrameworks.NetStandard16, null, - Constants.DefaultPlatformLibrary); + Constants.DefaultPlatformLibrary, + isSelfContained: false); IEnumerable privateAssetPackageIds = new[] { "Microsoft.Extensions.Logging.Abstractions" }; IDictionary libraryLookup = diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPublishAssembliesResolver.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPublishAssembliesResolver.cs index a6be1d2bed76..902a2fddc3f5 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPublishAssembliesResolver.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAPublishAssembliesResolver.cs @@ -24,7 +24,8 @@ public void ItResolvesAssembliesFromProjectLockFiles(string projectName, string ProjectContext projectContext = lockFile.CreateProjectContext( FrameworkConstants.CommonFrameworks.NetCoreApp10, runtime, - Constants.DefaultPlatformLibrary); + Constants.DefaultPlatformLibrary, + isSelfContained: false); IEnumerable resolvedFiles = new PublishAssembliesResolver(new MockPackageResolver()) .Resolve(projectContext); @@ -42,7 +43,8 @@ public void ItResolvesAssembliesFromProjectLockFilesWithCacheLayout(string proje ProjectContext projectContext = lockFile.CreateProjectContext( FrameworkConstants.CommonFrameworks.NetCoreApp10, runtime, - Constants.DefaultPlatformLibrary); + Constants.DefaultPlatformLibrary, + isSelfContained: false); IEnumerable resolvedFiles = new PublishAssembliesResolver(new MockPackageResolver()) .WithPreserveCacheLayout(true) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs b/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs index a19b4112bb30..97c531f30d7b 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs @@ -8,7 +8,6 @@ using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.DependencyModel; -using NuGet.Frameworks; using NuGet.Packaging; using NuGet.Packaging.Core; using NuGet.ProjectModel; @@ -125,7 +124,9 @@ public DependencyContext Build() _projectContext.LockFileTarget.TargetFramework.DotNetFrameworkName, _projectContext.LockFileTarget.RuntimeIdentifier, runtimeSignature, - _projectContext.IsPortable); + // DependencyContext's IsPortable strictly means it doesn't have a runtime dependency, + // not whether it is FrameworkDependent or !SelfContained. + isPortable: string.IsNullOrEmpty(_projectContext.LockFileTarget.RuntimeIdentifier)); return new DependencyContext( targetInfo, diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs index a7ea56f99b35..2bf4a5189544 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs @@ -7,7 +7,6 @@ using Microsoft.Build.Utilities; using Microsoft.Extensions.DependencyModel; using Newtonsoft.Json; -using NuGet.Frameworks; using NuGet.ProjectModel; namespace Microsoft.NET.Build.Tasks @@ -55,6 +54,8 @@ public class GenerateDepsFile : TaskBase public ITaskItem[] PrivateAssetsPackageReferences { get; set; } + public bool IsSelfContained { get; set; } + List _filesWritten = new List(); [Output] @@ -90,7 +91,8 @@ protected override void ExecuteCore() ProjectContext projectContext = lockFile.CreateProjectContext( NuGetUtils.ParseFrameworkName(TargetFramework), RuntimeIdentifier, - PlatformLibraryName); + PlatformLibraryName, + IsSelfContained); DependencyContext dependencyContext = new DependencyContextBuilder(mainProject, projectContext) .WithFrameworkReferences(frameworkReferences) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateRuntimeConfigurationFiles.cs b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateRuntimeConfigurationFiles.cs index 948d1d5795fe..90fd739dfe00 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/GenerateRuntimeConfigurationFiles.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/GenerateRuntimeConfigurationFiles.cs @@ -43,6 +43,8 @@ public class GenerateRuntimeConfigurationFiles : TaskBase public ITaskItem[] HostConfigurationOptions { get; set; } + public bool IsSelfContained { get; set; } + List _filesWritten = new List(); [Output] @@ -57,7 +59,8 @@ protected override void ExecuteCore() ProjectContext projectContext = lockFile.CreateProjectContext( NuGetUtils.ParseFrameworkName(TargetFrameworkMoniker), RuntimeIdentifier, - PlatformLibraryName); + PlatformLibraryName, + IsSelfContained); WriteRuntimeConfig(projectContext); @@ -86,7 +89,7 @@ private void WriteRuntimeConfig(ProjectContext projectContext) private void AddFramework(RuntimeOptions runtimeOptions, ProjectContext projectContext) { - if (projectContext.IsPortable) + if (projectContext.IsFrameworkDependent) { var platformLibrary = projectContext.PlatformLibrary; if (platformLibrary != null) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs b/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs index c441e365e3d9..6e0fe73d4629 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs @@ -16,7 +16,8 @@ public static ProjectContext CreateProjectContext( this LockFile lockFile, NuGetFramework framework, string runtime, - string platformLibraryName) + string platformLibraryName, + bool isSelfContained) { if (lockFile == null) { @@ -39,7 +40,10 @@ public static ProjectContext CreateProjectContext( throw new BuildErrorException(Strings.AssetsFileMissingTarget, lockFile.Path, targetMoniker, framework.GetShortFolderName(), runtime); } - return new ProjectContext(lockFile, lockFileTarget, platformLibraryName); + LockFileTargetLibrary platformLibrary = lockFileTarget.GetLibrary(platformLibraryName); + bool isFrameworkDependent = platformLibrary != null && (!isSelfContained || string.IsNullOrEmpty(lockFileTarget.RuntimeIdentifier)); + + return new ProjectContext(lockFile, lockFileTarget, platformLibrary, isFrameworkDependent); } public static LockFileTargetLibrary GetLibrary(this LockFileTarget lockFileTarget, string libraryName) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProjectContext.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProjectContext.cs index 9409583bb485..ba24f3af632e 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ProjectContext.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProjectContext.cs @@ -1,14 +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 NuGet.Packaging.Core; +using NuGet.ProjectModel; using System; using System.Collections.Generic; -using System.IO; +using System.Diagnostics; using System.Linq; -using NuGet.ProjectModel; -using NuGet.Packaging.Core; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; namespace Microsoft.NET.Build.Tasks { @@ -16,23 +14,28 @@ internal class ProjectContext { private readonly LockFile _lockFile; private readonly LockFileTarget _lockFileTarget; - private readonly string _platformLibraryName; internal HashSet PackagesToBeFiltered { get; set; } - public bool IsPortable { get; } + public bool IsFrameworkDependent { get; } public LockFileTargetLibrary PlatformLibrary { get; } public LockFile LockFile => _lockFile; public LockFileTarget LockFileTarget => _lockFileTarget; - public ProjectContext(LockFile lockFile, LockFileTarget lockFileTarget, string platformLibraryName) + public ProjectContext(LockFile lockFile, LockFileTarget lockFileTarget, LockFileTargetLibrary platformLibrary, bool isFrameworkDependent) { + Debug.Assert(lockFile != null); + Debug.Assert(lockFileTarget != null); + if (isFrameworkDependent) + { + Debug.Assert(platformLibrary != null); + } + _lockFile = lockFile; _lockFileTarget = lockFileTarget; - _platformLibraryName = platformLibraryName; - PlatformLibrary = _lockFileTarget.GetLibrary(_platformLibraryName); - IsPortable = PlatformLibrary != null && string.IsNullOrEmpty(_lockFileTarget.RuntimeIdentifier); + PlatformLibrary = platformLibrary; + IsFrameworkDependent = isFrameworkDependent; } public IEnumerable GetRuntimeLibraries(IEnumerable privateAssetPackageIds) @@ -43,7 +46,7 @@ public IEnumerable GetRuntimeLibraries(IEnumerable allExclusionList = new HashSet(StringComparer.OrdinalIgnoreCase); - if (IsPortable) + if (IsFrameworkDependent) { allExclusionList.UnionWith(_lockFileTarget.GetPlatformExclusionList(PlatformLibrary, libraryLookup)); } @@ -58,7 +61,7 @@ public IEnumerable GetRuntimeLibraries(IEnumerable>(StringComparer.OrdinalIgnoreCase); foreach (var pkg in PackagesToBeFiltered) @@ -201,7 +204,7 @@ private static HashSet GetPackagesToBeFiltered( IDictionary packagesToBePublished) { var exclusionList = new HashSet(StringComparer.OrdinalIgnoreCase); - + foreach (var entry in packagesToBePublished) { HashSet librarySet; diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePublishAssemblies.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePublishAssemblies.cs index 5834cea25f73..2a070f99b0ab 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePublishAssemblies.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePublishAssemblies.cs @@ -37,6 +37,8 @@ public class ResolvePublishAssemblies : TaskBase public string[] FilterProjectFiles { get; set; } + public bool IsSelfContained { get; set; } + /// /// All the assemblies to publish. /// @@ -80,7 +82,8 @@ protected override void ExecuteCore() ProjectContext projectContext = lockFile.CreateProjectContext( NuGetUtils.ParseFrameworkName(TargetFramework), RuntimeIdentifier, - PlatformLibraryName); + PlatformLibraryName, + IsSelfContained); projectContext.PackagesToBeFiltered = packagestoBeFiltered; diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.Designer.cs b/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.Designer.cs index adb2959cd21a..02d70728e889 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.Designer.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.Designer.cs @@ -11,7 +11,8 @@ namespace Microsoft.NET.Build.Tasks { using System; using System.Reflection; - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -59,7 +60,7 @@ internal Strings() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to Unable to use '{0}' as application host executable as it does not contain the expected placeholder byte sequence '{1}' that would mark where the application name would be written.. /// @@ -123,6 +124,15 @@ internal static string CannotFindProjectInfo { } } + /// + /// Looks up a localized string similar to It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier. Please either specify a RuntimeIdentifier or set SelfContained to false.. + /// + internal static string CannotHaveSelfContainedWithoutRuntimeIdentifier { + get { + return ResourceManager.GetString("CannotHaveSelfContainedWithoutRuntimeIdentifier", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cannot infer TargetFrameworkIdentifier and/or TargetFrameworkVersion from TargetFramework='{0}'. They must be specified explicitly.. /// @@ -205,13 +215,14 @@ internal static string DOTNET1017 { } /// - /// Looks up a localized string similar to Duplicate {0} items were included. The .NET SDK includes {0} items from your project directory by default. You can either remove these items from your project file, or set the '{1}' property to '{2}' if you want to explicitly include them in your project file. The duplicate items were: {3}. + /// Looks up a localized string similar to Duplicate '{0}' items were included. The .NET SDK includes '{0}' items from your project directory by default. You can either remove these items from your project file, or set the '{1}' property to '{2}' if you want to explicitly include them in your project file. For more information, see {4}. The duplicate items were: {3}. /// internal static string DuplicateItemsError { get { return ResourceManager.GetString("DuplicateItemsError", resourceCulture); } } + /// /// Looks up a localized string similar to The preprocessor token '{0}' has been given more than one value. Choosing '{1}' as the value.. /// @@ -229,7 +240,7 @@ internal static string ErrorsOccurredWhenEmittingSatelliteAssembly { return ResourceManager.GetString("ErrorsOccurredWhenEmittingSatelliteAssembly", resourceCulture); } } - + /// /// Looks up a localized string similar to Given file name '{0}' is longer than 1024 bytes. /// @@ -247,16 +258,16 @@ internal static string FolderAlreadyExists { return ResourceManager.GetString("FolderAlreadyExists", resourceCulture); } } - + /// - /// Looks up a localized string similar to The filter profile '{0}' provided is of not the correct format. + /// Looks up a localized string similar to The filter profile {0} provided is of not the correct format. /// internal static string IncorrectFilterFormat { get { return ResourceManager.GetString("IncorrectFilterFormat", resourceCulture); } } - + /// /// Looks up a localized string similar to Package Root {0} was incorrectly given for Resolved library {1}. /// @@ -303,7 +314,7 @@ internal static string MultipleFilesResolved { } /// - /// Looks up a localized string similar to Project '{0}' has no target framework compatible with '{1}'.. + /// Looks up a localized string similar to Project '{0}' targets '{2}'. It cannot be referenced by a project that targets '{1}'.. /// internal static string NoCompatibleTargetFramework { get { @@ -392,17 +403,15 @@ internal static string NU1012 { } } - /// + /// /// Looks up a localized string similar to Package Name='{0}', Version='{1}' was parsed. /// - internal static string PackageInfoLog - { - get - { + internal static string PackageInfoLog { + get { return ResourceManager.GetString("PackageInfoLog", resourceCulture); } } - + /// /// Looks up a localized string similar to A PackageReference for '{0}' was included in your project. This package is implicitly referenced by the .NET SDK and you do not typically need to reference it from your project. For more information, see {1}. /// @@ -412,17 +421,15 @@ internal static string PackageReferenceOverrideWarning { } } - /// + /// /// Looks up a localized string similar to Parsing the Files : '{0}'. /// - internal static string ParsingFiles - { - get - { + internal static string ParsingFiles { + get { return ResourceManager.GetString("ParsingFiles", resourceCulture); } } - + /// /// Looks up a localized string similar to Assets are consumed from project '{0}', but no corresponding MSBuild project path was found in '{1}'.. /// @@ -431,9 +438,9 @@ internal static string ProjectAssetsConsumedWithoutMSBuildProjectPath { return ResourceManager.GetString("ProjectAssetsConsumedWithoutMSBuildProjectPath", resourceCulture); } } - + /// - /// Looks up a localized string similar to RuntimeIdentifier must be set for .NETFramework executables. Consider RuntimeIdentifier=win7-x86 or RuntimeIdentifier=win7-x64.. + /// Looks up a localized string similar to Specify a RuntimeIdentifier. /// internal static string RuntimeIdentifierWasNotSpecified { get { diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.resx b/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.resx index ae8a30105594..d5cdc7d6beb4 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.resx +++ b/src/Tasks/Microsoft.NET.Build.Tasks/Resources/Strings.resx @@ -255,4 +255,7 @@ Given file name '{0}' is longer than 1024 bytes + + It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier. Please either specify a RuntimeIdentifier or set SelfContained to false. + \ No newline at end of file diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Publish.targets b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Publish.targets index de52d1ea2932..1273d6b698d7 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Publish.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Publish.targets @@ -25,7 +25,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_GetChildProjectCopyToPublishDirectoryItems Condition="'$(_GetChildProjectCopyToPublishDirectoryItems)' == ''">true - true + true @@ -238,7 +238,8 @@ Copyright (c) .NET Foundation. All rights reserved. PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" PrivateAssetsPackageReferences="@(PrivateAssetsPackageReference)" FilterProjectFiles="@(FilterProjectFileList)" - PreserveCacheLayout="$(PreserveCacheLayout)"> + PreserveCacheLayout="$(PreserveCacheLayout)" + IsSelfContained="$(SelfContained)" > @@ -462,7 +463,8 @@ Copyright (c) .NET Foundation. All rights reserved. RuntimeIdentifier="$(RuntimeIdentifier)" PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" CompilerOptions="@(DependencyFileCompilerOptions)" - PrivateAssetsPackageReferences="@(PrivateAssetsPackageReference)" /> + PrivateAssetsPackageReferences="@(PrivateAssetsPackageReference)" + IsSelfContained="$(SelfContained)" /> @@ -512,7 +514,8 @@ Copyright (c) .NET Foundation. All rights reserved. RuntimeIdentifier="$(RuntimeIdentifier)" PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" UserRuntimeConfig="$(UserRuntimeConfig)" - HostConfigurationOptions="@(RuntimeHostConfigurationOption)" /> + HostConfigurationOptions="@(RuntimeHostConfigurationOption)" + IsSelfContained="$(SelfContained)" /> diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.RuntimeIdentifierInference.targets b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.RuntimeIdentifierInference.targets index b29b3efbe787..754cf2600de1 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.RuntimeIdentifierInference.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.RuntimeIdentifierInference.targets @@ -99,6 +99,21 @@ Copyright (c) .NET Foundation. All rights reserved. + + + false + true + + + + + + true diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Sdk.targets b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Sdk.targets index aeab5b87e22f..170ebe25fac1 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Sdk.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/build/Microsoft.NET.Sdk.targets @@ -102,7 +102,8 @@ Copyright (c) .NET Foundation. All rights reserved. ReferenceSatellitePaths="@(ReferenceSatellitePaths)" RuntimeIdentifier="$(RuntimeIdentifier)" PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" - CompilerOptions="@(DependencyFileCompilerOptions)"> + CompilerOptions="@(DependencyFileCompilerOptions)" + IsSelfContained="$(SelfContained)"> @@ -135,7 +136,8 @@ Copyright (c) .NET Foundation. All rights reserved. RuntimeIdentifier="$(RuntimeIdentifier)" PlatformLibraryName="$(MicrosoftNETPlatformLibrary)" UserRuntimeConfig="$(UserRuntimeConfig)" - HostConfigurationOptions="@(RuntimeHostConfigurationOption)"> + HostConfigurationOptions="@(RuntimeHostConfigurationOption)" + IsSelfContained="$(SelfContained)"> @@ -207,7 +209,7 @@ Copyright (c) .NET Foundation. All rights reserved. it requires a host in the output directory to load the app. During "publish", all required assets are copied to the publish directory. --> - + <_NETCoreNativeFileItems Include="@(_ActiveTFMFileDependencies->WithMetadataValue('FileGroup', 'NativeLibrary'))" /> <__NETCoreNativeItems Include="@(FileDefinitions)" Exclude="@(_NETCoreNativeFileItems)" /> <_NETCoreNativeItems Include="@(FileDefinitions)" Exclude="@(__NETCoreNativeItems)" /> @@ -252,7 +254,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + PreserveNewest Never @@ -286,7 +288,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + dotnet @@ -295,7 +297,7 @@ Copyright (c) .NET Foundation. All rights reserved. $(_NetCoreRunArguments) - + $(TargetDir)$(AssemblyName)$(_NativeExecutableExtension) $(StartArguments) diff --git a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs index d74c9d000a02..1139eba31c03 100644 --- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs +++ b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedApp.cs @@ -3,14 +3,11 @@ using FluentAssertions; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.PlatformAbstractions; using Microsoft.NET.TestFramework; -using Microsoft.NET.TestFramework.Commands; using Microsoft.NET.TestFramework.Assertions; -using System; +using Microsoft.NET.TestFramework.Commands; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Xml.Linq; using Xunit; using static Microsoft.NET.TestFramework.Commands.MSBuildTest; @@ -47,8 +44,6 @@ public void It_builds_a_runnable_output() string selfContainedExecutableFullPath = Path.Combine(outputDirectory.FullName, selfContainedExecutable); - var libPrefix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "" : "lib"; - outputDirectory.Should().OnlyHaveFiles(new[] { selfContainedExecutable, "HelloWorld.dll", @@ -56,8 +51,8 @@ public void It_builds_a_runnable_output() "HelloWorld.deps.json", "HelloWorld.runtimeconfig.dev.json", "HelloWorld.runtimeconfig.json", - $"{libPrefix}hostfxr{Constants.DynamicLibSuffix}", - $"{libPrefix}hostpolicy{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}", }); Command.Create(selfContainedExecutableFullPath, new string[] { }) diff --git a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedAppWithRid.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedAppWithRid.cs deleted file mode 100644 index 11dbdafd1770..000000000000 --- a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildASelfContainedAppWithRid.cs +++ /dev/null @@ -1,65 +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 FluentAssertions; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.PlatformAbstractions; -using Microsoft.NET.TestFramework; -using Microsoft.NET.TestFramework.Commands; -using Microsoft.NET.TestFramework.Assertions; -using System.IO; -using Xunit; -using static Microsoft.NET.TestFramework.Commands.MSBuildTest; -using System.Runtime.InteropServices; - -namespace Microsoft.NET.Build.Tests -{ - public class GivenThatWeWantToBuildASelfContainedAppWithLibrariesAndRid : SdkTest - { - [Fact] - public void It_builds_a_RID_specific_runnable_output() - { - if (UsingFullFrameworkMSBuild) - { - // Disable this test on full framework, as the current build won't have access to - // https://github.com/Microsoft/msbuild/pull/1674 - // See https://github.com/dotnet/sdk/issues/877 - return; - } - - var runtimeIdentifier = RuntimeEnvironment.GetRuntimeIdentifier(); - var testAsset = _testAssetsManager - .CopyTestAsset("AppWithLibraryAndRid") - .WithSource(); - - var projectPath = Path.Combine(testAsset.TestRoot, "App"); - - var restoreCommand = new RestoreCommand(Stage0MSBuild, projectPath, "App.csproj"); - restoreCommand - .Execute($"/p:TestRuntimeIdentifier={runtimeIdentifier}") - .Should() - .Pass(); - - var buildCommand = new BuildCommand(Stage0MSBuild, projectPath); - - buildCommand - .Execute($"/p:RuntimeIdentifier={runtimeIdentifier}", $"/p:TestRuntimeIdentifier={runtimeIdentifier}") - .Should() - .Pass(); - - var outputDirectory = buildCommand.GetOutputDirectory("netcoreapp1.1", runtimeIdentifier: runtimeIdentifier); - var selfContainedExecutable = $"App{Constants.ExeSuffix}"; - - string selfContainedExecutableFullPath = Path.Combine(outputDirectory.FullName, selfContainedExecutable); - - Command.Create(selfContainedExecutableFullPath, new string[] { }) - .EnsureExecutable() - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining($"3.13.0 '{runtimeIdentifier}' 3.13.0 '{runtimeIdentifier}' Hello World"); - } - } -} diff --git a/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAnAppWithLibrariesAndRid.cs b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAnAppWithLibrariesAndRid.cs new file mode 100644 index 000000000000..4b3858e3f981 --- /dev/null +++ b/test/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAnAppWithLibrariesAndRid.cs @@ -0,0 +1,118 @@ +// 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 FluentAssertions; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.PlatformAbstractions; +using Microsoft.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using System.IO; +using Xunit; +using static Microsoft.NET.TestFramework.Commands.MSBuildTest; + +namespace Microsoft.NET.Build.Tests +{ + public class GivenThatWeWantToBuildAnAppWithLibrariesAndRid : SdkTest + { + [Fact] + public void It_builds_a_RID_specific_runnable_output() + { + if (UsingFullFrameworkMSBuild) + { + // Disable this test on full framework, as the current build won't have access to + // https://github.com/Microsoft/msbuild/pull/1674 + // See https://github.com/dotnet/sdk/issues/877 + return; + } + + var runtimeIdentifier = RuntimeEnvironment.GetRuntimeIdentifier(); + var testAsset = _testAssetsManager + .CopyTestAsset("AppWithLibraryAndRid") + .WithSource(); + + var projectPath = Path.Combine(testAsset.TestRoot, "App"); + + var restoreCommand = new RestoreCommand(Stage0MSBuild, projectPath, "App.csproj"); + restoreCommand + .Execute($"/p:TestRuntimeIdentifier={runtimeIdentifier}") + .Should() + .Pass(); + + var buildCommand = new BuildCommand(Stage0MSBuild, projectPath); + + buildCommand + .Execute($"/p:RuntimeIdentifier={runtimeIdentifier}", $"/p:TestRuntimeIdentifier={runtimeIdentifier}") + .Should() + .Pass(); + + var outputDirectory = buildCommand.GetOutputDirectory("netcoreapp1.1", runtimeIdentifier: runtimeIdentifier); + var selfContainedExecutable = $"App{Constants.ExeSuffix}"; + + string selfContainedExecutableFullPath = Path.Combine(outputDirectory.FullName, selfContainedExecutable); + + Command.Create(selfContainedExecutableFullPath, new string[] { }) + .EnsureExecutable() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining($"3.13.0 '{runtimeIdentifier}' 3.13.0 '{runtimeIdentifier}' Hello World"); + } + + [Fact] + public void It_builds_a_framework_dependent_RID_specific_runnable_output() + { + if (UsingFullFrameworkMSBuild) + { + // Disable this test on full framework, as the current build won't have access to + // https://github.com/Microsoft/msbuild/pull/1674 + // See https://github.com/dotnet/sdk/issues/877 + return; + } + + var runtimeIdentifier = RuntimeEnvironment.GetRuntimeIdentifier(); + var testAsset = _testAssetsManager + .CopyTestAsset("AppWithLibraryAndRid", "BuildFrameworkDependentRIDSpecific") + .WithSource(); + + var projectPath = Path.Combine(testAsset.TestRoot, "App"); + + var restoreCommand = new RestoreCommand(Stage0MSBuild, projectPath, "App.csproj"); + restoreCommand + .Execute($"/p:TestRuntimeIdentifier={runtimeIdentifier}") + .Should() + .Pass(); + + var buildCommand = new BuildCommand(Stage0MSBuild, projectPath); + + buildCommand + .Execute($"/p:RuntimeIdentifier={runtimeIdentifier}", $"/p:TestRuntimeIdentifier={runtimeIdentifier}", "/p:SelfContained=false") + .Should().Pass(); + + var outputDirectory = buildCommand.GetOutputDirectory("netcoreapp1.1", runtimeIdentifier: runtimeIdentifier); + + outputDirectory.Should().NotHaveSubDirectories(); + outputDirectory.Should().OnlyHaveFiles(new[] { + "App.dll", + "App.pdb", + "App.deps.json", + "App.runtimeconfig.json", + "App.runtimeconfig.dev.json", + "LibraryWithoutRid.dll", + "LibraryWithoutRid.pdb", + "LibraryWithRid.dll", + "LibraryWithRid.pdb", + "LibraryWithRids.dll", + "LibraryWithRids.pdb", + }); + + Command.Create(RepoInfo.DotNetHostPath, new[] { Path.Combine(outputDirectory.FullName, "App.dll") }) + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining($"3.13.0 '{runtimeIdentifier}' 3.13.0 '{runtimeIdentifier}' Hello World"); + } + } +} diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToCacheAProjectWithDependencies.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToCacheAProjectWithDependencies.cs index c28808648982..1eea35466046 100644 --- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToCacheAProjectWithDependencies.cs +++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToCacheAProjectWithDependencies.cs @@ -22,7 +22,7 @@ namespace Microsoft.NET.Publish.Tests { public class GivenThatWeWantToCacheAProjectWithDependencies : SdkTest { - private static string _libPrefix; + private static readonly string _libPrefix = FileConstants.DynamicLibPrefix; private static string _runtimeOs; private static string _runtimeLibOs; private static string _runtimeRid; @@ -34,7 +34,6 @@ static GivenThatWeWantToCacheAProjectWithDependencies() var rid = RuntimeEnvironment.GetRuntimeIdentifier(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - _libPrefix = ""; _runtimeOs = "win7"; _runtimeLibOs = "win"; _testArch = rid.Substring(rid.LastIndexOf("-") + 1); @@ -42,7 +41,6 @@ static GivenThatWeWantToCacheAProjectWithDependencies() } else { - _libPrefix = "lib"; _runtimeOs = "unix"; _runtimeLibOs = "unix"; diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs index e2be55b1496f..7e410dec6b22 100644 --- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs +++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs @@ -70,17 +70,15 @@ public void It_publishes_self_contained_apps_to_the_publish_folder_and_the_app_s string selfContainedExecutableFullPath = Path.Combine(publishDirectory.FullName, selfContainedExecutable); - var libPrefix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "" : "lib"; - publishDirectory.Should().HaveFiles(new[] { selfContainedExecutable, "HelloWorld.dll", "HelloWorld.pdb", "HelloWorld.deps.json", "HelloWorld.runtimeconfig.json", - $"{libPrefix}coreclr{Constants.DynamicLibSuffix}", - $"{libPrefix}hostfxr{Constants.DynamicLibSuffix}", - $"{libPrefix}hostpolicy{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}coreclr{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}", $"mscorlib.dll", $"System.Private.CoreLib.dll", }); @@ -140,17 +138,15 @@ public static void Main() string selfContainedExecutableFullPath = Path.Combine(publishDirectory.FullName, selfContainedExecutable); - var libPrefix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "" : "lib"; - publishDirectory.Should().HaveFiles(new[] { selfContainedExecutable, "Hello.dll", "Hello.pdb", "Hello.deps.json", "Hello.runtimeconfig.json", - $"{libPrefix}coreclr{Constants.DynamicLibSuffix}", - $"{libPrefix}hostfxr{Constants.DynamicLibSuffix}", - $"{libPrefix}hostpolicy{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}coreclr{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}", + $"{FileConstants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}", $"mscorlib.dll", $"System.Private.CoreLib.dll", }); diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAProjectWithDependencies.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAProjectWithDependencies.cs index 7ab9289aa0a1..075354bf9db8 100644 --- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAProjectWithDependencies.cs +++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAProjectWithDependencies.cs @@ -173,19 +173,13 @@ public void It_publishes_projects_with_filter_and_rid() DirectoryInfo publishDirectory = publishCommand.GetOutputDirectory(runtimeIdentifier: rid); - string libPrefix = ""; - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - libPrefix = "lib"; - } - publishDirectory.Should().HaveFiles(new[] { $"{project}.dll", $"{project}.pdb", $"{project}.deps.json", $"{project}.runtimeconfig.json", "System.Collections.NonGeneric.dll", - $"{libPrefix}coreclr{Constants.DynamicLibSuffix}" + $"{FileConstants.DynamicLibPrefix}coreclr{Constants.DynamicLibSuffix}" }); publishDirectory.Should().NotHaveFiles(new[] { diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAppWithLibrariesAndRid.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAppWithLibrariesAndRid.cs new file mode 100644 index 000000000000..42aae2aa2d6f --- /dev/null +++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAppWithLibrariesAndRid.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 FluentAssertions; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.PlatformAbstractions; +using Microsoft.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using System.IO; +using Xunit; +using static Microsoft.NET.TestFramework.Commands.MSBuildTest; + +namespace Microsoft.NET.Publish.Tests +{ + public class GivenThatWeWantToPublishAnAppWithLibrariesAndRid : SdkTest + { + [Fact] + public void It_publishes_a_framework_dependent_RID_specific_runnable_output() + { + if (UsingFullFrameworkMSBuild) + { + // Disable this test on full framework, as the current build won't have access to + // https://github.com/Microsoft/msbuild/pull/1674 + // See https://github.com/dotnet/sdk/issues/877 + return; + } + + var runtimeIdentifier = RuntimeEnvironment.GetRuntimeIdentifier(); + var testAsset = _testAssetsManager + .CopyTestAsset("AppWithLibraryAndRid", "PublishFrameworkDependentRIDSpecific") + .WithSource(); + + var projectPath = Path.Combine(testAsset.TestRoot, "App"); + + var restoreCommand = new RestoreCommand(Stage0MSBuild, projectPath, "App.csproj"); + restoreCommand + .Execute($"/p:TestRuntimeIdentifier={runtimeIdentifier}") + .Should() + .Pass(); + + var publishCommand = new PublishCommand(Stage0MSBuild, projectPath); + + publishCommand + .Execute($"/p:RuntimeIdentifier={runtimeIdentifier}", $"/p:TestRuntimeIdentifier={runtimeIdentifier}", "/p:SelfContained=false") + .Should().Pass(); + + var publishDirectory = publishCommand.GetOutputDirectory("netcoreapp1.1", runtimeIdentifier: runtimeIdentifier); + + publishDirectory.Should().NotHaveSubDirectories(); + publishDirectory.Should().OnlyHaveFiles(new[] { + "App.dll", + "App.pdb", + "App.deps.json", + "App.runtimeconfig.json", + "LibraryWithoutRid.dll", + "LibraryWithoutRid.pdb", + "LibraryWithRid.dll", + "LibraryWithRid.pdb", + "LibraryWithRids.dll", + "LibraryWithRids.pdb", + $"{FileConstants.DynamicLibPrefix}sqlite3{Constants.DynamicLibSuffix}", + }); + + Command.Create(RepoInfo.DotNetHostPath, new[] { Path.Combine(publishDirectory.FullName, "App.dll") }) + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining($"3.13.0 '{runtimeIdentifier}' 3.13.0 '{runtimeIdentifier}' Hello World"); + } + } +} diff --git a/test/Microsoft.NET.TestFramework/Assertions/DirectoryInfoAssertions.cs b/test/Microsoft.NET.TestFramework/Assertions/DirectoryInfoAssertions.cs index 2dc640aa4309..dae8ea4b1eb2 100644 --- a/test/Microsoft.NET.TestFramework/Assertions/DirectoryInfoAssertions.cs +++ b/test/Microsoft.NET.TestFramework/Assertions/DirectoryInfoAssertions.cs @@ -93,5 +93,15 @@ public AndConstraint OnlyHaveFiles(IEnumerable return new AndConstraint(this); } + + public AndConstraint NotHaveSubDirectories() + { + var subDirectories = _dirInfo.EnumerateDirectories(); + + Execute.Assertion.ForCondition(!subDirectories.Any()) + .FailWith("Directory {0} should not have any sub directories.", _dirInfo.FullName); + + return new AndConstraint(this); + } } } diff --git a/test/Microsoft.NET.TestFramework/FileConstants.cs b/test/Microsoft.NET.TestFramework/FileConstants.cs new file mode 100644 index 000000000000..c50aa9fa8b7c --- /dev/null +++ b/test/Microsoft.NET.TestFramework/FileConstants.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.Runtime.InteropServices; + +namespace Microsoft.NET.TestFramework +{ + public static class FileConstants + { + public static readonly string DynamicLibPrefix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "" : "lib"; + } +}