private static IPropagatorBlock <IProjectVersionedValue <IProjectSubscriptionUpdate>, IProjectVersionedValue <IProjectSubscriptionUpdate> > CreateVersionDropperBlock()
            {
                var transformBlock = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <IProjectSubscriptionUpdate>, IProjectVersionedValue <IProjectSubscriptionUpdate> >(data =>
                {
                    return(new ProjectVersionedValue <IProjectSubscriptionUpdate>(data.Value, data.DataSourceVersions.RemoveRange(s_keysToDrop)));
                });

                return(transformBlock);
            }
        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));
            }
        }
        protected override IDisposable LinkExternalInput(ITargetBlock <IProjectVersionedValue <IProjectTreePropertiesProvider> > targetBlock)
        {
            JoinUpstreamDataSources(_orderedItemSource);

            var providerProducerBlock = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <IReadOnlyCollection <ProjectItemIdentity> >, IProjectVersionedValue <IProjectTreePropertiesProvider> >(
                orderedItems =>
            {
                return(new ProjectVersionedValue <IProjectTreePropertiesProvider>(new TreeItemOrderPropertyProvider(orderedItems.Value, _project), orderedItems.DataSourceVersions));
            },
                new ExecutionDataflowBlockOptions()
            {
                NameFormat = "Ordered Tree Item Input: {1}"
            });

            providerProducerBlock.LinkTo(targetBlock, DataflowOption.PropagateCompletion);
            return(_orderedItemSource.SourceBlock.LinkTo(providerProducerBlock, DataflowOption.PropagateCompletion));
        }
Beispiel #4
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())
            });
Beispiel #5
0
        protected override void Initialize()
        {
            var debugProfilesBlock = DataflowBlockSlim.CreateTransformBlock <ILaunchSettings, IProjectVersionedValue <IReadOnlyList <IEnumValue> > >(
                update =>
            {
                // Compute the new enum values from the profile provider
                var generatedResult = DebugProfileEnumValuesGenerator.GetEnumeratorEnumValues(update).ToImmutableList();
                _dataSourceVersion++;
                ImmutableDictionary <NamedIdentity, IComparable> dataSources = ImmutableDictionary <NamedIdentity, IComparable> .Empty.Add(DataSourceKey, DataSourceVersion);
                return(new ProjectVersionedValue <IReadOnlyList <IEnumValue> >(generatedResult, dataSources));
            });

            var broadcastBlock = DataflowBlockSlim.CreateBroadcastBlock <IProjectVersionedValue <IReadOnlyList <IEnumValue> > >();

            _launchProfileProviderLink = LaunchSettingProvider.SourceBlock.LinkTo(
                debugProfilesBlock,
                linkOptions: DataflowOption.PropagateCompletion);

            _debugProviderLink = debugProfilesBlock.LinkTo(broadcastBlock, DataflowOption.PropagateCompletion);

            _publicBlock = broadcastBlock.SafePublicize();
        }
