Ejemplo n.º 1
0
        private IEnumerable <(string pathPostfix, string contents)> GetDotNotations(
            FileInfo projectFile,
            ImmutableDictionary <string, string> globalProperties,
            string[] targets,
            string[] endNodes)
        {
            Console.WriteLine("Loading graph...");

            var sw    = Stopwatch.StartNew();
            var graph = new ProjectGraph(new ProjectGraphEntryPoint(projectFile.FullName, globalProperties), ProjectCollection.GlobalProjectCollection);

            sw.Stop();

            Console.WriteLine($@"{projectFile} loaded {graph.ProjectNodes.Count} node(s) in {sw.ElapsedMilliseconds}ms.");

            var entryTargetsPerNode = graph.GetTargetLists(targets);

            if (endNodes != null)
            {
                var endGraphNodes = graph.ProjectNodes.Where(n => endNodes.Any(en => n.ProjectInstance.FullPath.Contains(en)));
                var paths         = GraphPaths.FindAllPathsBetween(graph.GraphRoots, endGraphNodes);

                var deduplicatedNodes = paths.SelectMany(p => p).ToHashSet();
                yield return($"_PathsEndingIn_{string.Join(",", endNodes)}", GraphVis.Create(deduplicatedNodes, entryTargetsPerNode));
            }

            yield return("", GraphVis.Create(graph, entryTargetsPerNode));
        }
Ejemplo n.º 2
0
        public void ConstructWithNoNodes()
        {
            var projectGraph = new ProjectGraph(Enumerable.Empty <ProjectGraphEntryPoint>());

            projectGraph.ProjectNodes.ShouldBeEmpty();
            projectGraph.EntryPointNodes.ShouldBeEmpty();
            projectGraph.GraphRoots.ShouldBeEmpty();
            projectGraph.ProjectNodesTopologicallySorted.ShouldBeEmpty();
            projectGraph.GetTargetLists(new [] { "restore", "build" }).ShouldBeEmpty();
        }
        private static bool BuildGraphWithCacheFileRoundtrip(IReadOnlyCollection <string> projectFiles, string cacheRoot)
        {
            ProjectGraph graph;

            var success = true;

            using (var collection = new ProjectCollection())
            {
                //collection.RegisterLogger(new EvaluationLogger());

                graph = new ProjectGraph(projectFiles, null, collection);
            }

            if (DebugBuild)
            {
                Console.WriteLine(ToDot(graph));
            }

            var cacheFiles = new Dictionary <ProjectGraphNode, string>(graph.ProjectNodes.Count);

            var targetLists = graph.GetTargetLists(null);

            var topoSortedNodes = graph.ProjectNodesTopologicallySorted;

            foreach (var node in topoSortedNodes)
            {
                var outputCacheFile  = graph.GraphRoots.Contains(node) ? null : Path.Combine(cacheRoot, node.CacheFileName());
                var inputCachesFiles = node.ProjectReferences.Select(r => cacheFiles[r]).ToArray();

                cacheFiles[node] = outputCacheFile;

                var targets = targetLists[node];

                var result = BuildProject(node.ProjectInstance.FullPath, node.ProjectInstance.GlobalProperties, targets, inputCachesFiles, outputCacheFile);

                if (result.OverallResult == BuildResultCode.Failure)
                {
                    success = false;
                }
            }

            return(success);
        }
