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() {