protected override void Initialize() { // Create our broadcast block for subscribers to get new ILaunchProfiles Information _broadcastBlock = DataflowBlockSlim.CreateBroadcastBlock <ILaunchSettings>(); _changedSourceBlock = _broadcastBlock.SafePublicize(); // Subscribe to changes to the broadcast block using the idle scheduler. This should filter out a lot of the intermediates // states that files can be in. if (_projectSubscriptionService != null) { // The use of AsyncLazy with dataflow can allow state stored in the execution context to leak through. The downstream affect is // calls to say, get properties, may fail. To avoid this, we capture the execution context here, and it will be reapplied when // we get new subscription data from the dataflow. ITargetBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCapabilitiesSnapshot> > > projectChangesBlock = DataflowBlockSlim.CreateActionBlock( DataflowUtilities.CaptureAndApplyExecutionContext <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCapabilitiesSnapshot> > >(ProjectRuleBlock_ChangedAsync)); StandardRuleDataflowLinkOptions evaluationLinkOptions = DataflowOption.WithRuleNames(ProjectDebugger.SchemaName); _projectRuleSubscriptionLink = ProjectDataSources.SyncLinkTo( _projectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions(evaluationLinkOptions), _commonProjectServices.Project.Capabilities.SourceBlock.SyncLinkOptions(), projectChangesBlock, linkOptions: DataflowOption.PropagateCompletion); } // Make sure we are watching the file at this point WatchLaunchSettingsFile(); }
protected override void Initialize() { base.Initialize(); // Create an action block to process the design time inputs and configuration general changes ITargetBlock <IProjectVersionedValue <ValueTuple <DesignTimeInputs, IProjectSubscriptionUpdate> > > inputsAction = DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <ValueTuple <DesignTimeInputs, IProjectSubscriptionUpdate> > >(ProcessDataflowChanges); _broadcastBlock = DataflowBlockSlim.CreateBroadcastBlock <IProjectVersionedValue <DesignTimeInputsDelta> >(nameFormat: nameof(DesignTimeInputsChangeTracker) + "Broadcast {1}"); _publicBlock = AllowSourceBlockCompletion ? _broadcastBlock : _broadcastBlock.SafePublicize(); Assumes.Present(_project.Services.ProjectAsynchronousTasks); IDisposable projectLink = ProjectDataSources.SyncLinkTo( _inputsDataSource.SourceBlock.SyncLinkOptions( linkOptions: DataflowOption.PropagateCompletion), _projectSubscriptionService.ProjectRuleSource.SourceBlock.SyncLinkOptions( linkOptions: DataflowOption.WithRuleNames(ConfigurationGeneral.SchemaName)), inputsAction, DataflowOption.PropagateCompletion, cancellationToken: _project.Services.ProjectAsynchronousTasks.UnloadCancellationToken); // Create an action block to process file change notifications ITargetBlock <IProjectVersionedValue <string[]> > fileWatcherAction = DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <string[]> >(ProcessFileChangeNotification); IDisposable watcherLink = _fileWatcher.SourceBlock.LinkTo(fileWatcherAction, DataflowOption.PropagateCompletion); _disposables.Add(projectLink); _disposables.Add(watcherLink); JoinUpstreamDataSources(_inputsDataSource, _projectSubscriptionService.ProjectRuleSource, _fileWatcher); }
protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> > targetBlock) { Assumes.Present(_configuredProject.Services.ProjectSubscription); // Initial state is empty. We will evolve this reference over time, updating it iteratively // on each new data update. UpToDateCheckImplicitConfiguredInput state = UpToDateCheckImplicitConfiguredInput.Empty; IPropagatorBlock <IProjectVersionedValue <UpdateValues>, IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> > transformBlock = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <UpdateValues>, IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> >(Transform); IProjectValueDataSource <IProjectSubscriptionUpdate> source1 = _configuredProject.Services.ProjectSubscription.JointRuleSource; IProjectValueDataSource <IProjectSubscriptionUpdate> source2 = _configuredProject.Services.ProjectSubscription.SourceItemsRuleSource; IProjectValueDataSource <IProjectSnapshot> source3 = _configuredProject.Services.ProjectSubscription.ProjectSource; IProjectItemSchemaService source4 = _projectItemSchemaService; IProjectValueDataSource <IProjectCatalogSnapshot> source5 = _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(), source5.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, source5) }); IProjectVersionedValue <UpToDateCheckImplicitConfiguredInput> Transform(IProjectVersionedValue <UpdateValues> e) { var snapshot = e.Value.Item3 as IProjectSnapshot2; Assumes.NotNull(snapshot); state = state.Update( jointRuleUpdate: e.Value.Item1, sourceItemsUpdate: e.Value.Item2, projectSnapshot: snapshot, projectItemSchema: e.Value.Item4, projectCatalogSnapshot: e.Value.Item5, configuredProjectVersion: e.DataSourceVersions[ProjectDataSources.ConfiguredProjectVersion]); return(new ProjectVersionedValue <UpToDateCheckImplicitConfiguredInput>(state, e.DataSourceVersions)); } }
/// <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; })); }
private void OnActiveConfigurationsChanged(IProjectVersionedValue <IConfigurationGroup <ConfiguredProject> > e) { if (IsDisposing || IsDisposed) { return; } // Clean up past subscriptions _designTimeBuildSubscriptionLink?.Dispose(); if (e.Value.Count > 0) { StandardRuleDataflowLinkOptions sourceLinkOptions = DataflowOption.WithRuleNames(s_designTimeBuildWatchedRules); 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 = DataflowBlockSlim.CreateActionBlock(action); DataflowLinkOptions targetLinkOptions = DataflowOption.PropagateCompletion; ImmutableList <ProjectDataSources.SourceBlockAndLink <IProjectValueVersions> > sourceBlocksAndCapabilitiesOptions = sourceBlocks.ToImmutableList() .Insert(0, _projectVsServices.Project.Capabilities.SourceBlock.SyncLinkOptions <IProjectValueVersions>()); disposableBag.AddDisposable(ProjectDataSources.SyncLinkTo(sourceBlocksAndCapabilitiesOptions, target, targetLinkOptions)); _designTimeBuildSubscriptionLink = disposableBag; } }
/// <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); }); }
protected override Task InitializeCoreAsync(CancellationToken cancellationToken) { _link = ProjectDataSources.SyncLinkTo( _configuredProject.Services.ProjectSubscription.JointRuleSource.SourceBlock.SyncLinkOptions(DataflowOption.WithRuleNames(ProjectPropertiesSchemas)), _configuredProject.Services.ProjectSubscription.SourceItemsRuleSource.SourceBlock.SyncLinkOptions(), _projectItemSchemaService.SourceBlock.SyncLinkOptions(), target: DataflowBlockSlim.CreateActionBlock <IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectSubscriptionUpdate, IProjectItemSchema> > >(OnChanged), linkOptions: DataflowOption.PropagateCompletion); return(Task.CompletedTask); }
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)); } }
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))); } }
protected override Task InitializeCoreAsync(CancellationToken cancellationToken) { Assumes.Present(_configuredProject.Services.ProjectSubscription); _link = ProjectDataSources.SyncLinkTo( _configuredProject.Services.ProjectSubscription.JointRuleSource.SourceBlock.SyncLinkOptions(DataflowOption.WithRuleNames(ProjectPropertiesSchemas)), _configuredProject.Services.ProjectSubscription.SourceItemsRuleSource.SourceBlock.SyncLinkOptions(), _configuredProject.Services.ProjectSubscription.ProjectSource.SourceBlock.SyncLinkOptions(), _projectItemSchemaService.SourceBlock.SyncLinkOptions(), _configuredProject.Services.ProjectSubscription.ProjectCatalogSource.SourceBlock.SyncLinkOptions(), target: DataflowBlockFactory.CreateActionBlock <IProjectVersionedValue <ValueTuple <IProjectSubscriptionUpdate, IProjectSubscriptionUpdate, IProjectSnapshot, IProjectItemSchema, IProjectCatalogSnapshot> > >(OnChanged, _configuredProject.UnconfiguredProject), linkOptions: DataflowOption.PropagateCompletion, cancellationToken: cancellationToken); return(Task.CompletedTask); }