示例#1
0
        public Task ReleaseSubscriptionsAsync()
        {
            _currentProjectContext = null;

            foreach (var link in _evaluationSubscriptionLinks.Concat(_designTimeBuildSubscriptionLinks))
            {
                link.Dispose();
            }

            _evaluationSubscriptionLinks.Clear();
            _designTimeBuildSubscriptionLinks.Clear();

            return(Task.CompletedTask);
        }
        private async Task UpdateProjectContextAndSubscriptionsAsync()
        {
            AggregateCrossTargetProjectContext previousProjectContext = await ExecuteWithinLockAsync(() => _currentAggregateProjectContext);

            AggregateCrossTargetProjectContext newProjectContext = await UpdateProjectContextAsync();

            if (previousProjectContext != newProjectContext)
            {
                // Dispose existing subscriptions.
                DisposeAndClearSubscriptions();

                // Add subscriptions for the configured projects in the new project context.
                await AddSubscriptionsAsync(newProjectContext);
            }
        }
        public void ReleaseProjectContext(AggregateCrossTargetProjectContext context)
        {
            Requires.NotNull(context, nameof(context));

            lock (_gate)
            {
                if (!_contexts.Remove(context))
                {
                    throw new ArgumentException("Specified context was not created by this instance, or has already been unregistered.");
                }

                // Update the maps storing configured project host objects and project contexts which are shared across created contexts.
                // We can remove the ones which are only used by the current context being released.
                RemoveUnusedConfiguredProjectsState_NoLock();
            }
        }
        public Task AddSubscriptionsAsync(AggregateCrossTargetProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            _currentProjectContext = newProjectContext;

            var watchedEvaluationRules      = GetWatchedRules(RuleHandlerType.Evaluation);
            var watchedDesignTimeBuildRules = GetWatchedRules(RuleHandlerType.DesignTimeBuild);

            foreach (var configuredProject in newProjectContext.InnerConfiguredProjects)
            {
                SubscribeToConfiguredProject(
                    configuredProject.Services.ProjectSubscription, watchedEvaluationRules, watchedDesignTimeBuildRules);
            }

            return(Task.CompletedTask);
        }
示例#5
0
        protected override void Handle(
            AggregateCrossTargetProjectContext currentAggregateContext,
            ITargetFramework targetFrameworkToUpdate,
            EventData e)
        {
            IProjectSharedFoldersSnapshot sharedProjectsUpdate = e.Item2;
            IProjectCatalogSnapshot       catalogs             = e.Item3;

            var changesBuilder = new DependenciesChangesBuilder();

            ProcessSharedProjectsUpdates(sharedProjectsUpdate, targetFrameworkToUpdate, changesBuilder);

            IDependenciesChanges?changes = changesBuilder.TryBuildChanges();

            if (changes != null)
            {
                RaiseDependenciesChanged(targetFrameworkToUpdate, changes, currentAggregateContext, catalogs);
            }
        }
        private async Task HandleAsync(Tuple <IProjectSubscriptionUpdate, IProjectSharedFoldersSnapshot, IProjectCatalogSnapshot> e)
        {
            AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContext();

            if (currentAggregateContext == null)
            {
                return;
            }

            IProjectSubscriptionUpdate    projectUpdate        = e.Item1;
            IProjectSharedFoldersSnapshot sharedProjectsUpdate = e.Item2;
            IProjectCatalogSnapshot       catalogs             = e.Item3;

            // We need to process the update within a lock to ensure that we do not release this context during processing.
            // TODO: Enable concurrent execution of updates themselves, i.e. two separate invocations of HandleAsync
            //       should be able to run concurrently.
            using (await _gate.DisposableWaitAsync())
            {
                // Get the inner workspace project context to update for this change.
                ITargetedProjectContext projectContextToUpdate = currentAggregateContext
                                                                 .GetInnerProjectContext(projectUpdate.ProjectConfiguration, out bool isActiveContext);

                if (projectContextToUpdate == null)
                {
                    return;
                }

                var dependencyChangeContext = new DependenciesRuleChangeContext(
                    currentAggregateContext.ActiveProjectContext.TargetFramework,
                    catalogs);

                ProcessSharedProjectsUpdates(sharedProjectsUpdate, projectContextToUpdate, dependencyChangeContext);

                if (dependencyChangeContext.AnyChanges)
                {
                    DependenciesChanged?.Invoke(this, new DependencySubscriptionChangedEventArgs(dependencyChangeContext));
                }
            }
        }
