From 3eb41d4f430d9cd96afbbc109718e55fde17ca28 Mon Sep 17 00:00:00 2001 From: Mihai Codoban Date: Sun, 7 Feb 2021 16:10:14 -0800 Subject: [PATCH] Add /graph:noBuild (#6016) This new option constructs the graph but does not build the nodes. This is useful for a few use cases: determine if a large repo can evaluate all of its projects (e.g., is VS setup right, are all imports magically pointing to where they should, etc) easily investigate evaluation perf. With noBuild, the only thing that MSBuild does is evaluate all projects under a single process, so it's easier to throw it under a profiler. in the future when project caching is available, it can be used to warm up / download the caches but not do the build. generally makes life easier for people that only want to investigate evaluation and not the build. The binlog also shows up nicely containing all the evaluation nodes. --- ref/Microsoft.Build/net/Microsoft.Build.cs | 17 +++ .../netstandard/Microsoft.Build.cs | 17 +++ .../BackEnd/BuildManager_Tests.cs | 38 +++++ .../Graph/ProjectGraph_Tests.cs | 1 - .../BackEnd/BuildManager/BuildManager.cs | 144 ++++++++++-------- src/Build/Graph/GraphBuildRequestData.cs | 24 ++- src/Build/Resources/Strings.resx | 4 +- src/Build/Resources/xlf/Strings.cs.xlf | 8 +- src/Build/Resources/xlf/Strings.de.xlf | 8 +- src/Build/Resources/xlf/Strings.en.xlf | 8 +- src/Build/Resources/xlf/Strings.es.xlf | 8 +- src/Build/Resources/xlf/Strings.fr.xlf | 8 +- src/Build/Resources/xlf/Strings.it.xlf | 8 +- src/Build/Resources/xlf/Strings.ja.xlf | 8 +- src/Build/Resources/xlf/Strings.ko.xlf | 8 +- src/Build/Resources/xlf/Strings.pl.xlf | 8 +- src/Build/Resources/xlf/Strings.pt-BR.xlf | 8 +- src/Build/Resources/xlf/Strings.ru.xlf | 8 +- src/Build/Resources/xlf/Strings.tr.xlf | 8 +- src/Build/Resources/xlf/Strings.zh-Hans.xlf | 8 +- src/Build/Resources/xlf/Strings.zh-Hant.xlf | 8 +- .../CommandLineSwitches_Tests.cs | 89 ++++++++++- src/MSBuild/CommandLineSwitches.cs | 2 +- src/MSBuild/Resources/Strings.resx | 2 +- src/MSBuild/Resources/xlf/Strings.cs.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.de.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.en.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.es.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.fr.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.it.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.ja.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.ko.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.pl.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.pt-BR.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.ru.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.tr.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf | 4 +- src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf | 4 +- src/MSBuild/XMake.cs | 49 ++++-- src/Shared/AssemblyUtilities.cs | 6 + src/Shared/UnitTests/MockLogger.cs | 20 +++ src/Shared/UnitTests/ObjectModelHelpers.cs | 5 + 42 files changed, 422 insertions(+), 164 deletions(-) diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 3b2268d29e2..f709b7788b8 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1545,6 +1545,21 @@ public static partial class MSBuildGlobExtensions } namespace Microsoft.Build.Graph { + public partial class GraphBuildOptions : System.IEquatable + { + public GraphBuildOptions() { } + protected GraphBuildOptions(Microsoft.Build.Graph.GraphBuildOptions original) { } + public bool Build { get { throw null; } set { } } + protected virtual System.Type EqualityContract { get { throw null; } } + public virtual bool Equals(Microsoft.Build.Graph.GraphBuildOptions other) { throw null; } + public override bool Equals(object obj) { throw null; } + public override int GetHashCode() { throw null; } + public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; } + public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; } + protected virtual bool PrintMembers(System.Text.StringBuilder builder) { throw null; } + public override string ToString() { throw null; } + public virtual Microsoft.Build.Graph.GraphBuildOptions $() { throw null; } + } public sealed partial class GraphBuildRequestData { public GraphBuildRequestData(Microsoft.Build.Graph.ProjectGraph projectGraph, System.Collections.Generic.ICollection targetsToBuild) { } @@ -1556,9 +1571,11 @@ public sealed partial class GraphBuildRequestData public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild) { } public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices) { } public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags) { } + public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags, Microsoft.Build.Graph.GraphBuildOptions graphBuildOptions) { } public GraphBuildRequestData(string projectFullPath, System.Collections.Generic.IDictionary globalProperties, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices) { } public GraphBuildRequestData(string projectFullPath, System.Collections.Generic.IDictionary globalProperties, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags) { } public Microsoft.Build.Execution.BuildRequestDataFlags Flags { get { throw null; } } + public Microsoft.Build.Graph.GraphBuildOptions GraphBuildOptions { get { throw null; } } public Microsoft.Build.Execution.HostServices HostServices { get { throw null; } } public Microsoft.Build.Graph.ProjectGraph ProjectGraph { get { throw null; } } public System.Collections.Generic.IEnumerable ProjectGraphEntryPoints { get { throw null; } } diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index 2d8bde06715..e5299ac48bd 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1539,6 +1539,21 @@ public static partial class MSBuildGlobExtensions } namespace Microsoft.Build.Graph { + public partial class GraphBuildOptions : System.IEquatable + { + public GraphBuildOptions() { } + protected GraphBuildOptions(Microsoft.Build.Graph.GraphBuildOptions original) { } + public bool Build { get { throw null; } set { } } + protected virtual System.Type EqualityContract { get { throw null; } } + public virtual bool Equals(Microsoft.Build.Graph.GraphBuildOptions other) { throw null; } + public override bool Equals(object obj) { throw null; } + public override int GetHashCode() { throw null; } + public static bool operator ==(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; } + public static bool operator !=(Microsoft.Build.Graph.GraphBuildOptions r1, Microsoft.Build.Graph.GraphBuildOptions r2) { throw null; } + protected virtual bool PrintMembers(System.Text.StringBuilder builder) { throw null; } + public override string ToString() { throw null; } + public virtual Microsoft.Build.Graph.GraphBuildOptions $() { throw null; } + } public sealed partial class GraphBuildRequestData { public GraphBuildRequestData(Microsoft.Build.Graph.ProjectGraph projectGraph, System.Collections.Generic.ICollection targetsToBuild) { } @@ -1550,9 +1565,11 @@ public sealed partial class GraphBuildRequestData public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild) { } public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices) { } public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags) { } + public GraphBuildRequestData(System.Collections.Generic.IEnumerable projectGraphEntryPoints, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags, Microsoft.Build.Graph.GraphBuildOptions graphBuildOptions) { } public GraphBuildRequestData(string projectFullPath, System.Collections.Generic.IDictionary globalProperties, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices) { } public GraphBuildRequestData(string projectFullPath, System.Collections.Generic.IDictionary globalProperties, System.Collections.Generic.ICollection targetsToBuild, Microsoft.Build.Execution.HostServices hostServices, Microsoft.Build.Execution.BuildRequestDataFlags flags) { } public Microsoft.Build.Execution.BuildRequestDataFlags Flags { get { throw null; } } + public Microsoft.Build.Graph.GraphBuildOptions GraphBuildOptions { get { throw null; } } public Microsoft.Build.Execution.HostServices HostServices { get { throw null; } } public Microsoft.Build.Graph.ProjectGraph ProjectGraph { get { throw null; } } public System.Collections.Generic.IEnumerable ProjectGraphEntryPoints { get { throw null; } } diff --git a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs index 3135035b20b..b09519f9f71 100644 --- a/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildManager_Tests.cs @@ -212,6 +212,14 @@ private void SimpleP2PBuild(BuildParameters buildParameters) .ShouldBe(3); } + [Fact] + public void GraphBuildOptionsDefaults() + { + var options = new GraphBuildOptions(); + + options.Build.ShouldBeTrue(); + } + /// /// A simple successful graph build. /// @@ -4279,5 +4287,35 @@ public void GraphBuildCircular() result.OverallResult.ShouldBe(BuildResultCode.Failure); result.CircularDependency.ShouldBeTrue(); } + + [Fact] + public void GraphBuildShouldBeAbleToConstructGraphButSkipBuild() + { + var graph = Helpers.CreateProjectGraph(env: _env, dependencyEdges: new Dictionary {{1, new[] {2, 3}}}); + + MockLogger logger = null; + + using (var buildSession = new Helpers.BuildManagerSession(_env)) + { + var graphResult = buildSession.BuildGraphSubmission( + new GraphBuildRequestData( + projectGraphEntryPoints: new[] {new ProjectGraphEntryPoint(graph.GraphRoots.First().ProjectInstance.FullPath)}, + targetsToBuild: new string[0], + hostServices: null, + flags: BuildRequestDataFlags.None, + graphBuildOptions: new GraphBuildOptions {Build = false})); + + graphResult.OverallResult.ShouldBe(BuildResultCode.Success); + logger = buildSession.Logger; + } + + logger.EvaluationStartedEvents.Count.ShouldBe(3); + logger.ProjectStartedEvents.ShouldBeEmpty(); + logger.TargetStartedEvents.ShouldBeEmpty(); + logger.BuildStartedEvents.ShouldHaveSingleItem(); + logger.BuildFinishedEvents.ShouldHaveSingleItem(); + logger.FullLog.ShouldContain("Static graph loaded in"); + logger.FullLog.ShouldContain("3 nodes, 2 edges"); + } } } diff --git a/src/Build.UnitTests/Graph/ProjectGraph_Tests.cs b/src/Build.UnitTests/Graph/ProjectGraph_Tests.cs index a52d2eace20..548a25b3858 100644 --- a/src/Build.UnitTests/Graph/ProjectGraph_Tests.cs +++ b/src/Build.UnitTests/Graph/ProjectGraph_Tests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; -using Microsoft.Build.BackEnd; using Microsoft.Build.Evaluation; using Microsoft.Build.Exceptions; using Microsoft.Build.Execution; diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 6327090ecca..e071160c912 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -1723,76 +1723,23 @@ private void ExecuteGraphBuildScheduler(GraphBuildSubmission submission) projectGraph.ConstructionMetrics.NodeCount, projectGraph.ConstructionMetrics.EdgeCount)); - var targetListTask = Task.Run(() => projectGraph.GetTargetLists(submission.BuildRequestData.TargetNames)); - var cacheServiceTask = Task.Run(() => SearchAndInitializeProjectCachePluginFromGraph(projectGraph)); + Dictionary resultsPerNode = null; - IReadOnlyDictionary> targetLists = targetListTask.Result; - using var cacheService = cacheServiceTask.Result; - - var waitHandle = new AutoResetEvent(true); - var graphBuildStateLock = new object(); - - var blockedNodes = new HashSet(projectGraph.ProjectNodes); - var finishedNodes = new HashSet(projectGraph.ProjectNodes.Count); - var buildingNodes = new Dictionary(); - var resultsPerNode = new Dictionary(projectGraph.ProjectNodes.Count); - - while (blockedNodes.Count > 0 || buildingNodes.Count > 0) + if (submission.BuildRequestData.GraphBuildOptions.Build) { - waitHandle.WaitOne(); - - lock (graphBuildStateLock) - { - var unblockedNodes = blockedNodes - .Where(node => node.ProjectReferences.All(projectReference => finishedNodes.Contains(projectReference))) - .ToList(); - foreach (var node in unblockedNodes) - { - var targetList = targetLists[node]; - if (targetList.Count == 0) - { - // An empty target list here means "no targets" instead of "default targets", so don't even build it. - finishedNodes.Add(node); - blockedNodes.Remove(node); - - waitHandle.Set(); + var cacheServiceTask = Task.Run(() => SearchAndInitializeProjectCachePluginFromGraph(projectGraph)); + var targetListTask = Task.Run(() => projectGraph.GetTargetLists(submission.BuildRequestData.TargetNames)); - continue; - } + using var cacheService = cacheServiceTask.Result; - var request = new BuildRequestData( - node.ProjectInstance, - targetList.ToArray(), - submission.BuildRequestData.HostServices, - submission.BuildRequestData.Flags); - - // TODO Tack onto the existing submission instead of pending a whole new submission for every node - // Among other things, this makes BuildParameters.DetailedSummary produce a summary for each node, which is not desirable. - // We basically want to submit all requests to the scheduler all at once and describe dependencies by requests being blocked by other requests. - // However today the scheduler only keeps track of MSBuild nodes being blocked by other MSBuild nodes, and MSBuild nodes haven't been assigned to the graph nodes yet. - var innerBuildSubmission = PendBuildRequest(request); - buildingNodes.Add(innerBuildSubmission, node); - blockedNodes.Remove(node); - innerBuildSubmission.ExecuteAsync(finishedBuildSubmission => - { - lock (graphBuildStateLock) - { - ProjectGraphNode finishedNode = buildingNodes[finishedBuildSubmission]; - - finishedNodes.Add(finishedNode); - buildingNodes.Remove(finishedBuildSubmission); - - resultsPerNode.Add(finishedNode, finishedBuildSubmission.BuildResult); - } - - waitHandle.Set(); - }, null); - } - } + resultsPerNode = BuildGraph(projectGraph, targetListTask.Result, submission.BuildRequestData); } // The overall submission is complete, so report it as complete - ReportResultsToSubmission(new GraphBuildResult(submission.SubmissionId, new ReadOnlyDictionary(resultsPerNode))); + ReportResultsToSubmission( + new GraphBuildResult( + submission.SubmissionId, + new ReadOnlyDictionary(resultsPerNode ?? new Dictionary()))); } catch (Exception ex) when (!ExceptionHandling.IsCriticalException(ex)) { @@ -1839,10 +1786,81 @@ private void ExecuteGraphBuildScheduler(GraphBuildSubmission submission) } ReportResultsToSubmission(result); + _overallBuildSuccess = false; } } + private Dictionary BuildGraph( + ProjectGraph projectGraph, + IReadOnlyDictionary> targetsPerNode, + GraphBuildRequestData graphBuildRequestData) + { + var waitHandle = new AutoResetEvent(true); + var graphBuildStateLock = new object(); + + var blockedNodes = new HashSet(projectGraph.ProjectNodes); + var finishedNodes = new HashSet(projectGraph.ProjectNodes.Count); + var buildingNodes = new Dictionary(); + var resultsPerNode = new Dictionary(projectGraph.ProjectNodes.Count); + + while (blockedNodes.Count > 0 || buildingNodes.Count > 0) + { + waitHandle.WaitOne(); + + lock (graphBuildStateLock) + { + var unblockedNodes = blockedNodes + .Where(node => node.ProjectReferences.All(projectReference => finishedNodes.Contains(projectReference))) + .ToList(); + foreach (var node in unblockedNodes) + { + var targetList = targetsPerNode[node]; + if (targetList.Count == 0) + { + // An empty target list here means "no targets" instead of "default targets", so don't even build it. + finishedNodes.Add(node); + blockedNodes.Remove(node); + + waitHandle.Set(); + + continue; + } + + var request = new BuildRequestData( + node.ProjectInstance, + targetList.ToArray(), + graphBuildRequestData.HostServices, + graphBuildRequestData.Flags); + + // TODO Tack onto the existing submission instead of pending a whole new submission for every node + // Among other things, this makes BuildParameters.DetailedSummary produce a summary for each node, which is not desirable. + // We basically want to submit all requests to the scheduler all at once and describe dependencies by requests being blocked by other requests. + // However today the scheduler only keeps track of MSBuild nodes being blocked by other MSBuild nodes, and MSBuild nodes haven't been assigned to the graph nodes yet. + var innerBuildSubmission = PendBuildRequest(request); + buildingNodes.Add(innerBuildSubmission, node); + blockedNodes.Remove(node); + innerBuildSubmission.ExecuteAsync(finishedBuildSubmission => + { + lock (graphBuildStateLock) + { + ProjectGraphNode finishedNode = buildingNodes[finishedBuildSubmission]; + + finishedNodes.Add(finishedNode); + buildingNodes.Remove(finishedBuildSubmission); + + resultsPerNode.Add(finishedNode, finishedBuildSubmission.BuildResult); + } + + waitHandle.Set(); + }, null); + } + } + } + + return resultsPerNode; + } + private DisposePluginService SearchAndInitializeProjectCachePluginFromGraph(ProjectGraph projectGraph) { // TODO: Consider allowing parallel graph submissions, each with its own separate cache plugin. Right now the second graph submission with a cache will fail. diff --git a/src/Build/Graph/GraphBuildRequestData.cs b/src/Build/Graph/GraphBuildRequestData.cs index 86a2231551b..0a1e008820b 100644 --- a/src/Build/Graph/GraphBuildRequestData.cs +++ b/src/Build/Graph/GraphBuildRequestData.cs @@ -7,6 +7,14 @@ namespace Microsoft.Build.Graph { + public record GraphBuildOptions + { + /// + /// If false, the graph is constructed but the nodes are not built. + /// + public bool Build { get; init; } = true; + } + /// /// GraphBuildRequestData encapsulates all of the data needed to submit a graph build request. /// @@ -142,10 +150,18 @@ public GraphBuildRequestData(IEnumerable projectGraphEnt ProjectGraphEntryPoints = projectGraphEntryPoints; } + public GraphBuildRequestData(IEnumerable projectGraphEntryPoints, ICollection targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags, GraphBuildOptions graphBuildOptions) + : this(targetsToBuild, hostServices, flags, graphBuildOptions) + { + ErrorUtilities.VerifyThrowArgumentNull(projectGraphEntryPoints, nameof(projectGraphEntryPoints)); + + ProjectGraphEntryPoints = projectGraphEntryPoints; + } + /// /// Common constructor. /// - private GraphBuildRequestData(ICollection targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags) + private GraphBuildRequestData(ICollection targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags, GraphBuildOptions graphBuildOptions = null) { ErrorUtilities.VerifyThrowArgumentNull(targetsToBuild, nameof(targetsToBuild)); foreach (string targetName in targetsToBuild) @@ -156,6 +172,7 @@ private GraphBuildRequestData(ICollection targetsToBuild, HostServices h HostServices = hostServices; TargetNames = new List(targetsToBuild); Flags = flags; + GraphBuildOptions = graphBuildOptions ?? new GraphBuildOptions(); } /// @@ -183,6 +200,11 @@ private GraphBuildRequestData(ICollection targetsToBuild, HostServices h /// public BuildRequestDataFlags Flags { get; } + /// + /// Options for how the graph should be built. + /// + public GraphBuildOptions GraphBuildOptions { get; } + /// /// Gets the HostServices object for this request. /// diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index 7d3fa3d7161..d05465726d2 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -1846,10 +1846,10 @@ Utilization: {0} Average Utilization: {1:###.0} A required NuGet assembly was not found. Expected Path: {0} - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" + Static graph loaded in {0} seconds: {1} nodes, {2} edges - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. "Loading the following project cache plugin: diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index ef9cb86340f..06e56e7d178 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - Objekty EvaluationContext vytvořené pomocí SharingPolicy.Isolated nepodporují předávání souborového systému MSBuildFileSystemBase. + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + Objekty EvaluationContext vytvořené pomocí SharingPolicy.Isolated nepodporují předávání souborového systému MSBuildFileSystemBase. @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - Statický graf se načetl za {0} s: počet uzlů: {1}, počet hraničních uzlů: {2} + Static graph loaded in {0} seconds: {1} nodes, {2} edges + Statický graf se načetl za {0} s: počet uzlů: {1}, počet hraničních uzlů: {2} diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 521aa8ab7d4..31d339fbdfe 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Die Übergabe eines MSBuildFileSystemBase-Dateisystems wird von EvaluationContext-Objekten, die mit SharingPolicy.Isolated erstellt wurden, nicht unterstützt." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Die Übergabe eines MSBuildFileSystemBase-Dateisystems wird von EvaluationContext-Objekten, die mit SharingPolicy.Isolated erstellt wurden, nicht unterstützt." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Statisches Diagramm in {0} Sekunden geladen: {1} Knoten, {2} Edges" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Statisches Diagramm in {0} Sekunden geladen: {1} Knoten, {2} Edges" diff --git a/src/Build/Resources/xlf/Strings.en.xlf b/src/Build/Resources/xlf/Strings.en.xlf index d2f150f9752..8e2bde072ed 100644 --- a/src/Build/Resources/xlf/Strings.en.xlf +++ b/src/Build/Resources/xlf/Strings.en.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + Static graph loaded in {0} seconds: {1} nodes, {2} edges diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index 6d67411bbee..370575d719c 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Los objetos EvaluationContext creados con SharingPolicy.Isolated no admiten que se les pase un sistema de archivos MSBuildFileSystemBase". + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Los objetos EvaluationContext creados con SharingPolicy.Isolated no admiten que se les pase un sistema de archivos MSBuildFileSystemBase". @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Grafo estático cargado en {0} segundos: {1} nodos, {2} bordes" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Grafo estático cargado en {0} segundos: {1} nodos, {2} bordes" diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 70e2bf605d2..f31ff7d8648 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Les objets EvaluationContext créés avec SharingPolicy.Isolated ne prennent pas en charge le passage d'un système de fichiers MSBuildFileSystemBase." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Les objets EvaluationContext créés avec SharingPolicy.Isolated ne prennent pas en charge le passage d'un système de fichiers MSBuildFileSystemBase." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Graphe statique chargé en {0} secondes : {1} nœuds, {2} arêtes" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Graphe statique chargé en {0} secondes : {1} nœuds, {2} arêtes" diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index d789f507fe0..b473c7d078b 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Agli oggetti EvaluationContext creati con SharingPolicy.Isolated non è possibile passare un file system MSBuildFileSystemBase." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Agli oggetti EvaluationContext creati con SharingPolicy.Isolated non è possibile passare un file system MSBuildFileSystemBase." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Il grafo statico è stato caricato in {0} secondi: {1} nodi, {2} vertici" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Il grafo statico è stato caricato in {0} secondi: {1} nodi, {2} vertici" diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 1a6e9ecec97..ffae30d2c77 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "SharingPolicy.Isolated を指定して作成された EvaluationContext オブジェクトに MSBuildFileSystemBase ファイル システムを渡すことはサポートされていません。" + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "SharingPolicy.Isolated を指定して作成された EvaluationContext オブジェクトに MSBuildFileSystemBase ファイル システムを渡すことはサポートされていません。" @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "{0} 秒で読み込まれた静的グラフ: {1} ノード、{2} エッジ" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "{0} 秒で読み込まれた静的グラフ: {1} ノード、{2} エッジ" diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index 8a0884231b9..2ae79b0fc10 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "SharingPolicy.Isolated로 만든 EvaluationContext 개체는 MSBuildFileSystemBase 파일 시스템 전달을 지원하지 않습니다." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "SharingPolicy.Isolated로 만든 EvaluationContext 개체는 MSBuildFileSystemBase 파일 시스템 전달을 지원하지 않습니다." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "정적 그래프가 {0}초 안에 로드됨: {1}개 노드, {2}개 에지" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "정적 그래프가 {0}초 안에 로드됨: {1}개 노드, {2}개 에지" diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index d621fd60552..3658751180c 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - „Obiekty EvaluationContext utworzone za pomocą elementu SharingPolicy.Isolated nie obsługują przekazywania za pomocą systemu plików MSBuildFileSystemBase.” + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + „Obiekty EvaluationContext utworzone za pomocą elementu SharingPolicy.Isolated nie obsługują przekazywania za pomocą systemu plików MSBuildFileSystemBase.” @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - „Wykres statyczny załadowany w {0} s, węzły: {1}, krawędzie: {2}” + Static graph loaded in {0} seconds: {1} nodes, {2} edges + „Wykres statyczny załadowany w {0} s, węzły: {1}, krawędzie: {2}” diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 0bede671260..d3e21242ac4 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Os objetos EvaluationContext criados com SharingPolicy.Isolable não são compatíveis com o recebimento de um sistema de arquivos MSBuildFileSystemBase." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Os objetos EvaluationContext criados com SharingPolicy.Isolable não são compatíveis com o recebimento de um sistema de arquivos MSBuildFileSystemBase." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Grafo estático carregado em {0} segundos: {1} nós, {2} bordas" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Grafo estático carregado em {0} segundos: {1} nós, {2} bordas" diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 40b2d46c4ee..1175fd129da 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "Объекты EvaluationContext, созданные с помощью SharingPolicy.Isolated, не поддерживают передачу в файловую систему MSBuildFileSystemBase." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "Объекты EvaluationContext, созданные с помощью SharingPolicy.Isolated, не поддерживают передачу в файловую систему MSBuildFileSystemBase." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Статический граф загружен за {0} с: узлов — {1}, ребер — {2}." + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Статический граф загружен за {0} с: узлов — {1}, ребер — {2}." diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index 8c22cd924ad..a052cb83ee2 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "SharingPolicy.Isolated ile oluşturulan EvaluationContext nesneleri bir MSBuildFileSystemBase dosya sisteminin geçirilmesini desteklemez." + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "SharingPolicy.Isolated ile oluşturulan EvaluationContext nesneleri bir MSBuildFileSystemBase dosya sisteminin geçirilmesini desteklemez." @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "Statik graf {0} saniye içinde yüklendi: {1} düğüm, {2} uç" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "Statik graf {0} saniye içinde yüklendi: {1} düğüm, {2} uç" diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 70a90a718a1..b9d2afdacd3 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - “使用 SharingPolicy.Isolated 创建的 EvaluationContext 对象不支持通过 MSBuildFileSystemBase 文件系统传递。” + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + “使用 SharingPolicy.Isolated 创建的 EvaluationContext 对象不支持通过 MSBuildFileSystemBase 文件系统传递。” @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - “静态图形已在 {0} 秒内加载: {1} 个节点、{2} 个边” + Static graph loaded in {0} seconds: {1} nodes, {2} edges + “静态图形已在 {0} 秒内加载: {1} 个节点、{2} 个边” diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index e7c3a79d890..0ed0fb9d4a0 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -128,8 +128,8 @@ - "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - "使用 SharingPolicy.Isolated 建立的 EvaluationContext 物件不支援以 MSBuildFileSystemBase 檔案系統傳遞。" + EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system. + "使用 SharingPolicy.Isolated 建立的 EvaluationContext 物件不支援以 MSBuildFileSystemBase 檔案系統傳遞。" @@ -262,8 +262,8 @@ - "Static graph loaded in {0} seconds: {1} nodes, {2} edges" - "在 {0} 秒內載入的靜態圖形: {1} 個節點、{2} 個邊緣" + Static graph loaded in {0} seconds: {1} nodes, {2} edges + "在 {0} 秒內載入的靜態圖形: {1} 個節點、{2} 個邊緣" diff --git a/src/MSBuild.UnitTests/CommandLineSwitches_Tests.cs b/src/MSBuild.UnitTests/CommandLineSwitches_Tests.cs index 03f84f7fd47..c0d09628fe3 100644 --- a/src/MSBuild.UnitTests/CommandLineSwitches_Tests.cs +++ b/src/MSBuild.UnitTests/CommandLineSwitches_Tests.cs @@ -11,6 +11,7 @@ using Microsoft.Build.CommandLine; using Microsoft.Build.Construction; using Microsoft.Build.Framework; +using Microsoft.Build.Graph; using Microsoft.Build.Shared; using Shouldly; using Xunit; @@ -503,7 +504,7 @@ public void GraphBuildSwitchIdentificationTests(string graph) CommandLineSwitches.IsParameterizedSwitch(graph, out parameterizedSwitch, out duplicateSwitchErrorMessage, out multipleParametersAllowed, out missingParametersErrorMessage, out unquoteParameters, out emptyParametersAllowed).ShouldBeTrue(); parameterizedSwitch.ShouldBe(CommandLineSwitches.ParameterizedSwitch.GraphBuild); duplicateSwitchErrorMessage.ShouldBeNull(); - multipleParametersAllowed.ShouldBeFalse(); + multipleParametersAllowed.ShouldBeTrue(); missingParametersErrorMessage.ShouldBeNull(); unquoteParameters.ShouldBeTrue(); emptyParametersAllowed.ShouldBeFalse(); @@ -531,6 +532,29 @@ public void LowPrioritySwitchIdentificationTests(string lowpriority) emptyParametersAllowed.ShouldBeFalse(); } + [Fact] + public void GraphBuildSwitchCanHaveParameters() + { + CommandLineSwitches switches = new CommandLineSwitches(); + + MSBuildApp.GatherCommandLineSwitches(new List{ "/graph", "/graph:true; NoBuild ;; ;", "/graph:foo"}, switches); + + switches[CommandLineSwitches.ParameterizedSwitch.GraphBuild].ShouldBe(new[] {"true", " NoBuild ", " ", "foo"}); + + switches.HaveErrors().ShouldBeFalse(); + } + + [Fact] + public void GraphBuildSwitchCanBeParameterless() + { + CommandLineSwitches switches = new CommandLineSwitches(); + + MSBuildApp.GatherCommandLineSwitches(new List{ "/graph" }, switches); + + switches[CommandLineSwitches.ParameterizedSwitch.GraphBuild].ShouldBe(new string[0]); + + switches.HaveErrors().ShouldBeFalse(); + } [Fact] public void InputResultsCachesSupportsMultipleOccurrence() @@ -967,7 +991,7 @@ public void InvalidToolsVersionErrors() enableProfiler: false, interactive: false, isolateProjects: false, - graphBuild: false, + graphBuildOptions: null, lowPriority: false, inputResultsCaches: null, outputResultsCache: null @@ -1201,6 +1225,67 @@ public void ProcessBooleanSwitchTest() Should.Throw(() => MSBuildApp.ProcessBooleanSwitch(new[] { "invalid" }, defaultValue: true, resourceName: "InvalidRestoreValue")); } + public static IEnumerable ProcessGraphBuildSwitchData() + { + var emptyOptions = new GraphBuildOptions(); + var noBuildOptions = new GraphBuildOptions {Build = false}; + + yield return new object[] {new string[0], emptyOptions, null}; + + yield return new object[] {new[] {"true"}, emptyOptions, null}; + + yield return new object[] {new[] {"false"}, null, null}; + + yield return new object[] {new[] {" ", " "}, emptyOptions, null}; + + yield return new object[] {new[] {"NoBuild"}, noBuildOptions, null}; + + yield return new object[] {new[] {"noBUILD"}, noBuildOptions, null}; + + yield return new object[] {new[] {"noBUILD "}, noBuildOptions, null}; + + yield return new object[] {new[] {"false", "true"}, null, new[] {"false"}}; + + yield return new object[] {new[] {"nobuild", "true"}, noBuildOptions, new[] {"true"}}; + + yield return new object[] {new[] { "false", "nobuild" }, null, new[] {"false"}}; + + yield return new object[] {new[] {"nobuild", "invalid"}, null, new[] {"invalid"}}; + } + + [Theory] + [MemberData(nameof(ProcessGraphBuildSwitchData))] + public void ProcessGraphBuildSwitch(string[] parameters, GraphBuildOptions expectedOptions, string[] expectedWordsInException) + { + CommandLineSwitchException exception = null; + + try + { + var graphBuildOptions = MSBuildApp.ProcessGraphBuildSwitch(parameters); + graphBuildOptions.ShouldBe(expectedOptions); + } + catch (CommandLineSwitchException e) + { + exception = e; + } + + if (expectedWordsInException != null) + { + exception.ShouldNotBeNull(); + + exception.Message.ShouldContain("Graph build value is not valid"); + + foreach (var expectedWord in expectedWordsInException) + { + exception.Message.ShouldContain(expectedWord); + } + } + else + { + exception.ShouldBeNull(); + } + } + /// /// Verifies that when the /profileevaluation switch is used with invalid filenames an error is shown. /// diff --git a/src/MSBuild/CommandLineSwitches.cs b/src/MSBuild/CommandLineSwitches.cs index c8b2ed78726..9e6eb9fd49c 100644 --- a/src/MSBuild/CommandLineSwitches.cs +++ b/src/MSBuild/CommandLineSwitches.cs @@ -269,7 +269,7 @@ bool emptyParametersAllowed new ParameterizedSwitchInfo( new string[] { "restoreproperty", "rp" }, ParameterizedSwitch.RestoreProperty, null, true, "MissingRestorePropertyError", true, false ), new ParameterizedSwitchInfo( new string[] { "interactive" }, ParameterizedSwitch.Interactive, null, false, null, true, false ), new ParameterizedSwitchInfo( new string[] { "isolateprojects", "isolate" }, ParameterizedSwitch.IsolateProjects, null, false, null, true, false ), - new ParameterizedSwitchInfo( new string[] { "graphbuild", "graph" }, ParameterizedSwitch.GraphBuild, null, false, null, true, false ), + new ParameterizedSwitchInfo( new string[] { "graphbuild", "graph" }, ParameterizedSwitch.GraphBuild, null, true, null, true, false ), new ParameterizedSwitchInfo( new string[] { "inputResultsCaches", "irc" }, ParameterizedSwitch.InputResultsCaches, null, true, null, true, true ), new ParameterizedSwitchInfo( new string[] { "outputResultsCache", "orc" }, ParameterizedSwitch.OutputResultsCache, "DuplicateOutputResultsCache", false, null, true, true ), new ParameterizedSwitchInfo( new string[] { "lowpriority", "low" }, ParameterizedSwitch.LowPriority, null, false, null, true, false ), diff --git a/src/MSBuild/Resources/Strings.resx b/src/MSBuild/Resources/Strings.resx index 3484f2cacaa..5f2b1ab2330 100644 --- a/src/MSBuild/Resources/Strings.resx +++ b/src/MSBuild/Resources/Strings.resx @@ -1172,7 +1172,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.cs.xlf b/src/MSBuild/Resources/xlf/Strings.cs.xlf index d3242d73401..ea203edd619 100644 --- a/src/MSBuild/Resources/xlf/Strings.cs.xlf +++ b/src/MSBuild/Resources/xlf/Strings.cs.xlf @@ -963,8 +963,8 @@ Copyright (C) Microsoft Corporation. Všechna práva vyhrazena. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Hodnota sestavení grafu není platná. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.de.xlf b/src/MSBuild/Resources/xlf/Strings.de.xlf index b12875ea503..dfbf6409b2d 100644 --- a/src/MSBuild/Resources/xlf/Strings.de.xlf +++ b/src/MSBuild/Resources/xlf/Strings.de.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Der Wert für die Diagrammerstellung ist nicht gültig. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.en.xlf b/src/MSBuild/Resources/xlf/Strings.en.xlf index a866ad64681..813d56eb252 100644 --- a/src/MSBuild/Resources/xlf/Strings.en.xlf +++ b/src/MSBuild/Resources/xlf/Strings.en.xlf @@ -1144,8 +1144,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Graph build value is not valid. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.es.xlf b/src/MSBuild/Resources/xlf/Strings.es.xlf index 84dfcc76473..be5821b7ddb 100644 --- a/src/MSBuild/Resources/xlf/Strings.es.xlf +++ b/src/MSBuild/Resources/xlf/Strings.es.xlf @@ -964,8 +964,8 @@ Copyright (C) Microsoft Corporation. Todos los derechos reservados. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: El valor de compilación del grafo no es válido. {0}. + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.fr.xlf b/src/MSBuild/Resources/xlf/Strings.fr.xlf index bc5d0cab144..1e9052ab0ec 100644 --- a/src/MSBuild/Resources/xlf/Strings.fr.xlf +++ b/src/MSBuild/Resources/xlf/Strings.fr.xlf @@ -956,8 +956,8 @@ Copyright (C) Microsoft Corporation. Tous droits réservés. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: La valeur de build du graphe n'est pas valide. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.it.xlf b/src/MSBuild/Resources/xlf/Strings.it.xlf index 792c30f845e..3576dee6f26 100644 --- a/src/MSBuild/Resources/xlf/Strings.it.xlf +++ b/src/MSBuild/Resources/xlf/Strings.it.xlf @@ -976,8 +976,8 @@ Copyright (C) Microsoft Corporation. Tutti i diritti sono riservati. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: il valore di graphBuild non è valido. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.ja.xlf b/src/MSBuild/Resources/xlf/Strings.ja.xlf index c4340920b51..d64a16c977d 100644 --- a/src/MSBuild/Resources/xlf/Strings.ja.xlf +++ b/src/MSBuild/Resources/xlf/Strings.ja.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation.All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Graph build 値が無効です。{0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.ko.xlf b/src/MSBuild/Resources/xlf/Strings.ko.xlf index 54603d31f2f..b627ff1eef4 100644 --- a/src/MSBuild/Resources/xlf/Strings.ko.xlf +++ b/src/MSBuild/Resources/xlf/Strings.ko.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: 그래프 빌드 값이 유효하지 않습니다. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.pl.xlf b/src/MSBuild/Resources/xlf/Strings.pl.xlf index aff42990b9e..8f1ee8b37b8 100644 --- a/src/MSBuild/Resources/xlf/Strings.pl.xlf +++ b/src/MSBuild/Resources/xlf/Strings.pl.xlf @@ -968,8 +968,8 @@ Copyright (C) Microsoft Corporation. Wszelkie prawa zastrzeżone. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Wartość kompilacji grafu jest nieprawidłowa. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.pt-BR.xlf b/src/MSBuild/Resources/xlf/Strings.pt-BR.xlf index e406782e4b3..5d4dd910080 100644 --- a/src/MSBuild/Resources/xlf/Strings.pt-BR.xlf +++ b/src/MSBuild/Resources/xlf/Strings.pt-BR.xlf @@ -956,8 +956,8 @@ isoladamente. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: O valor de build do gráfico não é válido. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.ru.xlf b/src/MSBuild/Resources/xlf/Strings.ru.xlf index f735d35d2be..b04ff45fb56 100644 --- a/src/MSBuild/Resources/xlf/Strings.ru.xlf +++ b/src/MSBuild/Resources/xlf/Strings.ru.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: значение сборки графа является недопустимым. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.tr.xlf b/src/MSBuild/Resources/xlf/Strings.tr.xlf index aac67729919..73a7f281be0 100644 --- a/src/MSBuild/Resources/xlf/Strings.tr.xlf +++ b/src/MSBuild/Resources/xlf/Strings.tr.xlf @@ -959,8 +959,8 @@ Telif Hakkı (C) Microsoft Corporation. Tüm hakları saklıdır. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: Grafik derleme değeri geçerli değil. {0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf b/src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf index e44b94a0e59..dcc8024c787 100644 --- a/src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: 关系图生成值无效。{0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf b/src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf index 0d183976b13..0e54b0e7198 100644 --- a/src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf @@ -955,8 +955,8 @@ Copyright (C) Microsoft Corporation. 著作權所有,並保留一切權利。 - MSBUILD : error MSB1057: Graph build value is not valid. {0} - MSBUILD : error MSB1057: 圖形組建值無效。{0} + MSBUILD : error MSB1057: Graph build value is not valid. + MSBUILD : error MSB1057: Graph build value is not valid. {StrBegin="MSBUILD : error MSB1057: "} UE: This message does not need in-line parameters because the exception takes care of displaying the invalid arg. diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 89b5641c4c4..7891c7923dd 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -563,7 +563,7 @@ string commandLine bool enableProfiler = false; bool interactive = false; bool isolateProjects = false; - bool graphBuild = false; + GraphBuildOptions graphBuildOptions = null; bool lowPriority = false; string[] inputResultsCaches = null; string outputResultsCache = null; @@ -597,7 +597,7 @@ string commandLine ref enableProfiler, ref restoreProperties, ref isolateProjects, - ref graphBuild, + ref graphBuildOptions, ref inputResultsCaches, ref outputResultsCache, ref lowPriority, @@ -675,7 +675,7 @@ string commandLine enableProfiler, interactive, isolateProjects, - graphBuild, + graphBuildOptions, lowPriority, inputResultsCaches, outputResultsCache)) @@ -984,7 +984,7 @@ internal static bool BuildProject bool enableProfiler, bool interactive, bool isolateProjects, - bool graphBuild, + GraphBuildOptions graphBuildOptions, bool lowPriority, string[] inputResultsCaches, string outputResultsCache @@ -1211,9 +1211,9 @@ string outputResultsCache BuildRequestData buildRequest = null; if (!restoreOnly) { - if (graphBuild) + if (graphBuildOptions != null) { - graphBuildRequest = new GraphBuildRequestData(new ProjectGraphEntryPoint(projectFile, globalProperties), targets, null); + graphBuildRequest = new GraphBuildRequestData(new[]{ new ProjectGraphEntryPoint(projectFile, globalProperties) }, targets, null, BuildRequestDataFlags.None, graphBuildOptions); } else { @@ -1233,7 +1233,7 @@ string outputResultsCache if (!restoreOnly) { - if (graphBuild) + if (graphBuildOptions != null) { (result, exception) = ExecuteGraphBuild(buildManager, graphBuildRequest); } @@ -2094,7 +2094,7 @@ private static bool ProcessCommandLineSwitches ref bool enableProfiler, ref Dictionary restoreProperties, ref bool isolateProjects, - ref bool graphBuild, + ref GraphBuildOptions graphBuild, ref string[] inputResultsCaches, ref string outputResultsCache, ref bool lowPriority, @@ -2276,7 +2276,7 @@ bool recursing if (commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.GraphBuild)) { - graphBuild = ProcessBooleanSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.GraphBuild], defaultValue: true, resourceName: "InvalidGraphBuildValue"); + graphBuild = ProcessGraphBuildSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.GraphBuild]); } if (commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.LowPriority)) @@ -2340,6 +2340,37 @@ out enableProfiler return invokeBuild; } + internal static GraphBuildOptions ProcessGraphBuildSwitch(string[] parameters) + { + var options = new GraphBuildOptions(); + + // Before /graph had parameters, it was treated as a boolean switch. + // Preserve that in case anyone is using /graph:{false|true} + if (parameters.Length == 1 && bool.TryParse(parameters[0], out var boolValue)) + { + return boolValue ? options : null; + } + + foreach (var parameter in parameters) + { + if (string.IsNullOrWhiteSpace(parameter)) + { + continue; + } + + if (parameter.Trim().Equals("NoBuild", StringComparison.OrdinalIgnoreCase)) + { + options = options with {Build = false}; + } + else + { + CommandLineSwitchException.Throw("InvalidGraphBuildValue", parameter); + } + } + + return options; + } + private static string ProcessOutputResultsCache(CommandLineSwitches commandLineSwitches) { return commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.OutputResultsCache) diff --git a/src/Shared/AssemblyUtilities.cs b/src/Shared/AssemblyUtilities.cs index f4194346f88..46d679293c5 100644 --- a/src/Shared/AssemblyUtilities.cs +++ b/src/Shared/AssemblyUtilities.cs @@ -6,6 +6,12 @@ using System.Linq; using System.Reflection; +// Declare this to get init properties. See https://github.com/dotnet/roslyn/issues/45510#issuecomment-694977239 +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit { } +} + namespace Microsoft.Build.Shared { /// diff --git a/src/Shared/UnitTests/MockLogger.cs b/src/Shared/UnitTests/MockLogger.cs index 07af5356dc7..f8a094bb442 100644 --- a/src/Shared/UnitTests/MockLogger.cs +++ b/src/Shared/UnitTests/MockLogger.cs @@ -81,6 +81,16 @@ internal sealed class MockLogger : ILogger /// internal List ExternalProjectFinishedEvents { get; } = new List(); + /// + /// List of ProjectStarted events + /// + internal List EvaluationStartedEvents { get; } = new List(); + + /// + /// List of ProjectFinished events + /// + internal List EvaluationFinishedEvents { get; } = new List(); + /// /// List of ProjectStarted events /// @@ -293,6 +303,16 @@ internal void LoggerEventHandler(object sender, BuildEventArgs eventArgs) ExternalProjectFinishedEvents.Add(finishedEventArgs); break; } + case ProjectEvaluationStartedEventArgs evaluationStartedEventArgs: + { + EvaluationStartedEvents.Add(evaluationStartedEventArgs); + break; + } + case ProjectEvaluationFinishedEventArgs evaluationFinishedEventArgs: + { + EvaluationFinishedEvents.Add(evaluationFinishedEventArgs); + break; + } case ProjectStartedEventArgs startedEventArgs: { ProjectStartedEvents.Add(startedEventArgs); diff --git a/src/Shared/UnitTests/ObjectModelHelpers.cs b/src/Shared/UnitTests/ObjectModelHelpers.cs index c20d923b67c..5c721b50c7e 100644 --- a/src/Shared/UnitTests/ObjectModelHelpers.cs +++ b/src/Shared/UnitTests/ObjectModelHelpers.cs @@ -1944,6 +1944,11 @@ internal class BuildManagerSession : IDisposable return buildResult; } + + public GraphBuildResult BuildGraphSubmission(GraphBuildRequestData requestData) + { + return _buildManager.BuildRequest(requestData); + } public void Dispose() {