public override Task HandleAsync( IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot> > e, IImmutableDictionary <string, IProjectChangeDescription> projectChanges, ITargetedProjectContext context, bool isActiveContext, DependenciesRuleChangeContext ruleChangeContext) { if (projectChanges.TryGetValue(UnresolvedRuleName, out IProjectChangeDescription unresolvedChanges) && unresolvedChanges.Difference.AnyChanges) { HandleChangesForRule( unresolvedChanges, ruleChangeContext, context.TargetFramework, resolved: false); } var caseInsensitiveUnresolvedChanges = new HashSet <string>(StringComparer.OrdinalIgnoreCase); caseInsensitiveUnresolvedChanges.AddRange(unresolvedChanges.After.Items.Keys); if (projectChanges.TryGetValue(ResolvedRuleName, out IProjectChangeDescription resolvedChanges) && resolvedChanges.Difference.AnyChanges) { HandleChangesForRule( resolvedChanges, ruleChangeContext, context.TargetFramework, resolved: true, unresolvedChanges: caseInsensitiveUnresolvedChanges); } return(Task.CompletedTask); }
private void AddConfiguredProjectState(ConfiguredProject configuredProject, ITargetedProjectContext projectContext) { lock (_gate) { _configuredProjectContextsMap.Add(configuredProject, projectContext); } }
public async Task OnContextReleasedAsync(ITargetedProjectContext innerContext) { foreach (var handler in Handlers) { await handler.Value.OnContextReleasedAsync(innerContext).ConfigureAwait(false); } }
public async Task OnContextReleasedAsync(ITargetedProjectContext innerContext) { foreach (Lazy <ICrossTargetRuleHandler <T>, IOrderPrecedenceMetadataView> handler in Handlers) { await handler.Value.OnContextReleasedAsync(innerContext).ConfigureAwait(false); } }
private void ProcessSharedProjectsUpdates( IProjectSharedFoldersSnapshot sharedFolders, ITargetedProjectContext targetContext, DependenciesRuleChangeContext dependencyChangeContext) { Requires.NotNull(sharedFolders, nameof(sharedFolders)); Requires.NotNull(targetContext, nameof(targetContext)); Requires.NotNull(dependencyChangeContext, nameof(dependencyChangeContext)); IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot; if (!snapshot.Targets.TryGetValue(targetContext.TargetFramework, out ITargetedDependenciesSnapshot targetedSnapshot)) { return; } IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath); var currentSharedImportNodes = targetedSnapshot.TopLevelDependencies .Where(x => x.Flags.Contains(DependencyTreeFlags.SharedProjectFlags)) .ToList(); IEnumerable <string> currentSharedImportNodePaths = currentSharedImportNodes.Select(x => x.Path); // process added nodes IEnumerable <string> addedSharedImportPaths = sharedFolderProjectPaths.Except(currentSharedImportNodePaths); foreach (string addedSharedImportPath in addedSharedImportPaths) { IDependencyModel added = new SharedProjectDependencyModel( addedSharedImportPath, addedSharedImportPath, isResolved: true, isImplicit: false, properties: ImmutableStringDictionary <string> .EmptyOrdinal); dependencyChangeContext.IncludeAddedChange(targetContext.TargetFramework, added); } // process removed nodes IEnumerable <string> removedSharedImportPaths = currentSharedImportNodePaths.Except(sharedFolderProjectPaths); foreach (string removedSharedImportPath in removedSharedImportPaths) { bool exists = currentSharedImportNodes.Any(node => PathHelper.IsSamePath(node.Path, removedSharedImportPath)); if (exists) { dependencyChangeContext.IncludeRemovedChange( targetContext.TargetFramework, ProjectRuleHandler.ProviderTypeString, dependencyId: removedSharedImportPath); } } }
public void SetProjectFilePathAndDisplayName(string projectFilePath, string displayName) { // Update the project file path and display name for all the inner project contexts. foreach (KeyValuePair <ITargetFramework, ITargetedProjectContext> innerProjectContextKvp in _configuredProjectContextsByTargetFramework) { ITargetFramework targetFramework = innerProjectContextKvp.Key; ITargetedProjectContext innerProjectContext = innerProjectContextKvp.Value; // For cross targeting projects, we ensure that the display name is unique per every target framework. innerProjectContext.DisplayName = IsCrossTargeting ? $"{displayName}({targetFramework})" : displayName; innerProjectContext.ProjectFilePath = projectFilePath; } }
private void ProcessSharedProjectsUpdates( IProjectSharedFoldersSnapshot sharedFolders, ITargetedProjectContext targetContext, DependenciesRuleChangeContext dependencyChangeContext) { Requires.NotNull(sharedFolders, nameof(sharedFolders)); Requires.NotNull(targetContext, nameof(targetContext)); Requires.NotNull(dependencyChangeContext, nameof(dependencyChangeContext)); IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot; if (!snapshot.Targets.TryGetValue(targetContext.TargetFramework, out ITargetedDependenciesSnapshot targetedSnapshot)) { return; } IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath); var currentSharedImportNodes = targetedSnapshot.TopLevelDependencies .Where(x => x.Flags.Contains(DependencyTreeFlags.SharedProjectFlags)) .ToList(); IEnumerable <string> currentSharedImportNodePaths = currentSharedImportNodes.Select(x => x.Path); // process added nodes IEnumerable <string> addedSharedImportPaths = sharedFolderProjectPaths.Except(currentSharedImportNodePaths); foreach (string addedSharedImportPath in addedSharedImportPaths) { IDependencyModel added = CreateDependencyModel(addedSharedImportPath, targetContext.TargetFramework, resolved: true); dependencyChangeContext.IncludeAddedChange(targetContext.TargetFramework, added); } // process removed nodes IEnumerable <string> removedSharedImportPaths = currentSharedImportNodePaths.Except(sharedFolderProjectPaths); foreach (string removedSharedImportPath in removedSharedImportPaths) { IDependency existingImportNode = currentSharedImportNodes .Where(node => PathHelper.IsSamePath(node.Path, removedSharedImportPath)) .FirstOrDefault(); if (existingImportNode != null) { IDependencyModel removed = CreateDependencyModel(removedSharedImportPath, targetContext.TargetFramework, resolved: true); dependencyChangeContext.IncludeRemovedChange(targetContext.TargetFramework, removed); } } }
private async Task HandleAsync(Tuple <IProjectSubscriptionUpdate, IProjectSharedFoldersSnapshot, IProjectCatalogSnapshot> e) { AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContext(); if (currentAggregateContext == null) { return; } IProjectSubscriptionUpdate projectUpdate = e.Item1; IProjectSharedFoldersSnapshot sharedProjectsUpdate = e.Item2; IProjectCatalogSnapshot catalogs = e.Item3; // We need to process the update within a lock to ensure that we do not release this context during processing. // TODO: Enable concurrent execution of updates themselves, i.e. two separate invocations of HandleAsync // should be able to run concurrently. using (await _gate.DisposableWaitAsync()) { // Get the inner workspace project context to update for this change. ITargetedProjectContext projectContextToUpdate = currentAggregateContext .GetInnerProjectContext(projectUpdate.ProjectConfiguration, out bool isActiveContext); if (projectContextToUpdate == null) { return; } var dependencyChangeContext = new DependenciesRuleChangeContext( currentAggregateContext.ActiveProjectContext.TargetFramework, catalogs); ProcessSharedProjectsUpdates(sharedProjectsUpdate, projectContextToUpdate, dependencyChangeContext); if (dependencyChangeContext.AnyChanges) { DependenciesChanged?.Invoke(this, new DependencySubscriptionChangedEventArgs(dependencyChangeContext)); } } }
private void HandleChangesForRule( bool resolved, IProjectChangeDescription projectChange, ITargetedProjectContext context, bool isActiveContext, DependenciesRuleChangeContext ruleChangeContext, Func <IDependencyModel, bool> shouldProcess) { foreach (var removedItem in projectChange.Difference.RemovedItems) { var model = CreateDependencyModelForRule(removedItem, resolved, projectChange.Before, context.TargetFramework); if (shouldProcess(model)) { ruleChangeContext.IncludeRemovedChange(context.TargetFramework, model); } } foreach (var changedItem in projectChange.Difference.ChangedItems) { var model = CreateDependencyModelForRule(changedItem, resolved, projectChange.After, context.TargetFramework); if (shouldProcess(model)) { // For changes we try to add new dependency. If it is a resolved dependency, it would just override // old one with new properties. If it is unresolved dependency, it would be added only when there no // resolved version in the snapshot. ruleChangeContext.IncludeAddedChange(context.TargetFramework, model); } } foreach (var addedItem in projectChange.Difference.AddedItems) { var model = CreateDependencyModelForRule(addedItem, resolved, projectChange.After, context.TargetFramework); if (shouldProcess(model)) { ruleChangeContext.IncludeAddedChange(context.TargetFramework, model); } } }
public virtual Task HandleAsync( IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > e, IImmutableDictionary <string, IProjectChangeDescription> projectChanges, ITargetedProjectContext context, bool isActiveContext, DependenciesRuleChangeContext ruleChangeContext) { if (projectChanges.TryGetValue(UnresolvedRuleName, out IProjectChangeDescription unresolvedChanges)) { HandleChangesForRule(false /*unresolved*/, unresolvedChanges, context, isActiveContext, ruleChangeContext, (itemSpec) => { return(true); }); } if (projectChanges.TryGetValue(ResolvedRuleName, out IProjectChangeDescription resolvedChanges)) { HandleChangesForRule(true /*resolved*/, resolvedChanges, context, isActiveContext, ruleChangeContext, (metadata) => { return(DoesUnresolvedProjectItemExist(metadata.OriginalItemSpec, unresolvedChanges)); }); } return(Task.CompletedTask); }
public Task OnContextReleasedAsync(ITargetedProjectContext context) { return(Task.CompletedTask); }
private bool TryGetConfiguredProjectState(ConfiguredProject configuredProject, out ITargetedProjectContext targetedProjectContext) { lock (_gate) { if (_configuredProjectContextsMap.TryGetValue(configuredProject, out targetedProjectContext)) { return(true); } else { targetedProjectContext = null; return(false); } } }
private async Task HandleAsync( IProjectVersionedValue <Tuple <IProjectSubscriptionUpdate, IProjectCatalogSnapshot, IProjectCapabilitiesSnapshot> > e, RuleHandlerType handlerType) { AggregateCrossTargetProjectContext currentAggregateContext = await _host.GetCurrentAggregateProjectContext().ConfigureAwait(false); if (currentAggregateContext == null || _currentProjectContext != currentAggregateContext) { return; } IProjectSubscriptionUpdate update = e.Value.Item1; IProjectCatalogSnapshot catalogs = e.Value.Item2; IEnumerable <ICrossTargetRuleHandler <T> > handlers = Handlers.Select(h => h.Value) .Where(h => h.SupportsHandlerType(handlerType)); // We need to process the update within a lock to ensure that we do not release this context during processing. // TODO: Enable concurrent execution of updates themeselves, i.e. two separate invocations of HandleAsync // should be able to run concurrently. using (await _gate.DisposableWaitAsync().ConfigureAwait(true)) { // Get the inner workspace project context to update for this change. ITargetedProjectContext projectContextToUpdate = currentAggregateContext .GetInnerProjectContext(update.ProjectConfiguration, out bool isActiveContext); if (projectContextToUpdate == null) { return; } // Broken design time builds sometimes cause updates with no project changes and sometimes // cause updates with a project change that has no difference. // We handle the former case here, and the latter case is handled in the CommandLineItemHandler. if (update.ProjectChanges.Count == 0) { if (handlerType == RuleHandlerType.DesignTimeBuild) { projectContextToUpdate.LastDesignTimeBuildSucceeded = false; } return; } T ruleChangeContext = CreateRuleChangeContext( currentAggregateContext.ActiveProjectContext.TargetFramework, catalogs); foreach (ICrossTargetRuleHandler <T> handler in handlers) { ImmutableDictionary <string, IProjectChangeDescription> .Builder builder = ImmutableDictionary.CreateBuilder <string, IProjectChangeDescription>(StringComparers.RuleNames); ImmutableHashSet <string> handlerRules = handler.GetRuleNames(handlerType); builder.AddRange(update.ProjectChanges.Where( x => handlerRules.Contains(x.Key))); ImmutableDictionary <string, IProjectChangeDescription> projectChanges = builder.ToImmutable(); if (handler.ReceiveUpdatesWithEmptyProjectChange || projectChanges.Any(x => x.Value.Difference.AnyChanges)) { await handler.HandleAsync(e, projectChanges, projectContextToUpdate, isActiveContext, ruleChangeContext) .ConfigureAwait(true); } } await CompleteHandleAsync(ruleChangeContext).ConfigureAwait(false); // record all the rules that have occurred _treeTelemetryService.ObserveTargetFrameworkRules(projectContextToUpdate.TargetFramework, update.ProjectChanges.Keys); } }
private bool TryGetConfiguredProjectState(ConfiguredProject configuredProject, out ITargetedProjectContext targetedProjectContext) { lock (_gate) { return(_configuredProjectContextsMap.TryGetValue(configuredProject, out targetedProjectContext)); } }