示例#7
0
        public void AddSubscriptions(AggregateCrossTargetProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            _currentProjectContext = newProjectContext;

            IEnumerable <string> watchedEvaluationRules      = GetWatchedRules(RuleHandlerType.Evaluation);
            IEnumerable <string> watchedDesignTimeBuildRules = GetWatchedRules(RuleHandlerType.DesignTimeBuild);

            // initialize telemetry with all rules for each target framework
            foreach (ITargetedProjectContext projectContext in newProjectContext.InnerProjectContexts)
            {
                _treeTelemetryService.InitializeTargetFrameworkRules(projectContext.TargetFramework, watchedEvaluationRules);
                _treeTelemetryService.InitializeTargetFrameworkRules(projectContext.TargetFramework, watchedDesignTimeBuildRules);
            }

            foreach (ConfiguredProject configuredProject in newProjectContext.InnerConfiguredProjects)
            {
                SubscribeToConfiguredProject(
                    configuredProject, configuredProject.Services.ProjectSubscription, watchedEvaluationRules, watchedDesignTimeBuildRules);
            }
        }
        public async Task <AggregateCrossTargetProjectContext> CreateProjectContextAsync()
        {
            EnsureInitialized();

            AggregateCrossTargetProjectContext context = await CreateProjectContextAsyncCore().ConfigureAwait(false);

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

            lock (_gate)
            {
                // There's a race here, by the time we've created the project context,
                // the project could have been renamed, handle this.
                ProjectData projectData = GetProjectData();

                context.SetProjectFilePathAndDisplayName(projectData.FullPath, projectData.DisplayName);
                _contexts.Add(context);
            }

            return(context);
        }
示例#9
0
        private async Task HandleAsync(Tuple <IProjectSubscriptionUpdate, IProjectSharedFoldersSnapshot, IProjectCatalogSnapshot> e)
        {
            AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContextAsync();

            if (currentAggregateContext == null)
            {
                return;
            }

            IProjectSubscriptionUpdate    projectUpdate        = e.Item1;
            IProjectSharedFoldersSnapshot sharedProjectsUpdate = e.Item2;
            IProjectCatalogSnapshot       catalogs             = e.Item3;

            // Get the target framework to update for this change.
            ITargetFramework targetFrameworkToUpdate = currentAggregateContext.GetProjectFramework(projectUpdate.ProjectConfiguration);

            if (targetFrameworkToUpdate == null)
            {
                return;
            }

            var changesBuilder = new CrossTargetDependenciesChangesBuilder();

            ProcessSharedProjectsUpdates(sharedProjectsUpdate, targetFrameworkToUpdate, changesBuilder);

            ImmutableDictionary <ITargetFramework, IDependenciesChanges> changes = changesBuilder.TryBuildChanges();

            if (changes != null)
            {
                DependenciesChanged?.Invoke(
                    this,
                    new DependencySubscriptionChangedEventArgs(
                        currentAggregateContext.ActiveTargetFramework,
                        catalogs,
                        changes));
            }
        }
