protected override Task InitializeCoreAsync(CancellationToken cancellationToken)
            {
                _joinedDataSources = ProjectDataSources.JoinUpstreamDataSources(JoinableFactory, _projectFaultHandlerService, _projectSubscriptionService.ProjectSource, _dataSource);

                _progressRegistration = _dataProgressTrackerService.RegisterOutputDataSource(this);

                Action <IProjectVersionedValue <ValueTuple <IProjectSnapshot, RestoreData> > > action = OnRestoreCompleted;

                _subscription = ProjectDataSources.SyncLinkTo(
                    _projectSubscriptionService.ProjectSource.SourceBlock.SyncLinkOptions(),
                    _dataSource.SourceBlock.SyncLinkOptions(),
                    DataflowBlockSlim.CreateActionBlock(action),
                    linkOptions: DataflowOption.PropagateCompletion);

                return(Task.CompletedTask);
            }
            private void OnActiveConfigurationsChanged(IProjectVersionedValue <IConfigurationGroup <ConfiguredProject> > e)
            {
                if (IsDisposing || IsDisposed)
                {
                    return;
                }

                // Clean up past subscriptions
                _designTimeBuildSubscriptionLink?.Dispose();

                if (e.Value.Count > 0)
                {
                    var sourceLinkOptions = new StandardRuleDataflowLinkOptions
                    {
                        RuleNames           = s_designTimeBuildWatchedRules,
                        PropagateCompletion = true
                    };

                    var disposableBag = new DisposableBag(CancellationToken.None);
                    // We are taking source blocks from multiple configured projects and creating a SyncLink to combine the sources.
                    // The SyncLink will only publish data when the versions of the sources match. There is a problem with that.
                    // The sources have some version components that will make this impossible to match across TFMs. We introduce a
                    // intermediate block here that will remove those version components so that the synclink can actually sync versions.
                    IEnumerable <ProjectDataSources.SourceBlockAndLink <IProjectValueVersions> > sourceBlocks = e.Value.Select(
                        cp =>
                    {
                        IReceivableSourceBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> > sourceBlock = cp.Services.ProjectSubscription.JointRuleSource.SourceBlock;
                        IPropagatorBlock <IProjectVersionedValue <IProjectSubscriptionUpdate>, IProjectVersionedValue <IProjectSubscriptionUpdate> > versionDropper = CreateVersionDropperBlock();
                        disposableBag.AddDisposable(sourceBlock.LinkTo(versionDropper, sourceLinkOptions));
                        return(versionDropper.SyncLinkOptions <IProjectValueVersions>(sourceLinkOptions));
                    });

                    Action <Tuple <ImmutableList <IProjectValueVersions>, TIdentityDictionary> > action = ProjectPropertyChanged;
                    var target = new ActionBlock <Tuple <ImmutableList <IProjectValueVersions>, TIdentityDictionary> >(action);

                    var targetLinkOptions = new DataflowLinkOptions {
                        PropagateCompletion = true
                    };

                    ImmutableList <ProjectDataSources.SourceBlockAndLink <IProjectValueVersions> > sourceBlocksAndCapabilitiesOptions = sourceBlocks.ToImmutableList()
                                                                                                                                        .Insert(0, _projectVsServices.Project.Capabilities.SourceBlock.SyncLinkOptions <IProjectValueVersions>());

                    disposableBag.AddDisposable(ProjectDataSources.SyncLinkTo(sourceBlocksAndCapabilitiesOptions, target, targetLinkOptions));

                    _designTimeBuildSubscriptionLink = disposableBag;
                }
            }
示例#3
0
 protected override void SubscribeToConfiguredProject(
     ConfiguredProject configuredProject,
     IProjectSubscriptionService subscriptionService)
 {
     Subscribe(
         configuredProject,
         subscriptionService.ProjectRuleSource,
         ruleNames: new[] { ConfigurationGeneral.SchemaName },
         "Dependencies Shared Projects Input: {1}",
         blocks => ProjectDataSources.SyncLinkTo(
             blocks.Intermediate.SyncLinkOptions(),
             subscriptionService.SharedFoldersSource.SourceBlock.SyncLinkOptions(),
             subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
             configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
             blocks.Action,
             linkOptions: DataflowOption.PropagateCompletion));
 }
