示例#1
0
        public IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > GetTargetLists(ICollection <string> entryProjectTargets)
        {
            ThrowOnEmptyTargetNames(entryProjectTargets);

            // Seed the dictionary with empty lists for every node. In this particular case though an empty list means "build nothing" rather than "default targets".
            var targetLists = ProjectNodes.ToDictionary(node => node, node => ImmutableList <string> .Empty);

            var encounteredEdges = new HashSet <ProjectGraphBuildRequest>();
            var edgesToVisit     = new Queue <ProjectGraphBuildRequest>();

            // Initial state for the graph roots
            foreach (var entryPointNode in GraphRoots)
            {
                var entryTargets = entryProjectTargets == null || entryProjectTargets.Count == 0
                    ? ImmutableList.CreateRange(entryPointNode.ProjectInstance.DefaultTargets)
                    : ImmutableList.CreateRange(entryProjectTargets);
                var entryEdge = new ProjectGraphBuildRequest(entryPointNode, entryTargets);
                encounteredEdges.Add(entryEdge);
                edgesToVisit.Enqueue(entryEdge);
            }

            // Traverse the entire graph, visiting each edge once.
            while (edgesToVisit.Count > 0)
            {
                var buildRequest     = edgesToVisit.Dequeue();
                var node             = buildRequest.Node;
                var requestedTargets = buildRequest.RequestedTargets;

                targetLists[node] = targetLists[node].AddRange(requestedTargets);

                // No need to continue if this node has no project references.
                if (node.ProjectReferences.Count == 0)
                {
                    continue;
                }

                // Based on the entry points of this project, determine which targets to propagate down to project references.
                var targetsToPropagate = ProjectInterpretation.TargetsToPropagate.FromProjectAndEntryTargets(node.ProjectInstance, requestedTargets);

                // Queue the project references for visitation, if the edge hasn't already been traversed.
                foreach (var referenceNode in node.ProjectReferences)
                {
                    var applicableTargets = targetsToPropagate.GetApplicableTargetsForReference(referenceNode.ProjectInstance);

                    if (applicableTargets.IsEmpty)
                    {
                        continue;
                    }

                    var expandedTargets = ExpandDefaultTargets(
                        applicableTargets,
                        referenceNode.ProjectInstance.DefaultTargets,
                        Edges[(node, referenceNode)]);
示例#2
0
        // Rest of members solely private!
        //

        /// <summary>
        /// Private constructor, one has to use dedicated methods Create()
        /// or Load() for creating an project file instance
        /// </summary>
        private ProjectFile(string filename = null, string project = null, string source = null)
        {
            Filename = filename;
            Project  = project;
            Source   = source;
            Nodes    = new ProjectNodes();

            if (Source != null)
            {
                _OpenMem();

                Nodes.Add(new ProjectNode(this, 0, Filesize));
            }

            // Newly created projects are always modified
            IsModified = true;
        }
示例#3
0
        /// <summary>
        /// Gets the target list to be executed for every project in the graph, given a particular target list for the entry project.
        /// </summary>
        /// <remarks>
        /// This method uses the ProjectReferenceTargets items to determine the targets to run per node. The results can then be used
        /// to start building each project individually, assuming a given project is built after its references.
        /// </remarks>
        /// <param name="entryProjectTargets">The target list for the entry project. May be null or empty, in which case the entry projects' default targets will be used.</param>
        /// <returns>A dictionary containing the target list for each node.</returns>
        public IReadOnlyDictionary <ProjectGraphNode, ImmutableList <string> > GetTargetLists(ICollection <string> entryProjectTargets)
        {
            // Seed the dictionary with empty lists for every node. In this particular case though an empty list means "build nothing" rather than "default targets".
            Dictionary <ProjectGraphNode, ImmutableList <string> > targetLists = ProjectNodes.ToDictionary(node => node, node => ImmutableList <string> .Empty);

            var encounteredEdges = new HashSet <ProjectGraphBuildRequest>();
            var edgesToVisit     = new Queue <ProjectGraphBuildRequest>();

            // Initial state of the graph traversal.
            foreach (var entryPointNode in EntryPointNodes)
            {
                ImmutableList <string> entryTargets = entryProjectTargets == null || entryProjectTargets.Count == 0
                    ? ImmutableList.CreateRange(entryPointNode.ProjectInstance.DefaultTargets)
                    : ImmutableList.CreateRange(entryProjectTargets);
                var entryEdge = new ProjectGraphBuildRequest(entryPointNode, entryTargets);
                encounteredEdges.Add(entryEdge);
                edgesToVisit.Enqueue(entryEdge);
            }

            // Traverse the entire graph, visiting each edge once.
            while (edgesToVisit.Count > 0)
            {
                ProjectGraphBuildRequest buildRequest     = edgesToVisit.Dequeue();
                ProjectGraphNode         node             = buildRequest.Node;
                ImmutableList <string>   requestedTargets = buildRequest.RequestedTargets;

                targetLists[node] = targetLists[node].AddRange(requestedTargets);

                // No need to continue if this node has no project references.
                if (node.ProjectReferences.Count == 0)
                {
                    continue;
                }

                // Based on the entry points of this project, determine which targets to propagate down to project references.
                ImmutableList <string> targetsToPropagate = DetermineTargetsToPropagate(node, requestedTargets);

                // Queue the project references for visitation, if the edge hasn't already been traversed.
                foreach (var projectReference in node.ProjectReferences)
                {
                    var projectReferenceEdge = new ProjectGraphBuildRequest(
                        projectReference,
                        ExpandDefaultTargets(projectReference.ProjectInstance, targetsToPropagate));
                    if (encounteredEdges.Add(projectReferenceEdge))
                    {
                        edgesToVisit.Enqueue(projectReferenceEdge);
                    }
                }
            }

            // Dedupe target lists
            List <KeyValuePair <ProjectGraphNode, ImmutableList <string> > > entriesToUpdate = new List <KeyValuePair <ProjectGraphNode, ImmutableList <string> > >();

            foreach (KeyValuePair <ProjectGraphNode, ImmutableList <string> > pair in targetLists)
            {
                ImmutableList <string> targetList = pair.Value;

                SortedSet <string> seenTargets = new SortedSet <string>(StringComparer.OrdinalIgnoreCase);
                int i = 0;
                while (i < targetList.Count)
                {
                    if (seenTargets.Add(targetList[i]))
                    {
                        i++;
                    }
                    else
                    {
                        targetList = targetList.RemoveAt(i);
                    }
                }

                // Only update if it changed
                if (targetList != pair.Value)
                {
                    entriesToUpdate.Add(new KeyValuePair <ProjectGraphNode, ImmutableList <string> >(pair.Key, targetList));
                }
            }

            // Update in a separate pass to avoid modifying a collection while iterating it.
            foreach (KeyValuePair <ProjectGraphNode, ImmutableList <string> > pair in entriesToUpdate)
            {
                targetLists[pair.Key] = pair.Value;
            }

            return(targetLists);
        }