示例#10
0
        public Task AddSubscriptionsAsync(AggregateCrossTargetProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            _currentProjectContext = newProjectContext;

            var watchedEvaluationRules      = GetWatchedRules(RuleHandlerType.Evaluation);
            var watchedDesignTimeBuildRules = GetWatchedRules(RuleHandlerType.DesignTimeBuild);

            // initialize telemetry with all rules for each target framework
            foreach (var projectContext in newProjectContext.InnerProjectContexts)
            {
                _treeTelemetryService.InitializeTargetFrameworkRules(projectContext.TargetFramework, watchedEvaluationRules);
                _treeTelemetryService.InitializeTargetFrameworkRules(projectContext.TargetFramework, watchedDesignTimeBuildRules);
            }

            foreach (var configuredProject in newProjectContext.InnerConfiguredProjects)
            {
                SubscribeToConfiguredProject(
                    configuredProject, configuredProject.Services.ProjectSubscription, watchedEvaluationRules, watchedDesignTimeBuildRules);
            }

            return(Task.CompletedTask);
        }
        private async Task AddSubscriptionsAsync(AggregateCrossTargetProjectContext newProjectContext)
        {
            Requires.NotNull(newProjectContext, nameof(newProjectContext));

            await _commonServices.ThreadingService.SwitchToUIThread();

            using (_tasksService.LoadedProject())
            {
                lock (_linksLock)
                {
                    foreach (var configuredProject in newProjectContext.InnerConfiguredProjects)
                    {
                        SubscribeToConfiguredProject(configuredProject.Services.ProjectSubscription,
                                                     new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                                                         e => OnProjectChangedCoreAsync(e, RuleHandlerType.Evaluation)));
                    }

                    foreach (var subscriber in Subscribers)
                    {
                        subscriber.Value.AddSubscriptionsAsync(newProjectContext);
                    }
                }
            }
        }
 protected virtual void OnAggregateContextChanged(AggregateCrossTargetProjectContext oldContext,
                                                  AggregateCrossTargetProjectContext newContext)
 {
     // by default do nothing
 }
        private async Task HandleAsync(
            IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > e,
            RuleHandlerType handlerType)
        {
            AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContext().ConfigureAwait(false);

            if (currentAggregateContext == null || _currentProjectContext != currentAggregateContext)
            {
                return;
            }

            IProjectSubscriptionUpdate update   = e.Value.Item1;
            IProjectCatalogSnapshot    catalogs = e.Value.Item2;
            IEnumerable <ICrossTargetRuleHandler <T> > handlers = Handlers.Select(h => h.Value)
                                                                  .Where(h => h.SupportsHandlerType(handlerType));

            // We need to process the update within a lock to ensure that we do not release this context during processing.
            // TODO: Enable concurrent execution of updates themeselves, i.e. two separate invocations of HandleAsync
            //       should be able to run concurrently.
            using (await _gate.DisposableWaitAsync().ConfigureAwait(true))
            {
                // Get the inner workspace project context to update for this change.
                ITargetedProjectContext projectContextToUpdate = currentAggregateContext
                                                                 .GetInnerProjectContext(update.ProjectConfiguration, out bool isActiveContext);
                if (projectContextToUpdate == null)
                {
                    return;
                }

                // Broken design time builds sometimes cause updates with no project changes and sometimes
                // cause updates with a project change that has no difference.
                // We handle the former case here, and the latter case is handled in the CommandLineItemHandler.
                if (update.ProjectChanges.Count == 0)
                {
                    if (handlerType == RuleHandlerType.DesignTimeBuild)
                    {
                        projectContextToUpdate.LastDesignTimeBuildSucceeded = false;
                    }

                    return;
                }

                T ruleChangeContext = CreateRuleChangeContext(
                    currentAggregateContext.ActiveProjectContext.TargetFramework, catalogs);
                foreach (ICrossTargetRuleHandler <T> handler in handlers)
                {
                    ImmutableDictionary <string, IProjectChangeDescription> .Builder builder = ImmutableDictionary.CreateBuilder <string, IProjectChangeDescription>(StringComparers.RuleNames);
                    ImmutableHashSet <string> handlerRules = handler.GetRuleNames(handlerType);
                    builder.AddRange(update.ProjectChanges.Where(
                                         x => handlerRules.Contains(x.Key)));
                    ImmutableDictionary <string, IProjectChangeDescription> projectChanges = builder.ToImmutable();

                    if (handler.ReceiveUpdatesWithEmptyProjectChange ||
                        projectChanges.Any(x => x.Value.Difference.AnyChanges))
                    {
                        await handler.HandleAsync(e,
                                                  projectChanges,
                                                  projectContextToUpdate,
                                                  isActiveContext,
                                                  ruleChangeContext)
                        .ConfigureAwait(true);
                    }
                }

                await CompleteHandleAsync(ruleChangeContext).ConfigureAwait(false);

                // record all the rules that have occurred
                _treeTelemetryService.ObserveTargetFrameworkRules(projectContextToUpdate.TargetFramework, update.ProjectChanges.Keys);
            }
        }