Beispiel #6
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));
            }
        }
        /// <summary>
        ///     Creates a source block that produces a transformed value for each value from original source block,
        ///     skipping intermediate input and output states, and hence is not suitable for producing or consuming
        ///     deltas.
        /// </summary>
        /// <typeparam name="TOut">
        ///     The type of value produced by <paramref name="transform"/>.
        ///  </typeparam>
        /// <param name="source">
        ///     The source block whose values are to be transformed.
        /// </param>
        /// <param name="transform">
        ///     The function to execute on each value from <paramref name="source"/>.
        /// </param>
        /// <param name="suppressVersionOnlyUpdates">
        ///     A value indicating whether to prevent messages from propagating to the target
        ///     block if no project changes are include other than an incremented version number.
        /// </param>
        /// <param name="ruleNames">
        ///     The names of the rules that describe the project data the caller is interested in.
        /// </param>
        /// <returns>
        ///     The transformed source block and a disposable value that terminates the link.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="source"/> is <see langword="null"/>.
        ///     <para>
        ///         -or-
        ///     </para>
        ///     <paramref name="transform"/> is <see langword="null"/>.
        /// </exception>
        public static DisposableValue <ISourceBlock <TOut> > TransformWithNoDelta <TOut>(this ISourceBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> > source, Func <IProjectVersionedValue <IProjectSubscriptionUpdate>, TOut> transform, bool suppressVersionOnlyUpdates, IEnumerable <string> ruleNames = null)
        {
            Requires.NotNull(source, nameof(source));
            Requires.NotNull(transform, nameof(transform));

            IPropagatorBlock <IProjectVersionedValue <IProjectSubscriptionUpdate>, TOut> transformBlock = DataflowBlockSlim.CreateTransformBlock(transform, skipIntermediateInputData: true, skipIntermediateOutputData: true);

            IDisposable link = source.LinkTo(transformBlock,
                                             DataflowOption.PropagateCompletion,
                                             initialDataAsNew: true,
                                             suppressVersionOnlyUpdates: suppressVersionOnlyUpdates,
                                             ruleNames: ruleNames);

            return(new DisposableValue <ISourceBlock <TOut> >(transformBlock, link));
        }
        /// <summary>
        ///     Creates a source block that produces a transformed value for each value from original source block,
        ///     skipping intermediate input and output states, and hence is not suitable for producing or consuming
        ///     deltas.
        /// </summary>
        /// <typeparam name="TInput">
        ///     The type of the input value produced by <paramref name="source"/>.
        /// </typeparam>
        /// <typeparam name="TOut">
        ///     The type of value produced by <paramref name="transform"/>.
        ///  </typeparam>
        /// <param name="source">
        ///     The source block whose values are to be transformed.
        /// </param>
        /// <param name="transform">
        ///     The function to execute on each value from <paramref name="source"/>.
        /// </param>
        /// <returns>
        ///     The transformed source block and a disposable value that terminates the link.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="source"/> is <see langword="null"/>.
        ///     <para>
        ///         -or-
        ///     </para>
        ///     <paramref name="transform"/> is <see langword="null"/>.
        /// </exception>
        public static DisposableValue <ISourceBlock <TOut> > TransformWithNoDelta <TInput, TOut>(this ISourceBlock <IProjectVersionedValue <TInput> > source, Func <IProjectVersionedValue <TInput>, TOut> transform)
        {
            Requires.NotNull(source, nameof(source));
            Requires.NotNull(transform, nameof(transform));

            IPropagatorBlock <IProjectVersionedValue <TInput>, TOut> transformBlock = DataflowBlockSlim.CreateTransformBlock(transform, skipIntermediateInputData: true, skipIntermediateOutputData: true);

            IDisposable link = source.LinkTo(transformBlock, DataflowOption.PropagateCompletion);

            return(new DisposableValue <ISourceBlock <TOut> >(transformBlock, link));
        }
        protected override void Initialize()
        {
            IPropagatorBlock <IProjectVersionedValue <ILaunchSettings>, IProjectVersionedValue <IReadOnlyList <IEnumValue> > > debugProfilesBlock = DataflowBlockSlim.CreateTransformBlock <IProjectVersionedValue <ILaunchSettings>, IProjectVersionedValue <IReadOnlyList <IEnumValue> > >(
                update =>
            {
                // Compute the new enum values from the profile provider
                var generatedResult = DebugProfileEnumValuesGenerator.GetEnumeratorEnumValues(update.Value).ToImmutableList();
                _dataSourceVersion++;
                ImmutableDictionary <NamedIdentity, IComparable> dataSources = ImmutableDictionary <NamedIdentity, IComparable> .Empty.Add(DataSourceKey, DataSourceVersion);
                return(new ProjectVersionedValue <IReadOnlyList <IEnumValue> >(generatedResult, dataSources));
            });

            IBroadcastBlock <IProjectVersionedValue <IReadOnlyList <IEnumValue> > > broadcastBlock = DataflowBlockSlim.CreateBroadcastBlock <IProjectVersionedValue <IReadOnlyList <IEnumValue> > >();

            // The interface has two definitions of SourceBlock: one from
            // ILaunchSettingsProvider, and one from IProjectValueDataSource<T> (via
            // IVersionedLaunchSettingsProvider). We need the cast to pick the proper one.
            _launchProfileProviderLink = ((IProjectValueDataSource <ILaunchSettings>)LaunchSettingProvider).SourceBlock.LinkTo(
                debugProfilesBlock,
                linkOptions: DataflowOption.PropagateCompletion);

            JoinUpstreamDataSources(LaunchSettingProvider);

            _debugProviderLink = debugProfilesBlock.LinkTo(broadcastBlock, DataflowOption.PropagateCompletion);

            _publicBlock = broadcastBlock.SafePublicize();
        }