示例#4
0
            protected override async Task InitializeCoreAsync(CancellationToken cancellationToken)
            {
                _contextAccessor = await _workspaceProjectContextProvider.CreateProjectContextAsync(_project);

                if (_contextAccessor == null)
                {
                    return;
                }

                _activeWorkspaceProjectContextTracker.RegisterContext(_contextAccessor.ContextId);

                _applyChangesToWorkspaceContext = _applyChangesToWorkspaceContextFactory.CreateExport();
                _applyChangesToWorkspaceContext.Value.Initialize(_contextAccessor.Context);

                _evaluationProgressRegistration   = _dataProgressTrackerService.RegisterForIntelliSense(this, _project, nameof(WorkspaceProjectContextHostInstance) + ".Evaluation");
                _projectBuildProgressRegistration = _dataProgressTrackerService.RegisterForIntelliSense(this, _project, nameof(WorkspaceProjectContextHostInstance) + ".ProjectBuild");

                _disposables = new DisposableBag
                {
                    _applyChangesToWorkspaceContext,
                    _evaluationProgressRegistration,
                    _projectBuildProgressRegistration,

                    ProjectDataSources.SyncLinkTo(
                        _activeConfiguredProjectProvider.ActiveConfiguredProjectBlock.SyncLinkOptions(),
                        _projectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(GetProjectEvaluationOptions()),
                        _projectBuildSnapshotService.SourceBlock.SyncLinkOptions(),
                        target: DataflowBlockFactory.CreateActionBlock <IProjectVersionedValue <ValueTuple <ConfiguredProject, IProjectSubscriptionUpdate, IProjectBuildSnapshot> > >(e =>
                                                                                                                                                                                      OnProjectChangedAsync(e, evaluation: true),
                                                                                                                                                                                      _project.UnconfiguredProject,
                                                                                                                                                                                      ProjectFaultSeverity.LimitedFunctionality),
                        linkOptions: DataflowOption.PropagateCompletion,
                        cancellationToken: cancellationToken),

                    ProjectDataSources.SyncLinkTo(
                        _activeConfiguredProjectProvider.ActiveConfiguredProjectBlock.SyncLinkOptions(),
                        _projectSubscriptionService.ProjectBuildRuleSource.SourceBlock.SyncLinkOptions(GetProjectBuildOptions()),
                        _projectBuildSnapshotService.SourceBlock.SyncLinkOptions(),
                        target: DataflowBlockFactory.CreateActionBlock <IProjectVersionedValue <ValueTuple <ConfiguredProject, IProjectSubscriptionUpdate, IProjectBuildSnapshot> > >(e =>
                                                                                                                                                                                      OnProjectChangedAsync(e, evaluation: false),
                                                                                                                                                                                      _project.UnconfiguredProject,
                                                                                                                                                                                      ProjectFaultSeverity.LimitedFunctionality),
                        linkOptions: DataflowOption.PropagateCompletion,
                        cancellationToken: cancellationToken),
                };
            }
        private void SubscribeToConfiguredProject(
            ConfiguredProject configuredProject,
            IProjectSubscriptionService subscriptionService,
            IReadOnlyCollection <string> watchedEvaluationRules,
            IReadOnlyCollection <string> watchedJointRules)
        {
            Subscribe(RuleSource.Evaluation, subscriptionService.ProjectRuleSource, watchedEvaluationRules);
            Subscribe(RuleSource.Joint, subscriptionService.JointRuleSource, watchedJointRules);

            void Subscribe(RuleSource source, IProjectValueDataSource <IProjectSubscriptionUpdate> dataSource, IReadOnlyCollection <string> ruleNames)
            {
                // Use intermediate buffer blocks for project rule data to allow subsequent blocks
                // to only observe specific rule name(s).

                var intermediateBlock =
                    new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                        new ExecutionDataflowBlockOptions()
                {
                    NameFormat = string.Intern($"CrossTarget Intermediate {source} Input: {{1}}")
                });

                ITargetBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > > actionBlock =
                    DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > >(
                        e => OnProjectChangedAsync(e.Value.Item1, e.Value.Item2, e.Value.Item3, configuredProject),
                        new ExecutionDataflowBlockOptions()
                {
                    NameFormat = string.Intern($"CrossTarget {source} Input: {{1}}")
                });

                _subscriptions ??= new DisposableBag();

                _subscriptions.Add(
                    dataSource.SourceBlock.LinkTo(
                        intermediateBlock,
                        ruleNames: ruleNames,
                        suppressVersionOnlyUpdates: true,
                        linkOptions: DataflowOption.PropagateCompletion));

                _subscriptions.Add(ProjectDataSources.SyncLinkTo(
                                       intermediateBlock.SyncLinkOptions(),
                                       subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                       configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
                                       actionBlock,
                                       linkOptions: DataflowOption.PropagateCompletion));
            }
        }
示例#6
0
        protected override async Task InitializeCoreAsync(CancellationToken cancellationToken)
        {
            _projectGuid = await _project.UnconfiguredProject.GetProjectGuidAsync();

            _joinedDataSources = ProjectDataSources.JoinUpstreamDataSources(JoinableFactory, _projectFaultHandlerService, _projectSubscriptionService.ProjectSource, _workloadDescriptorDataSource);

            _missingSetupComponentRegistrationService.RegisterProjectConfiguration(_projectGuid, _project);

            Action <IProjectVersionedValue <ValueTuple <IProjectSnapshot, ISet <WorkloadDescriptor> > > > action = OnWorkloadDescriptorsComputed;

            _subscription = ProjectDataSources.SyncLinkTo(
                _projectSubscriptionService.ProjectSource.SourceBlock.SyncLinkOptions(),
                _workloadDescriptorDataSource.SourceBlock.SyncLinkOptions(),
                DataflowBlockFactory.CreateActionBlock(action, _project.UnconfiguredProject, ProjectFaultSeverity.LimitedFunctionality),
                linkOptions: DataflowOption.PropagateCompletion,
                cancellationToken: cancellationToken);
        }
        /// <summary>
        /// Note: this is important to merge data source versions correctly here, since
        /// and different providers sending this event might have different processing time
        /// and we might end up in later data source versions coming before earlier ones. If
        /// we post greater versions before lower ones there will be exception and data flow
        /// might be broken after that.
        /// Another reason post data source versions here is that there could be other
        /// components waiting for Dependencies tree changes and if we don't post versions,
        /// they could not track our changes.
        /// </summary>
        private IImmutableDictionary <NamedIdentity, IComparable> GetMergedDataSourceVersions(
            DependenciesChangedEventArgs e)
        {
            IImmutableDictionary <NamedIdentity, IComparable> mergedDataSourcesVersions = null;

            lock (_latestDataSourcesVersions)
            {
                if (!string.IsNullOrEmpty(e.Provider.ProviderType) && e.DataSourceVersions != null)
                {
                    _latestDataSourcesVersions[e.Provider.ProviderType] = e.DataSourceVersions;
                }

                mergedDataSourcesVersions =
                    ProjectDataSources.MergeDataSourceVersions(_latestDataSourcesVersions.Values);
            }

            return(mergedDataSourcesVersions);
        }
示例#8
0
            /// <summary>
            /// Initialize the watcher.
            /// </summary>
            protected override Task InitializeCoreAsync(CancellationToken cancellationToken)
            {
                return(_projectTasksService.LoadedProjectAsync(() =>
                {
                    // The tree source to get changes to the tree so that we can identify when the assets file changes.
                    ProjectDataSources.SourceBlockAndLink <IProjectVersionedValue <IProjectTreeSnapshot> > treeSource = _fileSystemTreeProvider.Tree.SyncLinkOptions();

                    // The property source used to get the value of the $ProjectAssetsFile property so that we can identify the location of the assets file.
                    StandardRuleDataflowLinkOptions sourceLinkOptions = DataflowOption.WithRuleNames(ConfigurationGeneral.SchemaName);

                    ProjectDataSources.SourceBlockAndLink <IProjectVersionedValue <IProjectSubscriptionUpdate> > propertySource = _activeConfiguredProjectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(sourceLinkOptions);
                    ITargetBlock <IProjectVersionedValue <Tuple <IProjectTreeSnapshot, IProjectSubscriptionUpdate> > > target = DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <Tuple <IProjectTreeSnapshot, IProjectSubscriptionUpdate> > >(DataFlow_ChangedAsync);

                    // Join the two sources so that we get synchronized versions of the data.
                    _treeWatcher = ProjectDataSources.SyncLinkTo(treeSource, propertySource, target);

                    return Task.CompletedTask;
                }));
            }
示例#9
0
        /// <summary>
        /// Initialize the watcher.
        /// </summary>
        protected override void Initialize()
        {
            _fileChangeService = _serviceProvider.GetService <IVsFileChangeEx, SVsFileChangeEx>();

            // The tree source to get changes to the tree so that we can identify when the assets file changes.
            var treeSource = _fileSystemTreeProvider.Tree.SyncLinkOptions();

            // The property source used to get the value of the $ProjectAssetsFile property so that we can identify the location of the assets file.
            var sourceLinkOptions = new StandardRuleDataflowLinkOptions
            {
                RuleNames           = Empty.OrdinalIgnoreCaseStringSet.Add(ConfigurationGeneral.SchemaName),
                PropagateCompletion = true
            };
            var propertySource = _activeConfiguredProjectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(sourceLinkOptions);
            var target         = new ActionBlock <IProjectVersionedValue <Tuple <IProjectTreeSnapshot, IProjectSubscriptionUpdate> > >(new Action <IProjectVersionedValue <Tuple <IProjectTreeSnapshot, IProjectSubscriptionUpdate> > >(DataFlow_Changed));

            // Join the two sources so that we get synchronized versions of the data.
            _treeWatcher = ProjectDataSources.SyncLinkTo(treeSource, propertySource, target);
        }
示例#10
0
        protected override IDisposable LinkExternalInput(ITargetBlock <RestoreInfo> targetBlock)
        {
            // At a high-level, we want to combine all implicitly active configurations (ie the active config of each TFM) restore data
            // (via ProjectRestoreUpdate) and combine it into a single IVsProjectRestoreInfo2 instance and publish that. When a change is
            // made to a configuration, such as adding a PackageReference, we should react to it and push a new version of our output. If the
            // active configuration changes, we should react to it, and publish data from the new set of implicitly active configurations.
            var disposables = new DisposableBag();

            var restoreConfiguredInputSource = new UnwrapCollectionChainedProjectValueDataSource <IReadOnlyCollection <ConfiguredProject>, PackageRestoreConfiguredInput>(
                _project,
                projects => projects.Select(project => project.Services.ExportProvider.GetExportedValueOrDefault <IPackageRestoreConfiguredInputDataSource>())
                .WhereNotNull()                     // Filter out those without PackageReference
                .Select(DropConfiguredProjectVersions),
                includeSourceVersions: true);

            disposables.Add(restoreConfiguredInputSource);

            IProjectValueDataSource <IConfigurationGroup <ConfiguredProject> > activeConfiguredProjectsSource = _activeConfigurationGroupService.ActiveConfiguredProjectGroupSource;

            disposables.Add(activeConfiguredProjectsSource.SourceBlock.LinkTo(restoreConfiguredInputSource, DataflowOption.PropagateCompletion));

            // Dataflow from two configurations can depend on a same unconfigured level data source, and processes it at a different speed.
            // Introduce a forward-only block to prevent regressions in versions.
            var forwardOnlyBlock = ProjectDataSources.CreateDataSourceVersionForwardOnlyFilteringBlock <IReadOnlyCollection <PackageRestoreConfiguredInput> >();

            disposables.Add(restoreConfiguredInputSource.SourceBlock.LinkTo(forwardOnlyBlock, DataflowOption.PropagateCompletion));

            // Transform all restore data -> combined restore data
            DisposableValue <ISourceBlock <RestoreInfo> > mergeBlock = forwardOnlyBlock.TransformWithNoDelta(update => update.Derive(MergeRestoreInputs));

            disposables.Add(mergeBlock);

            // Set the link up so that we publish changes to target block
            mergeBlock.Value.LinkTo(targetBlock, DataflowOption.PropagateCompletion);

            // Join the source blocks, so if they need to switch to UI thread to complete
            // and someone is blocked on us on the same thread, the call proceeds
            JoinUpstreamDataSources(restoreConfiguredInputSource, activeConfiguredProjectsSource);

            _packageReferenceTelemetryService.PostPackageRestoreEvent(PackageRestoreOperationNames.PackageRestoreUnconfiguredInputDataSourceLinkedToExternalInput);

            return(disposables);
        }
示例#11
0
        private async Task ResetSubscriptionsAsync()
        {
            // active configuration should be updated before resetting subscriptions
            await RefreshActiveConfigurationAsync().ConfigureAwait(false);

            _designTimeBuildSubscriptionLink?.Dispose();

            var currentProjects = await _activeConfiguredProjectsProvider.GetActiveConfiguredProjectsAsync()
                                  .ConfigureAwait(false);

            if (currentProjects != null)
            {
                var sourceLinkOptions = new StandardRuleDataflowLinkOptions
                {
                    RuleNames           = s_designTimeBuildWatchedRules,
                    PropagateCompletion = true
                };

                var disposableBag = new DisposableBag(CancellationToken.None);
                // We are taking source blocks from multiple configured projects and creating a SyncLink to combine the sources.
                // The SyncLink will only publish data when the versions of the sources match. There is a problem with that.
                // The sources have some version components that will make this impossible to match across TFMs. We introduce a
                // intermediate block here that will remove those version components so that the synclink can actually sync versions.
                var sourceBlocks = currentProjects.Objects.Select(
                    cp =>
                {
                    var sourceBlock    = cp.Services.ProjectSubscription.JointRuleSource.SourceBlock;
                    var versionDropper = CreateVersionDropperBlock();
                    disposableBag.AddDisposable(sourceBlock.LinkTo(versionDropper, sourceLinkOptions));
                    return(versionDropper.SyncLinkOptions <IProjectValueVersions>(sourceLinkOptions));
                });

                var target = new ActionBlock <Tuple <ImmutableList <IProjectValueVersions>, TIdentityDictionary> >(ProjectPropertyChangedAsync);

                var targetLinkOptions = new DataflowLinkOptions {
                    PropagateCompletion = true
                };

                disposableBag.AddDisposable(ProjectDataSources.SyncLinkTo(sourceBlocks.ToImmutableList(), target, targetLinkOptions));

                _designTimeBuildSubscriptionLink = disposableBag;
            }
        }
示例#12
0
            protected override Task InitializeCoreAsync(CancellationToken cancellationToken)
            {
                _joinedDataSources = ProjectDataSources.JoinUpstreamDataSources(JoinableFactory, _projectFaultHandlerService, _projectSubscriptionService.ProjectSource, _dataSource);

                _progressRegistration = _dataProgressTrackerService.RegisterOutputDataSource(this);

                Action <IProjectVersionedValue <ValueTuple <IProjectSnapshot, RestoreData> > > action = OnRestoreCompleted;

                _subscription = ProjectDataSources.SyncLinkTo(
                    _projectSubscriptionService.ProjectSource.SourceBlock.SyncLinkOptions(),
                    _dataSource.SourceBlock.SyncLinkOptions(),
                    DataflowBlockFactory.CreateActionBlock(action, ConfiguredProject.UnconfiguredProject, ProjectFaultSeverity.LimitedFunctionality),
                    linkOptions: DataflowOption.PropagateCompletion,
                    cancellationToken: cancellationToken);

                _packageReferenceTelemetryService.PostPackageRestoreEvent(PackageRestoreOperationNames.PackageRestoreProgressTrackerInstanceInitialized, _packageRestoreProgressTrackerId);

                return(Task.CompletedTask);
            }
示例#13
0
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <AssetsFileDependenciesSnapshot> > targetBlock)
        {
            JoinUpstreamDataSources(_activeConfiguredProjectSubscriptionService.ProjectRuleSource);
            JoinUpstreamDataSources(_activeConfiguredProjectSnapshotService);

            string?  lastAssetsFilePath = null;
            DateTime lastTimestampUtc   = DateTime.MinValue;
            AssetsFileDependenciesSnapshot lastSnapshot = AssetsFileDependenciesSnapshot.Empty;

            var intermediateBlock =
                new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                    new ExecutionDataflowBlockOptions {
                NameFormat = nameof(AssetsFileDependenciesDataSource) + " Intermediate: {1}"
            });

            IReceivableSourceBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> > projectRuleSource
                = _activeConfiguredProjectSubscriptionService.ProjectRuleSource.SourceBlock;

            IPropagatorBlock <IProjectVersionedValue <ValueTuple <IProjectSnapshot, IProjectSubscriptionUpdate> >, IProjectVersionedValue <AssetsFileDependenciesSnapshot> > transformBlock
                = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <ValueTuple <IProjectSnapshot, IProjectSubscriptionUpdate> >, IProjectVersionedValue <AssetsFileDependenciesSnapshot> >(Transform, skipIntermediateInputData: true, skipIntermediateOutputData: true);

            return(new DisposableBag
            {
                // Subscribe to "ConfigurationGeneral" rule data
                projectRuleSource.LinkTo(
                    intermediateBlock,
                    ruleNames: ConfigurationGeneralRule.SchemaName,
                    suppressVersionOnlyUpdates: false,
                    linkOptions: PropagateCompletion()),

                // Sync link inputs, joining on versions, and passing joined data to our transform block
                ProjectDataSources.SyncLinkTo(
                    _activeConfiguredProjectSnapshotService.SourceBlock.SyncLinkOptions(),
                    intermediateBlock.SyncLinkOptions(),
                    transformBlock,
                    linkOptions: PropagateCompletion()),

                // Flow transformed data to the output/target
                transformBlock.LinkTo(targetBlock, PropagateCompletion())
            });
        /// <summary>
        /// Initialize the watcher.
        /// </summary>
        protected override async Task InitializeCoreAsync(CancellationToken cancellationToken)
        {
            // Explicitly get back to the thread pool for the rest of this method so we don't tie up the UI thread;
            await TaskScheduler.Default;

            await _projectTasksService.LoadedProjectAsync(() =>
            {
                // The tree source to get changes to the tree so that we can identify when the assets file changes.
                ProjectDataSources.SourceBlockAndLink <IProjectVersionedValue <IProjectTreeSnapshot> > treeSource = _fileSystemTreeProvider.Tree.SyncLinkOptions();

                // The property source used to get the value of the $ProjectAssetsFile property so that we can identify the location of the assets file.
                StandardRuleDataflowLinkOptions sourceLinkOptions = DataflowOption.WithRuleNames(ConfigurationGeneral.SchemaName);

                ProjectDataSources.SourceBlockAndLink <IProjectVersionedValue <IProjectSubscriptionUpdate> > propertySource = _activeConfiguredProjectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(sourceLinkOptions);
                var target = new ActionBlock <IProjectVersionedValue <Tuple <IProjectTreeSnapshot, IProjectSubscriptionUpdate> > >(DataFlow_ChangedAsync);

                // Join the two sources so that we get synchronized versions of the data.
                _treeWatcher = ProjectDataSources.SyncLinkTo(treeSource, propertySource, target);

                return(Task.CompletedTask);
            });
        }
示例#15
0
        /// <summary>
        /// This method is where we tell data flow which blocks we're interested in receiving updates for
        /// </summary>
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <InputTuple> > targetBlock)
        {
            JoinUpstreamDataSources(_projectSubscriptionService.SourceItemsRuleSource, _projectSubscriptionService.ProjectRuleSource);

            return(ProjectDataSources.SyncLinkTo(
                       _projectSubscriptionService.SourceItemsRuleSource.SourceBlock.SyncLinkOptions(
                           linkOptions: new StandardRuleDataflowLinkOptions
            {
                RuleNames = Empty.OrdinalIgnoreCaseStringSet.Add(Compile.SchemaName),
                PropagateCompletion = true,
            }),
                       _projectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(
                           linkOptions: new StandardRuleDataflowLinkOptions
            {
                RuleNames = Empty.OrdinalIgnoreCaseStringSet.Add(ConfigurationGeneral.SchemaName),
                PropagateCompletion = true,
            }),
                       targetBlock,
                       new DataflowLinkOptions {
                PropagateCompletion = true
            },
                       cancellationToken: ProjectAsynchronousTasksService.UnloadCancellationToken));
        }
示例#16
0
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <UpToDateCheckConfiguredInput> > targetBlock)
        {
            // Provides the set of implicitly active configured projects
            IProjectValueDataSource <IConfigurationGroup <ConfiguredProject> > activeConfiguredProjectsSource = _activeConfigurationGroupService.ActiveConfiguredProjectGroupSource;

            // Aggregates implicitly active UpToDateCheckImplicitConfiguredInput inputs from their sources
            var restoreConfiguredInputSource = new UnwrapCollectionChainedProjectValueDataSource <IReadOnlyCollection <ConfiguredProject>, UpToDateCheckImplicitConfiguredInput>(
                _configuredProject,
                projects => projects.Select(project => project.Services.ExportProvider.GetExportedValueOrDefault <IUpToDateCheckImplicitConfiguredInputDataSource>())
                .WhereNotNull()     // Filter out any configurations which don't have this export
                .Select(DropConfiguredProjectVersions),
                includeSourceVersions: true);

            // Dataflow from two configurations can depend on a same unconfigured level data source, and processes it at a different speed.
            // Introduce a forward-only block to prevent regressions in versions.
            var forwardOnlyBlock = ProjectDataSources.CreateDataSourceVersionForwardOnlyFilteringBlock <IReadOnlyCollection <UpToDateCheckImplicitConfiguredInput> >();

            DisposableValue <ISourceBlock <IProjectVersionedValue <UpToDateCheckConfiguredInput> > >
            mergeBlock = forwardOnlyBlock.TransformWithNoDelta(update => update.Derive(MergeInputs));

            JoinUpstreamDataSources(restoreConfiguredInputSource, activeConfiguredProjectsSource);

            return(new DisposableBag
            {
                restoreConfiguredInputSource,
                activeConfiguredProjectsSource.SourceBlock.LinkTo(restoreConfiguredInputSource, DataflowOption.PropagateCompletion),
                restoreConfiguredInputSource.SourceBlock.LinkTo(forwardOnlyBlock, DataflowOption.PropagateCompletion),
                mergeBlock,
                mergeBlock.Value.LinkTo(targetBlock, DataflowOption.PropagateCompletion)
            });

            IProjectValueDataSource <UpToDateCheckImplicitConfiguredInput> DropConfiguredProjectVersions(IUpToDateCheckImplicitConfiguredInputDataSource dataSource)
            {
                // Wrap it in a data source that will drop project version and identity versions so as they will never agree
                // on these versions as they are unique to each configuration. They'll be consistent by all other versions.
                return(new DropConfiguredProjectVersionDataSource <UpToDateCheckImplicitConfiguredInput>(_configuredProject.UnconfiguredProject, dataSource));
            }
        protected override void Initialize()
        {
            _subscriptionLinks = new List <IDisposable>();
            _projectSyncLinks  = new List <IDisposable>();

            using (UnconfiguredProjectAsynchronousTasksService.LoadedProject())
            {
                // this.IsApplicable may take a project lock, so we can't do it inline with this method
                // which is holding a private lock.  It turns out that doing it asynchronously isn't a problem anyway,
                // so long as we guard against races with the Dispose method.
                UnconfiguredProjectAsynchronousTasksService.LoadedProjectAsync(
                    async delegate
                {
                    await TaskScheduler.Default.SwitchTo(alwaysYield: true);
                    UnconfiguredProjectAsynchronousTasksService.
                    UnloadCancellationToken.ThrowIfCancellationRequested();

                    lock (SyncObject)
                    {
                        Verify.NotDisposed(this);

                        var intermediateBlockDesignTime = new BufferBlock <
                            IProjectVersionedValue <
                                IProjectSubscriptionUpdate> >();

                        _subscriptionLinks.Add(ProjectSubscriptionService.JointRuleSource.SourceBlock.LinkTo(
                                                   intermediateBlockDesignTime,
                                                   ruleNames: UnresolvedReferenceRuleNames.Union(ResolvedReferenceRuleNames),
                                                   suppressVersionOnlyUpdates: true));

                        var actionBlock = new ActionBlock <
                            IProjectVersionedValue <
                                Tuple <IProjectSubscriptionUpdate,
                                       IProjectCatalogSnapshot,
                                       IProjectSharedFoldersSnapshot> > >
                                              (new Action <
                                                  IProjectVersionedValue <
                                                      Tuple <IProjectSubscriptionUpdate,
                                                             IProjectCatalogSnapshot,
                                                             IProjectSharedFoldersSnapshot> > >(
                                                  ProjectSubscriptionService_Changed),
                                              new ExecutionDataflowBlockOptions()
                        {
                            NameFormat = "ReferencesSubtree Input: {1}"
                        });

                        _projectSyncLinks.Add(ProjectDataSources.SyncLinkTo(
                                                  intermediateBlockDesignTime.SyncLinkOptions(),
                                                  ProjectSubscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                                  ProjectSubscriptionService.SharedFoldersSource.SourceBlock.SyncLinkOptions(),
                                                  actionBlock));

                        var intermediateBlockEvaluation = new BufferBlock <
                            IProjectVersionedValue <
                                IProjectSubscriptionUpdate> >();
                        _subscriptionLinks.Add(ProjectSubscriptionService.ProjectRuleSource.SourceBlock.LinkTo(
                                                   intermediateBlockEvaluation,
                                                   ruleNames: UnresolvedReferenceRuleNames,
                                                   suppressVersionOnlyUpdates: true));

                        _projectSyncLinks.Add(ProjectDataSources.SyncLinkTo(
                                                  intermediateBlockEvaluation.SyncLinkOptions(),
                                                  ProjectSubscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                                  ProjectSubscriptionService.SharedFoldersSource.SourceBlock.SyncLinkOptions(),
                                                  actionBlock));
                    }
                },
                    registerFaultHandler: true);
            }
        }
        private void SubscribeToConfiguredProject(
            ConfiguredProject configuredProject,
            IProjectSubscriptionService subscriptionService,
            IReadOnlyCollection <string> watchedEvaluationRules,
            IReadOnlyCollection <string> watchedDesignTimeBuildRules)
        {
            // Use intermediate buffer blocks for project rule data to allow subsequent blocks
            // to only observe specific rule name(s).

            var intermediateBlockDesignTime =
                new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Intermediate DesignTime Input: {1}"
            });

            var intermediateBlockEvaluation =
                new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Intermediate Evaluation Input: {1}"
            });

            _subscriptions = _subscriptions ?? new DisposableBag();

            _subscriptions.AddDisposable(
                subscriptionService.JointRuleSource.SourceBlock.LinkTo(
                    intermediateBlockDesignTime,
                    ruleNames: watchedDesignTimeBuildRules.Union(watchedEvaluationRules),
                    suppressVersionOnlyUpdates: true,
                    linkOptions: DataflowOption.PropagateCompletion));

            _subscriptions.AddDisposable(
                subscriptionService.ProjectRuleSource.SourceBlock.LinkTo(
                    intermediateBlockEvaluation,
                    ruleNames: watchedEvaluationRules,
                    suppressVersionOnlyUpdates: true,
                    linkOptions: DataflowOption.PropagateCompletion));

            ITargetBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > > actionBlockDesignTimeBuild =
                DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > >(
                    e => OnProjectChangedAsync(e.Value.Item1, e.Value.Item2, e.Value.Item3, configuredProject, RuleHandlerType.DesignTimeBuild),
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget DesignTime Input: {1}"
            });

            ITargetBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > > actionBlockEvaluation =
                DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > >(
                    e => OnProjectChangedAsync(e.Value.Item1, e.Value.Item2, e.Value.Item3, configuredProject, RuleHandlerType.Evaluation),
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Evaluation Input: {1}"
            });

            _subscriptions.AddDisposable(ProjectDataSources.SyncLinkTo(
                                             intermediateBlockDesignTime.SyncLinkOptions(),
                                             subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                             configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
                                             actionBlockDesignTimeBuild,
                                             linkOptions: DataflowOption.PropagateCompletion));

            _subscriptions.AddDisposable(ProjectDataSources.SyncLinkTo(
                                             intermediateBlockEvaluation.SyncLinkOptions(),
                                             subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                             configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
                                             actionBlockEvaluation,
                                             linkOptions: DataflowOption.PropagateCompletion));
        }
示例#19
0
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> > targetBlock)
        {
            Assumes.Present(_configuredProject.Services.ProjectSubscription);

            bool attemptedStateRestore = false;

            // Initial state is empty. We will evolve this reference over time, updating it iteratively
            // on each new data update.
            UpToDateCheckImplicitConfiguredInput state = UpToDateCheckImplicitConfiguredInput.CreateEmpty(_configuredProject.ProjectConfiguration);

            IPropagatorBlock <IProjectVersionedValue <UpdateValues>, IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> > transformBlock
                = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <UpdateValues>, IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> >(TransformAsync);

            IProjectValueDataSource <IProjectSubscriptionUpdate> source1 = _configuredProject.Services.ProjectSubscription.JointRuleSource;
            IProjectValueDataSource <IProjectSubscriptionUpdate> source2 = _configuredProject.Services.ProjectSubscription.SourceItemsRuleSource;
            IProjectItemSchemaService source3 = _projectItemSchemaService;
            IProjectValueDataSource <IProjectCatalogSnapshot> source4 = _configuredProject.Services.ProjectSubscription.ProjectCatalogSource;

            return(new DisposableBag
            {
                // Sync-link various sources to our transform block
                ProjectDataSources.SyncLinkTo(
                    source1.SourceBlock.SyncLinkOptions(DataflowOption.WithRuleNames(ProjectPropertiesSchemas)),
                    source2.SourceBlock.SyncLinkOptions(),
                    source3.SourceBlock.SyncLinkOptions(),
                    source4.SourceBlock.SyncLinkOptions(),
                    target: transformBlock,
                    linkOptions: DataflowOption.PropagateCompletion,
                    CancellationToken.None),

                // Link the transform block to our target block
                transformBlock.LinkTo(targetBlock, DataflowOption.PropagateCompletion),

                JoinUpstreamDataSources(source1, source2, source3, source4)
            });

            async Task <IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> > TransformAsync(IProjectVersionedValue <UpdateValues> e)
            {
                if (!attemptedStateRestore)
                {
                    attemptedStateRestore = true;

                    if (_persistentState is not null)
                    {
                        // Restoring state requires the UI thread. We must use JTF.RunAsync here to ensure the UI
                        // thread is shared between related work and prevent deadlocks.
                        (int ItemHash, DateTime InputsChangedAtUtc)? restoredState =
                            await JoinableFactory.RunAsync(() => _persistentState.RestoreStateAsync(_configuredProject.UnconfiguredProject.FullPath, _configuredProject.ProjectConfiguration.Dimensions, _projectAsynchronousTasksService.UnloadCancellationToken));

                        if (restoredState is not null)
                        {
                            state = state.WithRestoredState(restoredState.Value.ItemHash, restoredState.Value.InputsChangedAtUtc);
                        }
                    }
                }

                int?     priorItemHash = state.ItemHash;
                DateTime priorLastItemsChangedAtUtc = state.LastItemsChangedAtUtc;

                state = state.Update(
                    jointRuleUpdate: e.Value.Item1,
                    sourceItemsUpdate: e.Value.Item2,
                    projectItemSchema: e.Value.Item3,
                    projectCatalogSnapshot: e.Value.Item4);

                if (state.ItemHash is not null && _persistentState is not null && (priorItemHash != state.ItemHash || priorLastItemsChangedAtUtc != state.LastItemsChangedAtUtc))
                {
                    await _persistentState.StoreStateAsync(_configuredProject.UnconfiguredProject.FullPath, _configuredProject.ProjectConfiguration.Dimensions, state.ItemHash.Value, state.LastItemsChangedAtUtc, _projectAsynchronousTasksService.UnloadCancellationToken);
                }

                return(new ProjectVersionedValue <UpToDateCheckImplicitConfiguredInput>(state, e.DataSourceVersions));
            }
        }
示例#20
0
        private void SubscribeToConfiguredProject(
            ConfiguredProject configuredProject,
            IProjectSubscriptionService subscriptionService,
            IEnumerable <string> watchedEvaluationRules,
            IEnumerable <string> watchedDesignTimeBuildRules)
        {
            var intermediateBlockDesignTime =
                new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Intermediate DesignTime Input: {1}"
            });

            var intermediateBlockEvaluation =
                new BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >(
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Intermediate Evaluation Input: {1}"
            });

            _designTimeBuildSubscriptionLinks.Add(
                subscriptionService.JointRuleSource.SourceBlock.LinkTo(
                    intermediateBlockDesignTime,
                    ruleNames: watchedDesignTimeBuildRules.Union(watchedEvaluationRules),
                    suppressVersionOnlyUpdates: true,
                    linkOptions: new DataflowLinkOptions {
                PropagateCompletion = true
            }));

            _evaluationSubscriptionLinks.Add(
                subscriptionService.ProjectRuleSource.SourceBlock.LinkTo(
                    intermediateBlockEvaluation,
                    ruleNames: watchedEvaluationRules,
                    suppressVersionOnlyUpdates: true,
                    linkOptions: new DataflowLinkOptions {
                PropagateCompletion = true
            }));

            var actionBlockDesignTimeBuild =
                new ActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > >(
                    e => OnProjectChangedAsync(e, configuredProject, RuleHandlerType.DesignTimeBuild),
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget DesignTime Input: {1}"
            });

            var actionBlockEvaluation =
                new ActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > >(
                    e => OnProjectChangedAsync(e, configuredProject, RuleHandlerType.Evaluation),
                    new ExecutionDataflowBlockOptions()
            {
                NameFormat = "CrossTarget Evaluation Input: {1}"
            });

            _designTimeBuildSubscriptionLinks.Add(ProjectDataSources.SyncLinkTo(
                                                      intermediateBlockDesignTime.SyncLinkOptions(),
                                                      subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                                      configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
                                                      actionBlockDesignTimeBuild,
                                                      linkOptions: new DataflowLinkOptions {
                PropagateCompletion = true
            }));

            _evaluationSubscriptionLinks.Add(ProjectDataSources.SyncLinkTo(
                                                 intermediateBlockEvaluation.SyncLinkOptions(),
                                                 subscriptionService.ProjectCatalogSource.SourceBlock.SyncLinkOptions(),
                                                 configuredProject.Capabilities.SourceBlock.SyncLinkOptions(),
                                                 actionBlockEvaluation,
                                                 linkOptions: new DataflowLinkOptions {
                PropagateCompletion = true
            }));
        }
示例#21
0
            protected override async Task InitializeCoreAsync(CancellationToken cancellationToken)
            {
                _contextAccessor = await _workspaceProjectContextProvider.CreateProjectContextAsync(_project);

                if (_contextAccessor == null)
                {
                    return;
                }

                _activeWorkspaceProjectContextTracker.RegisterContext(_contextAccessor.ContextId);

                _applyChangesToWorkspaceContext = _applyChangesToWorkspaceContextFactory.CreateExport();
                _applyChangesToWorkspaceContext.Value.Initialize(_contextAccessor.Context);

                _evaluationProgressRegistration   = _dataProgressTrackerService.RegisterForIntelliSense(this, _project, nameof(WorkspaceProjectContextHostInstance) + ".Evaluation");
                _projectBuildProgressRegistration = _dataProgressTrackerService.RegisterForIntelliSense(this, _project, nameof(WorkspaceProjectContextHostInstance) + ".ProjectBuild");

                _disposables = new DisposableBag
                {
                    _applyChangesToWorkspaceContext,
                    _evaluationProgressRegistration,
                    _projectBuildProgressRegistration,

                    ProjectDataSources.SyncLinkTo(
                        _activeConfiguredProjectProvider.ActiveConfiguredProjectBlock.SyncLinkOptions(),
                        _projectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(GetProjectEvaluationOptions()),
                        _projectSubscriptionService.SourceItemsRuleSource.SourceBlock.SyncLinkOptions(),
                        target: DataflowBlockFactory.CreateActionBlock <IProjectVersionedValue <(ConfiguredProject, IProjectSubscriptionUpdate, IProjectSubscriptionUpdate)> >(
                            OnEvaluationUpdateAsync,
                            _project.UnconfiguredProject,
                            ProjectFaultSeverity.LimitedFunctionality),
                        linkOptions: DataflowOption.PropagateCompletion,
                        cancellationToken: cancellationToken),

                    ProjectDataSources.SyncLinkTo(
                        _activeConfiguredProjectProvider.ActiveConfiguredProjectBlock.SyncLinkOptions(),
                        _projectSubscriptionService.ProjectBuildRuleSource.SourceBlock.SyncLinkOptions(GetProjectBuildOptions()),
                        _commandLineArgumentsProvider.SourceBlock.SyncLinkOptions(),
                        target: DataflowBlockFactory.CreateActionBlock <IProjectVersionedValue <(ConfiguredProject, IProjectSubscriptionUpdate, CommandLineArgumentsSnapshot)> >(
                            OnBuildUpdateAsync,
                            _project.UnconfiguredProject,
                            ProjectFaultSeverity.LimitedFunctionality),
                        linkOptions: DataflowOption.PropagateCompletion,
                        cancellationToken: cancellationToken)
                };

                return;

                StandardRuleDataflowLinkOptions GetProjectEvaluationOptions()
                {
                    return(DataflowOption.WithRuleNames(_applyChangesToWorkspaceContext.Value.GetProjectEvaluationRules()));
                }

                StandardRuleDataflowLinkOptions GetProjectBuildOptions()
                {
                    return(DataflowOption.WithRuleNames(_applyChangesToWorkspaceContext.Value.GetProjectBuildRules()));
                }

                Task OnEvaluationUpdateAsync(IProjectVersionedValue <(ConfiguredProject ActiveConfiguredProject, IProjectSubscriptionUpdate ProjectUpdate, IProjectSubscriptionUpdate SourceItemsUpdate)> e)
                {
                    return(OnProjectChangedAsync(
                               _evaluationProgressRegistration,
                               e.Value.ActiveConfiguredProject,
                               e,
                               hasChange: static e => e.Value.ProjectUpdate.ProjectChanges.HasChange() || e.Value.SourceItemsUpdate.ProjectChanges.HasChange(),
                               applyFunc: static (e, applyChangesToWorkspaceContext, contextState, token) => applyChangesToWorkspaceContext.ApplyProjectEvaluation(e.Derive(v => (v.ProjectUpdate, v.SourceItemsUpdate)), contextState, token)));
                }

                Task OnBuildUpdateAsync(IProjectVersionedValue <(ConfiguredProject ActiveConfiguredProject, IProjectSubscriptionUpdate BuildUpdate, CommandLineArgumentsSnapshot CommandLineArgumentsUpdate)> e)
                {
                    return(OnProjectChangedAsync(
                               _projectBuildProgressRegistration,
                               e.Value.ActiveConfiguredProject,
                               e,
                               hasChange: static e => e.Value.BuildUpdate.ProjectChanges.HasChange() || e.Value.CommandLineArgumentsUpdate.IsChanged,
                               applyFunc: static (e, applyChangesToWorkspaceContext, contextState, token) => applyChangesToWorkspaceContext.ApplyProjectBuild(e.Derive(v => (v.BuildUpdate, v.CommandLineArgumentsUpdate)), contextState, token)));
                }
            }