示例#14
0
        private async Task HandleAsync(
            IProjectSubscriptionUpdate projectUpdate,
            IProjectCatalogSnapshot catalogSnapshot,
            RuleHandlerType handlerType)
        {
            AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContext();

            if (currentAggregateContext == null || _currentProjectContext != currentAggregateContext)
            {
                return;
            }

            IEnumerable <ICrossTargetRuleHandler <T> > handlers
                = Handlers
                  .Select(h => h.Value)
                  .Where(h => h.SupportsHandlerType(handlerType));

            ITargetedProjectContext projectContextToUpdate;

            // We need to process the update within a lock to ensure that we do not release this context during processing.
            // TODO: Enable concurrent execution of updates themselves, i.e. two separate invocations of HandleAsync
            //       should be able to run concurrently.
            using (await _gate.DisposableWaitAsync())
            {
                // Get the inner workspace project context to update for this change.
                projectContextToUpdate = currentAggregateContext
                                         .GetInnerProjectContext(projectUpdate.ProjectConfiguration, out bool isActiveContext);

                if (projectContextToUpdate == null)
                {
                    return;
                }

                // Broken design time builds sometimes cause updates with no project changes and sometimes
                // cause updates with a project change that has no difference.
                // We handle the former case here, and the latter case is handled in the CommandLineItemHandler.
                if (projectUpdate.ProjectChanges.Count == 0)
                {
                    if (handlerType == RuleHandlerType.DesignTimeBuild)
                    {
                        projectContextToUpdate.LastDesignTimeBuildSucceeded = false;
                    }

                    return;
                }

                // Get the subclass-specific context that will aggregate data during the processing of rule data by handlers.
                T ruleChangeContext = CreateRuleChangeContext(
                    currentAggregateContext.ActiveProjectContext.TargetFramework,
                    catalogSnapshot);

                // Give each handler a chance to modify the rule change context.
                foreach (ICrossTargetRuleHandler <T> handler in handlers)
                {
                    ImmutableHashSet <string> handlerRules = handler.GetRuleNames(handlerType);

                    // Slice project changes to include only rules the handler claims an interest in.
                    var projectChanges = projectUpdate.ProjectChanges
                                         .Where(x => handlerRules.Contains(x.Key))
                                         .ToImmutableDictionary();

                    if (handler.ReceiveUpdatesWithEmptyProjectChange ||
                        projectChanges.Any(x => x.Value.Difference.AnyChanges))
                    {
                        // Handlers respond to rule changes in a way that's specific to the rule change context
                        // type (T). For example, DependencyRulesSubscriber uses DependenciesRuleChangeContext
                        // which holds IDependencyModel, so its ICrossTargetRuleHandler<DependenciesRuleChangeContext>
                        // implementations will produce IDependencyModel objects in response to rule changes.
                        handler.Handle(projectChanges, projectContextToUpdate.TargetFramework, ruleChangeContext);
                    }
                }

                // Notify the subclass that their rule change context object is ready for finalization.
                CompleteHandle(ruleChangeContext);
            }

            // record all the rules that have occurred
            _treeTelemetryService.ObserveTargetFrameworkRules(projectContextToUpdate.TargetFramework, projectUpdate.ProjectChanges.Keys);
        }
示例#15
0
 private async Task DisposeAggregateProjectContextAsync(AggregateCrossTargetProjectContext projectContext)
 {
     await _contextProvider.Value.ReleaseProjectContextAsync(projectContext);
 }
 private void DisposeAggregateProjectContext(AggregateCrossTargetProjectContext projectContext)
 {
     _contextProvider.Value.ReleaseProjectContext(projectContext);
 }