Memory usage improvements in build (#2626)

* Use a WorkspaceContext in dotnet-build to cache project data across
multiple compilations in a single build action
* Dramatically reduce string and object duplication by introducing a
"Symbol Table" that shares instances of NuGetVersion, NuGetFramework,
VersionRange and string across multiple lock-file parses

Test Results:
* Testing was done by compiling Microsoft.AspNetCore.Mvc (and it's
dependencies) and taking memory snapshots after each compilation in
dotMemory
* We used to allocate ~3MB and deallocate ~2.5MB on EACH compilation in
a single build action. This has been reduced to ~120KB
allocated/deallocated
* After introducing WorkspaceContext, total memory usage spiked from 6MB
across the whole build action to about 13MB, introducing the symbol
table dropped it back to about 5-6MB.
This commit is contained in:
Andrew Stanton-Nurse 2016-04-22 15:01:56 -07:00
parent 80df3688b1
commit ef0ca39da1
42 changed files with 496 additions and 268 deletions

View file

@ -1,8 +1,5 @@
{ {
"version": "1.0.0-*", "version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": { "dependencies": {
"NETStandard.Library": "1.5.0-rc2-24022", "NETStandard.Library": "1.5.0-rc2-24022",
"System.Runtime.Analyzers": { "System.Runtime.Analyzers": {

View file

@ -1,3 +1,3 @@
{ {
"projects": [ "src", "test", "tools" ] "projects": [ "src", "test", "tools" ]
} }

View file

@ -280,7 +280,7 @@ namespace Microsoft.DotNet.Cli.Build
return rid; return rid;
} }
[Target] [Target(nameof(PrepareTargets.Init))]
public static BuildTargetResult CompileStage1(BuildTargetContext c) public static BuildTargetResult CompileStage1(BuildTargetContext c)
{ {
CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src")); CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src"));
@ -305,7 +305,7 @@ namespace Microsoft.DotNet.Cli.Build
return result; return result;
} }
[Target] [Target(nameof(PrepareTargets.Init))]
public static BuildTargetResult CompileStage2(BuildTargetContext c) public static BuildTargetResult CompileStage2(BuildTargetContext c)
{ {
var configuration = c.BuildContext.Get<string>("Configuration"); var configuration = c.BuildContext.Get<string>("Configuration");

View file

@ -7,6 +7,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.DotNet.Cli.Utils namespace Microsoft.DotNet.Cli.Utils
{ {
@ -51,17 +52,16 @@ namespace Microsoft.DotNet.Cli.Utils
// Reset the Reporters to the new Console Out and Error. // Reset the Reporters to the new Console Out and Error.
Reporter.Reset(); Reporter.Reset();
Thread threadOut = _stdOut.BeginRead(new StreamReader(outStream)); var taskOut = _stdOut.BeginRead(new StreamReader(outStream));
Thread threadErr = _stdErr.BeginRead(new StreamReader(errorStream)); var taskErr = _stdErr.BeginRead(new StreamReader(errorStream));
int exitCode = _builtInCommand(_commandArgs.ToArray()); int exitCode = _builtInCommand(_commandArgs.ToArray());
outStream.DoneWriting(); outStream.DoneWriting();
errorStream.DoneWriting(); errorStream.DoneWriting();
threadOut.Join(); Task.WaitAll(taskOut, taskErr);
threadErr.Join();
// fake out a ProcessStartInfo using the Muxer command name, since this is a built-in command // fake out a ProcessStartInfo using the Muxer command name, since this is a built-in command
ProcessStartInfo startInfo = new ProcessStartInfo(new Muxer().MuxerPath, $"{CommandName} {CommandArgs}"); ProcessStartInfo startInfo = new ProcessStartInfo(new Muxer().MuxerPath, $"{CommandName} {CommandArgs}");
return new CommandResult(startInfo, exitCode, null, null); return new CommandResult(startInfo, exitCode, null, null);

View file

@ -7,8 +7,9 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using NuGet.Frameworks; using System.Threading.Tasks;
using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Cli.Utils namespace Microsoft.DotNet.Cli.Utils
{ {
@ -131,12 +132,11 @@ namespace Microsoft.DotNet.Cli.Utils
Reporter.Verbose.WriteLine($"Process ID: {_process.Id}"); Reporter.Verbose.WriteLine($"Process ID: {_process.Id}");
var threadOut = _stdOut.BeginRead(_process.StandardOutput); var taskOut = _stdOut.BeginRead(_process.StandardOutput);
var threadErr = _stdErr.BeginRead(_process.StandardError); var taskErr = _stdErr.BeginRead(_process.StandardError);
_process.WaitForExit(); _process.WaitForExit();
threadOut.Join();
threadErr.Join(); Task.WaitAll(taskOut, taskErr);
var exitCode = _process.ExitCode; var exitCode = _process.ExitCode;

View file

@ -1,8 +1,11 @@
// 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;
using System.IO; using System.IO;
using System.Text;
using System.Threading;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.DotNet.Cli.Utils namespace Microsoft.DotNet.Cli.Utils
{ {
@ -17,7 +20,7 @@ namespace Microsoft.DotNet.Cli.Utils
public string CapturedOutput public string CapturedOutput
{ {
get get
{ {
return _capture?.GetStringBuilder()?.ToString(); return _capture?.GetStringBuilder()?.ToString();
} }
@ -43,18 +46,16 @@ namespace Microsoft.DotNet.Cli.Utils
return this; return this;
} }
public Thread BeginRead(TextReader reader) public Task BeginRead(TextReader reader)
{ {
var thread = new Thread(() => Read(reader)) { IsBackground = true }; return Task.Run(() => Read(reader));
thread.Start();
return thread;
} }
public void Read(TextReader reader) public void Read(TextReader reader)
{ {
var bufferSize = 1; var bufferSize = 1;
int readCharacterCount; int readCharacterCount;
char currentCharacter; char currentCharacter;
var buffer = new char[bufferSize]; var buffer = new char[bufferSize];
@ -93,7 +94,7 @@ namespace Microsoft.DotNet.Cli.Utils
} }
private void WriteLine(string str) private void WriteLine(string str)
{ {
if (_capture != null) if (_capture != null)
{ {
_capture.WriteLine(str); _capture.WriteLine(str);

View file

@ -13,10 +13,12 @@ namespace Microsoft.DotNet.ProjectModel.Graph
{ {
private readonly LockFile _lockFile; private readonly LockFile _lockFile;
private Dictionary<string, IList<LockFileTargetLibrary>> _msbuildTargetLibraries; private Dictionary<string, IList<LockFileTargetLibrary>> _msbuildTargetLibraries;
private readonly LockFileReader _reader;
public LockFilePatcher(LockFile lockFile) public LockFilePatcher(LockFile lockFile, LockFileReader reader)
{ {
_lockFile = lockFile; _lockFile = lockFile;
_reader = reader;
var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(MSBuildDependencyProvider.IsMSBuildProjectLibrary); var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(MSBuildDependencyProvider.IsMSBuildProjectLibrary);
_msbuildTargetLibraries = msbuildProjectLibraries.ToDictionary(GetProjectLibraryKey, l => GetTargetsForLibrary(_lockFile, l)); _msbuildTargetLibraries = msbuildProjectLibraries.ToDictionary(GetProjectLibraryKey, l => GetTargetsForLibrary(_lockFile, l));
@ -27,8 +29,8 @@ namespace Microsoft.DotNet.ProjectModel.Graph
var exportFilePath = GetExportFilePath(_lockFile.LockFilePath); var exportFilePath = GetExportFilePath(_lockFile.LockFilePath);
if (File.Exists(exportFilePath) && _msbuildTargetLibraries.Any()) if (File.Exists(exportFilePath) && _msbuildTargetLibraries.Any())
{ {
var exportFile = LockFileReader.ReadExportFile(exportFilePath); var exportFile = _reader.ReadExportFile(exportFilePath);
PatchLockWithExport(exportFile); PatchLockWithExport(exportFile);
} }
else else
{ {

View file

@ -13,15 +13,24 @@ using NuGet.Versioning;
namespace Microsoft.DotNet.ProjectModel.Graph namespace Microsoft.DotNet.ProjectModel.Graph
{ {
public static class LockFileReader public class LockFileReader
{ {
private readonly LockFileSymbolTable _symbols;
public LockFileReader() : this(new LockFileSymbolTable()) { }
public LockFileReader(LockFileSymbolTable symbols)
{
_symbols = symbols;
}
public static LockFile Read(string lockFilePath, bool designTime) public static LockFile Read(string lockFilePath, bool designTime)
{ {
using (var stream = ResilientFileStreamOpener.OpenFile(lockFilePath)) using (var stream = ResilientFileStreamOpener.OpenFile(lockFilePath))
{ {
try try
{ {
return Read(lockFilePath, stream, designTime); return new LockFileReader().ReadLockFile(lockFilePath, stream, designTime);
} }
catch (FileFormatException ex) catch (FileFormatException ex)
{ {
@ -34,7 +43,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
} }
public static LockFile Read(string lockFilePath, Stream stream, bool designTime) public LockFile ReadLockFile(string lockFilePath, Stream stream, bool designTime)
{ {
try try
{ {
@ -47,10 +56,10 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
var lockFile = ReadLockFile(lockFilePath, jobject); var lockFile = ReadLockFile(lockFilePath, jobject);
if (!designTime) if (!designTime)
{ {
var patcher = new LockFilePatcher(lockFile); var patcher = new LockFilePatcher(lockFile, this);
patcher.Patch(); patcher.Patch();
} }
@ -70,7 +79,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
} }
public static ExportFile ReadExportFile(string fragmentLockFilePath) public ExportFile ReadExportFile(string fragmentLockFilePath)
{ {
using (var stream = ResilientFileStreamOpener.OpenFile(fragmentLockFilePath)) using (var stream = ResilientFileStreamOpener.OpenFile(fragmentLockFilePath))
{ {
@ -100,7 +109,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
} }
private static LockFile ReadLockFile(string lockFilePath, JsonObject cursor) private LockFile ReadLockFile(string lockFilePath, JsonObject cursor)
{ {
var lockFile = new LockFile(lockFilePath); var lockFile = new LockFile(lockFilePath);
lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue); lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue);
@ -111,7 +120,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
return lockFile; return lockFile;
} }
private static void ReadLibrary(JsonObject json, LockFile lockFile) private void ReadLibrary(JsonObject json, LockFile lockFile)
{ {
if (json == null) if (json == null)
{ {
@ -128,9 +137,9 @@ namespace Microsoft.DotNet.ProjectModel.Graph
var parts = key.Split(new[] { '/' }, 2); var parts = key.Split(new[] { '/' }, 2);
var name = parts[0]; var name = parts[0];
var version = parts.Length == 2 ? NuGetVersion.Parse(parts[1]) : null; var version = parts.Length == 2 ? _symbols.GetVersion(parts[1]) : null;
var type = value.ValueAsString("type")?.Value; var type = _symbols.GetString(value.ValueAsString("type")?.Value);
if (type == null || string.Equals(type, "package", StringComparison.OrdinalIgnoreCase)) if (type == null || string.Equals(type, "package", StringComparison.OrdinalIgnoreCase))
{ {
@ -162,7 +171,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
} }
private static LockFileTarget ReadTarget(string property, JsonValue json) private LockFileTarget ReadTarget(string property, JsonValue json)
{ {
var jobject = json as JsonObject; var jobject = json as JsonObject;
if (jobject == null) if (jobject == null)
@ -172,10 +181,10 @@ namespace Microsoft.DotNet.ProjectModel.Graph
var target = new LockFileTarget(); var target = new LockFileTarget();
var parts = property.Split(new[] { '/' }, 2); var parts = property.Split(new[] { '/' }, 2);
target.TargetFramework = NuGetFramework.Parse(parts[0]); target.TargetFramework = _symbols.GetFramework(parts[0]);
if (parts.Length == 2) if (parts.Length == 2)
{ {
target.RuntimeIdentifier = parts[1]; target.RuntimeIdentifier = _symbols.GetString(parts[1]);
} }
target.Libraries = ReadObject(jobject, ReadTargetLibrary); target.Libraries = ReadObject(jobject, ReadTargetLibrary);
@ -183,7 +192,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
return target; return target;
} }
private static LockFileTargetLibrary ReadTargetLibrary(string property, JsonValue json) private LockFileTargetLibrary ReadTargetLibrary(string property, JsonValue json)
{ {
var jobject = json as JsonObject; var jobject = json as JsonObject;
if (jobject == null) if (jobject == null)
@ -194,17 +203,17 @@ namespace Microsoft.DotNet.ProjectModel.Graph
var library = new LockFileTargetLibrary(); var library = new LockFileTargetLibrary();
var parts = property.Split(new[] { '/' }, 2); var parts = property.Split(new[] { '/' }, 2);
library.Name = parts[0]; library.Name = _symbols.GetString(parts[0]);
if (parts.Length == 2) if (parts.Length == 2)
{ {
library.Version = NuGetVersion.Parse(parts[1]); library.Version = _symbols.GetVersion(parts[1]);
} }
library.Type = jobject.ValueAsString("type"); library.Type = _symbols.GetString(jobject.ValueAsString("type"));
var framework = jobject.ValueAsString("framework"); var framework = jobject.ValueAsString("framework");
if (framework != null) if (framework != null)
{ {
library.TargetFramework = NuGetFramework.Parse(framework); library.TargetFramework = _symbols.GetFramework(framework);
} }
library.Dependencies = ReadObject(jobject.ValueAsJsonObject("dependencies"), ReadPackageDependency); library.Dependencies = ReadObject(jobject.ValueAsJsonObject("dependencies"), ReadPackageDependency);
@ -215,10 +224,11 @@ namespace Microsoft.DotNet.ProjectModel.Graph
library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem); library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem);
library.ContentFiles = ReadObject(jobject.ValueAsJsonObject("contentFiles"), ReadContentFile); library.ContentFiles = ReadObject(jobject.ValueAsJsonObject("contentFiles"), ReadContentFile);
library.RuntimeTargets = ReadObject(jobject.ValueAsJsonObject("runtimeTargets"), ReadRuntimeTarget); library.RuntimeTargets = ReadObject(jobject.ValueAsJsonObject("runtimeTargets"), ReadRuntimeTarget);
return library; return library;
} }
private static LockFileRuntimeTarget ReadRuntimeTarget(string property, JsonValue json) private LockFileRuntimeTarget ReadRuntimeTarget(string property, JsonValue json)
{ {
var jsonObject = json as JsonObject; var jsonObject = json as JsonObject;
if (jsonObject == null) if (jsonObject == null)
@ -227,13 +237,13 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
return new LockFileRuntimeTarget( return new LockFileRuntimeTarget(
path: property, path: _symbols.GetString(property),
runtime: jsonObject.ValueAsString("rid"), runtime: _symbols.GetString(jsonObject.ValueAsString("rid")),
assetType: jsonObject.ValueAsString("assetType") assetType: _symbols.GetString(jsonObject.ValueAsString("assetType"))
); );
} }
private static LockFileContentFile ReadContentFile(string property, JsonValue json) private LockFileContentFile ReadContentFile(string property, JsonValue json)
{ {
var contentFile = new LockFileContentFile() var contentFile = new LockFileContentFile()
{ {
@ -248,7 +258,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
BuildAction.TryParse(jsonObject.ValueAsString("buildAction"), out action); BuildAction.TryParse(jsonObject.ValueAsString("buildAction"), out action);
contentFile.BuildAction = action; contentFile.BuildAction = action;
var codeLanguage = jsonObject.ValueAsString("codeLanguage"); var codeLanguage = _symbols.GetString(jsonObject.ValueAsString("codeLanguage"));
if (codeLanguage == "any") if (codeLanguage == "any")
{ {
codeLanguage = null; codeLanguage = null;
@ -262,37 +272,37 @@ namespace Microsoft.DotNet.ProjectModel.Graph
return contentFile; return contentFile;
} }
private static ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json) private ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json)
{ {
return new ProjectFileDependencyGroup( return new ProjectFileDependencyGroup(
string.IsNullOrEmpty(property) ? null : NuGetFramework.Parse(property), string.IsNullOrEmpty(property) ? null : NuGetFramework.Parse(property),
ReadArray(json, ReadString)); ReadArray(json, ReadString));
} }
private static PackageDependency ReadPackageDependency(string property, JsonValue json) private PackageDependency ReadPackageDependency(string property, JsonValue json)
{ {
var versionStr = ReadString(json); var versionStr = ReadString(json);
return new PackageDependency( return new PackageDependency(
property, _symbols.GetString(property),
versionStr == null ? null : VersionRange.Parse(versionStr)); versionStr == null ? null : _symbols.GetVersionRange(versionStr));
} }
private static LockFileItem ReadFileItem(string property, JsonValue json) private LockFileItem ReadFileItem(string property, JsonValue json)
{ {
var item = new LockFileItem { Path = PathUtility.GetPathWithDirectorySeparator(property) }; var item = new LockFileItem { Path = _symbols.GetString(PathUtility.GetPathWithDirectorySeparator(property)) };
var jobject = json as JsonObject; var jobject = json as JsonObject;
if (jobject != null) if (jobject != null)
{ {
foreach (var subProperty in jobject.Keys) foreach (var subProperty in jobject.Keys)
{ {
item.Properties[subProperty] = jobject.ValueAsString(subProperty); item.Properties[_symbols.GetString(subProperty)] = jobject.ValueAsString(subProperty);
} }
} }
return item; return item;
} }
private static string ReadFrameworkAssemblyReference(JsonValue json) private string ReadFrameworkAssemblyReference(JsonValue json)
{ {
return ReadString(json); return ReadString(json);
} }
@ -318,9 +328,9 @@ namespace Microsoft.DotNet.ProjectModel.Graph
return items; return items;
} }
private static IList<string> ReadPathArray(JsonValue json, Func<JsonValue, string> readItem) private IList<string> ReadPathArray(JsonValue json, Func<JsonValue, string> readItem)
{ {
return ReadArray(json, readItem).Select(f => PathUtility.GetPathWithDirectorySeparator(f)).ToList(); return ReadArray(json, readItem).Select(f => _symbols.GetString(PathUtility.GetPathWithDirectorySeparator(f))).ToList();
} }
private static IList<TItem> ReadObject<TItem>(JsonObject json, Func<string, JsonValue, TItem> readItem) private static IList<TItem> ReadObject<TItem>(JsonObject json, Func<string, JsonValue, TItem> readItem)
@ -368,11 +378,11 @@ namespace Microsoft.DotNet.ProjectModel.Graph
} }
} }
private static string ReadString(JsonValue json) private string ReadString(JsonValue json)
{ {
if (json is JsonString) if (json is JsonString)
{ {
return (json as JsonString).Value; return _symbols.GetString((json as JsonString).Value);
} }
else if (json is JsonNull) else if (json is JsonNull)
{ {

View file

@ -0,0 +1,23 @@
// 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.Concurrent;
using NuGet.Frameworks;
using NuGet.Versioning;
namespace Microsoft.DotNet.ProjectModel.Graph
{
public class LockFileSymbolTable
{
private ConcurrentDictionary<string, NuGetVersion> _versionTable = new ConcurrentDictionary<string, NuGetVersion>(Environment.ProcessorCount * 4, 1000, StringComparer.Ordinal);
private ConcurrentDictionary<string, VersionRange> _versionRangeTable = new ConcurrentDictionary<string, VersionRange>(Environment.ProcessorCount * 4, 1000, StringComparer.Ordinal);
private ConcurrentDictionary<string, NuGetFramework> _frameworksTable = new ConcurrentDictionary<string, NuGetFramework>(Environment.ProcessorCount * 4, 1000, StringComparer.Ordinal);
private ConcurrentDictionary<string, string> _stringsTable = new ConcurrentDictionary<string, string>(Environment.ProcessorCount * 4, 1000, StringComparer.Ordinal);
public NuGetVersion GetVersion(string versionString) => _versionTable.GetOrAdd(versionString, (s) => NuGetVersion.Parse(s));
public VersionRange GetVersionRange(string versionRangeString) => _versionRangeTable.GetOrAdd(versionRangeString, (s) => VersionRange.Parse(s));
public NuGetFramework GetFramework(string frameworkString) => _frameworksTable.GetOrAdd(frameworkString, (s) => NuGetFramework.Parse(s));
public string GetString(string frameworkString) => _stringsTable.GetOrAdd(frameworkString, frameworkString);
}
}

View file

@ -154,39 +154,6 @@ namespace Microsoft.DotNet.ProjectModel
.BuildAllTargets(); .BuildAllTargets();
} }
/// <summary>
/// Creates a project context based on existing context but using runtime target
/// </summary>
/// <param name="context"></param>
/// <param name="runtimeIdentifiers"></param>
/// <returns></returns>
public ProjectContext CreateRuntimeContext(IEnumerable<string> runtimeIdentifiers)
{
// Temporary until we have removed RID inference from NuGet
if(TargetFramework.IsCompileOnly)
{
return this;
}
var context = CreateBuilder(ProjectFile.ProjectFilePath, TargetFramework)
.WithRuntimeIdentifiers(runtimeIdentifiers)
.WithLockFile(LockFile)
.Build();
if (!context.IsPortable && context.RuntimeIdentifier == null)
{
// We are standalone, but don't support this runtime
var rids = string.Join(", ", runtimeIdentifiers);
throw new InvalidOperationException($"Can not find runtime target for framework '{TargetFramework}' compatible with one of the target runtimes: '{rids}'. " +
"Possible causes:" + Environment.NewLine +
"1. The project has not been restored or restore failed - run `dotnet restore`" + Environment.NewLine +
$"2. The project does not list one of '{rids}' in the 'runtimes' section.");
}
return context;
}
public OutputPaths GetOutputPaths(string configuration, string buidBasePath = null, string outputPath = null) public OutputPaths GetOutputPaths(string configuration, string buidBasePath = null, string outputPath = null)
{ {
return OutputPathsCalculator.GetOutputPaths(ProjectFile, return OutputPathsCalculator.GetOutputPaths(ProjectFile,

View file

@ -132,16 +132,42 @@ namespace Microsoft.DotNet.ProjectModel
EnsureProjectLoaded(); EnsureProjectLoaded();
LockFile = LockFile ?? LockFileResolver(ProjectDirectory); LockFile = LockFile ?? LockFileResolver(ProjectDirectory);
if (LockFile != null) if (LockFile != null && LockFile.Targets.Any())
{ {
var deduper = new HashSet<string>();
foreach (var target in LockFile.Targets) foreach (var target in LockFile.Targets)
{ {
yield return new ProjectContextBuilder() var id = $"{target.TargetFramework}/{target.RuntimeIdentifier}";
.WithProject(Project) if (deduper.Add(id))
.WithLockFile(LockFile) {
.WithTargetFramework(target.TargetFramework) var builder = new ProjectContextBuilder()
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier }) .WithProject(Project)
.Build(); .WithLockFile(LockFile)
.WithTargetFramework(target.TargetFramework)
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier });
if (IsDesignTime)
{
builder.AsDesignTime();
}
yield return builder.Build();
}
}
}
else
{
// Build a context for each framework. It won't be fully valid, since it won't have resolved data or runtime data, but the diagnostics will show that
// (Project Model Server needs this)
foreach (var framework in Project.GetTargetFrameworks())
{
var builder = new ProjectContextBuilder()
.WithProject(Project)
.WithTargetFramework(framework.FrameworkName);
if (IsDesignTime)
{
builder.AsDesignTime();
}
yield return builder.Build();
} }
} }
} }
@ -165,8 +191,17 @@ namespace Microsoft.DotNet.ProjectModel
RootDirectory = GlobalSettings?.DirectoryPath ?? RootDirectory; RootDirectory = GlobalSettings?.DirectoryPath ?? RootDirectory;
PackagesDirectory = PackagesDirectory ?? PackageDependencyProvider.ResolvePackagesPath(RootDirectory, GlobalSettings); PackagesDirectory = PackagesDirectory ?? PackageDependencyProvider.ResolvePackagesPath(RootDirectory, GlobalSettings);
ReferenceAssembliesPath = ReferenceAssembliesPath ?? FrameworkReferenceResolver.GetDefaultReferenceAssembliesPath();
var frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath); FrameworkReferenceResolver frameworkReferenceResolver;
if (string.IsNullOrEmpty(ReferenceAssembliesPath))
{
// Use the default static resolver
frameworkReferenceResolver = FrameworkReferenceResolver.Default;
}
else
{
frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath);
}
LockFileLookup lockFileLookup = null; LockFileLookup lockFileLookup = null;
EnsureProjectLoaded(); EnsureProjectLoaded();
@ -202,7 +237,7 @@ namespace Microsoft.DotNet.ProjectModel
if (mainProject != null) if (mainProject != null)
{ {
platformDependency = mainProject.Dependencies platformDependency = mainProject.Dependencies
.Where(d => d.Type.Equals(LibraryDependencyType.Platform)) .Where(d => d.Type.Equals(LibraryDependencyType.Platform))
.Cast<LibraryRange?>() .Cast<LibraryRange?>()
.FirstOrDefault(); .FirstOrDefault();
} }
@ -274,7 +309,7 @@ namespace Microsoft.DotNet.ProjectModel
{ {
var frameworkInfo = Project.GetTargetFramework(TargetFramework); var frameworkInfo = Project.GetTargetFramework(TargetFramework);
if (string.IsNullOrEmpty(ReferenceAssembliesPath)) if (frameworkReferenceResolver == null || string.IsNullOrEmpty(frameworkReferenceResolver.ReferenceAssembliesPath))
{ {
// If there was an attempt to use reference assemblies but they were not installed // If there was an attempt to use reference assemblies but they were not installed
// report an error // report an error
@ -373,13 +408,13 @@ namespace Microsoft.DotNet.ProjectModel
{ {
var library = pair.Value; var library = pair.Value;
// The System.* packages provide placeholders on any non netstandard platform // The System.* packages provide placeholders on any non netstandard platform
// To make them work seamlessly on those platforms, we fill the gap with a reference // To make them work seamlessly on those platforms, we fill the gap with a reference
// assembly (if available) // assembly (if available)
var package = library as PackageDescription; var package = library as PackageDescription;
if (package != null && if (package != null &&
package.Resolved && package.Resolved &&
package.HasCompileTimePlaceholder && package.HasCompileTimePlaceholder &&
!TargetFramework.IsPackageBased()) !TargetFramework.IsPackageBased())
{ {
var newKey = new LibraryKey(library.Identity.Name, LibraryType.ReferenceAssembly); var newKey = new LibraryKey(library.Identity.Name, LibraryType.ReferenceAssembly);
@ -583,7 +618,7 @@ namespace Microsoft.DotNet.ProjectModel
return combiner.CombinedHash; return combiner.CombinedHash;
} }
public override string ToString() public override string ToString()
{ {
return Name + " " + LibraryType; return Name + " " + LibraryType;

View file

@ -4,6 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel namespace Microsoft.DotNet.ProjectModel
{ {
@ -13,6 +15,8 @@ namespace Microsoft.DotNet.ProjectModel
public List<ProjectContext> ProjectContexts { get; } = new List<ProjectContext>(); public List<ProjectContext> ProjectContexts { get; } = new List<ProjectContext>();
public IEnumerable<ProjectContext> FrameworkOnlyContexts => ProjectContexts.Where(c => string.IsNullOrEmpty(c.RuntimeIdentifier));
public List<DiagnosticMessage> ProjectDiagnostics { get; } = new List<DiagnosticMessage>(); public List<DiagnosticMessage> ProjectDiagnostics { get; } = new List<DiagnosticMessage>();
public string LockFilePath { get; set; } public string LockFilePath { get; set; }
@ -51,6 +55,16 @@ namespace Microsoft.DotNet.ProjectModel
} }
} }
public ProjectContext GetTarget(NuGetFramework targetFramework) => GetTarget(targetFramework, string.Empty);
public ProjectContext GetTarget(NuGetFramework targetFramework, string runtimeIdentifier)
{
return ProjectContexts
.FirstOrDefault(c =>
Equals(c.TargetFramework, targetFramework) &&
string.Equals(c.RuntimeIdentifier ?? string.Empty, runtimeIdentifier ?? string.Empty));
}
public void Reset() public void Reset()
{ {
Project = null; Project = null;

View file

@ -85,8 +85,16 @@ namespace Microsoft.DotNet.ProjectModel
var project = new Project(); var project = new Project();
var reader = new StreamReader(stream); var reader = new StreamReader(stream);
JObject rawProject;
using (var jsonReader = new JsonTextReader(reader))
{
rawProject = JObject.Load(jsonReader);
// Try to read another token to ensure we're at the end of the document.
// This will no-op if we are, and throw a JsonReaderException if there is additional content (which is what we want)
jsonReader.Read();
}
var rawProject = JObject.Parse(reader.ReadToEnd());
if (rawProject == null) if (rawProject == null)
{ {
throw FileFormatException.Create( throw FileFormatException.Create(

View file

@ -2,10 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.DotNet.ProjectModel.Utilities; using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.DependencyModel.Resolution; using Microsoft.Extensions.DependencyModel.Resolution;
@ -23,7 +25,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
private static FrameworkReferenceResolver _default; private static FrameworkReferenceResolver _default;
private readonly IDictionary<NuGetFramework, FrameworkInformation> _cache = new Dictionary<NuGetFramework, FrameworkInformation>(); private readonly ConcurrentDictionary<NuGetFramework, FrameworkInformation> _cache = new ConcurrentDictionary<NuGetFramework, FrameworkInformation>();
private static readonly IDictionary<NuGetFramework, NuGetFramework[]> _aliases = new Dictionary<NuGetFramework, NuGetFramework[]> private static readonly IDictionary<NuGetFramework, NuGetFramework[]> _aliases = new Dictionary<NuGetFramework, NuGetFramework[]>
{ {

View file

@ -83,7 +83,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
LibraryDependencyType.Default)); LibraryDependencyType.Default));
} }
if (!targetFramework.IsPackageBased) if (!targetFramework.IsPackageBased())
{ {
// Only add framework assemblies for non-package based frameworks. // Only add framework assemblies for non-package based frameworks.
foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies) foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies)

View file

@ -138,7 +138,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
LibraryDependencyType.Default)); LibraryDependencyType.Default));
} }
if (!targetFramework.IsPackageBased) if (!targetFramework.IsPackageBased())
{ {
// Only add framework assemblies for non-package based frameworks. // Only add framework assemblies for non-package based frameworks.
foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies) foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies)

View file

@ -56,7 +56,7 @@ namespace NuGet.Frameworks
} }
return name + "-" + frameworkName.Profile; return name + "-" + frameworkName.Profile;
} }
internal static bool IsPackageBased(this NuGetFramework self) internal static bool IsPackageBased(this NuGetFramework self)
{ {
return self.IsPackageBased || return self.IsPackageBased ||

View file

@ -13,18 +13,18 @@ namespace Microsoft.DotNet.ProjectModel.Utilities
{ {
return OpenFile(filepath, 0); return OpenFile(filepath, 0);
} }
public static FileStream OpenFile(string filepath, int retry) public static FileStream OpenFile(string filepath, int retry)
{ {
if (retry < 0) if (retry < 0)
{ {
throw new ArgumentException("Retry can't be fewer than 0", nameof(retry)); throw new ArgumentException("Retry can't be fewer than 0", nameof(retry));
} }
var count = 0; var count = 0;
while (true) while (true)
{ {
try try
{ {
return new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read); return new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
} }

View file

@ -8,6 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Graph; using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Utilities; using Microsoft.DotNet.ProjectModel.Utilities;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel namespace Microsoft.DotNet.ProjectModel
{ {
@ -28,9 +29,16 @@ namespace Microsoft.DotNet.ProjectModel
private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private bool _needRefresh; private bool _needRefresh;
private readonly ProjectReaderSettings _settings;
private readonly bool _designTime;
private readonly LockFileReader _lockFileReader;
private WorkspaceContext(IEnumerable<string> projectPaths) private WorkspaceContext(IEnumerable<string> projectPaths, ProjectReaderSettings settings, bool designTime)
{ {
_settings = settings;
_designTime = designTime;
_lockFileReader = new LockFileReader();
foreach (var path in projectPaths) foreach (var path in projectPaths)
{ {
AddProject(path); AddProject(path);
@ -41,31 +49,60 @@ namespace Microsoft.DotNet.ProjectModel
/// <summary> /// <summary>
/// Create a WorkspaceContext from a given path. /// Create a WorkspaceContext from a given path.
/// ///
/// There must be either a global.json or project.json at under the given path. Otherwise
/// null is returned.
///
/// If the given path points to a global.json, all the projects found under the search paths /// If the given path points to a global.json, all the projects found under the search paths
/// are added to the WorkspaceContext. /// are added to the WorkspaceContext.
/// ///
/// If the given path points to a project.json, all the projects it referenced as well as itself /// If the given path points to a project.json, all the projects it referenced as well as itself
/// are added to the WorkspaceContext. /// are added to the WorkspaceContext.
///
/// If no path is provided, the workspace context is created empty and projects must be manually added
/// to it using <see cref="AddProject(string)"/>.
/// </summary> /// </summary>
public static WorkspaceContext CreateFrom(string projectPath) public static WorkspaceContext CreateFrom(string projectPath, bool designTime)
{ {
var projectPaths = ResolveProjectPath(projectPath); var projectPaths = ResolveProjectPath(projectPath);
if (projectPaths == null || !projectPaths.Any()) if (projectPaths == null || !projectPaths.Any())
{ {
return null; return new WorkspaceContext(Enumerable.Empty<string>(), ProjectReaderSettings.ReadFromEnvironment(), designTime);
} }
var context = new WorkspaceContext(projectPaths); var context = new WorkspaceContext(projectPaths, ProjectReaderSettings.ReadFromEnvironment(), designTime);
return context; return context;
} }
public static WorkspaceContext Create() /// <summary>
/// Create an empty <see cref="WorkspaceContext" /> using the default <see cref="ProjectReaderSettings" />
/// </summary>
/// <param name="designTime">A boolean indicating if the workspace should be created in Design-Time mode</param>
/// <returns></returns>
public static WorkspaceContext Create(bool designTime) => Create(ProjectReaderSettings.ReadFromEnvironment(), designTime);
/// <summary>
/// Create an empty <see cref="WorkspaceContext" /> using the default <see cref="ProjectReaderSettings" />, with the specified Version Suffix
/// </summary>
/// <param name="versionSuffix">The suffix to use to replace any '-*' snapshot tokens in Project versions.</param>
/// <param name="designTime">A boolean indicating if the workspace should be created in Design-Time mode</param>
/// <returns></returns>
public static WorkspaceContext Create(string versionSuffix, bool designTime)
{ {
return new WorkspaceContext(Enumerable.Empty<string>()); var settings = ProjectReaderSettings.ReadFromEnvironment();
if (!string.IsNullOrEmpty(versionSuffix))
{
settings.VersionSuffix = versionSuffix;
}
return Create(settings, designTime);
}
/// <summary>
/// Create an empty <see cref="WorkspaceContext" /> using the provided <see cref="ProjectReaderSettings" />.
/// </summary>
/// <param name="settings">The settings to use when reading projects</param>
/// <param name="designTime">A boolean indicating if the workspace should be created in Design-Time mode</param>
/// <returns></returns>
public static WorkspaceContext Create(ProjectReaderSettings settings, bool designTime)
{
return new WorkspaceContext(Enumerable.Empty<string>(), settings, designTime);
} }
public void AddProject(string path) public void AddProject(string path)
@ -104,7 +141,7 @@ namespace Microsoft.DotNet.ProjectModel
foreach (var projectDirectory in basePaths) foreach (var projectDirectory in basePaths)
{ {
var project = GetProject(projectDirectory).Model; var project = GetProjectCore(projectDirectory).Model;
if (project == null) if (project == null)
{ {
continue; continue;
@ -116,7 +153,7 @@ namespace Microsoft.DotNet.ProjectModel
{ {
foreach (var reference in GetProjectReferences(projectContext)) foreach (var reference in GetProjectReferences(projectContext))
{ {
var referencedProject = GetProject(reference.Path).Model; var referencedProject = GetProjectCore(reference.Path).Model;
if (referencedProject != null) if (referencedProject != null)
{ {
_projects.Add(referencedProject.ProjectDirectory); _projects.Add(referencedProject.ProjectDirectory);
@ -130,29 +167,100 @@ namespace Microsoft.DotNet.ProjectModel
public IReadOnlyList<ProjectContext> GetProjectContexts(string projectPath) public IReadOnlyList<ProjectContext> GetProjectContexts(string projectPath)
{ {
return GetProjectContextCollection(projectPath).ProjectContexts; return (IReadOnlyList<ProjectContext>)GetProjectContextCollection(projectPath)?.ProjectContexts.AsReadOnly() ??
EmptyArray<ProjectContext>.Value;
} }
public ProjectContext GetProjectContext(string projectPath, NuGetFramework framework) => GetProjectContext(projectPath, framework, EmptyArray<string>.Value);
public ProjectContext GetProjectContext(string projectPath, NuGetFramework framework, IEnumerable<string> runtimeIdentifier)
{
var contexts = GetProjectContextCollection(projectPath);
if (contexts == null)
{
return null;
}
return contexts
.ProjectContexts
.FirstOrDefault(c => Equals(c.TargetFramework, framework) && RidsMatch(c.RuntimeIdentifier, runtimeIdentifier));
}
public ProjectContext GetRuntimeContext(ProjectContext context, IEnumerable<string> runtimeIdentifiers)
{
var contexts = GetProjectContextCollection(context.ProjectDirectory);
if (contexts == null)
{
return null;
}
var runtimeContext = runtimeIdentifiers
.Select(r => contexts.GetTarget(context.TargetFramework, r))
.FirstOrDefault(c => c != null);
if (runtimeContext == null)
{
if (context.IsPortable)
{
// We're specializing a portable target, so synthesize a runtime target manually
// We don't cache this project context, but we'll still use the cached Project and LockFile
return InitializeProjectContextBuilder(context.ProjectFile)
.WithTargetFramework(context.TargetFramework)
.WithRuntimeIdentifiers(runtimeIdentifiers)
.Build();
}
// We are standalone, but don't support this runtime
var rids = string.Join(", ", runtimeIdentifiers);
throw new InvalidOperationException($"Can not find runtime target for framework '{context.TargetFramework}' compatible with one of the target runtimes: '{rids}'. " +
"Possible causes:" + Environment.NewLine +
"1. The project has not been restored or restore failed - run `dotnet restore`" + Environment.NewLine +
$"2. The project does not list one of '{rids}' in the 'runtimes' section.");
}
return runtimeContext;
}
public Project GetProject(string projectDirectory) => GetProjectCore(projectDirectory)?.Model;
public ProjectContextCollection GetProjectContextCollection(string projectPath) public ProjectContextCollection GetProjectContextCollection(string projectPath)
{ {
var normalizedPath = NormalizeProjectPath(projectPath);
if (normalizedPath == null)
{
return null;
}
return _projectContextsCache.AddOrUpdate( return _projectContextsCache.AddOrUpdate(
projectPath, normalizedPath,
key => AddProjectContextEntry(key, null), key => AddProjectContextEntry(key, null),
(key, oldEntry) => AddProjectContextEntry(key, oldEntry)); (key, oldEntry) => AddProjectContextEntry(key, oldEntry));
} }
private FileModelEntry<Project> GetProject(string projectDirectory) private FileModelEntry<Project> GetProjectCore(string projectDirectory)
{ {
var normalizedPath = NormalizeProjectPath(projectDirectory);
if (normalizedPath == null)
{
return null;
}
return _projectsCache.AddOrUpdate( return _projectsCache.AddOrUpdate(
projectDirectory, normalizedPath,
key => AddProjectEntry(key, null), key => AddProjectEntry(key, null),
(key, oldEntry) => AddProjectEntry(key, oldEntry)); (key, oldEntry) => AddProjectEntry(key, oldEntry));
} }
private LockFile GetLockFile(string projectDirectory) private LockFile GetLockFile(string projectDirectory)
{ {
var normalizedPath = NormalizeProjectPath(projectDirectory);
if (normalizedPath == null)
{
return null;
}
return _lockFileCache.AddOrUpdate( return _lockFileCache.AddOrUpdate(
projectDirectory, normalizedPath,
key => AddLockFileEntry(key, null), key => AddLockFileEntry(key, null),
(key, oldEntry) => AddLockFileEntry(key, oldEntry)).Model; (key, oldEntry) => AddLockFileEntry(key, oldEntry)).Model;
} }
@ -173,7 +281,7 @@ namespace Microsoft.DotNet.ProjectModel
if (currentEntry.IsInvalid) if (currentEntry.IsInvalid)
{ {
Project project; Project project;
if (!ProjectReader.TryGetProject(projectDirectory, out project, currentEntry.Diagnostics)) if (!ProjectReader.TryGetProject(projectDirectory, out project, currentEntry.Diagnostics, _settings))
{ {
currentEntry.Reset(); currentEntry.Reset();
} }
@ -211,7 +319,7 @@ namespace Microsoft.DotNet.ProjectModel
{ {
try try
{ {
currentEntry.Model = LockFileReader.Read(currentEntry.FilePath, fs, designTime: true); currentEntry.Model = _lockFileReader.ReadLockFile(currentEntry.FilePath, fs, designTime: true);
currentEntry.UpdateLastWriteTimeUtc(); currentEntry.UpdateLastWriteTimeUtc();
} }
catch (FileFormatException ex) catch (FileFormatException ex)
@ -238,8 +346,9 @@ namespace Microsoft.DotNet.ProjectModel
currentEntry = new ProjectContextCollection(); currentEntry = new ProjectContextCollection();
} }
var projectEntry = GetProject(projectDirectory); var projectEntry = GetProjectCore(projectDirectory);
if (projectEntry.Model == null)
if (projectEntry?.Model == null)
{ {
// project doesn't exist anymore // project doesn't exist anymore
currentEntry.Reset(); currentEntry.Reset();
@ -251,17 +360,9 @@ namespace Microsoft.DotNet.ProjectModel
{ {
currentEntry.Reset(); currentEntry.Reset();
foreach (var framework in project.GetTargetFrameworks()) var builder = InitializeProjectContextBuilder(project);
{
var builder = new ProjectContextBuilder()
.WithProjectResolver(path => GetProject(path).Model)
.WithLockFileResolver(path => GetLockFile(path))
.WithProject(project)
.WithTargetFramework(framework.FrameworkName)
.AsDesignTime();
currentEntry.ProjectContexts.Add(builder.Build()); currentEntry.ProjectContexts.AddRange(builder.BuildAllTargets());
}
currentEntry.Project = project; currentEntry.Project = project;
currentEntry.ProjectFilePath = project.ProjectFilePath; currentEntry.ProjectFilePath = project.ProjectFilePath;
@ -280,6 +381,20 @@ namespace Microsoft.DotNet.ProjectModel
return currentEntry; return currentEntry;
} }
private ProjectContextBuilder InitializeProjectContextBuilder(Project project)
{
var builder = new ProjectContextBuilder()
.WithProjectResolver(path => GetProjectCore(path)?.Model)
.WithLockFileResolver(path => GetLockFile(path))
.WithProject(project);
if (_designTime)
{
builder.AsDesignTime();
}
return builder;
}
private class FileModelEntry<TModel> where TModel : class private class FileModelEntry<TModel> where TModel : class
{ {
private DateTime _lastWriteTimeUtc; private DateTime _lastWriteTimeUtc;
@ -400,5 +515,11 @@ namespace Microsoft.DotNet.ProjectModel
yield return description; yield return description;
} }
} }
private static bool RidsMatch(string rid, IEnumerable<string> compatibleRids)
{
return (string.IsNullOrEmpty(rid) && !compatibleRids.Any()) ||
(compatibleRids.Contains(rid));
}
} }
} }

View file

@ -11,7 +11,7 @@ namespace Microsoft.Extensions.DependencyModel.Resolution
public class DotNetReferenceAssembliesPathResolver public class DotNetReferenceAssembliesPathResolver
{ {
public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH"; public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH";
internal static string Resolve(IEnvironment envirnment, IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment) internal static string Resolve(IEnvironment envirnment, IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment)
{ {
var path = envirnment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv); var path = envirnment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv);
@ -19,40 +19,40 @@ namespace Microsoft.Extensions.DependencyModel.Resolution
{ {
return path; return path;
} }
return GetDefaultDotNetReferenceAssembliesPath(fileSystem, runtimeEnvironment); return GetDefaultDotNetReferenceAssembliesPath(fileSystem, runtimeEnvironment);
} }
public static string Resolve() public static string Resolve()
{ {
return Resolve(EnvironmentWrapper.Default, FileSystemWrapper.Default, PlatformServices.Default.Runtime); return Resolve(EnvironmentWrapper.Default, FileSystemWrapper.Default, PlatformServices.Default.Runtime);
} }
private static string GetDefaultDotNetReferenceAssembliesPath(IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment) private static string GetDefaultDotNetReferenceAssembliesPath(IFileSystem fileSystem, IRuntimeEnvironment runtimeEnvironment)
{ {
var os = runtimeEnvironment.OperatingSystemPlatform; var os = runtimeEnvironment.OperatingSystemPlatform;
if (os == Platform.Windows) if (os == Platform.Windows)
{ {
return null; return null;
} }
if (os == Platform.Darwin && if (os == Platform.Darwin &&
fileSystem.Directory.Exists("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks")) fileSystem.Directory.Exists("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"))
{ {
return "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"; return "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks";
} }
if (fileSystem.Directory.Exists("/usr/local/lib/mono/xbuild-frameworks")) if (fileSystem.Directory.Exists("/usr/local/lib/mono/xbuild-frameworks"))
{ {
return "/usr/local/lib/mono/xbuild-frameworks"; return "/usr/local/lib/mono/xbuild-frameworks";
} }
if (fileSystem.Directory.Exists("/usr/lib/mono/xbuild-frameworks")) if (fileSystem.Directory.Exists("/usr/lib/mono/xbuild-frameworks"))
{ {
return "/usr/lib/mono/xbuild-frameworks"; return "/usr/lib/mono/xbuild-frameworks";
} }
return null; return null;
} }
} }

View file

@ -111,7 +111,7 @@ namespace Microsoft.DotNet.Cli
command = "help"; command = "help";
} }
int exitCode; int exitCode;
Func<string[], int> builtIn; Func<string[], int> builtIn;
if (s_builtIns.TryGetValue(command, out builtIn)) if (s_builtIns.TryGetValue(command, out builtIn))
{ {
@ -175,16 +175,16 @@ namespace Microsoft.DotNet.Cli
{ {
return (shortName != null && candidate.Equals("-" + shortName)) || (longName != null && candidate.Equals("--" + longName)); return (shortName != null && candidate.Equals("-" + shortName)) || (longName != null && candidate.Equals("--" + longName));
} }
private static string GetCommitSha() private static string GetCommitSha()
{ {
var versionFile = DotnetFiles.VersionFile; var versionFile = DotnetFiles.VersionFile;
if (File.Exists(versionFile)) if (File.Exists(versionFile))
{ {
return File.ReadLines(versionFile).FirstOrDefault()?.Substring(0, 10); return File.ReadLines(versionFile).FirstOrDefault()?.Substring(0, 10);
} }
return null; return null;
} }
} }

View file

@ -52,12 +52,17 @@ namespace Microsoft.DotNet.Tools.Compiler
yield return filePatternMatch.Path; yield return filePatternMatch.Path;
} }
} }
else if (value.Contains("*"))
{
throw new InvalidOperationException($"Globbing pattern '{value}' did not match any files");
}
else if (value.EndsWith(Project.FileName))
{
throw new InvalidOperationException($"Could not find project file '{value}'");
}
else else
{ {
throw new InvalidOperationException($"Could not resolve project path from '{value}':" + throw new InvalidOperationException($"Couldn't find '{Project.FileName}' in '{value}'");
"1. It's not project file" +
"2. It's not directory containing project.json file" +
"3. Globbing returned no mathces");
} }
} }
} }

View file

@ -4,6 +4,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.Extensions.PlatformAbstractions; using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks; using NuGet.Frameworks;
@ -44,11 +45,16 @@ namespace Microsoft.DotNet.Tools.Compiler
public bool ShouldNotUseIncrementality { get; set; } public bool ShouldNotUseIncrementality { get; set; }
public bool ShouldSkipDependencies { get; set; } public bool ShouldSkipDependencies { get; set; }
public WorkspaceContext Workspace { get; private set; }
// workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params // workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params
private readonly Dictionary<string, CommandOption> baseClassOptions; private readonly Dictionary<string, CommandOption> baseClassOptions;
public BuildCommandApp(string name, string fullName, string description) public BuildCommandApp(string name, string fullName, string description) : this(name, fullName, description, workspace: null) { }
public BuildCommandApp(string name, string fullName, string description, WorkspaceContext workspace)
{ {
Workspace = workspace;
_app = new CommandLineApplication _app = new CommandLineApplication
{ {
Name = name, Name = name,
@ -99,6 +105,18 @@ namespace Microsoft.DotNet.Tools.Compiler
ShouldNotUseIncrementality = _shouldNotUseIncrementalityArgument.HasValue(); ShouldNotUseIncrementality = _shouldNotUseIncrementalityArgument.HasValue();
ShouldSkipDependencies = _shouldSkipDependenciesArgument.HasValue(); ShouldSkipDependencies = _shouldSkipDependenciesArgument.HasValue();
// Set defaults based on the environment
if (Workspace == null)
{
var settings = ProjectReaderSettings.ReadFromEnvironment();
if (!string.IsNullOrEmpty(VersionSuffixValue))
{
settings.VersionSuffix = VersionSuffixValue;
}
Workspace = WorkspaceContext.Create(settings, designTime: false);
}
var files = new ProjectGlobbingResolver().Resolve(_projectArgument.Values); var files = new ProjectGlobbingResolver().Resolve(_projectArgument.Values);
IEnumerable<NuGetFramework> frameworks = null; IEnumerable<NuGetFramework> frameworks = null;
if (_frameworkOption.HasValue()) if (_frameworkOption.HasValue())

View file

@ -18,16 +18,19 @@ namespace Microsoft.DotNet.Tools.Build
private readonly string _outputPath; private readonly string _outputPath;
private readonly string _buildBasePath; private readonly string _buildBasePath;
private readonly IList<string> _runtimes; private readonly IList<string> _runtimes;
private readonly WorkspaceContext _workspace;
public CompilerIOManager(string configuration, public CompilerIOManager(string configuration,
string outputPath, string outputPath,
string buildBasePath, string buildBasePath,
IEnumerable<string> runtimes) IEnumerable<string> runtimes,
WorkspaceContext workspace)
{ {
_configuration = configuration; _configuration = configuration;
_outputPath = outputPath; _outputPath = outputPath;
_buildBasePath = buildBasePath; _buildBasePath = buildBasePath;
_runtimes = runtimes.ToList(); _runtimes = runtimes.ToList();
_workspace = workspace;
} }
public bool AnyMissingIO(ProjectContext project, IEnumerable<string> items, string itemsType) public bool AnyMissingIO(ProjectContext project, IEnumerable<string> items, string itemsType)
@ -75,7 +78,7 @@ namespace Microsoft.DotNet.Tools.Build
var allOutputPath = new HashSet<string>(calculator.CompilationFiles.All()); var allOutputPath = new HashSet<string>(calculator.CompilationFiles.All());
if (isRootProject && project.ProjectFile.HasRuntimeOutput(_configuration)) if (isRootProject && project.ProjectFile.HasRuntimeOutput(_configuration))
{ {
var runtimeContext = project.CreateRuntimeContext(_runtimes); var runtimeContext = _workspace.GetRuntimeContext(project, _runtimes);
foreach (var path in runtimeContext.GetOutputPaths(_configuration, _buildBasePath, _outputPath).RuntimeFiles.All()) foreach (var path in runtimeContext.GetOutputPaths(_configuration, _buildBasePath, _outputPath).RuntimeFiles.All())
{ {
allOutputPath.Add(path); allOutputPath.Add(path);

View file

@ -33,7 +33,8 @@ namespace Microsoft.DotNet.Tools.Build
args.ConfigValue, args.ConfigValue,
args.OutputValue, args.OutputValue,
args.BuildBasePathValue, args.BuildBasePathValue,
args.GetRuntimes() args.GetRuntimes(),
args.Workspace
); );
_scriptRunner = new ScriptRunner(); _scriptRunner = new ScriptRunner();
_commandFactory = new DotNetCommandFactory(); _commandFactory = new DotNetCommandFactory();
@ -120,7 +121,7 @@ namespace Microsoft.DotNet.Tools.Build
private void MakeRunnable(ProjectGraphNode graphNode) private void MakeRunnable(ProjectGraphNode graphNode)
{ {
var runtimeContext = graphNode.ProjectContext.ProjectFile.HasRuntimeOutput(_args.ConfigValue) ? var runtimeContext = graphNode.ProjectContext.ProjectFile.HasRuntimeOutput(_args.ConfigValue) ?
graphNode.ProjectContext.CreateRuntimeContext(_args.GetRuntimes()) : _args.Workspace.GetRuntimeContext(graphNode.ProjectContext, _args.GetRuntimes()) :
graphNode.ProjectContext; graphNode.ProjectContext;
var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue); var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);

View file

@ -15,13 +15,19 @@ namespace Microsoft.DotNet.Tools.Build
{ {
public class BuildCommand public class BuildCommand
{ {
public static int Run(string[] args) public static int Run(string[] args) => Run(args, null);
public static int Run(string[] args, WorkspaceContext workspace)
{ {
DebugHelper.HandleDebugSwitch(ref args); DebugHelper.HandleDebugSwitch(ref args);
try try
{ {
var app = new BuildCommandApp("dotnet build", ".NET Builder", "Builder for the .NET Platform. It performs incremental compilation if it's safe to do so. Otherwise it delegates to dotnet-compile which performs non-incremental compilation"); var app = new BuildCommandApp(
"dotnet build",
".NET Builder",
"Builder for the .NET Platform. It performs incremental compilation if it's safe to do so. Otherwise it delegates to dotnet-compile which performs non-incremental compilation",
workspace);
return app.Execute(OnExecute, args); return app.Execute(OnExecute, args);
} }
catch (Exception ex) catch (Exception ex)
@ -40,7 +46,7 @@ namespace Microsoft.DotNet.Tools.Build
var builderCommandApp = args; var builderCommandApp = args;
var graphCollector = new ProjectGraphCollector( var graphCollector = new ProjectGraphCollector(
!builderCommandApp.ShouldSkipDependencies, !builderCommandApp.ShouldSkipDependencies,
(project, target) => ProjectContext.Create(project, target)); (project, target) => args.Workspace.GetProjectContext(project, target));
var contexts = ResolveRootContexts(files, frameworks, args); var contexts = ResolveRootContexts(files, frameworks, args);
var graph = graphCollector.Collect(contexts).ToArray(); var graph = graphCollector.Collect(contexts).ToArray();
@ -53,19 +59,11 @@ namespace Microsoft.DotNet.Tools.Build
IEnumerable<NuGetFramework> frameworks, IEnumerable<NuGetFramework> frameworks,
BuildCommandApp args) BuildCommandApp args)
{ {
List<Task<ProjectContext>> tasks = new List<Task<ProjectContext>>(); List<Task<ProjectContext>> tasks = new List<Task<ProjectContext>>();
// Set defaults based on the environment
var settings = ProjectReaderSettings.ReadFromEnvironment();
if (!string.IsNullOrEmpty(args.VersionSuffixValue))
{
settings.VersionSuffix = args.VersionSuffixValue;
}
foreach (var file in files) foreach (var file in files)
{ {
var project = ProjectReader.GetProject(file); var project = args.Workspace.GetProject(file);
var projectFrameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName); var projectFrameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName);
if (!projectFrameworks.Any()) if (!projectFrameworks.Any())
{ {
@ -91,11 +89,7 @@ namespace Microsoft.DotNet.Tools.Build
foreach (var framework in selectedFrameworks) foreach (var framework in selectedFrameworks)
{ {
tasks.Add(Task.Run(() => new ProjectContextBuilder() tasks.Add(Task.Run(() => args.Workspace.GetProjectContext(file, framework)));
.WithProjectDirectory(Path.GetDirectoryName(file))
.WithTargetFramework(framework)
.WithReaderSettings(settings)
.Build()));
} }
} }
return Task.WhenAll(tasks).GetAwaiter().GetResult(); return Task.WhenAll(tasks).GetAwaiter().GetResult();

View file

@ -26,7 +26,7 @@ namespace Microsoft.DotNet.Tools.Compiler
success &= _managedCompiler.Compile(context, args); success &= _managedCompiler.Compile(context, args);
if (args.IsNativeValue && success) if (args.IsNativeValue && success)
{ {
var runtimeContext = context.CreateRuntimeContext(args.GetRuntimes()); var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
success &= _nativeCompiler.Compile(runtimeContext, args); success &= _nativeCompiler.Compile(runtimeContext, args);
} }
} }

View file

@ -170,7 +170,7 @@ namespace Microsoft.DotNet.Tools.Compiler
if (context.ProjectFile.HasRuntimeOutput(args.ConfigValue)) if (context.ProjectFile.HasRuntimeOutput(args.ConfigValue))
{ {
var runtimeContext = context.CreateRuntimeContext(args.GetRuntimes()); var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
var runtimeOutputPath = runtimeContext.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue); var runtimeOutputPath = runtimeContext.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue);
contextVariables.Add( contextVariables.Add(

View file

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.Helpers; using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
@ -35,12 +36,12 @@ namespace Microsoft.DotNet.ProjectModel.Server
snapshot.ProjectSearchPaths = currentSearchPaths.ToList(); snapshot.ProjectSearchPaths = currentSearchPaths.ToList();
snapshot.GlobalJsonPath = globalSettings?.FilePath; snapshot.GlobalJsonPath = globalSettings?.FilePath;
foreach (var projectContext in projectContextsCollection.ProjectContexts) foreach (var projectContext in projectContextsCollection.FrameworkOnlyContexts)
{ {
snapshot.ProjectContexts[projectContext.TargetFramework] = snapshot.ProjectContexts[projectContext.TargetFramework] =
ProjectContextSnapshot.Create(projectContext, configuration, currentSearchPaths); ProjectContextSnapshot.Create(projectContext, configuration, currentSearchPaths);
} }
return snapshot; return snapshot;
} }
} }

View file

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. // 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. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
@ -26,7 +27,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
_hostName = hostName; _hostName = hostName;
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory); _protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory);
_workspaceContext = WorkspaceContext.Create(); _workspaceContext = WorkspaceContext.Create(designTime: true);
_projects = new Dictionary<int, ProjectManager>(); _projects = new Dictionary<int, ProjectManager>();
} }
@ -51,26 +52,34 @@ namespace Microsoft.DotNet.ProjectModel.Server
var logger = loggerFactory.CreateLogger<ProjectModelServerCommand>(); var logger = loggerFactory.CreateLogger<ProjectModelServerCommand>();
if (!MonitorHostProcess(hostpid, logger)) try
{ {
return 1; if (!MonitorHostProcess(hostpid, logger))
} {
return 1;
}
var intPort = CheckPort(port, logger); var intPort = CheckPort(port, logger);
if (intPort == -1) if (intPort == -1)
{
return 1;
}
if (!hostname.HasValue())
{
logger.LogError($"Option \"{hostname.LongName}\" is missing.");
return 1;
}
var program = new ProjectModelServerCommand(intPort, hostname.Value(), loggerFactory);
program.OpenChannel();
}
catch (Exception ex)
{ {
return 1; logger.LogCritical($"Unhandled exception in server main: {ex}");
throw;
} }
if (!hostname.HasValue())
{
logger.LogError($"Option \"{hostname.LongName}\" is missing.");
return 1;
}
var program = new ProjectModelServerCommand(intPort, hostname.Value(), loggerFactory);
program.OpenChannel();
return 0; return 0;
}); });

View file

@ -123,7 +123,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
catch (Exception ex) catch (Exception ex)
{ {
_log.LogError("A unexpected exception occurred: {0}", ex.ToString()); _log.LogError("A unexpected exception occurred: {0}", ex.ToString());
var error = new ErrorMessage var error = new ErrorMessage
{ {
Message = ex.Message Message = ex.Message

View file

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
namespace Microsoft.DotNet.Tools.Publish namespace Microsoft.DotNet.Tools.Publish
{ {
@ -44,6 +45,8 @@ namespace Microsoft.DotNet.Tools.Publish
publish.VersionSuffix = versionSuffix.Value(); publish.VersionSuffix = versionSuffix.Value();
publish.ShouldBuild = !noBuild.HasValue(); publish.ShouldBuild = !noBuild.HasValue();
publish.Workspace = WorkspaceContext.Create(versionSuffix.Value(), designTime: false);
if (string.IsNullOrEmpty(publish.ProjectPath)) if (string.IsNullOrEmpty(publish.ProjectPath))
{ {
publish.ProjectPath = Directory.GetCurrentDirectory(); publish.ProjectPath = Directory.GetCurrentDirectory();

View file

@ -30,6 +30,7 @@ namespace Microsoft.DotNet.Tools.Publish
public string Runtime { get; set; } public string Runtime { get; set; }
public bool NativeSubdirectories { get; set; } public bool NativeSubdirectories { get; set; }
public NuGetFramework NugetFramework { get; set; } public NuGetFramework NugetFramework { get; set; }
public WorkspaceContext Workspace { get; set; }
public IList<ProjectContext> ProjectContexts { get; set; } public IList<ProjectContext> ProjectContexts { get; set; }
public string VersionSuffix { get; set; } public string VersionSuffix { get; set; }
public int NumberOfProjects { get; private set; } public int NumberOfProjects { get; private set; }
@ -432,14 +433,17 @@ namespace Microsoft.DotNet.Tools.Publish
throw new InvalidProjectException($"'{projectPath}' does not contain a project.json file"); throw new InvalidProjectException($"'{projectPath}' does not contain a project.json file");
} }
var allContexts = framework == null ? var contexts = Workspace.GetProjectContextCollection(projectPath).FrameworkOnlyContexts;
ProjectContext.CreateContextForEachFramework(projectPath) :
new[] { ProjectContext.Create(projectPath, framework) };
var runtimes = !string.IsNullOrEmpty(runtime) ? contexts = framework == null ?
new [] {runtime} : contexts :
PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); contexts.Where(c => Equals(c.TargetFramework, framework));
return allContexts.Select(c => c.CreateRuntimeContext(runtimes));
var rids = string.IsNullOrEmpty(runtime) ?
PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers() :
new[] { runtime };
return contexts.Select(c => Workspace.GetRuntimeContext(c, rids));
} }
private static void CopyContents(ProjectContext context, string outputPath) private static void CopyContents(ProjectContext context, string outputPath)

View file

@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Tools.Run
ProjectContext _context; ProjectContext _context;
List<string> _args; List<string> _args;
private WorkspaceContext _workspace;
public int Start() public int Start()
{ {
@ -60,6 +61,8 @@ namespace Microsoft.DotNet.Tools.Run
Configuration = Constants.DefaultConfiguration; Configuration = Constants.DefaultConfiguration;
} }
var frameworkContexts = _workspace.GetProjectContexts(Project).Where(c => string.IsNullOrEmpty(c.RuntimeIdentifier));
var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
if (Framework == null) if (Framework == null)
@ -70,16 +73,14 @@ namespace Microsoft.DotNet.Tools.Run
FrameworkConstants.FrameworkIdentifiers.NetStandardApp, FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
}; };
var contexts = ProjectContext.CreateContextForEachFramework(Project, null);
ProjectContext context; ProjectContext context;
if (contexts.Count() == 1) if (frameworkContexts.Count() == 1)
{ {
context = contexts.Single(); context = frameworkContexts.Single();
} }
else else
{ {
context = contexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework)); context = frameworkContexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework));
if (context == null) if (context == null)
{ {
throw new InvalidOperationException($"Couldn't find target to run. Possible causes:" + Environment.NewLine + throw new InvalidOperationException($"Couldn't find target to run. Possible causes:" + Environment.NewLine +
@ -88,11 +89,11 @@ namespace Microsoft.DotNet.Tools.Run
} }
} }
_context = context.CreateRuntimeContext(rids); _context = _workspace.GetRuntimeContext(context, rids);
} }
else else
{ {
_context = ProjectContext.Create(Project, NuGetFramework.Parse(Framework), rids); _context = _workspace.GetProjectContext(Project, NuGetFramework.Parse(Framework), rids);
} }
if (Args == null) if (Args == null)
@ -107,6 +108,9 @@ namespace Microsoft.DotNet.Tools.Run
private int RunExecutable() private int RunExecutable()
{ {
// Set up the workspace
_workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
CalculateDefaultsForNonAssigned(); CalculateDefaultsForNonAssigned();
// Compile to that directory // Compile to that directory

View file

@ -42,7 +42,10 @@ namespace Microsoft.DotNet.Tools.Test
RegisterForParentProcessExit(dotnetTestParams.ParentProcessId.Value); RegisterForParentProcessExit(dotnetTestParams.ParentProcessId.Value);
} }
var projectContexts = CreateProjectContexts(dotnetTestParams.ProjectPath, dotnetTestParams.Runtime); // Create a workspace
var workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
var projectContexts = CreateProjectContexts(workspace, dotnetTestParams.ProjectPath, dotnetTestParams.Runtime);
var projectContext = projectContexts.First(); var projectContext = projectContexts.First();
@ -98,7 +101,7 @@ namespace Microsoft.DotNet.Tools.Test
} }
} }
private static IEnumerable<ProjectContext> CreateProjectContexts(string projectPath, string runtime) private static IEnumerable<ProjectContext> CreateProjectContexts(WorkspaceContext workspace, string projectPath, string runtime)
{ {
projectPath = projectPath ?? Directory.GetCurrentDirectory(); projectPath = projectPath ?? Directory.GetCurrentDirectory();
@ -116,7 +119,8 @@ namespace Microsoft.DotNet.Tools.Test
new[] { runtime } : new[] { runtime } :
PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
return ProjectContext.CreateContextForEachFramework(projectPath).Select(context => context.CreateRuntimeContext(runtimeIdentifiers)); var contexts = workspace.GetProjectContextCollection(projectPath).FrameworkOnlyContexts;
return contexts.Select(c => workspace.GetRuntimeContext(c, runtimeIdentifiers));
} }
} }
} }

View file

@ -43,14 +43,14 @@ namespace Microsoft.DotNet.ProjectModel.Tests
} }
[Theory] [Theory]
[InlineDataAttribute("TestMscorlibReference", true)] [InlineData("TestMscorlibReference", true)]
[InlineDataAttribute("TestMscorlibReference", false)] [InlineData("TestMscorlibReference", false)]
[InlineDataAttribute("TestMicrosoftCSharpReference", true)] [InlineData("TestMicrosoftCSharpReference", true)]
[InlineDataAttribute("TestMicrosoftCSharpReference", false)] [InlineData("TestMicrosoftCSharpReference", false)]
[InlineDataAttribute("TestSystemReference", true)] [InlineData("TestSystemReference", true)]
[InlineDataAttribute("TestSystemReference", false)] [InlineData("TestSystemReference", false)]
[InlineDataAttribute("TestSystemCoreReference", true)] [InlineData("TestSystemCoreReference", true)]
[InlineDataAttribute("TestSystemCoreReference", false)] [InlineData("TestSystemCoreReference", false)]
public void TestDuplicateDefaultDesktopReferences(string sampleName, bool withLockFile) public void TestDuplicateDefaultDesktopReferences(string sampleName, bool withLockFile)
{ {
var instance = TestAssetsManager.CreateTestInstance(sampleName); var instance = TestAssetsManager.CreateTestInstance(sampleName);
@ -65,7 +65,7 @@ namespace Microsoft.DotNet.ProjectModel.Tests
Assert.Equal(4, context.RootProject.Dependencies.Count()); Assert.Equal(4, context.RootProject.Dependencies.Count());
} }
[Fact] [Fact]
public void NoDuplicateReferencesWhenFrameworkMissing() public void NoDuplicateReferencesWhenFrameworkMissing()
{ {
@ -79,7 +79,7 @@ namespace Microsoft.DotNet.ProjectModel.Tests
// Will fail with dupes if any // Will fail with dupes if any
context.LibraryManager.GetLibraries().ToDictionary(l => l.Identity.Name); context.LibraryManager.GetLibraries().ToDictionary(l => l.Identity.Name);
} }
[Fact] [Fact]
public void NetCore50ShouldNotResolveFrameworkAssemblies() public void NetCore50ShouldNotResolveFrameworkAssemblies()
{ {

View file

@ -109,12 +109,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr) private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
{ {
CurrentProcess = StartProcess(executable, args); CurrentProcess = StartProcess(executable, args);
var threadOut = stdOut.BeginRead(CurrentProcess.StandardOutput); var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
var threadErr = stdErr.BeginRead(CurrentProcess.StandardError); var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
CurrentProcess.WaitForExit(); CurrentProcess.WaitForExit();
threadOut.Join(); Task.WaitAll(taskOut, taskErr);
threadErr.Join();
var result = new CommandResult( var result = new CommandResult(
CurrentProcess.StartInfo, CurrentProcess.StartInfo,
@ -128,14 +127,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private Task<CommandResult> RunProcessAsync(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr) private Task<CommandResult> RunProcessAsync(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
{ {
CurrentProcess = StartProcess(executable, args); CurrentProcess = StartProcess(executable, args);
var threadOut = stdOut.BeginRead(CurrentProcess.StandardOutput); var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
var threadErr = stdErr.BeginRead(CurrentProcess.StandardError); var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
var tcs = new TaskCompletionSource<CommandResult>(); var tcs = new TaskCompletionSource<CommandResult>();
CurrentProcess.Exited += (sender, arg) => CurrentProcess.Exited += (sender, arg) =>
{ {
threadOut.Join(); Task.WaitAll(taskOut, taskErr);
threadErr.Join();
var result = new CommandResult( var result = new CommandResult(
CurrentProcess.StartInfo, CurrentProcess.StartInfo,
CurrentProcess.ExitCode, CurrentProcess.ExitCode,

View file

@ -20,6 +20,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
private Mock<ICompiler> _nativeCompilerMock; private Mock<ICompiler> _nativeCompilerMock;
private List<ProjectContext> _contexts; private List<ProjectContext> _contexts;
private BuildCommandApp _args; private BuildCommandApp _args;
private readonly WorkspaceContext _workspace;
public GivenACompilationDriverController() public GivenACompilationDriverController()
{ {
@ -34,12 +35,13 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
.Compile(It.IsAny<ProjectContext>(), It.IsAny<BuildCommandApp>())) .Compile(It.IsAny<ProjectContext>(), It.IsAny<BuildCommandApp>()))
.Returns(true); .Returns(true);
_workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
_contexts = new List<ProjectContext> _contexts = new List<ProjectContext>
{ {
ProjectContext.Create(_projectJson, NuGetFramework.Parse("netcoreapp1.0")) _workspace.GetProjectContext(_projectJson, NuGetFramework.Parse("netcoreapp1.0"))
}; };
_args = new BuildCommandApp("dotnet compile", ".NET Compiler", "Compiler for the .NET Platform"); _args = new BuildCommandApp("dotnet compile", ".NET Compiler", "Compiler for the .NET Platform", WorkspaceContext.Create(designTime: false));
} }
[Fact] [Fact]

View file

@ -188,7 +188,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
It.IsAny<string>())) It.IsAny<string>()))
.Returns(command.Object); .Returns(command.Object);
var _args = new BuildCommandApp("dotnet compile", ".NET Compiler", "Compiler for the .NET Platform"); var _args = new BuildCommandApp("dotnet compile", ".NET Compiler", "Compiler for the .NET Platform", WorkspaceContext.Create(designTime: false));
_args.ConfigValue = ConfigValue; _args.ConfigValue = ConfigValue;
PreCompileScriptVariables = new Dictionary<string, string>(); PreCompileScriptVariables = new Dictionary<string, string>();
@ -219,7 +219,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
rids.Add(rid); rids.Add(rid);
} }
var context = ProjectContext.Create(projectJson, TestAssetFramework, rids); var workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
var context = workspace.GetProjectContext(projectJson, TestAssetFramework, rids);
managedCompiler.Compile(context, _args); managedCompiler.Compile(context, _args);
RuntimeOutputDir = Path.Combine(OutputPath, rid); RuntimeOutputDir = Path.Combine(OutputPath, rid);

View file

@ -228,7 +228,7 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
_writer.Dispose(); _writer.Dispose();
_networkStream.Dispose(); _networkStream.Dispose();
_readCancellationToken.Cancel(); _readCancellationToken.Cancel();
try try
{ {
_socket.Shutdown(SocketShutdown.Both); _socket.Shutdown(SocketShutdown.Both);

View file

@ -506,13 +506,13 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
var testProjectRoot = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects", "ValidCase01"); var testProjectRoot = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects", "ValidCase01");
foreach (var classLibrary in classLibraries) foreach (var classLibrary in classLibraries)
{ {
dependencies.RetrieveDependency(classLibrary) var dependency = dependencies.RetrieveDependency(classLibrary);
.AssertProperty("Type", LibraryType.MSBuildProject.ToString()) dependency.AssertProperty("Type", LibraryType.MSBuildProject.ToString());
.AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, classLibrary, $"{classLibrary}.csproj"))) dependency.AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, classLibrary, $"{classLibrary}.csproj")));
.AssertProperty<bool>("Resolved", true) dependency.AssertProperty<bool>("Resolved", true);
.AssertProperty("Name", classLibrary) dependency.AssertProperty("Name", classLibrary);
.AssertProperty<JArray>("Errors", array => array.Count == 0) dependency.AssertProperty<JArray>("Errors", array => array.Count == 0);
.AssertProperty<JArray>("Warnings", array => array.Count == 0); dependency.AssertProperty<JArray>("Warnings", array => array.Count == 0);
} }
var references = messages.RetrieveSingleMessage(MessageTypes.References) var references = messages.RetrieveSingleMessage(MessageTypes.References)
@ -632,12 +632,12 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
afterDependencies.RetrieveDependency("ClassLibrary3"); afterDependencies.RetrieveDependency("ClassLibrary3");
} }
} }
[Fact] [Fact]
public void TestMscorlibLibraryDuplication() public void TestMscorlibLibraryDuplication()
{ {
var projectPath = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MscorlibLibraryDuplication"); var projectPath = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MscorlibLibraryDuplication");
using (var server = new DthTestServer(_loggerFactory)) using (var server = new DthTestServer(_loggerFactory))
using (var client = new DthTestClient(server, _loggerFactory)) using (var client = new DthTestClient(server, _loggerFactory))
{ {

View file

@ -28,7 +28,8 @@
} }
}, },
"content": [ "content": [
"../../TestAssets/TestProjects/ProjectWithTests/project.json" "../../TestAssets/TestProjects/ProjectWithTests/project.json",
"../../TestAssets/TestProjects/ProjectWithTests/project.lock.json"
], ],
"testRunner": "xunit" "testRunner": "xunit"
} }