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 packageRestoreConfiguredSource = new UnwrapCollectionChainedProjectValueDataSource <IReadOnlyCollection <ConfiguredProject>, ProjectRestoreUpdate>(
                _project.Services,
                projects => projects.Select(project => GetProjectRestoreDataSource(project)),
                includeSourceVersions: true);

            disposables.AddDisposable(packageRestoreConfiguredSource);

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

            disposables.AddDisposable(activeConfiguredProjectsSource.SourceBlock.LinkTo(packageRestoreConfiguredSource, DataflowOption.PropagateCompletion));

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

            disposables.AddDisposable(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(packageRestoreConfiguredSource, activeConfiguredProjectsSource);

            return(disposables);
        }
Пример #2
0
        public static IActiveConfigurationGroupService Implement(IProjectValueDataSource <IConfigurationGroup <ProjectConfiguration> > source)
        {
            var mock = new Mock <IActiveConfigurationGroupService>();

            mock.SetupGet(s => s.ActiveConfigurationGroupSource)
            .Returns(source);

            return(mock.Object);
        }
        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));
            }
        }
        public static IActiveConfiguredProjectSubscriptionService Create(IProjectValueDataSource <IProjectSubscriptionUpdate>?sourceItemsRuleSource = null)
        {
            var mock = new Mock <IActiveConfiguredProjectSubscriptionService>();

            mock.SetupGet(s => s.ProjectRuleSource)
            .Returns(() => IProjectValueDataSourceFactory.CreateInstance <IProjectSubscriptionUpdate>());

            if (sourceItemsRuleSource != null)
            {
                mock.SetupGet(s => s.SourceItemsRuleSource)
                .Returns(() => sourceItemsRuleSource);
            }

            return(mock.Object);
        }
Пример #5
0
        protected override IDisposable LinkExternalInput(ITargetBlock <RestoreUpdate> targetBlock)
        {
            IProjectValueDataSource <IProjectSubscriptionUpdate> source = _projectSubscriptionService.JointRuleSource;

            // Transform the changes from evaluation/design-time build -> restore data
            DisposableValue <ISourceBlock <RestoreUpdate> > transformBlock = source.SourceBlock.TransformWithNoDelta(update => update.Derive(u => CreateRestoreInput(u.ProjectConfiguration, u.CurrentState)),
                                                                                                                     suppressVersionOnlyUpdates: false, // We need to coordinate these at the unconfigured-level
                                                                                                                     ruleNames: s_rules);

            // Set the link up so that we publish changes to target block
            transformBlock.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(source);

            return(transformBlock);
        }
        protected override IDisposable?LinkExternalInput(ITargetBlock <IProjectVersionedValue <ISet <WorkloadDescriptor> > > targetBlock)
        {
            IProjectValueDataSource <IProjectSubscriptionUpdate> source = _projectSubscriptionService.ProjectBuildRuleSource;

            // Transform the changes from design-time build -> workload data
            DisposableValue <ISourceBlock <IProjectVersionedValue <ISet <WorkloadDescriptor> > > > transformBlock =
                source.SourceBlock.TransformWithNoDelta(update => update.Derive(u => CreateWorkloadDescriptor(u.CurrentState)),
                                                        suppressVersionOnlyUpdates: false,
                                                        ruleNames: s_rules);

            // Set the link up so that we publish changes to target block
            transformBlock.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(source);

            return(transformBlock);
        }
Пример #7
0
        protected override IDisposable?LinkExternalInput(ITargetBlock <EnumCollectionProjectValue> targetBlock)
        {
            IProjectValueDataSource <IProjectSubscriptionUpdate> source = SubscriptionService.ProjectRuleSource;

            // Transform the values from evaluation to structure from the rule schema.
            DisposableValue <ISourceBlock <EnumCollectionProjectValue> > transformBlock = source.SourceBlock.TransformWithNoDelta(
                update => update.Derive(Transform),
                suppressVersionOnlyUpdates: false,
                ruleNames: RuleNames);

            // Set the link up so that we publish changes to target block.
            transformBlock.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(source);

            return(transformBlock);
        }
Пример #8
0
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <FileWatchData> > targetBlock)
        {
            IProjectValueDataSource <IProjectSubscriptionUpdate> source = _projectSubscriptionService.ProjectRuleSource;

            // Transform the changes from evaluation -> FileWatchData
            DisposableValue <ISourceBlock <IProjectVersionedValue <FileWatchData> > > transformBlock = source.SourceBlock
                                                                                                       .TransformWithNoDelta(update => update.Derive(u => CreateFileWatch(u.CurrentState)),
                                                                                                                             suppressVersionOnlyUpdates: true,
                                                                                                                             ruleNames: new[] { ItemSchemaName });

            // Set the link up so that we publish changes to target block
            transformBlock.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(source);

            return(transformBlock);
        }
Пример #9
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);
        }
Пример #10
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));
            }
Пример #11
0
 protected void Subscribe(
     ConfiguredProject configuredProject,
     IProjectValueDataSource <IProjectSubscriptionUpdate> dataSource,
     string[] ruleNames,
     string nameFormat,
     Func <(BufferBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> > Intermediate, ITargetBlock <IProjectVersionedValue <T> > Action), IDisposable> syncLink)
Пример #12
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));
            }
        }
 public DropConfiguredProjectVersionDataSource(IProjectServices commonServices, IProjectValueDataSource <T> dataSource)
     : base(commonServices, synchronousDisposal: true, registerDataSource: false)
 {
     _dataSource = dataSource;
 }
 public DropConfiguredProjectVersionDataSource(UnconfiguredProject project, IProjectValueDataSource <T> dataSource)
     : base(project, synchronousDisposal: true, registerDataSource: false)
 {
     _dataSource = dataSource;
 }