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; } }
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)); }
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), }; }
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); }
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)); } }
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; } }
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); }
/// <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; })); }
/// <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); }
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); }); }
/// <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)); }
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)); }
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)); } }
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 })); }
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))); } }