From f0c2cb2c1806b8c699352d0a15fbdf45672dbf07 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Thu, 17 Mar 2016 11:45:13 -0700 Subject: [PATCH] product changes to support portable tools --- .../IPackagedCommandSpecFactory.cs | 6 +- .../PackagedCommandSpecFactory.cs | 61 +++++++-- .../ProjectToolsCommandResolver.cs | 122 +++++++++++++++--- .../CommandResolution/ToolPathCalculator.cs | 70 ++++++++++ src/Microsoft.DotNet.Cli.Utils/Muxer.cs | 34 +++++ .../RuntimeConfigGenerator.cs | 53 ++++++++ src/Microsoft.DotNet.Cli.Utils/project.json | 6 +- .../Executable.cs | 26 +--- .../ProjectContext.cs | 2 +- .../ProjectContextBuilder.cs | 26 ++-- .../commands/dotnet-build/CompileContext.cs | 32 +++-- .../commands/dotnet-compile/CompilerUtil.cs | 2 +- .../commands/dotnet-pack/PackageGenerator.cs | 1 + 13 files changed, 363 insertions(+), 78 deletions(-) create mode 100644 src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/Muxer.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs index 34c14e56c..c285654da 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; namespace Microsoft.DotNet.Cli.Utils { @@ -15,7 +17,9 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath); + string depsFilePath, + LibraryExporter exporter = null, + bool generateRuntimeConfig = false); } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index 8129fa2e5..9302d05d0 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Runtime.InteropServices; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.Extensions.PlatformAbstractions; using NuGet.Frameworks; using NuGet.Packaging; @@ -20,7 +21,9 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable allowedExtensions, string nugetPackagesRoot, CommandResolutionStrategy commandResolutionStrategy, - string depsFilePath) + string depsFilePath, + LibraryExporter exporter = null, + bool generateRuntimeConfig = false) { var packageDirectory = GetPackageDirectoryFullPath(library, nugetPackagesRoot); @@ -38,11 +41,15 @@ namespace Microsoft.DotNet.Cli.Utils var commandPath = Path.Combine(packageDirectory, commandFile); + var isPortable = DetermineIfPortableApp(commandPath); + return CreateCommandSpecWrappingWithCorehostfDll( commandPath, commandArguments, depsFilePath, - commandResolutionStrategy); + commandResolutionStrategy, + nugetPackagesRoot, + isPortable); } private string GetPackageDirectoryFullPath(LockFilePackageLibrary library, string nugetPackagesRoot) @@ -69,7 +76,9 @@ namespace Microsoft.DotNet.Cli.Utils string commandPath, IEnumerable commandArguments, string depsFilePath, - CommandResolutionStrategy commandResolutionStrategy) + CommandResolutionStrategy commandResolutionStrategy, + string nugetPackagesRoot, + bool isPortable) { var commandExtension = Path.GetExtension(commandPath); @@ -79,7 +88,9 @@ namespace Microsoft.DotNet.Cli.Utils commandPath, commandArguments, depsFilePath, - commandResolutionStrategy); + commandResolutionStrategy, + nugetPackagesRoot, + isPortable); } return CreateCommandSpec(commandPath, commandArguments, commandResolutionStrategy); @@ -89,11 +100,30 @@ namespace Microsoft.DotNet.Cli.Utils string commandPath, IEnumerable commandArguments, string depsFilePath, - CommandResolutionStrategy commandResolutionStrategy) + CommandResolutionStrategy commandResolutionStrategy, + string nugetPackagesRoot, + bool isPortable) { - var corehost = CoreHost.HostExePath; - + string host = string.Empty; var arguments = new List(); + + if (isPortable) + { + var muxer = new Muxer(); + + host = muxer.MuxerPath; + if (host == null) + { + throw new Exception("Unable to locate dotnet multiplexer"); + } + + arguments.Add("exec"); + } + else + { + host = CoreHost.LocalHostExePath; + } + arguments.Add(commandPath); if (depsFilePath != null) @@ -102,9 +132,12 @@ namespace Microsoft.DotNet.Cli.Utils arguments.Add(depsFilePath); } + arguments.Add("--additionalprobingpath"); + arguments.Add(nugetPackagesRoot); + arguments.AddRange(commandArguments); - return CreateCommandSpec(corehost, arguments, commandResolutionStrategy); + return CreateCommandSpec(host, arguments, commandResolutionStrategy); } private CommandSpec CreateCommandSpec( @@ -115,6 +148,16 @@ namespace Microsoft.DotNet.Cli.Utils var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(commandArguments); return new CommandSpec(commandPath, escapedArgs, commandResolutionStrategy); - } + } + + private bool DetermineIfPortableApp(string commandPath) + { + var commandDir = Path.GetDirectoryName(commandPath); + + var runtimeConfig = Directory.EnumerateFiles(commandDir) + .FirstOrDefault(x => x.EndsWith("runtimeconfig.json")); + + return runtimeConfig != null; + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs index 906d660e9..e49c4192e 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs @@ -5,18 +5,28 @@ using System.Linq; using System.Runtime.InteropServices; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.PlatformAbstractions; using NuGet.Frameworks; using NuGet.Packaging; +using NuGet.ProjectModel; + +using LockFile = Microsoft.DotNet.ProjectModel.Graph.LockFile; +using FileFormatException = Microsoft.DotNet.ProjectModel.FileFormatException; namespace Microsoft.DotNet.Cli.Utils { public class ProjectToolsCommandResolver : ICommandResolver { private static readonly NuGetFramework s_toolPackageFramework = FrameworkConstants.CommonFrameworks.NetStandardApp15; + private static readonly CommandResolutionStrategy s_commandResolutionStrategy = CommandResolutionStrategy.ProjectToolsPackage; + private static readonly string s_currentRuntimeIdentifier = PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier(); + + private List _allowedCommandExtensions; private IPackagedCommandSpecFactory _packagedCommandSpecFactory; @@ -90,23 +100,21 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable args, ProjectContext projectContext) { - //todo: change this for new resolution strategy - var lockFilePath = Path.Combine( - projectContext.ProjectDirectory, - "artifacts", "Tools", toolLibrary.Name, - "project.lock.json"); - - if (!File.Exists(lockFilePath)) - { - return null; - } - - var lockFile = LockFileReader.Read(lockFilePath); - - var lockFilePackageLibrary = lockFile.PackageLibraries.FirstOrDefault(l => l.Name == toolLibrary.Name); - var nugetPackagesRoot = projectContext.PackagesDirectory; + var lockFile = GetToolLockFile(toolLibrary, nugetPackagesRoot); + var lockFilePackageLibrary = lockFile.PackageLibraries.FirstOrDefault(l => l.Name == toolLibrary.Name); + + var depsFileRoot = Path.GetDirectoryName(lockFile.LockFilePath); + var depsFilePath = GetToolDepsFilePath(toolLibrary, lockFile, depsFileRoot); + + var toolProjectContext = new ProjectContextBuilder() + .WithLockFile(lockFile) + .WithTargetFramework(s_toolPackageFramework.ToString()) + .Build(); + + var exporter = toolProjectContext.CreateExporter(Constants.DefaultConfiguration); + return _packagedCommandSpecFactory.CreateCommandSpecFromLibrary( lockFilePackageLibrary, commandName, @@ -114,7 +122,44 @@ namespace Microsoft.DotNet.Cli.Utils _allowedCommandExtensions, projectContext.PackagesDirectory, s_commandResolutionStrategy, - null); + depsFilePath); + } + + private LockFile GetToolLockFile( + LibraryRange toolLibrary, + string nugetPackagesRoot) + { + var lockFilePath = GetToolLockFilePath(toolLibrary, nugetPackagesRoot); + + if (!File.Exists(lockFilePath)) + { + return null; + } + + LockFile lockFile = null; + + try + { + lockFile = LockFileReader.Read(lockFilePath); + } + catch (FileFormatException ex) + { + throw ex; + } + + return lockFile; + } + + private string GetToolLockFilePath( + LibraryRange toolLibrary, + string nugetPackagesRoot) + { + var toolPathCalculator = new ToolPathCalculator(nugetPackagesRoot); + + return toolPathCalculator.GetBestLockFilePath( + toolLibrary.Name, + toolLibrary.VersionRange, + s_toolPackageFramework); } private ProjectContext GetProjectContextFromDirectory(string directory, NuGetFramework framework) @@ -143,5 +188,50 @@ namespace Microsoft.DotNet.Cli.Utils return projectContext; } + + private string GetToolDepsFilePath( + LibraryRange toolLibrary, + LockFile toolLockFile, + string depsPathRoot) + { + var depsJsonPath = Path.Combine( + depsPathRoot, + toolLibrary.Name + FileNameSuffixes.DepsJson); + + EnsureToolJsonDepsFileExists(toolLibrary, toolLockFile, depsJsonPath); + + return depsJsonPath; + } + + private void EnsureToolJsonDepsFileExists( + LibraryRange toolLibrary, + LockFile toolLockFile, + string depsPath) + { + if (!File.Exists(depsPath)) + { + var projectContext = new ProjectContextBuilder() + .WithLockFile(toolLockFile) + .WithTargetFramework(s_toolPackageFramework.ToString()) + .Build(); + + var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration); + + var dependencyContext = new DependencyContextBuilder() + .Build(null, + null, + exporter.GetAllExports(), + true, + s_toolPackageFramework, + string.Empty); + + using (var fileStream = File.Create(depsPath)) + { + var dependencyContextWriter = new DependencyContextWriter(); + + dependencyContextWriter.Write(dependencyContext, fileStream); + } + } + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs new file mode 100644 index 000000000..5dd24c0c5 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ToolPathCalculator.cs @@ -0,0 +1,70 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Collections.Generic; +using NuGet.Frameworks; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class ToolPathCalculator + { + private readonly string _packagesDirectory; + + public ToolPathCalculator(string packagesDirectory) + { + _packagesDirectory = packagesDirectory; + } + + public string GetBestLockFilePath(string packageId, VersionRange versionRange, NuGetFramework framework) + { + var availableToolVersions = GetAvailableToolVersions(packageId); + + var bestVersion = versionRange.FindBestMatch(availableToolVersions); + + return GetLockFilePath(packageId, bestVersion, framework); + } + + public string GetLockFilePath(string packageId, NuGetVersion version, NuGetFramework framework) + { + return Path.Combine( + GetBaseToolPath(packageId), + version.ToNormalizedString(), + framework.GetShortFolderName(), + "project.lock.json"); + } + + private string GetBaseToolPath(string packageId) + { + return Path.Combine( + _packagesDirectory, + ".tools", + packageId); + } + + private IEnumerable GetAvailableToolVersions(string packageId) + { + var availableVersions = new List(); + + var toolBase = GetBaseToolPath(packageId); + var versionDirectories = Directory.EnumerateDirectories(toolBase); + + foreach (var versionDirectory in versionDirectories) + { + var version = Path.GetFileName(versionDirectory); + + NuGetVersion nugetVersion = null; + NuGetVersion.TryParse(version, out nugetVersion); + + if (nugetVersion != null) + { + availableVersions.Add(nugetVersion); + } + } + + return availableVersions; + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/Muxer.cs b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs new file mode 100644 index 000000000..516e0fdd8 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/Muxer.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class Muxer + { + private static readonly string s_muxerFileName = "dotnet" + Constants.ExeSuffix; + + private string _muxerPath; + + public string MuxerPath + { + get + { + return _muxerPath; + } + } + + public Muxer() + { + var appBase = new DirectoryInfo(PlatformServices.Default.Application.ApplicationBasePath); + var muxerDir = appBase.Parent.Parent; + + var muxerCandidate = Path.Combine(muxerDir.FullName, s_muxerFileName); + + if (File.Exists(muxerCandidate)) + { + _muxerPath = muxerCandidate; + } + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs b/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs new file mode 100644 index 000000000..92ba1728d --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/RuntimeConfigGenerator.cs @@ -0,0 +1,53 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.Extensions.DependencyModel; +using NuGet.Frameworks; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; + +namespace Microsoft.DotNet.Cli.Utils +{ + public static class RuntimeConfigGenerator + { + // GROOOOOSS + private static readonly string RedistPackageName = "Microsoft.NETCore.App"; + + public static void WriteRuntimeConfigToFile(LibraryExporter exporter, string runtimeConfigJsonFile) + { + // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated + // in order to prevent breaking incremental compilation... + + var json = new JObject(); + var runtimeOptions = new JObject(); + json.Add("runtimeOptions", runtimeOptions); + + var redistExport = exporter + .GetAllExports() + .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); + if (redistExport != null) + { + var framework = new JObject( + new JProperty("name", redistExport.Library.Identity.Name), + new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); + runtimeOptions.Add("framework", framework); + } + + using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) + { + writer.Formatting = Formatting.Indented; + json.WriteTo(writer); + } + + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json index 3e97e0621..e6cdae2f9 100644 --- a/src/Microsoft.DotNet.Cli.Utils/project.json +++ b/src/Microsoft.DotNet.Cli.Utils/project.json @@ -6,7 +6,11 @@ }, "dependencies": { "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537" + "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537", + "NuGet.Versioning": "3.4.0-rtm-0763", + "NuGet.Packaging": "3.4.0-rtm-0763", + "NuGet.Frameworks": "3.4.0-rtm-0763", + "NuGet.ProjectModel": "3.4.0-rtm-0763" }, "frameworks": { "net451": { diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs index 3fa63b148..431fc76fe 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs +++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs @@ -126,30 +126,9 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common { if (!_context.TargetFramework.IsDesktop()) { - // TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated - // in order to prevent breaking incremental compilation... - - var json = new JObject(); - var runtimeOptions = new JObject(); - json.Add("runtimeOptions", runtimeOptions); - - var redistExport = exporter - .GetAllExports() - .FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase)); - if (redistExport != null) - { - var framework = new JObject( - new JProperty("name", redistExport.Library.Identity.Name), - new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString())); - runtimeOptions.Add("framework", framework); - } - var runtimeConfigJsonFile = Path.Combine(_runtimeOutputPath, _context.ProjectFile.Name + FileNameSuffixes.RuntimeConfigJson); - using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile)))) - { - writer.Formatting = Formatting.Indented; - json.WriteTo(writer); - } + + RuntimeConfigGenerator.WriteRuntimeConfigToFile(exporter, runtimeConfigJsonFile); } } @@ -210,7 +189,6 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common } } - private static void CreateDirectoryIfNotExists(string path) { var depsFile = new FileInfo(path); diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index c82e3927f..b920e857c 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -22,7 +22,7 @@ namespace Microsoft.DotNet.ProjectModel public string RuntimeIdentifier { get; } - public Project ProjectFile => RootProject.Project; + public Project ProjectFile => RootProject?.Project; public LockFile LockFile { get; } diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs index 8d617df63..6e2d6b58f 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContextBuilder.cs @@ -140,7 +140,7 @@ namespace Microsoft.DotNet.ProjectModel { ProjectDirectory = Project?.ProjectDirectory ?? ProjectDirectory; - if (GlobalSettings == null) + if (GlobalSettings == null && ProjectDirectory != null) { RootDirectory = ProjectRootResolver.ResolveRootDirectory(ProjectDirectory); @@ -157,7 +157,6 @@ namespace Microsoft.DotNet.ProjectModel var frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath); LockFileLookup lockFileLookup = null; - EnsureProjectLoaded(); LockFile = LockFile ?? LockFileResolver(ProjectDirectory); @@ -167,7 +166,10 @@ namespace Microsoft.DotNet.ProjectModel if (LockFile != null) { - validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage); + if (Project != null) + { + validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage); + } lockFileLookup = new LockFileLookup(LockFile); } @@ -175,10 +177,14 @@ namespace Microsoft.DotNet.ProjectModel var libraries = new Dictionary(); var projectResolver = new ProjectDependencyProvider(ProjectResolver); - var mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null); + ProjectDescription mainProject = null; + if (Project != null) + { + mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null); - // Add the main project - libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject); + // Add the main project + libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject); + } LockFileTarget target = null; if (lockFileLookup != null) @@ -251,7 +257,7 @@ namespace Microsoft.DotNet.ProjectModel } // Create a library manager - var libraryManager = new LibraryManager(libraries.Values.ToList(), diagnostics, Project.ProjectFilePath); + var libraryManager = new LibraryManager(libraries.Values.ToList(), diagnostics, Project?.ProjectFilePath); return new ProjectContext( GlobalSettings, @@ -375,13 +381,9 @@ namespace Microsoft.DotNet.ProjectModel private void EnsureProjectLoaded() { - if (Project == null) + if (Project == null && ProjectDirectory != null) { Project = ProjectResolver(ProjectDirectory); - if (Project == null) - { - throw new InvalidOperationException($"Unable to resolve project from {ProjectDirectory}"); - } } } diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs index 4768f12e7..229c5af15 100644 --- a/src/dotnet/commands/dotnet-build/CompileContext.cs +++ b/src/dotnet/commands/dotnet-build/CompileContext.cs @@ -255,27 +255,33 @@ namespace Microsoft.DotNet.Tools.Build private void CollectCompilerNamePreconditions(ProjectContext project, IncrementalPreconditions preconditions) { - var projectCompiler = project.ProjectFile.CompilerName; - - if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) + if (project.ProjectFile != null) { - preconditions.AddUnknownCompilerPrecondition(project.ProjectName(), projectCompiler); + var projectCompiler = project.ProjectFile.CompilerName; + + if (!KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) + { + preconditions.AddUnknownCompilerPrecondition(project.ProjectName(), projectCompiler); + } } } private void CollectScriptPreconditions(ProjectContext project, IncrementalPreconditions preconditions) { - var preCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PreCompile); - var postCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PostCompile); - - if (preCompileScripts.Any()) + if (project.ProjectFile != null) { - preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PreCompile); - } + var preCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PreCompile); + var postCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PostCompile); - if (postCompileScripts.Any()) - { - preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PostCompile); + if (preCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PreCompile); + } + + if (postCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PostCompile); + } } } diff --git a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs index 739e46dfe..f258dc43c 100644 --- a/src/dotnet/commands/dotnet-compile/CompilerUtil.cs +++ b/src/dotnet/commands/dotnet-compile/CompilerUtil.cs @@ -122,7 +122,7 @@ namespace Microsoft.DotNet.Tools.Compiler //used in incremental precondition checks public static IEnumerable GetCommandsInvokedByCompile(ProjectContext project) { - return new List {project.ProjectFile.CompilerName, "compile"}; + return new List {project.ProjectFile?.CompilerName, "compile"}; } } } \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-pack/PackageGenerator.cs b/src/dotnet/commands/dotnet-pack/PackageGenerator.cs index 8995e2025..44a793b6f 100644 --- a/src/dotnet/commands/dotnet-pack/PackageGenerator.cs +++ b/src/dotnet/commands/dotnet-pack/PackageGenerator.cs @@ -94,6 +94,7 @@ namespace Microsoft.DotNet.Tools.Compiler TryAddOutputFile(context, inputFolder, outputName); TryAddOutputFile(context, inputFolder, $"{Project.Name}.xml"); + TryAddOutputFile(context, inputFolder, $"{Project.Name}.runtimeconfig.json"); } protected virtual bool GeneratePackage(string nupkg, List packDiagnostics)