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:
parent
80df3688b1
commit
ef0ca39da1
42 changed files with 496 additions and 268 deletions
|
@ -1,8 +1,5 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"compilationOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.5.0-rc2-24022",
|
||||
"System.Runtime.Analyzers": {
|
||||
|
|
|
@ -280,7 +280,7 @@ namespace Microsoft.DotNet.Cli.Build
|
|||
return rid;
|
||||
}
|
||||
|
||||
[Target]
|
||||
[Target(nameof(PrepareTargets.Init))]
|
||||
public static BuildTargetResult CompileStage1(BuildTargetContext c)
|
||||
{
|
||||
CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "src"));
|
||||
|
@ -305,7 +305,7 @@ namespace Microsoft.DotNet.Cli.Build
|
|||
return result;
|
||||
}
|
||||
|
||||
[Target]
|
||||
[Target(nameof(PrepareTargets.Init))]
|
||||
public static BuildTargetResult CompileStage2(BuildTargetContext c)
|
||||
{
|
||||
var configuration = c.BuildContext.Get<string>("Configuration");
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
|
@ -51,16 +52,15 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
// Reset the Reporters to the new Console Out and Error.
|
||||
Reporter.Reset();
|
||||
|
||||
Thread threadOut = _stdOut.BeginRead(new StreamReader(outStream));
|
||||
Thread threadErr = _stdErr.BeginRead(new StreamReader(errorStream));
|
||||
var taskOut = _stdOut.BeginRead(new StreamReader(outStream));
|
||||
var taskErr = _stdErr.BeginRead(new StreamReader(errorStream));
|
||||
|
||||
int exitCode = _builtInCommand(_commandArgs.ToArray());
|
||||
|
||||
outStream.DoneWriting();
|
||||
errorStream.DoneWriting();
|
||||
|
||||
threadOut.Join();
|
||||
threadErr.Join();
|
||||
Task.WaitAll(taskOut, taskErr);
|
||||
|
||||
// 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}");
|
||||
|
|
|
@ -7,8 +7,9 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using NuGet.Frameworks;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
|
@ -131,12 +132,11 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
|
||||
Reporter.Verbose.WriteLine($"Process ID: {_process.Id}");
|
||||
|
||||
var threadOut = _stdOut.BeginRead(_process.StandardOutput);
|
||||
var threadErr = _stdErr.BeginRead(_process.StandardError);
|
||||
|
||||
var taskOut = _stdOut.BeginRead(_process.StandardOutput);
|
||||
var taskErr = _stdErr.BeginRead(_process.StandardError);
|
||||
_process.WaitForExit();
|
||||
threadOut.Join();
|
||||
threadErr.Join();
|
||||
|
||||
Task.WaitAll(taskOut, taskErr);
|
||||
|
||||
var exitCode = _process.ExitCode;
|
||||
|
||||
|
|
|
@ -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.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils
|
||||
{
|
||||
|
@ -43,11 +46,9 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
return this;
|
||||
}
|
||||
|
||||
public Thread BeginRead(TextReader reader)
|
||||
public Task BeginRead(TextReader reader)
|
||||
{
|
||||
var thread = new Thread(() => Read(reader)) { IsBackground = true };
|
||||
thread.Start();
|
||||
return thread;
|
||||
return Task.Run(() => Read(reader));
|
||||
}
|
||||
|
||||
public void Read(TextReader reader)
|
||||
|
|
|
@ -13,10 +13,12 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
{
|
||||
private readonly LockFile _lockFile;
|
||||
private Dictionary<string, IList<LockFileTargetLibrary>> _msbuildTargetLibraries;
|
||||
private readonly LockFileReader _reader;
|
||||
|
||||
public LockFilePatcher(LockFile lockFile)
|
||||
public LockFilePatcher(LockFile lockFile, LockFileReader reader)
|
||||
{
|
||||
_lockFile = lockFile;
|
||||
_reader = reader;
|
||||
|
||||
var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(MSBuildDependencyProvider.IsMSBuildProjectLibrary);
|
||||
_msbuildTargetLibraries = msbuildProjectLibraries.ToDictionary(GetProjectLibraryKey, l => GetTargetsForLibrary(_lockFile, l));
|
||||
|
@ -27,7 +29,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
var exportFilePath = GetExportFilePath(_lockFile.LockFilePath);
|
||||
if (File.Exists(exportFilePath) && _msbuildTargetLibraries.Any())
|
||||
{
|
||||
var exportFile = LockFileReader.ReadExportFile(exportFilePath);
|
||||
var exportFile = _reader.ReadExportFile(exportFilePath);
|
||||
PatchLockWithExport(exportFile);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -13,15 +13,24 @@ using NuGet.Versioning;
|
|||
|
||||
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)
|
||||
{
|
||||
using (var stream = ResilientFileStreamOpener.OpenFile(lockFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
return Read(lockFilePath, stream, designTime);
|
||||
return new LockFileReader().ReadLockFile(lockFilePath, stream, designTime);
|
||||
}
|
||||
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
|
||||
{
|
||||
|
@ -50,7 +59,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
|
||||
if (!designTime)
|
||||
{
|
||||
var patcher = new LockFilePatcher(lockFile);
|
||||
var patcher = new LockFilePatcher(lockFile, this);
|
||||
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))
|
||||
{
|
||||
|
@ -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);
|
||||
lockFile.Version = ReadInt(cursor, "version", defaultValue: int.MinValue);
|
||||
|
@ -111,7 +120,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
return lockFile;
|
||||
}
|
||||
|
||||
private static void ReadLibrary(JsonObject json, LockFile lockFile)
|
||||
private void ReadLibrary(JsonObject json, LockFile lockFile)
|
||||
{
|
||||
if (json == null)
|
||||
{
|
||||
|
@ -128,9 +137,9 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
|
||||
var parts = key.Split(new[] { '/' }, 2);
|
||||
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))
|
||||
{
|
||||
|
@ -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;
|
||||
if (jobject == null)
|
||||
|
@ -172,10 +181,10 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
|
||||
var target = new LockFileTarget();
|
||||
var parts = property.Split(new[] { '/' }, 2);
|
||||
target.TargetFramework = NuGetFramework.Parse(parts[0]);
|
||||
target.TargetFramework = _symbols.GetFramework(parts[0]);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
target.RuntimeIdentifier = parts[1];
|
||||
target.RuntimeIdentifier = _symbols.GetString(parts[1]);
|
||||
}
|
||||
|
||||
target.Libraries = ReadObject(jobject, ReadTargetLibrary);
|
||||
|
@ -183,7 +192,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
return target;
|
||||
}
|
||||
|
||||
private static LockFileTargetLibrary ReadTargetLibrary(string property, JsonValue json)
|
||||
private LockFileTargetLibrary ReadTargetLibrary(string property, JsonValue json)
|
||||
{
|
||||
var jobject = json as JsonObject;
|
||||
if (jobject == null)
|
||||
|
@ -194,17 +203,17 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
var library = new LockFileTargetLibrary();
|
||||
|
||||
var parts = property.Split(new[] { '/' }, 2);
|
||||
library.Name = parts[0];
|
||||
library.Name = _symbols.GetString(parts[0]);
|
||||
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");
|
||||
if (framework != null)
|
||||
{
|
||||
library.TargetFramework = NuGetFramework.Parse(framework);
|
||||
library.TargetFramework = _symbols.GetFramework(framework);
|
||||
}
|
||||
|
||||
library.Dependencies = ReadObject(jobject.ValueAsJsonObject("dependencies"), ReadPackageDependency);
|
||||
|
@ -215,10 +224,11 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
library.NativeLibraries = ReadObject(jobject.ValueAsJsonObject("native"), ReadFileItem);
|
||||
library.ContentFiles = ReadObject(jobject.ValueAsJsonObject("contentFiles"), ReadContentFile);
|
||||
library.RuntimeTargets = ReadObject(jobject.ValueAsJsonObject("runtimeTargets"), ReadRuntimeTarget);
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
private static LockFileRuntimeTarget ReadRuntimeTarget(string property, JsonValue json)
|
||||
private LockFileRuntimeTarget ReadRuntimeTarget(string property, JsonValue json)
|
||||
{
|
||||
var jsonObject = json as JsonObject;
|
||||
if (jsonObject == null)
|
||||
|
@ -227,13 +237,13 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
}
|
||||
|
||||
return new LockFileRuntimeTarget(
|
||||
path: property,
|
||||
runtime: jsonObject.ValueAsString("rid"),
|
||||
assetType: jsonObject.ValueAsString("assetType")
|
||||
path: _symbols.GetString(property),
|
||||
runtime: _symbols.GetString(jsonObject.ValueAsString("rid")),
|
||||
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()
|
||||
{
|
||||
|
@ -248,7 +258,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
BuildAction.TryParse(jsonObject.ValueAsString("buildAction"), out action);
|
||||
|
||||
contentFile.BuildAction = action;
|
||||
var codeLanguage = jsonObject.ValueAsString("codeLanguage");
|
||||
var codeLanguage = _symbols.GetString(jsonObject.ValueAsString("codeLanguage"));
|
||||
if (codeLanguage == "any")
|
||||
{
|
||||
codeLanguage = null;
|
||||
|
@ -262,37 +272,37 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
return contentFile;
|
||||
}
|
||||
|
||||
private static ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json)
|
||||
private ProjectFileDependencyGroup ReadProjectFileDependencyGroup(string property, JsonValue json)
|
||||
{
|
||||
return new ProjectFileDependencyGroup(
|
||||
string.IsNullOrEmpty(property) ? null : NuGetFramework.Parse(property),
|
||||
ReadArray(json, ReadString));
|
||||
}
|
||||
|
||||
private static PackageDependency ReadPackageDependency(string property, JsonValue json)
|
||||
private PackageDependency ReadPackageDependency(string property, JsonValue json)
|
||||
{
|
||||
var versionStr = ReadString(json);
|
||||
return new PackageDependency(
|
||||
property,
|
||||
versionStr == null ? null : VersionRange.Parse(versionStr));
|
||||
_symbols.GetString(property),
|
||||
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;
|
||||
|
||||
if (jobject != null)
|
||||
{
|
||||
foreach (var subProperty in jobject.Keys)
|
||||
{
|
||||
item.Properties[subProperty] = jobject.ValueAsString(subProperty);
|
||||
item.Properties[_symbols.GetString(subProperty)] = jobject.ValueAsString(subProperty);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private static string ReadFrameworkAssemblyReference(JsonValue json)
|
||||
private string ReadFrameworkAssemblyReference(JsonValue json)
|
||||
{
|
||||
return ReadString(json);
|
||||
}
|
||||
|
@ -318,9 +328,9 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
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)
|
||||
|
@ -368,11 +378,11 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
}
|
||||
}
|
||||
|
||||
private static string ReadString(JsonValue json)
|
||||
private string ReadString(JsonValue json)
|
||||
{
|
||||
if (json is JsonString)
|
||||
{
|
||||
return (json as JsonString).Value;
|
||||
return _symbols.GetString((json as JsonString).Value);
|
||||
}
|
||||
else if (json is JsonNull)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -154,39 +154,6 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
.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)
|
||||
{
|
||||
return OutputPathsCalculator.GetOutputPaths(ProjectFile,
|
||||
|
|
|
@ -132,16 +132,42 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
EnsureProjectLoaded();
|
||||
LockFile = LockFile ?? LockFileResolver(ProjectDirectory);
|
||||
|
||||
if (LockFile != null)
|
||||
if (LockFile != null && LockFile.Targets.Any())
|
||||
{
|
||||
var deduper = new HashSet<string>();
|
||||
foreach (var target in LockFile.Targets)
|
||||
{
|
||||
yield return new ProjectContextBuilder()
|
||||
var id = $"{target.TargetFramework}/{target.RuntimeIdentifier}";
|
||||
if (deduper.Add(id))
|
||||
{
|
||||
var builder = new ProjectContextBuilder()
|
||||
.WithProject(Project)
|
||||
.WithLockFile(LockFile)
|
||||
.WithTargetFramework(target.TargetFramework)
|
||||
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier })
|
||||
.Build();
|
||||
.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;
|
||||
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;
|
||||
EnsureProjectLoaded();
|
||||
|
@ -274,7 +309,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
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
|
||||
// report an error
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
{
|
||||
|
@ -13,6 +15,8 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
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 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()
|
||||
{
|
||||
Project = null;
|
||||
|
|
|
@ -85,8 +85,16 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
var project = new Project();
|
||||
|
||||
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)
|
||||
{
|
||||
throw FileFormatException.Create(
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.Extensions.DependencyModel.Resolution;
|
||||
|
@ -23,7 +25,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
|
||||
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[]>
|
||||
{
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
LibraryDependencyType.Default));
|
||||
}
|
||||
|
||||
if (!targetFramework.IsPackageBased)
|
||||
if (!targetFramework.IsPackageBased())
|
||||
{
|
||||
// Only add framework assemblies for non-package based frameworks.
|
||||
foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies)
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
|
|||
LibraryDependencyType.Default));
|
||||
}
|
||||
|
||||
if (!targetFramework.IsPackageBased)
|
||||
if (!targetFramework.IsPackageBased())
|
||||
{
|
||||
// Only add framework assemblies for non-package based frameworks.
|
||||
foreach (var frameworkAssembly in targetLibrary.FrameworkAssemblies)
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
{
|
||||
|
@ -28,9 +29,16 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
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)
|
||||
{
|
||||
AddProject(path);
|
||||
|
@ -42,30 +50,59 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
/// <summary>
|
||||
/// 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
|
||||
/// are added to the WorkspaceContext.
|
||||
///
|
||||
/// If the given path points to a project.json, all the projects it referenced as well as itself
|
||||
/// 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>
|
||||
public static WorkspaceContext CreateFrom(string projectPath)
|
||||
public static WorkspaceContext CreateFrom(string projectPath, bool designTime)
|
||||
{
|
||||
var projectPaths = ResolveProjectPath(projectPath);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -104,7 +141,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
foreach (var projectDirectory in basePaths)
|
||||
{
|
||||
var project = GetProject(projectDirectory).Model;
|
||||
var project = GetProjectCore(projectDirectory).Model;
|
||||
if (project == null)
|
||||
{
|
||||
continue;
|
||||
|
@ -116,7 +153,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
foreach (var reference in GetProjectReferences(projectContext))
|
||||
{
|
||||
var referencedProject = GetProject(reference.Path).Model;
|
||||
var referencedProject = GetProjectCore(reference.Path).Model;
|
||||
if (referencedProject != null)
|
||||
{
|
||||
_projects.Add(referencedProject.ProjectDirectory);
|
||||
|
@ -130,29 +167,100 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
|
||||
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)
|
||||
{
|
||||
var normalizedPath = NormalizeProjectPath(projectPath);
|
||||
if (normalizedPath == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _projectContextsCache.AddOrUpdate(
|
||||
projectPath,
|
||||
normalizedPath,
|
||||
key => AddProjectContextEntry(key, null),
|
||||
(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(
|
||||
projectDirectory,
|
||||
normalizedPath,
|
||||
key => AddProjectEntry(key, null),
|
||||
(key, oldEntry) => AddProjectEntry(key, oldEntry));
|
||||
}
|
||||
|
||||
private LockFile GetLockFile(string projectDirectory)
|
||||
{
|
||||
var normalizedPath = NormalizeProjectPath(projectDirectory);
|
||||
if (normalizedPath == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _lockFileCache.AddOrUpdate(
|
||||
projectDirectory,
|
||||
normalizedPath,
|
||||
key => AddLockFileEntry(key, null),
|
||||
(key, oldEntry) => AddLockFileEntry(key, oldEntry)).Model;
|
||||
}
|
||||
|
@ -173,7 +281,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
if (currentEntry.IsInvalid)
|
||||
{
|
||||
Project project;
|
||||
if (!ProjectReader.TryGetProject(projectDirectory, out project, currentEntry.Diagnostics))
|
||||
if (!ProjectReader.TryGetProject(projectDirectory, out project, currentEntry.Diagnostics, _settings))
|
||||
{
|
||||
currentEntry.Reset();
|
||||
}
|
||||
|
@ -211,7 +319,7 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
try
|
||||
{
|
||||
currentEntry.Model = LockFileReader.Read(currentEntry.FilePath, fs, designTime: true);
|
||||
currentEntry.Model = _lockFileReader.ReadLockFile(currentEntry.FilePath, fs, designTime: true);
|
||||
currentEntry.UpdateLastWriteTimeUtc();
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
|
@ -238,8 +346,9 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
currentEntry = new ProjectContextCollection();
|
||||
}
|
||||
|
||||
var projectEntry = GetProject(projectDirectory);
|
||||
if (projectEntry.Model == null)
|
||||
var projectEntry = GetProjectCore(projectDirectory);
|
||||
|
||||
if (projectEntry?.Model == null)
|
||||
{
|
||||
// project doesn't exist anymore
|
||||
currentEntry.Reset();
|
||||
|
@ -251,17 +360,9 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
{
|
||||
currentEntry.Reset();
|
||||
|
||||
foreach (var framework in project.GetTargetFrameworks())
|
||||
{
|
||||
var builder = new ProjectContextBuilder()
|
||||
.WithProjectResolver(path => GetProject(path).Model)
|
||||
.WithLockFileResolver(path => GetLockFile(path))
|
||||
.WithProject(project)
|
||||
.WithTargetFramework(framework.FrameworkName)
|
||||
.AsDesignTime();
|
||||
var builder = InitializeProjectContextBuilder(project);
|
||||
|
||||
currentEntry.ProjectContexts.Add(builder.Build());
|
||||
}
|
||||
currentEntry.ProjectContexts.AddRange(builder.BuildAllTargets());
|
||||
|
||||
currentEntry.Project = project;
|
||||
currentEntry.ProjectFilePath = project.ProjectFilePath;
|
||||
|
@ -280,6 +381,20 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
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 DateTime _lastWriteTimeUtc;
|
||||
|
@ -400,5 +515,11 @@ namespace Microsoft.DotNet.ProjectModel
|
|||
yield return description;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RidsMatch(string rid, IEnumerable<string> compatibleRids)
|
||||
{
|
||||
return (string.IsNullOrEmpty(rid) && !compatibleRids.Any()) ||
|
||||
(compatibleRids.Contains(rid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,12 +52,17 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
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
|
||||
{
|
||||
throw new InvalidOperationException($"Could not resolve project path from '{value}':" +
|
||||
"1. It's not project file" +
|
||||
"2. It's not directory containing project.json file" +
|
||||
"3. Globbing returned no mathces");
|
||||
throw new InvalidOperationException($"Couldn't find '{Project.FileName}' in '{value}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
|
@ -44,11 +45,16 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
public bool ShouldNotUseIncrementality { 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
|
||||
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
|
||||
{
|
||||
Name = name,
|
||||
|
@ -99,6 +105,18 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
ShouldNotUseIncrementality = _shouldNotUseIncrementalityArgument.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);
|
||||
IEnumerable<NuGetFramework> frameworks = null;
|
||||
if (_frameworkOption.HasValue())
|
||||
|
|
|
@ -18,16 +18,19 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
private readonly string _outputPath;
|
||||
private readonly string _buildBasePath;
|
||||
private readonly IList<string> _runtimes;
|
||||
private readonly WorkspaceContext _workspace;
|
||||
|
||||
public CompilerIOManager(string configuration,
|
||||
string outputPath,
|
||||
string buildBasePath,
|
||||
IEnumerable<string> runtimes)
|
||||
IEnumerable<string> runtimes,
|
||||
WorkspaceContext workspace)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_outputPath = outputPath;
|
||||
_buildBasePath = buildBasePath;
|
||||
_runtimes = runtimes.ToList();
|
||||
_workspace = workspace;
|
||||
}
|
||||
|
||||
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());
|
||||
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())
|
||||
{
|
||||
allOutputPath.Add(path);
|
||||
|
|
|
@ -33,7 +33,8 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
args.ConfigValue,
|
||||
args.OutputValue,
|
||||
args.BuildBasePathValue,
|
||||
args.GetRuntimes()
|
||||
args.GetRuntimes(),
|
||||
args.Workspace
|
||||
);
|
||||
_scriptRunner = new ScriptRunner();
|
||||
_commandFactory = new DotNetCommandFactory();
|
||||
|
@ -120,7 +121,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
private void MakeRunnable(ProjectGraphNode graphNode)
|
||||
{
|
||||
var runtimeContext = graphNode.ProjectContext.ProjectFile.HasRuntimeOutput(_args.ConfigValue) ?
|
||||
graphNode.ProjectContext.CreateRuntimeContext(_args.GetRuntimes()) :
|
||||
_args.Workspace.GetRuntimeContext(graphNode.ProjectContext, _args.GetRuntimes()) :
|
||||
graphNode.ProjectContext;
|
||||
|
||||
var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
|
||||
|
|
|
@ -15,13 +15,19 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -40,7 +46,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
var builderCommandApp = args;
|
||||
var graphCollector = new ProjectGraphCollector(
|
||||
!builderCommandApp.ShouldSkipDependencies,
|
||||
(project, target) => ProjectContext.Create(project, target));
|
||||
(project, target) => args.Workspace.GetProjectContext(project, target));
|
||||
|
||||
var contexts = ResolveRootContexts(files, frameworks, args);
|
||||
var graph = graphCollector.Collect(contexts).ToArray();
|
||||
|
@ -53,19 +59,11 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
IEnumerable<NuGetFramework> frameworks,
|
||||
BuildCommandApp args)
|
||||
{
|
||||
|
||||
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)
|
||||
{
|
||||
var project = ProjectReader.GetProject(file);
|
||||
var project = args.Workspace.GetProject(file);
|
||||
var projectFrameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName);
|
||||
if (!projectFrameworks.Any())
|
||||
{
|
||||
|
@ -91,11 +89,7 @@ namespace Microsoft.DotNet.Tools.Build
|
|||
|
||||
foreach (var framework in selectedFrameworks)
|
||||
{
|
||||
tasks.Add(Task.Run(() => new ProjectContextBuilder()
|
||||
.WithProjectDirectory(Path.GetDirectoryName(file))
|
||||
.WithTargetFramework(framework)
|
||||
.WithReaderSettings(settings)
|
||||
.Build()));
|
||||
tasks.Add(Task.Run(() => args.Workspace.GetProjectContext(file, framework)));
|
||||
}
|
||||
}
|
||||
return Task.WhenAll(tasks).GetAwaiter().GetResult();
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
success &= _managedCompiler.Compile(context, args);
|
||||
if (args.IsNativeValue && success)
|
||||
{
|
||||
var runtimeContext = context.CreateRuntimeContext(args.GetRuntimes());
|
||||
var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
|
||||
success &= _nativeCompiler.Compile(runtimeContext, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
|
||||
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);
|
||||
|
||||
contextVariables.Add(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.Server.Helpers;
|
||||
using Microsoft.DotNet.ProjectModel.Server.Models;
|
||||
|
@ -35,7 +36,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
|
|||
snapshot.ProjectSearchPaths = currentSearchPaths.ToList();
|
||||
snapshot.GlobalJsonPath = globalSettings?.FilePath;
|
||||
|
||||
foreach (var projectContext in projectContextsCollection.ProjectContexts)
|
||||
foreach (var projectContext in projectContextsCollection.FrameworkOnlyContexts)
|
||||
{
|
||||
snapshot.ProjectContexts[projectContext.TargetFramework] =
|
||||
ProjectContextSnapshot.Create(projectContext, configuration, currentSearchPaths);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
|
@ -26,7 +27,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
|
|||
_hostName = hostName;
|
||||
_loggerFactory = loggerFactory;
|
||||
_protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory);
|
||||
_workspaceContext = WorkspaceContext.Create();
|
||||
_workspaceContext = WorkspaceContext.Create(designTime: true);
|
||||
_projects = new Dictionary<int, ProjectManager>();
|
||||
}
|
||||
|
||||
|
@ -51,6 +52,8 @@ namespace Microsoft.DotNet.ProjectModel.Server
|
|||
|
||||
var logger = loggerFactory.CreateLogger<ProjectModelServerCommand>();
|
||||
|
||||
try
|
||||
{
|
||||
if (!MonitorHostProcess(hostpid, logger))
|
||||
{
|
||||
return 1;
|
||||
|
@ -70,6 +73,12 @@ namespace Microsoft.DotNet.ProjectModel.Server
|
|||
|
||||
var program = new ProjectModelServerCommand(intPort, hostname.Value(), loggerFactory);
|
||||
program.OpenChannel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogCritical($"Unhandled exception in server main: {ex}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.IO;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Publish
|
||||
{
|
||||
|
@ -44,6 +45,8 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
publish.VersionSuffix = versionSuffix.Value();
|
||||
publish.ShouldBuild = !noBuild.HasValue();
|
||||
|
||||
publish.Workspace = WorkspaceContext.Create(versionSuffix.Value(), designTime: false);
|
||||
|
||||
if (string.IsNullOrEmpty(publish.ProjectPath))
|
||||
{
|
||||
publish.ProjectPath = Directory.GetCurrentDirectory();
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
public string Runtime { get; set; }
|
||||
public bool NativeSubdirectories { get; set; }
|
||||
public NuGetFramework NugetFramework { get; set; }
|
||||
public WorkspaceContext Workspace { get; set; }
|
||||
public IList<ProjectContext> ProjectContexts { get; set; }
|
||||
public string VersionSuffix { get; 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");
|
||||
}
|
||||
|
||||
var allContexts = framework == null ?
|
||||
ProjectContext.CreateContextForEachFramework(projectPath) :
|
||||
new[] { ProjectContext.Create(projectPath, framework) };
|
||||
var contexts = Workspace.GetProjectContextCollection(projectPath).FrameworkOnlyContexts;
|
||||
|
||||
var runtimes = !string.IsNullOrEmpty(runtime) ?
|
||||
new [] {runtime} :
|
||||
PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
|
||||
return allContexts.Select(c => c.CreateRuntimeContext(runtimes));
|
||||
contexts = framework == null ?
|
||||
contexts :
|
||||
contexts.Where(c => Equals(c.TargetFramework, framework));
|
||||
|
||||
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)
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Tools.Run
|
|||
|
||||
ProjectContext _context;
|
||||
List<string> _args;
|
||||
private WorkspaceContext _workspace;
|
||||
|
||||
public int Start()
|
||||
{
|
||||
|
@ -60,6 +61,8 @@ namespace Microsoft.DotNet.Tools.Run
|
|||
Configuration = Constants.DefaultConfiguration;
|
||||
}
|
||||
|
||||
var frameworkContexts = _workspace.GetProjectContexts(Project).Where(c => string.IsNullOrEmpty(c.RuntimeIdentifier));
|
||||
|
||||
var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
|
||||
|
||||
if (Framework == null)
|
||||
|
@ -70,16 +73,14 @@ namespace Microsoft.DotNet.Tools.Run
|
|||
FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
|
||||
};
|
||||
|
||||
var contexts = ProjectContext.CreateContextForEachFramework(Project, null);
|
||||
|
||||
ProjectContext context;
|
||||
if (contexts.Count() == 1)
|
||||
if (frameworkContexts.Count() == 1)
|
||||
{
|
||||
context = contexts.Single();
|
||||
context = frameworkContexts.Single();
|
||||
}
|
||||
else
|
||||
{
|
||||
context = contexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework));
|
||||
context = frameworkContexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework));
|
||||
if (context == null)
|
||||
{
|
||||
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
|
||||
{
|
||||
_context = ProjectContext.Create(Project, NuGetFramework.Parse(Framework), rids);
|
||||
_context = _workspace.GetProjectContext(Project, NuGetFramework.Parse(Framework), rids);
|
||||
}
|
||||
|
||||
if (Args == null)
|
||||
|
@ -107,6 +108,9 @@ namespace Microsoft.DotNet.Tools.Run
|
|||
|
||||
private int RunExecutable()
|
||||
{
|
||||
// Set up the workspace
|
||||
_workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
|
||||
|
||||
CalculateDefaultsForNonAssigned();
|
||||
|
||||
// Compile to that directory
|
||||
|
|
|
@ -42,7 +42,10 @@ namespace Microsoft.DotNet.Tools.Test
|
|||
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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -116,7 +119,8 @@ namespace Microsoft.DotNet.Tools.Test
|
|||
new[] { runtime } :
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,14 +43,14 @@ namespace Microsoft.DotNet.ProjectModel.Tests
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineDataAttribute("TestMscorlibReference", true)]
|
||||
[InlineDataAttribute("TestMscorlibReference", false)]
|
||||
[InlineDataAttribute("TestMicrosoftCSharpReference", true)]
|
||||
[InlineDataAttribute("TestMicrosoftCSharpReference", false)]
|
||||
[InlineDataAttribute("TestSystemReference", true)]
|
||||
[InlineDataAttribute("TestSystemReference", false)]
|
||||
[InlineDataAttribute("TestSystemCoreReference", true)]
|
||||
[InlineDataAttribute("TestSystemCoreReference", false)]
|
||||
[InlineData("TestMscorlibReference", true)]
|
||||
[InlineData("TestMscorlibReference", false)]
|
||||
[InlineData("TestMicrosoftCSharpReference", true)]
|
||||
[InlineData("TestMicrosoftCSharpReference", false)]
|
||||
[InlineData("TestSystemReference", true)]
|
||||
[InlineData("TestSystemReference", false)]
|
||||
[InlineData("TestSystemCoreReference", true)]
|
||||
[InlineData("TestSystemCoreReference", false)]
|
||||
public void TestDuplicateDefaultDesktopReferences(string sampleName, bool withLockFile)
|
||||
{
|
||||
var instance = TestAssetsManager.CreateTestInstance(sampleName);
|
||||
|
|
|
@ -109,12 +109,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
||||
{
|
||||
CurrentProcess = StartProcess(executable, args);
|
||||
var threadOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
var threadErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
|
||||
CurrentProcess.WaitForExit();
|
||||
threadOut.Join();
|
||||
threadErr.Join();
|
||||
Task.WaitAll(taskOut, taskErr);
|
||||
|
||||
var result = new CommandResult(
|
||||
CurrentProcess.StartInfo,
|
||||
|
@ -128,14 +127,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
private Task<CommandResult> RunProcessAsync(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
||||
{
|
||||
CurrentProcess = StartProcess(executable, args);
|
||||
var threadOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
var threadErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
var taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
var taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
|
||||
var tcs = new TaskCompletionSource<CommandResult>();
|
||||
CurrentProcess.Exited += (sender, arg) =>
|
||||
{
|
||||
threadOut.Join();
|
||||
threadErr.Join();
|
||||
Task.WaitAll(taskOut, taskErr);
|
||||
var result = new CommandResult(
|
||||
CurrentProcess.StartInfo,
|
||||
CurrentProcess.ExitCode,
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
|
|||
private Mock<ICompiler> _nativeCompilerMock;
|
||||
private List<ProjectContext> _contexts;
|
||||
private BuildCommandApp _args;
|
||||
private readonly WorkspaceContext _workspace;
|
||||
|
||||
public GivenACompilationDriverController()
|
||||
{
|
||||
|
@ -34,12 +35,13 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
|
|||
.Compile(It.IsAny<ProjectContext>(), It.IsAny<BuildCommandApp>()))
|
||||
.Returns(true);
|
||||
|
||||
_workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
|
||||
_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]
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
|
|||
It.IsAny<string>()))
|
||||
.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;
|
||||
|
||||
PreCompileScriptVariables = new Dictionary<string, string>();
|
||||
|
@ -219,7 +219,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
|
|||
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);
|
||||
|
||||
RuntimeOutputDir = Path.Combine(OutputPath, rid);
|
||||
|
|
|
@ -506,13 +506,13 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
|
|||
var testProjectRoot = Path.Combine(RepoRoot, "TestAssets", "ProjectModelServer", "MSBuildReferencesProjects", "ValidCase01");
|
||||
foreach (var classLibrary in classLibraries)
|
||||
{
|
||||
dependencies.RetrieveDependency(classLibrary)
|
||||
.AssertProperty("Type", LibraryType.MSBuildProject.ToString())
|
||||
.AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, classLibrary, $"{classLibrary}.csproj")))
|
||||
.AssertProperty<bool>("Resolved", true)
|
||||
.AssertProperty("Name", classLibrary)
|
||||
.AssertProperty<JArray>("Errors", array => array.Count == 0)
|
||||
.AssertProperty<JArray>("Warnings", array => array.Count == 0);
|
||||
var dependency = dependencies.RetrieveDependency(classLibrary);
|
||||
dependency.AssertProperty("Type", LibraryType.MSBuildProject.ToString());
|
||||
dependency.AssertProperty("Path", NormalizePathString(Path.Combine(testProjectRoot, classLibrary, $"{classLibrary}.csproj")));
|
||||
dependency.AssertProperty<bool>("Resolved", true);
|
||||
dependency.AssertProperty("Name", classLibrary);
|
||||
dependency.AssertProperty<JArray>("Errors", array => array.Count == 0);
|
||||
dependency.AssertProperty<JArray>("Warnings", array => array.Count == 0);
|
||||
}
|
||||
|
||||
var references = messages.RetrieveSingleMessage(MessageTypes.References)
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
}
|
||||
},
|
||||
"content": [
|
||||
"../../TestAssets/TestProjects/ProjectWithTests/project.json"
|
||||
"../../TestAssets/TestProjects/ProjectWithTests/project.json",
|
||||
"../../TestAssets/TestProjects/ProjectWithTests/project.lock.json"
|
||||
],
|
||||
"testRunner": "xunit"
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue