private Task BuildTreeForSnapshotAsync(IDependenciesSnapshot snapshot)
        {
            var viewProvider = ViewProviders.FirstOrDefault();

            if (viewProvider == null)
            {
                return(Task.CompletedTask);
            }

            var nowait = SubmitTreeUpdateAsync(
                (treeSnapshot, configuredProjectExports, cancellationToken) =>
            {
                var dependenciesNode = treeSnapshot.Value.Tree;
                if (!cancellationToken.IsCancellationRequested)
                {
                    dependenciesNode = viewProvider.Value.BuildTree(dependenciesNode, snapshot, cancellationToken);
                }

                // TODO We still are getting mismatched data sources and need to figure out better
                // way of merging, mute them for now and get to it in U1
                return(Task.FromResult(new TreeUpdateResult(dependenciesNode, false, null)));
            });

            return(Task.CompletedTask);
        }
        private ITargetedDependenciesSnapshot GetSnapshot(string projectPath, IDependency dependency, out string dependencyProjectPath)
        {
            dependencyProjectPath = dependency.FullPath;

            IDependenciesSnapshotProvider snapshotProvider = AggregateSnapshotProvider.GetSnapshotProvider(dependencyProjectPath);

            if (snapshotProvider == null)
            {
                return(null);
            }

            IDependenciesSnapshot snapshot = snapshotProvider.CurrentSnapshot;

            if (snapshot == null)
            {
                return(null);
            }

            ITargetFramework targetFramework = TargetFrameworkProvider.GetNearestFramework(
                dependency.TargetFramework, snapshot.Targets.Keys);

            if (targetFramework == null)
            {
                return(null);
            }

            return(snapshot.Targets[targetFramework]);
        }
        public SnapshotChangedEventArgs(IDependenciesSnapshot snapshot, CancellationToken token)
        {
            Requires.NotNull(snapshot, nameof(snapshot));

            Snapshot = snapshot;
            Token    = token;
        }
Example #4
0
        protected IDependency GetDependency(
            IGraphContext graphContext,
            GraphNode inputGraphNode,
            out IDependenciesSnapshot snapshot)
        {
            snapshot = null;

            var projectPath = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.Assembly);

            if (string.IsNullOrEmpty(projectPath))
            {
                return(null);
            }

            var projectFolder = Path.GetDirectoryName(projectPath);
            var id            = inputGraphNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);

            if (id == null)
            {
                // this is top level node and it contains full path
                id = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.File);
                if (id.StartsWith(projectFolder, StringComparison.OrdinalIgnoreCase))
                {
                    id = id.Substring(projectFolder.Length).TrimStart('\\');
                }

                return(GetTopLevelDependency(projectPath, id, out snapshot));
            }
            else
            {
                return(GetDependency(projectPath, id, out snapshot));
            }
        }
        private Task BuildTreeForSnapshotAsync(IDependenciesSnapshot snapshot)
        {
            Lazy <IDependenciesTreeViewProvider, IOrderPrecedenceMetadataView> viewProvider = ViewProviders.FirstOrDefault();

            if (viewProvider == null)
            {
                return(Task.CompletedTask);
            }

            Task <IProjectVersionedValue <IProjectTreeSnapshot> > nowait = SubmitTreeUpdateAsync(
                async(treeSnapshot, configuredProjectExports, cancellationToken) =>
            {
                IProjectTree dependenciesNode = treeSnapshot.Value.Tree;
                if (!cancellationToken.IsCancellationRequested)
                {
                    dependenciesNode = await viewProvider.Value.BuildTreeAsync(dependenciesNode, snapshot, cancellationToken)
                                       .ConfigureAwait(false);

                    _treeTelemetryService.ObserveTreeUpdateCompleted(snapshot.HasUnresolvedDependency);
                }

                // TODO We still are getting mismatched data sources and need to figure out better
                // way of merging, mute them for now and get to it in U1
                return(new TreeUpdateResult(dependenciesNode, false, null));
            });

            return(Task.CompletedTask);
        }
Example #6
0
        /// <summary>
        /// Executes <paramref name="updateFunc"/> on the current snapshot within a lock.
        /// If a different snapshot object is returned, <see cref="CurrentSnapshot"/> is updated
        /// and an invocation of <see cref="SnapshotChanged"/> is scheduled.
        /// </summary>
        private void TryUpdateSnapshot(Func <DependenciesSnapshot, DependenciesSnapshot> updateFunc, CancellationToken token = default)
        {
            lock (_snapshotLock)
            {
                DependenciesSnapshot updatedSnapshot = updateFunc(_currentSnapshot);

                if (ReferenceEquals(_currentSnapshot, updatedSnapshot))
                {
                    return;
                }

                _currentSnapshot = updatedSnapshot;
            }

            // avoid unnecessary tree updates
            _dependenciesUpdateScheduler.ScheduleAsyncTask(
                ct =>
            {
                if (ct.IsCancellationRequested || IsDisposing || IsDisposed)
                {
                    return(Task.FromCanceled(ct));
                }

                IDependenciesSnapshot snapshot = _currentSnapshot;

                if (snapshot != null)
                {
                    SnapshotChanged?.Invoke(this, new SnapshotChangedEventArgs(snapshot, ct));
                }

                return(Task.CompletedTask);
            }, token);
        }
        private void TryUpdateSnapshot(Func <DependenciesSnapshot, DependenciesSnapshot> updateFunc, CancellationToken token = default)
        {
            lock (_snapshotLock)
            {
                DependenciesSnapshot updatedSnapshot = updateFunc(_currentSnapshot);

                if (ReferenceEquals(_currentSnapshot, updatedSnapshot))
                {
                    return;
                }

                _currentSnapshot = updatedSnapshot;
            }

            // Conflate rapid snapshot updates by debouncing events over a short window.
            // This reduces the frequency of tree updates with minimal perceived latency.
            _dependenciesUpdateScheduler.ScheduleAsyncTask(
                ct =>
            {
                if (ct.IsCancellationRequested || IsDisposing || IsDisposed)
                {
                    return(Task.FromCanceled(ct));
                }

                // Always publish the latest snapshot
                IDependenciesSnapshot snapshot = _currentSnapshot;

                var events = new SnapshotChangedEventArgs(snapshot, ct);
                _snapshotChangedSource.Post(events);
                SnapshotChanged?.Invoke(this, events);

                return(Task.CompletedTask);
            }, token);
        }
        private void OnDependenciesSnapshotChanged(object sender, SnapshotChangedEventArgs e)
        {
            IDependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null)
            {
                return;
            }

            lock (_treeUpdateLock)
            {
                if (_treeUpdateQueueTask == null || _treeUpdateQueueTask.IsCompleted)
                {
                    _treeUpdateQueueTask = ThreadingService.JoinableTaskFactory.RunAsync(async() =>
                    {
                        if (TasksService.UnloadCancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        await BuildTreeForSnapshotAsync(snapshot).ConfigureAwait(false);
                    }).Task;
                }
                else
                {
                    _treeUpdateQueueTask = _treeUpdateQueueTask.ContinueWith(
                        t => BuildTreeForSnapshotAsync(snapshot), TaskScheduler.Default);
                }
            }
        }
 protected IDependency GetTopLevelDependency(
     string projectPath,
     string dependencyId,
     out IDependenciesSnapshot snapshot)
 {
     snapshot = GetSnapshot(projectPath);
     return(snapshot?.FindDependency(dependencyId, topLevel: true));
 }
 protected abstract void ProcessInputNode(
     IGraphContext graphContext,
     GraphNode inputGraphNode,
     IDependency dependency,
     IDependenciesSnapshot snapshot,
     IDependenciesGraphViewProvider viewProvider,
     string projectPath,
     ref bool trackChanges);
        private IDependency FindDependency(GraphNode inputGraphNode, out IDependenciesSnapshot snapshot)
        {
            string projectPath = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.Assembly);

            if (string.IsNullOrWhiteSpace(projectPath))
            {
                snapshot = null;
                return(null);
            }

            string projectFolder = Path.GetDirectoryName(projectPath);

            if (projectFolder == null)
            {
                snapshot = null;
                return(null);
            }

            string id = inputGraphNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);

            bool topLevel;

            if (id == null)
            {
                // this is top level node and it contains full path
                id = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.File);

                if (id == null)
                {
                    // No full path, so this must be a node generated by a different provider.
                    snapshot = null;
                    return(null);
                }

                if (id.StartsWith(projectFolder, StringComparison.OrdinalIgnoreCase))
                {
                    int startIndex = projectFolder.Length;

                    // Trim backslashes (without allocating)
                    while (startIndex < id.Length && id[startIndex] == '\\')
                    {
                        startIndex++;
                    }

                    id = id.Substring(startIndex);
                }

                topLevel = true;
            }
            else
            {
                topLevel = false;
            }

            snapshot = AggregateSnapshotProvider.GetSnapshot(projectPath);

            return(snapshot?.FindDependency(id, topLevel));
        }
Example #12
0
        public bool Equals(IDependenciesSnapshot other)
        {
            if (other != null && other.ProjectPath.Equals(ProjectPath, StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            return(false);
        }
        public override bool HandleChanges(IGraphContext graphContext, SnapshotChangedEventArgs e)
        {
            IDependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null || e.Token.IsCancellationRequested)
            {
                return(false);
            }

            foreach (GraphNode inputGraphNode in graphContext.InputNodes.ToList())
            {
                string existingDependencyId = inputGraphNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);
                if (string.IsNullOrEmpty(existingDependencyId))
                {
                    continue;
                }

                string projectPath = inputGraphNode.Id.GetValue(CodeGraphNodeIdName.Assembly);
                if (string.IsNullOrEmpty(projectPath))
                {
                    continue;
                }

                IDependency updatedDependency = GetDependency(projectPath, existingDependencyId, out IDependenciesSnapshot updatedSnapshot);
                if (updatedDependency == null)
                {
                    continue;
                }

                IDependenciesGraphViewProvider viewProvider = ViewProviders
                                                              .FirstOrDefaultValue((x, d) => x.SupportsDependency(d), updatedDependency);
                if (viewProvider == null)
                {
                    continue;
                }

                if (!viewProvider.ShouldTrackChanges(projectPath, snapshot.ProjectPath, updatedDependency))
                {
                    continue;
                }

                using (var scope = new GraphTransactionScope())
                {
                    viewProvider.TrackChanges(
                        graphContext,
                        projectPath,
                        updatedDependency,
                        inputGraphNode,
                        updatedSnapshot.Targets[updatedDependency.TargetFramework]);

                    scope.Complete();
                }
            }

            return(false);
        }
Example #14
0
 public static IEnumerable <IDependency> GetFlatTopLevelDependencies(this IDependenciesSnapshot self)
 {
     foreach ((ITargetFramework _, ITargetedDependenciesSnapshot targetedSnapshot) in self.DependenciesByTargetFramework)
     {
         foreach (IDependency dependency in targetedSnapshot.TopLevelDependencies)
         {
             yield return(dependency);
         }
     }
 }
 public static IEnumerable <IDependency> GetFlatTopLevelDependencies(this IDependenciesSnapshot self)
 {
     foreach (ITargetedDependenciesSnapshot targetedSnapshot in self.Targets.Values)
     {
         foreach (IDependency dependency in targetedSnapshot.TopLevelDependencies)
         {
             yield return(dependency);
         }
     }
 }
        private void ProcessSharedProjectsUpdates(
            IProjectSharedFoldersSnapshot sharedFolders,
            ITargetedProjectContext targetContext,
            DependenciesRuleChangeContext dependencyChangeContext)
        {
            Requires.NotNull(sharedFolders, nameof(sharedFolders));
            Requires.NotNull(targetContext, nameof(targetContext));
            Requires.NotNull(dependencyChangeContext, nameof(dependencyChangeContext));

            IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot;

            if (!snapshot.Targets.TryGetValue(targetContext.TargetFramework, out ITargetedDependenciesSnapshot targetedSnapshot))
            {
                return;
            }

            IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath);
            var currentSharedImportNodes = targetedSnapshot.TopLevelDependencies
                                           .Where(x => x.Flags.Contains(DependencyTreeFlags.SharedProjectFlags))
                                           .ToList();
            IEnumerable <string> currentSharedImportNodePaths = currentSharedImportNodes.Select(x => x.Path);

            // process added nodes
            IEnumerable <string> addedSharedImportPaths = sharedFolderProjectPaths.Except(currentSharedImportNodePaths);

            foreach (string addedSharedImportPath in addedSharedImportPaths)
            {
                IDependencyModel added = new SharedProjectDependencyModel(
                    addedSharedImportPath,
                    addedSharedImportPath,
                    isResolved: true,
                    isImplicit: false,
                    properties: ImmutableStringDictionary <string> .EmptyOrdinal);
                dependencyChangeContext.IncludeAddedChange(targetContext.TargetFramework, added);
            }

            // process removed nodes
            IEnumerable <string> removedSharedImportPaths = currentSharedImportNodePaths.Except(sharedFolderProjectPaths);

            foreach (string removedSharedImportPath in removedSharedImportPaths)
            {
                bool exists = currentSharedImportNodes.Any(node => PathHelper.IsSamePath(node.Path, removedSharedImportPath));

                if (exists)
                {
                    dependencyChangeContext.IncludeRemovedChange(
                        targetContext.TargetFramework,
                        ProjectRuleHandler.ProviderTypeString,
                        dependencyId: removedSharedImportPath);
                }
            }
        }
        private void OnDependenciesSnapshotChanged(object sender, SnapshotChangedEventArgs e)
        {
            IDependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null)
            {
                return;
            }

            if (_tasksService.UnloadCancellationToken.IsCancellationRequested || e.Token.IsCancellationRequested)
            {
                return;
            }

            // Take the highest priority view provider
            IDependenciesTreeViewProvider viewProvider = _viewProviders.FirstOrDefault()?.Value;

            if (viewProvider == null)
            {
                return;
            }

            try
            {
                _ = SubmitTreeUpdateAsync(
                    async(treeSnapshot, configuredProjectExports, cancellationToken) =>
                {
                    IProjectTree dependenciesNode = treeSnapshot.Value.Tree;

                    if (!cancellationToken.IsCancellationRequested)
                    {
                        dependenciesNode = await viewProvider.BuildTreeAsync(dependenciesNode, snapshot, cancellationToken);

                        await _treeTelemetryService.ObserveTreeUpdateCompletedAsync(snapshot.HasUnresolvedDependency);
                    }

                    // TODO We still are getting mismatched data sources and need to figure out better
                    // way of merging, mute them for now and get to it in U1
                    return(new TreeUpdateResult(dependenciesNode));
                },
                    _treeUpdateCancellationSeries.CreateNext(e.Token));
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception ex)
            {
                // We do not expect any exception when we call SubmitTreeUpdateAsync, but we don't want to leak an exception here.
                // Because it will fail the dataflow block and stops updating the project tree silently.
                _ = ProjectFaultHandlerService.ReportFaultAsync(ex, UnconfiguredProject);
            }
        }
        public static IDependenciesSnapshotProvider Implement(
            IDependenciesSnapshot currentSnapshot = null,
            MockBehavior mockBehavior             = MockBehavior.Default)
        {
            var mock = new Mock <IDependenciesSnapshotProvider>(mockBehavior);

            if (currentSnapshot != null)
            {
                mock.Setup(x => x.CurrentSnapshot).Returns(currentSnapshot);
            }

            return(mock.Object);
        }
Example #19
0
        private void ProcessSharedProjectsUpdates(
            IProjectSharedFoldersSnapshot sharedFolders,
            ITargetFramework targetFramework,
            CrossTargetDependenciesChangesBuilder changesBuilder)
        {
            Requires.NotNull(sharedFolders, nameof(sharedFolders));
            Requires.NotNull(targetFramework, nameof(targetFramework));
            Requires.NotNull(changesBuilder, nameof(changesBuilder));

            IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot;

            if (!snapshot.Targets.TryGetValue(targetFramework, out ITargetedDependenciesSnapshot targetedSnapshot))
            {
                return;
            }

            IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath);
            var currentSharedImportNodePaths = targetedSnapshot.TopLevelDependencies
                                               .Where(x => x.Flags.Contains(DependencyTreeFlags.SharedProjectFlags))
                                               .Select(x => x.Path)
                                               .ToList();

            var diff = new SetDiff <string>(currentSharedImportNodePaths, sharedFolderProjectPaths);

            // process added nodes
            foreach (string addedSharedImportPath in diff.Added)
            {
                IDependencyModel added = new SharedProjectDependencyModel(
                    addedSharedImportPath,
                    addedSharedImportPath,
                    isResolved: true,
                    isImplicit: false,
                    properties: ImmutableStringDictionary <string> .EmptyOrdinal);
                changesBuilder.Added(targetFramework, added);
            }

            // process removed nodes
            foreach (string removedSharedImportPath in diff.Removed)
            {
                bool exists = currentSharedImportNodePaths.Any(nodePath => PathHelper.IsSamePath(nodePath, removedSharedImportPath));

                if (exists)
                {
                    changesBuilder.Removed(
                        targetFramework,
                        ProjectRuleHandler.ProviderTypeString,
                        dependencyId: removedSharedImportPath);
                }
            }
        }
Example #20
0
        private void ProcessSharedProjectsUpdates(
            IProjectSharedFoldersSnapshot sharedFolders,
            ITargetedProjectContext targetContext,
            DependenciesRuleChangeContext dependencyChangeContext)
        {
            Requires.NotNull(sharedFolders, nameof(sharedFolders));
            Requires.NotNull(targetContext, nameof(targetContext));
            Requires.NotNull(dependencyChangeContext, nameof(dependencyChangeContext));

            IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot;

            if (!snapshot.Targets.TryGetValue(targetContext.TargetFramework, out ITargetedDependenciesSnapshot targetedSnapshot))
            {
                return;
            }

            IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath);
            var currentSharedImportNodes = targetedSnapshot.TopLevelDependencies
                                           .Where(x => x.Flags.Contains(DependencyTreeFlags.SharedProjectFlags))
                                           .ToList();
            IEnumerable <string> currentSharedImportNodePaths = currentSharedImportNodes.Select(x => x.Path);

            // process added nodes
            IEnumerable <string> addedSharedImportPaths = sharedFolderProjectPaths.Except(currentSharedImportNodePaths);

            foreach (string addedSharedImportPath in addedSharedImportPaths)
            {
                IDependencyModel added = CreateDependencyModel(addedSharedImportPath, targetContext.TargetFramework, resolved: true);
                dependencyChangeContext.IncludeAddedChange(targetContext.TargetFramework, added);
            }

            // process removed nodes
            IEnumerable <string> removedSharedImportPaths = currentSharedImportNodePaths.Except(sharedFolderProjectPaths);

            foreach (string removedSharedImportPath in removedSharedImportPaths)
            {
                IDependency existingImportNode = currentSharedImportNodes
                                                 .Where(node => PathHelper.IsSamePath(node.Path, removedSharedImportPath))
                                                 .FirstOrDefault();

                if (existingImportNode != null)
                {
                    IDependencyModel removed = CreateDependencyModel(removedSharedImportPath, targetContext.TargetFramework, resolved: true);
                    dependencyChangeContext.IncludeRemovedChange(targetContext.TargetFramework, removed);
                }
            }
        }
        /// <summary>
        /// Does flat search among dependency world lists to find any dependencies that match search criteria.
        /// </summary>
        private static HashSet <IDependency> SearchFlat(string searchTerm, IDependenciesSnapshot dependenciesSnapshot)
        {
            var matchedDependencies = new HashSet <IDependency>();

            foreach ((ITargetFramework _, ITargetedDependenciesSnapshot targetedSnapshot) in dependenciesSnapshot.DependenciesByTargetFramework)
            {
                foreach ((string _, IDependency dependency) in targetedSnapshot.DependenciesWorld)
                {
                    if (dependency.Visible && dependency.Caption.IndexOf(searchTerm, StringComparison.CurrentCultureIgnoreCase) != -1)
                    {
                        matchedDependencies.Add(dependency);
                    }
                }
            }

            return(matchedDependencies);
        }
        /// <summary>
        /// Does flat search among dependency world lists to find any dependencies that match search criteria.
        /// </summary>
        private static HashSet <IDependency> SearchFlat(string searchTerm, IDependenciesSnapshot dependenciesSnapshot)
        {
            var matchedDependencies = new HashSet <IDependency>();

            foreach ((ITargetFramework _, ITargetedDependenciesSnapshot targetedSnapshot) in dependenciesSnapshot.Targets)
            {
                foreach ((string _, IDependency dependency) in targetedSnapshot.DependenciesWorld)
                {
                    if (dependency.Visible && dependency.Caption.ToLowerInvariant().Contains(searchTerm))
                    {
                        matchedDependencies.Add(dependency);
                    }
                }
            }

            return(matchedDependencies);
        }
        private void ScheduleDependenciesUpdate(CancellationToken token = default)
        {
            _dependenciesUpdateScheduler.ScheduleAsyncTask(ct =>
            {
                if (ct.IsCancellationRequested || IsDisposing || IsDisposed)
                {
                    return(Task.FromCanceled(ct));
                }

                IDependenciesSnapshot snapshot = _currentSnapshot;

                if (snapshot != null)
                {
                    SnapshotChanged?.Invoke(this, new SnapshotChangedEventArgs(snapshot, ct));
                }

                return(Task.CompletedTask);
            }, token);
        }
Example #24
0
        /// <inheritdoc />
        public ITargetedDependenciesSnapshot GetSnapshot(IDependency dependency)
        {
            IDependenciesSnapshot snapshot = GetSnapshot(dependency.FullPath);

            if (snapshot == null)
            {
                return(null);
            }

            ITargetFramework targetFramework = _targetFrameworkProvider.GetNearestFramework(
                dependency.TargetFramework, snapshot.Targets.Keys);

            if (targetFramework == null)
            {
                return(null);
            }

            return(snapshot.Targets[targetFramework]);
        }
        private void ScheduleDependenciesUpdate()
        {
            DependenciesUpdateScheduler.ScheduleAsyncTask((token) =>
            {
                if (token.IsCancellationRequested || IsDisposing || IsDisposed)
                {
                    return(Task.FromCanceled(token));
                }

                IDependenciesSnapshot snapshot = CurrentSnapshot;
                if (snapshot == null)
                {
                    return(Task.CompletedTask);
                }

                OnDependenciesSnapshotChanged(snapshot);

                return(Task.CompletedTask);
            });
        }
Example #26
0
        private ITargetedDependenciesSnapshot GetSnapshot(IDependency dependency)
        {
            IDependenciesSnapshot snapshot =
                AggregateSnapshotProvider.GetSnapshotProvider(dependency.FullPath)?.CurrentSnapshot;

            if (snapshot == null)
            {
                return(null);
            }

            ITargetFramework targetFramework = TargetFrameworkProvider.GetNearestFramework(
                dependency.TargetFramework, snapshot.Targets.Keys);

            if (targetFramework == null)
            {
                return(null);
            }

            return(snapshot.Targets[targetFramework]);
        }
        /// <summary>
        /// Gets a value indicating whether deleting a given set of items from the project, and optionally from disk,
        /// would be allowed.
        /// Note: CanRemove can be called several times since there two types of remove operations:
        ///   - Remove is a command that can remove project tree items form the tree/project but not from disk.
        ///     For that command requests deleteOptions has DeleteOptions.None flag.
        ///   - Delete is a command that can remove project tree items and form project and from disk.
        ///     For this command requests deleteOptions has DeleteOptions.DeleteFromStorage flag.
        /// We can potentially support only Remove command here, since we don't remove Dependencies form disk,
        /// thus we return false when DeleteOptions.DeleteFromStorage is provided.
        /// </summary>
        /// <param name="nodes">The nodes that should be deleted.</param>
        /// <param name="deleteOptions">
        /// A value indicating whether the items should be deleted from disk as well as from the project file.
        /// </param>
        public override bool CanRemove(IImmutableSet <IProjectTree> nodes,
                                       DeleteOptions deleteOptions = DeleteOptions.None)
        {
            if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage))
            {
                return(false);
            }

            IDependenciesSnapshot snapshot = DependenciesSnapshotProvider.CurrentSnapshot;

            if (snapshot == null)
            {
                return(false);
            }

            bool canRemove = true;

            foreach (IProjectTree node in nodes)
            {
                if (!node.Flags.Contains(DependencyTreeFlags.SupportsRemove))
                {
                    canRemove = false;
                    break;
                }

                string filePath = UnconfiguredProject.GetRelativePath(node.FilePath);
                if (string.IsNullOrEmpty(filePath))
                {
                    continue;
                }

                IDependency dependency = snapshot.FindDependency(filePath, topLevel: true);
                if (dependency == null || dependency.Implicit)
                {
                    canRemove = false;
                    break;
                }
            }

            return(canRemove);
        }
        /// <summary>
        /// Does flat search among dependency world lists to find any dependencies that match search criteria.
        /// </summary>
        private HashSet <IDependency> SearchFlat(
            string projectPath,
            string searchTerm,
            IGraphContext graphContext,
            IDependenciesSnapshot dependenciesSnapshot)
        {
            var matchedDependencies = new HashSet <IDependency>();

            foreach (var targetedSnapshot in dependenciesSnapshot.Targets)
            {
                foreach (var dependency in targetedSnapshot.Value.DependenciesWorld)
                {
                    if (dependency.Value.Visible && dependency.Value.Caption.ToLowerInvariant().Contains(searchTerm))
                    {
                        matchedDependencies.Add(dependency.Value);
                    }
                }
            }

            return(matchedDependencies);
        }
