/// <summary>
        /// Discovers if there any changes to apply for existing node, after it's context changed.
        /// </summary>
        private bool AnyChangesToTrack(IDependencyNode node,
                                       IDependencyNode updatedNode,
                                       IDependenciesChangeDiff diff,
                                       out IEnumerable <IDependencyNode> nodesToAdd,
                                       out IEnumerable <IDependencyNode> nodesToRemove)
        {
            var existingChildren = node.Children;

            if (node.Flags.Contains(DependencyNode.DependsOnOtherProviders))
            {
                var remove = new HashSet <IDependencyNode>(diff.RemovedNodes);
                var add    = new HashSet <IDependencyNode>(diff.AddedNodes);
                foreach (var changedNode in diff.UpdatedNodes)
                {
                    remove.Add(changedNode);
                    add.Add(changedNode);
                }

                nodesToAdd    = add;
                nodesToRemove = remove;
            }
            else
            {
                var updatedChildren = updatedNode.Children;
                var comparer        = new DependencyNodeResolvedStateComparer();
                nodesToRemove = existingChildren.Except(updatedChildren, comparer).ToList();
                nodesToAdd    = updatedChildren.Except(existingChildren, comparer).ToList();
            }

            return(nodesToAdd.Any() || nodesToRemove.Any());
        }
Exemplo n.º 2
0
        private async Task TrackChangesOnGraphContextAsync(IGraphContext graphContext,
                                                           IDependenciesGraphProjectContext updatedProjectContext)
        {
            foreach (var inputGraphNode in graphContext.InputNodes.ToList())
            {
                var existingNodeInfo = inputGraphNode.GetValue <IDependencyNode>(
                    DependenciesGraphSchema.DependencyNodeProperty);
                if (existingNodeInfo == null)
                {
                    continue;
                }

                var  projectPath   = GetPartialValueFromGraphNodeId(inputGraphNode.Id, CodeGraphNodeIdName.Assembly);
                bool shouldProcess = !string.IsNullOrEmpty(projectPath) &&
                                     projectPath.Equals(updatedProjectContext.ProjectFilePath, StringComparison.OrdinalIgnoreCase);
                var contextProject = updatedProjectContext.ProjectFilePath;
                if (!shouldProcess)
                {
                    shouldProcess = !string.IsNullOrEmpty(existingNodeInfo.Id.ContextProject) &&
                                    existingNodeInfo.Id.ContextProject.Equals(updatedProjectContext.ProjectFilePath,
                                                                              StringComparison.OrdinalIgnoreCase);
                }

                if (!shouldProcess)
                {
                    continue;
                }

                var subTreeProvider = await GetSubTreeProviderAsync(graphContext,
                                                                    inputGraphNode,
                                                                    projectPath,
                                                                    existingNodeInfo.Id).ConfigureAwait(false);

                if (subTreeProvider == null)
                {
                    continue;
                }

                // store existing children, since existingNodeInfo instance might be updated
                // (this is a side effect for top level nodes)
                var existingChildren = new HashSet <IDependencyNode>(existingNodeInfo.Children);

                // Get updated reference from the new snapshot
                var updatedNodeInfo = subTreeProvider.GetDependencyNode(existingNodeInfo.Id);
                if (updatedNodeInfo == null)
                {
                    continue;
                }

                using (var scope = new GraphTransactionScope())
                {
                    var comparer = new DependencyNodeResolvedStateComparer();
                    // Diff existing node children and updated node children to get whats removed
                    var nodesToRemove = existingChildren.Except(updatedNodeInfo.Children, comparer).ToList();
                    // Diff updated node children and existing node children to get whats added
                    var nodesToAdd = updatedNodeInfo.Children.Except(existingChildren, comparer).ToList();

                    foreach (var nodeToRemove in nodesToRemove)
                    {
                        RemoveGraphNode(graphContext, contextProject, nodeToRemove);
                        existingNodeInfo.RemoveChild(nodeToRemove);
                    }

                    foreach (var nodeToAdd in nodesToAdd)
                    {
                        AddGraphNode(graphContext, contextProject, null, inputGraphNode, nodeToAdd);
                        existingNodeInfo.AddChild(nodeToAdd);
                    }

                    // Update the node info saved on the 'inputNode'
                    inputGraphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, updatedNodeInfo);

                    scope.Complete();
                }
            }
        }