Ejemplo n.º 4
0
        private static bool TryConstructGraph(
            ProjectGraph projectGraph,
            GraphBuilderReporter reporter,
            ConcurrentDictionary <ProjectInstance, Project> projectInstanceToProjectCache,
            IReadOnlyCollection <string> entryPointTargets,
            IReadOnlyCollection <IProjectPredictor> projectPredictorsForTesting,
            bool allowProjectsWithoutTargetProtocol,
            out ProjectGraphWithPredictions projectGraphWithPredictions,
            out string failure)
        {
            Contract.Assert(projectGraph != null);

            var projectNodes = new ProjectWithPredictions[projectGraph.ProjectNodes.Count];

            var nodes = projectGraph.ProjectNodes.ToArray();

            // Compute the list of targets to run per project
            reporter.ReportMessage("Computing targets to execute for each project...");

            // This dictionary should be exclusively read only at this point, and therefore thread safe
            var targetsPerProject = projectGraph.GetTargetLists(entryPointTargets.ToArray());

            // Bidirectional access from nodes with predictions to msbuild nodes in order to compute node references in the second pass
            // TODO: revisit the structures, since the projects are known upfront we might be able to use lock-free structures
            var nodeWithPredictionsToMsBuildNodes     = new ConcurrentDictionary <ProjectWithPredictions, ProjectGraphNode>(Environment.ProcessorCount, projectNodes.Length);
            var msBuildNodesToNodeWithPredictionIndex = new ConcurrentDictionary <ProjectGraphNode, ProjectWithPredictions>(Environment.ProcessorCount, projectNodes.Length);

            reporter.ReportMessage("Statically predicting inputs and outputs...");

            // Create the registered predictors and initialize the prediction executor
            // The prediction executor potentially initializes third-party predictors, which may contain bugs. So let's be very defensive here
            IReadOnlyCollection <IProjectPredictor> predictors;

            try
            {
                predictors = projectPredictorsForTesting ?? ProjectPredictors.AllPredictors;
            }
            catch (Exception ex)
            {
                failure = $"Cannot create standard predictors. An unexpected error occurred. Please contact BuildPrediction project owners with this stack trace: {ex.ToString()}";
                projectGraphWithPredictions = new ProjectGraphWithPredictions(new ProjectWithPredictions <string>[] { });
                return(false);
            }

            // Using single-threaded prediction since we're parallelizing on project nodes instead.
            var predictionExecutor = new ProjectPredictionExecutor(predictors, new ProjectPredictionOptions {
                MaxDegreeOfParallelism = 1
            });

            // Each predictor may return unexpected/incorrect results and targets may not be able to be predicted. We put those failures here for post-processing.
            ConcurrentQueue <(string predictorName, string failure)> predictionFailures = new ConcurrentQueue <(string, string)>();
            var predictedTargetFailures = new ConcurrentQueue <string>();

            // The predicted targets to execute (per project) go here
            var computedTargets = new ConcurrentBigMap <ProjectGraphNode, PredictedTargetsToExecute>();
            // When projects are allowed to not implement the target protocol, its references need default targets as a post-processing step
            var pendingAddDefaultTargets = new ConcurrentBigSet <ProjectGraphNode>();

            // First pass
            // Predict all projects in the graph in parallel and populate ProjectNodes
            Parallel.For(0, projectNodes.Length, (int i) => {
                ProjectGraphNode msBuildNode    = nodes[i];
                ProjectInstance projectInstance = msBuildNode.ProjectInstance;
                Project project = projectInstanceToProjectCache[projectInstance];

                var outputFolderPredictions = new List <string>();

                var predictionCollector = new MsBuildOutputPredictionCollector(outputFolderPredictions, predictionFailures);
                try
                {
                    // Again, be defensive when using arbitrary predictors
                    predictionExecutor.PredictInputsAndOutputs(project, predictionCollector);
                }
                catch (Exception ex)
                {
                    predictionFailures.Enqueue((
                                                   "Unknown predictor",
                                                   $"Cannot run static predictor on project '{project.FullPath ?? "Unknown project"}'. An unexpected error occurred. Please contact BuildPrediction project owners with this stack trace: {ex.ToString()}"));
                }
Ejemplo n.º 5
0
        public void GetTargetListsDefaultComplexPropagation()
        {
            var projectReferenceTargets = new Dictionary <string, string[]>
            {
                { "Build", new[] { "A", ".default" } },
                { "X", new[] { "B", ".default" } },
                { "Y", new[] { "C", ".default" } },
            };

            using (var env = TestEnvironment.Create())
            {
                TransientTestFile entryProject = CreateProjectFile(env, 1, new[] { 2, 3, 4 }, projectReferenceTargets, defaultTargets: null);
                CreateProjectFile(env, 2, new[] { 5 }, projectReferenceTargets, defaultTargets: null);
                CreateProjectFile(env, 3, new[] { 6 }, projectReferenceTargets, defaultTargets: "X");
                CreateProjectFile(env, 4, new[] { 7 }, projectReferenceTargets, defaultTargets: "Y");
                CreateProjectFile(env, 5, defaultTargets: null);
                CreateProjectFile(env, 6, defaultTargets: null);
                CreateProjectFile(env, 7, defaultTargets: "Z;W");

                var projectGraph = new ProjectGraph(entryProject.Path);
                projectGraph.ProjectNodes.Count.ShouldBe(7);

                IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > targetLists = projectGraph.GetTargetLists(null);
                targetLists.Count.ShouldBe(projectGraph.ProjectNodes.Count);
                targetLists[GetNodeForProject(projectGraph, 1)].ShouldBe(new[] { "Build" });
                targetLists[GetNodeForProject(projectGraph, 2)].ShouldBe(new[] { "A", "Build" });
                targetLists[GetNodeForProject(projectGraph, 3)].ShouldBe(new[] { "A", "X" });
                targetLists[GetNodeForProject(projectGraph, 4)].ShouldBe(new[] { "A", "Y" });
                targetLists[GetNodeForProject(projectGraph, 5)].ShouldBe(new[] { "A", "Build" });
                targetLists[GetNodeForProject(projectGraph, 6)].ShouldBe(new[] { "B", "Build" });
                targetLists[GetNodeForProject(projectGraph, 7)].ShouldBe(new[] { "C", "Z", "W" });
            }
        }
Ejemplo n.º 6
0
        public void GetTargetListsUnspecifiedTargetsDefaultToBuild()
        {
            using (var env = TestEnvironment.Create())
            {
                TransientTestFile entryProject = CreateProjectFile(env, 1, new[] { 2 }, new Dictionary <string, string[]> {
                    { "Build", new[] { "A", ".default" } }
                });
                CreateProjectFile(env, 2);

                var projectGraph = new ProjectGraph(entryProject.Path);
                projectGraph.ProjectNodes.Count.ShouldBe(2);

                IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > targetLists = projectGraph.GetTargetLists(null);
                targetLists.Count.ShouldBe(projectGraph.ProjectNodes.Count);
                targetLists[GetNodeForProject(projectGraph, 1)].ShouldBe(new[] { "Build" });
                targetLists[GetNodeForProject(projectGraph, 2)].ShouldBe(new[] { "A", "Build" });
            }
        }
Ejemplo n.º 7
0
        public void GetTargetListsForComplexGraph()
        {
            var projectReferenceTargets = new Dictionary <string, string[]>
            {
                { "A", new[] { "B" } },
                { "B", new[] { "C" } },
                { "C", new[] { "D" } },
                { "D", new[] { "E" } },
            };

            using (var env = TestEnvironment.Create())
            {
                TransientTestFile entryProject = CreateProjectFile(env, 1, new[] { 2, 3, 5 }, projectReferenceTargets);
                CreateProjectFile(env, 2, new[] { 4, 5 }, projectReferenceTargets);
                CreateProjectFile(env, 3, new[] { 5, 6 }, projectReferenceTargets);
                CreateProjectFile(env, 4, new[] { 5 }, projectReferenceTargets);
                CreateProjectFile(env, 5, new[] { 6 }, projectReferenceTargets);
                CreateProjectFile(env, 6, Array.Empty <int>(), projectReferenceTargets);

                var projectGraph = new ProjectGraph(entryProject.Path);
                projectGraph.ProjectNodes.Count.ShouldBe(6);

                IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > targetLists = projectGraph.GetTargetLists(new[] { "A" });
                targetLists.Count.ShouldBe(projectGraph.ProjectNodes.Count);
                targetLists[GetNodeForProject(projectGraph, 1)].ShouldBe(new[] { "A" });
                targetLists[GetNodeForProject(projectGraph, 2)].ShouldBe(new[] { "B" });
                targetLists[GetNodeForProject(projectGraph, 3)].ShouldBe(new[] { "B" });
                targetLists[GetNodeForProject(projectGraph, 4)].ShouldBe(new[] { "C" });
                targetLists[GetNodeForProject(projectGraph, 5)].ShouldBe(new[] { "B", "C", "D" });
                targetLists[GetNodeForProject(projectGraph, 6)].ShouldBe(new[] { "C", "D", "E" });
            }
        }
Ejemplo n.º 8
0
        public void GetTargetListsDedupesTargets()
        {
            var projectReferenceTargets = new Dictionary <string, string[]>
            {
                { "A", new[] { "B", "X", "C" } },
                { "B", new[] { "X", "Y" } },
                { "C", new[] { "X", "Z" } },
            };

            using (var env = TestEnvironment.Create())
            {
                TransientTestFile entryProject = CreateProjectFile(env, 1, new[] { 2 }, projectReferenceTargets);
                CreateProjectFile(env, 2, new[] { 3 }, projectReferenceTargets);
                CreateProjectFile(env, 3, Array.Empty <int>(), projectReferenceTargets);

                var projectGraph = new ProjectGraph(entryProject.Path);
                projectGraph.ProjectNodes.Count.ShouldBe(3);

                IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > targetLists = projectGraph.GetTargetLists(new[] { "A" });
                targetLists.Count.ShouldBe(projectGraph.ProjectNodes.Count);
                targetLists[GetNodeForProject(projectGraph, 1)].ShouldBe(new[] { "A" });
                targetLists[GetNodeForProject(projectGraph, 2)].ShouldBe(new[] { "B", "X", "C" });
                targetLists[GetNodeForProject(projectGraph, 3)].ShouldBe(new[] { "X", "Y", "Z" }); // Simplified from X, Y, X, Z
            }
        }
Ejemplo n.º 9
0
        public void GetTargetListsAggregatesFromMultipleEdges()
        {
            using (var env = TestEnvironment.Create())
            {
                TransientTestFile entryProject = CreateProjectFile(env, 1, new[] { 2, 3 }, new Dictionary <string, string[]> {
                    { "A", new[] { "B" } }
                });
                CreateProjectFile(env, 2, new[] { 4 }, new Dictionary <string, string[]> {
                    { "B", new[] { "C" } }
                });
                CreateProjectFile(env, 3, new[] { 4 }, new Dictionary <string, string[]> {
                    { "B", new[] { "D" } }
                });
                CreateProjectFile(env, 4);

                var projectGraph = new ProjectGraph(entryProject.Path);
                projectGraph.ProjectNodes.Count.ShouldBe(4);

                IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > targetLists = projectGraph.GetTargetLists(new[] { "A" });
                targetLists.Count.ShouldBe(projectGraph.ProjectNodes.Count);
                targetLists[GetNodeForProject(projectGraph, 1)].ShouldBe(new[] { "A" });
                targetLists[GetNodeForProject(projectGraph, 2)].ShouldBe(new[] { "B" });
                targetLists[GetNodeForProject(projectGraph, 3)].ShouldBe(new[] { "B" });
                targetLists[GetNodeForProject(projectGraph, 4)].ShouldBe(new[] { "C", "D" }); // From B => C and B => D
            }
        }