Example #29
0
        private void OnDependenciesSnapshotChanged(object sender, SnapshotChangedEventArgs e)
        {
            IDependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null)
            {
                return;
            }

            if (_tasksService.UnloadCancellationToken.IsCancellationRequested || e.Token.IsCancellationRequested)
            {
                return;
            }

            // Take the highest priority view provider
            IDependenciesTreeViewProvider viewProvider = _viewProviders.FirstOrDefault()?.Value;

            if (viewProvider == null)
            {
                return;
            }

            _ = SubmitTreeUpdateAsync(
                async(treeSnapshot, configuredProjectExports, cancellationToken) =>
            {
                IProjectTree dependenciesNode = treeSnapshot.Value.Tree;

                if (!cancellationToken.IsCancellationRequested)
                {
                    dependenciesNode = await viewProvider.BuildTreeAsync(dependenciesNode, snapshot, cancellationToken);

                    await _treeTelemetryService.ObserveTreeUpdateCompletedAsync(snapshot.HasUnresolvedDependency);
                }

                // TODO We still are getting mismatched data sources and need to figure out better
                // way of merging, mute them for now and get to it in U1
                return(new TreeUpdateResult(dependenciesNode));
            },
                _treeUpdateCancellationSeries.CreateNext(e.Token));
        }
        /// <summary>
        /// ProjectContextChanged gets fired everytime dependencies change for projects accross solution.
        /// ExpandedGraphContexts contain all nodes that we need to check for potential updates in their
        /// children dependencies.
        /// </summary>
        private void OnSnapshotChanged(object sender, SnapshotChangedEventArgs e)
        {
            IDependenciesSnapshot snapshot = e.Snapshot;

            if (snapshot == null)
            {
                return;
            }

            lock (_changedContextsQueueLock)
            {
                _changedContextsQueue[snapshot.ProjectPath] = e;

                // schedule new track changes request in the queue
                if (_trackChangesTask == null || _trackChangesTask.IsCompleted)
                {
                    _trackChangesTask = RunTrackChangesAsync();
                }
                else
                {
                    _trackChangesTask = _trackChangesTask.ContinueWith(t => RunTrackChangesAsync(), TaskScheduler.Default);
                }
            }
        }