protected virtual void HandleChangedItem( string changedItem, bool resolved, IProjectChangeDescription projectChange, DependenciesChangesBuilder changesBuilder, ITargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { IDependencyModel model = CreateDependencyModelForRule(changedItem, projectChange.After, resolved); if (isEvaluatedItemSpec == null || isEvaluatedItemSpec(model.Id)) { // 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. changesBuilder.Added(model); } }
public async Task ApplyProjectBuildAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> update, bool isActiveContext, CancellationToken cancellationToken) { Requires.NotNull(update, nameof(update)); VerifyInitializedAndNotDisposed(); IProjectChangeDescription projectChange = update.Value.ProjectChanges[ProjectBuildRuleName]; if (projectChange.Difference.AnyChanges) { IComparable version = GetConfiguredProjectVersion(update); ProcessOptions(projectChange.After); await ProcessCommandLineAsync(version, projectChange.Difference, isActiveContext, cancellationToken); ProcessProjectBuildFailure(projectChange.After); } }
private HostDocument[] GetChangedAndRemovedDocuments(IProjectSubscriptionUpdate update) { IProjectChangeDescription rule = null; var documents = new List <HostDocument>(); if (update.ProjectChanges.TryGetValue(Rules.RazorComponentWithTargetPath.SchemaName, out rule)) { foreach (var key in rule.Difference.RemovedItems.Concat(rule.Difference.ChangedItems)) { if (rule.Before.Items.TryGetValue(key, out var value)) { if (value.TryGetValue(Rules.RazorComponentWithTargetPath.TargetPathProperty, out var targetPath) && !string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(targetPath)) { var filePath = CommonServices.UnconfiguredProject.MakeRooted(key); var fileKind = FileKinds.GetComponentFileKindFromFilePath(filePath); documents.Add(new HostDocument(filePath, targetPath, fileKind)); } } } } if (update.ProjectChanges.TryGetValue(Rules.RazorGenerateWithTargetPath.SchemaName, out rule)) { foreach (var key in rule.Difference.RemovedItems.Concat(rule.Difference.ChangedItems)) { if (rule.Before.Items.TryGetValue(key, out var value)) { if (value.TryGetValue(Rules.RazorGenerateWithTargetPath.TargetPathProperty, out var targetPath) && !string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(targetPath)) { var filePath = CommonServices.UnconfiguredProject.MakeRooted(key); documents.Add(new HostDocument(filePath, targetPath, FileKinds.Legacy)); } } } } return(documents.ToArray()); }
public void Handle( IProjectChangeDescription evaluation, IProjectChangeDescription?projectBuild, TargetFramework targetFramework, DependenciesChangesBuilder changesBuilder) { HandleChangesForRule( resolved: false, projectChange: evaluation, isEvaluatedItemSpec: null); // We only have resolved data if the update came via the JointRule data source. if (projectBuild != null) { Func <string, bool>?isEvaluatedItemSpec = ResolvedItemRequiresEvaluatedItem ? evaluation.After.Items.ContainsKey : (Func <string, bool>?)null; HandleChangesForRule( resolved: true, projectChange: projectBuild, isEvaluatedItemSpec); } return; void HandleChangesForRule(bool resolved, IProjectChangeDescription projectChange, Func <string, bool>?isEvaluatedItemSpec) { foreach (string removedItem in projectChange.Difference.RemovedItems) { HandleRemovedItem(removedItem, resolved, projectChange, changesBuilder, targetFramework, isEvaluatedItemSpec); } foreach (string changedItem in projectChange.Difference.ChangedItems) { HandleChangedItem(changedItem, resolved, projectChange, changesBuilder, targetFramework, isEvaluatedItemSpec); } foreach (string addedItem in projectChange.Difference.AddedItems) { HandleAddedItem(addedItem, resolved, projectChange, changesBuilder, targetFramework, isEvaluatedItemSpec); } System.Diagnostics.Debug.Assert(projectChange.Difference.RenamedItems.Count == 0, "Project rule diff should not contain renamed items"); } }
protected override void HandleAddedItem( string addedItem, bool resolved, IProjectChangeDescription projectChange, DependenciesChangesBuilder changesBuilder, ITargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { if (TryCreatePackageDependencyModel( addedItem, resolved, properties: projectChange.After.GetProjectItemProperties(addedItem) !, isEvaluatedItemSpec, targetFramework, out PackageDependencyModel? dependencyModel)) { changesBuilder.Added(dependencyModel); } }
protected virtual void HandleRemovedItem( string projectFullPath, string removedItem, bool resolved, IProjectChangeDescription projectChange, IProjectRuleSnapshot evaluationRuleSnapshot, DependenciesChangesBuilder changesBuilder, TargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { string dependencyId = resolved ? projectChange.Before.GetProjectItemProperties(removedItem) !.GetStringProperty(ProjectItemMetadata.OriginalItemSpec) ?? removedItem : removedItem; if (isEvaluatedItemSpec == null || isEvaluatedItemSpec(dependencyId)) { changesBuilder.Removed(ProviderType, removedItem); } }
public void Handle( string projectFullPath, IProjectChangeDescription evaluationProjectChange, IProjectChangeDescription?buildProjectChange, TargetFramework targetFramework, DependenciesChangesBuilder changesBuilder) { bool hasResolvedData = buildProjectChange is not null; HandleChangesForRule(evaluationProjectChange, isResolvedItem: false); // We only have resolved data if the update came via the JointRule data source. if (hasResolvedData) { Func <string, bool>?isEvaluatedItemSpec = ResolvedItemRequiresEvaluatedItem ? evaluationProjectChange.After.Items.ContainsKey : null; HandleChangesForRule(evaluationProjectChange, isResolvedItem: true, buildProjectChange, isEvaluatedItemSpec); } return; void HandleChangesForRule(IProjectChangeDescription evaluationProjectChange, bool isResolvedItem, IProjectChangeDescription?buildProjectChange = null, Func <string, bool>?isEvaluatedItemSpec = null) { IProjectChangeDescription projectChange = buildProjectChange ?? evaluationProjectChange; foreach (string removedItem in projectChange.Difference.RemovedItems) { HandleRemovedItem(projectFullPath, removedItem, isResolvedItem, projectChange, evaluationProjectChange.After, changesBuilder, targetFramework, isEvaluatedItemSpec); } foreach (string changedItem in projectChange.Difference.ChangedItems) { HandleAddedItem(projectFullPath, changedItem, isResolvedItem, projectChange, evaluationProjectChange.After, changesBuilder, targetFramework, isEvaluatedItemSpec); } foreach (string addedItem in projectChange.Difference.AddedItems) { HandleAddedItem(projectFullPath, addedItem, isResolvedItem, projectChange, evaluationProjectChange.After, changesBuilder, targetFramework, isEvaluatedItemSpec); } System.Diagnostics.Debug.Assert(projectChange.Difference.RenamedItems.Count == 0, "Project rule diff should not contain renamed items"); } }
protected override void HandleRemovedItem( string removedItem, bool resolved, IProjectChangeDescription projectChange, DependenciesChangesBuilder changesBuilder, ITargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { if (TryCreatePackageDependencyModel( removedItem, resolved, properties: projectChange.Before.GetProjectItemProperties(removedItem) !, isEvaluatedItemSpec, targetFramework, out PackageDependencyModel? dependencyModel)) { changesBuilder.Removed(ProviderTypeString, dependencyModel.OriginalItemSpec); } }
internal void OnNamespaceImportChanged(IProjectVersionedValue <IProjectSubscriptionUpdate> e) { IProjectChangeDescription projectChange = e.Value.ProjectChanges[NamespaceImport.SchemaName]; if (projectChange.Difference.AnyChanges) { lock (_lock) { IOrderedEnumerable <string> sortedItems = projectChange.After.Items.Keys.OrderBy(s => s, StringComparer.OrdinalIgnoreCase); int newListCount = sortedItems.Count(); int oldListCount = _list.Count; int trackingIndex = 0; while (trackingIndex < oldListCount && trackingIndex < newListCount) { string incomingItem = sortedItems.ElementAt(trackingIndex); if (string.Compare(_list[trackingIndex], incomingItem, StringComparison.OrdinalIgnoreCase) == 0) { trackingIndex++; continue; } _list[trackingIndex] = incomingItem; trackingIndex++; } if (oldListCount == newListCount) { return; } else if (oldListCount < newListCount) { _list.AddRange(sortedItems.Skip(trackingIndex)); } else { _list.RemoveRange(trackingIndex, oldListCount - trackingIndex); } } } }
private async Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> update, RuleHandlerType handlerType) { var handlers = Handlers.Select(h => h.Value) .Where(h => h.HandlerType == 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. await ExecuteWithinLockAsync(async() => { // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 await _commonServices.ThreadingService.SwitchToUIThread(); // Get the inner workspace project context to update for this change. var projectContextToUpdate = _currentAggregateProjectContext.GetInnerProjectContext(update.Value.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.Value.ProjectChanges.Count == 0) { if (handlerType == RuleHandlerType.DesignTimeBuild) { projectContextToUpdate.LastDesignTimeBuildSucceeded = false; } return; } foreach (var handler in handlers) { IProjectChangeDescription projectChange = update.Value.ProjectChanges[handler.RuleName]; if (handler.ReceiveUpdatesWithEmptyProjectChange || projectChange.Difference.AnyChanges) { await handler.HandleAsync(update, projectChange, projectContextToUpdate, isActiveContext).ConfigureAwait(true); } } }); }
public void Handle(IComparable version, IProjectChangeDescription projectChange, ContextState state, IProjectLogger logger) { Requires.NotNull(version, nameof(version)); Requires.NotNull(projectChange, nameof(projectChange)); Requires.NotNull(logger, nameof(logger)); VerifyInitialized(); if (projectChange.Difference.ChangedProperties.Contains(ConfigurationGeneral.MSBuildProjectFullPathProperty) && projectChange.After.Properties.TryGetValue(ConfigurationGeneral.MSBuildProjectFullPathProperty, out string projectFilePath)) { string displayName = GetDisplayName(projectFilePath); logger.WriteLine("DisplayName: {0}", displayName); logger.WriteLine("ProjectFilePath: {0}", projectFilePath); Context.ProjectFilePath = projectFilePath; Context.DisplayName = displayName; } }
protected virtual void HandleChangedItem( string projectFullPath, string changedItem, bool resolved, IProjectChangeDescription projectChange, IProjectRuleSnapshot evaluationRuleSnapshot, DependenciesChangesBuilder changesBuilder, TargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { IDependencyModel?model = CreateDependencyModelForRule(changedItem, evaluationRuleSnapshot, projectChange.After, resolved, projectFullPath); if (model != null && (isEvaluatedItemSpec == null || isEvaluatedItemSpec(model.Id))) { // 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 is // no resolved version in the snapshot (due to UnresolvedDependenciesSnapshotFilter). changesBuilder.Added(model); } }
private Task ProcessProjectEvaluationHandlersAsync(IComparable version, IProjectVersionedValue <IProjectSubscriptionUpdate> update, bool isActiveContext, CancellationToken cancellationToken) { foreach (ExportLifetimeContext <IWorkspaceContextHandler> handler in _handlers) { cancellationToken.ThrowIfCancellationRequested(); if (handler.Value is IProjectEvaluationHandler evaluationHandler) { IProjectChangeDescription projectChange = update.Value.ProjectChanges[evaluationHandler.ProjectEvaluationRule]; if (!projectChange.Difference.AnyChanges) { continue; } evaluationHandler.Handle(version, projectChange, isActiveContext, _logger); } } return(Task.CompletedTask); }
public void ApplyDesignTime(IProjectVersionedValue <IProjectSubscriptionUpdate> update, bool isActiveContext, CancellationToken cancellationToken) { Requires.NotNull(update, nameof(update)); lock (SyncObject) { VerifyInitializedAndNotDisposed(); IProjectChangeDescription projectChange = update.Value.ProjectChanges[DesignTimeRuleName]; if (projectChange.Difference.AnyChanges) { IComparable version = GetConfiguredProjectVersion(update); ProcessOptions(projectChange.After); ProcessCommandLine(version, projectChange.Difference, isActiveContext, cancellationToken); ProcessDesignTimeBuildFailure(projectChange.After); } } }
protected override void HandleChangedItem( string changedItem, bool resolved, IProjectChangeDescription projectChange, DependenciesChangesBuilder changesBuilder, ITargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { if (PackageDependencyMetadata.TryGetMetadata( changedItem, resolved, properties: projectChange.After.GetProjectItemProperties(changedItem) !, isEvaluatedItemSpec, targetFramework, _targetFrameworkProvider, out PackageDependencyMetadata metadata)) { changesBuilder.Removed(ProviderTypeString, metadata.OriginalItemSpec); changesBuilder.Added(metadata.CreateDependencyModel()); } }
private void ProcessProjectEvaluationHandlers(IComparable version, IProjectVersionedValue <IProjectSubscriptionUpdate> update, bool isActiveContext, CancellationToken cancellationToken) { foreach (ExportLifetimeContext <IWorkspaceContextHandler> handler in _handlers) { if (cancellationToken.IsCancellationRequested) { break; } if (handler.Value is IProjectEvaluationHandler evaluationHandler) { IProjectChangeDescription projectChange = update.Value.ProjectChanges[evaluationHandler.ProjectEvaluationRule]; if (!projectChange.Difference.AnyChanges) { continue; } evaluationHandler.Handle(version, projectChange, isActiveContext, _logger); } } }
public void Handle(IComparable version, IProjectChangeDescription projectChange, bool isActiveContext, IProjectLogger logger) { Requires.NotNull(version, nameof(version)); Requires.NotNull(projectChange, nameof(projectChange)); Requires.NotNull(logger, nameof(logger)); VerifyInitialized(); IProjectChangeDiff difference = HandlerServices.NormalizeRenames(projectChange.Difference); foreach (string includePath in difference.RemovedItems) { if (IsDynamicFile(includePath)) { RemoveFromContextIfPresent(includePath, logger); } } foreach (string includePath in difference.AddedItems) { if (IsDynamicFile(includePath)) { IImmutableDictionary <string, string> metadata = projectChange.After.Items.GetValueOrDefault(includePath, ImmutableStringDictionary <string> .EmptyOrdinal); AddToContextIfNotPresent(includePath, metadata, logger); } } // We Remove then Add changed items to pick up the Linked metadata foreach (string includePath in difference.ChangedItems) { if (IsDynamicFile(includePath)) { IImmutableDictionary <string, string> metadata = projectChange.After.Items.GetValueOrDefault(includePath, ImmutableStringDictionary <string> .EmptyOrdinal); RemoveFromContextIfPresent(includePath, logger); AddToContextIfNotPresent(includePath, metadata, logger); } } }
private void HandleChangesForRule( bool resolved, IProjectChangeDescription projectChange, ITargetFramework targetFramework, DependenciesRuleChangeContext ruleChangeContext, Func <string, bool> shouldProcess) { foreach (string removedItem in projectChange.Difference.RemovedItems) { string dependencyId = resolved ? projectChange.Before.GetProjectItemProperties(removedItem).GetStringProperty(OriginalItemSpecPropertyName) : removedItem; if (shouldProcess(dependencyId)) { ruleChangeContext.IncludeRemovedChange(targetFramework, ProviderType, removedItem); } } foreach (string changedItem in projectChange.Difference.ChangedItems) { IDependencyModel model = CreateDependencyModelForRule(changedItem, resolved, projectChange.After); if (shouldProcess(model.Id)) { // 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(targetFramework, model); } } foreach (string addedItem in projectChange.Difference.AddedItems) { IDependencyModel model = CreateDependencyModelForRule(addedItem, resolved, projectChange.After); if (shouldProcess(model.Id)) { ruleChangeContext.IncludeAddedChange(targetFramework, model); } } }
protected override void Handle( string projectFullPath, AggregateCrossTargetProjectContext currentAggregateContext, TargetFramework targetFrameworkToUpdate, EventData e) { IProjectSubscriptionUpdate projectUpdate = e.Item1; IProjectCatalogSnapshot catalogSnapshot = e.Item2; // Broken design-time builds can produce updates containing no rule data. // Later code assumes that the requested rules are available. // If we see no rule data, return now. if (projectUpdate.ProjectChanges.Count == 0) { return; } // Create an object to track dependency changes. var changesBuilder = new DependenciesChangesBuilder(); // Give each handler a chance to register dependency changes. foreach (Lazy <IDependenciesRuleHandler, IOrderPrecedenceMetadataView> handler in _handlers) { IProjectChangeDescription evaluation = projectUpdate.ProjectChanges[handler.Value.EvaluatedRuleName]; IProjectChangeDescription?build = projectUpdate.ProjectChanges.GetValueOrDefault(handler.Value.ResolvedRuleName); handler.Value.Handle(projectFullPath, evaluation, build, targetFrameworkToUpdate, changesBuilder); } IDependenciesChanges?changes = changesBuilder.TryBuildChanges(); // Notify subscribers of a change in dependency data. // NOTE even if changes is null, it's possible the catalog has changed. If we don't take the newer // catalog we end up retaining a reference to an old catalog, which in turn retains an old project // instance which can be very large. RaiseDependenciesChanged(targetFrameworkToUpdate, changes, currentAggregateContext, catalogSnapshot); // Record all the rules that have occurred _treeTelemetryService.ObserveTargetFrameworkRules(targetFrameworkToUpdate, projectUpdate.ProjectChanges.Keys); }
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); } } }
protected virtual void HandleRemovedItem( string projectFullPath, string removedItem, IProjectChangeDescription projectChange, IProjectRuleSnapshot evaluationRuleSnapshot, DependenciesChangesBuilder changesBuilder, TargetFramework targetFramework, Func <string, bool>?isEvaluatedItemSpec) { if (isEvaluatedItemSpec is not null) { // The item is resolved string dependencyId = projectChange.Before.GetProjectItemProperties(removedItem) !.GetStringProperty(ProjectItemMetadata.OriginalItemSpec) ?? removedItem; if (!isEvaluatedItemSpec(dependencyId)) { // Skip any items returned by build that were not present in evaluation return; } } changesBuilder.Removed(targetFramework, ProviderType, removedItem); }
public void Handle(IComparable version, IProjectChangeDescription projectChange, bool isActiveContext, IProjectLogger logger) { Requires.NotNull(version, nameof(version)); Requires.NotNull(projectChange, nameof(projectChange)); Requires.NotNull(logger, nameof(logger)); // The language service wants both the intermediate (bin\obj) and output (bin\debug)) paths // so that it can automatically hook up project-to-project references. It does this by matching the // bin output path with the another project's /reference argument, if they match, then it automatically // introduces a project reference between the two. We pass the intermediate path via the /out // command-line argument and set via one of the other handlers, where as the latter is calculated via // the TargetPath property and explictly set on the context. if (projectChange.Difference.ChangedProperties.Contains(ConfigurationGeneral.TargetPathProperty)) { string newBinOutputPath = projectChange.After.Properties[ConfigurationGeneral.TargetPathProperty]; if (!string.IsNullOrEmpty(newBinOutputPath)) { logger.WriteLine("BinOutputPath: {0}", newBinOutputPath); _context.BinOutputPath = newBinOutputPath; } } }
public void Handle(IComparable version, IProjectChangeDescription projectChange, bool isActiveContext, IProjectLogger logger) { Requires.NotNull(version, nameof(version)); Requires.NotNull(projectChange, nameof(projectChange)); Requires.NotNull(logger, nameof(logger)); VerifyInitialized(); foreach (string name in projectChange.Difference.ChangedProperties) { string value = projectChange.After.Properties[name]; // Is it a property we're specifically aware of? if (TryHandleSpecificProperties(name, value, logger)) { continue; } // Otherwise, just pass it through logger.WriteLine("{0}: {1}", name, value); Context.SetProperty(name, value); } }
protected bool DoesUnresolvedProjectItemExist(string itemSpec, IProjectChangeDescription unresolvedChanges) { return(unresolvedChanges != null && unresolvedChanges.After.Items.ContainsKey(itemSpec)); }
public Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e, IProjectChangeDescription projectChange) { Requires.NotNull(e, nameof(e)); Requires.NotNull(projectChange, nameof(projectChange)); if (projectChange.Difference.ChangedProperties.Contains(ConfigurationGeneral.ProjectGuidProperty)) { Guid result; if (Guid.TryParse(projectChange.After.Properties[ConfigurationGeneral.ProjectGuidProperty], out result)) { _context.Guid = result; } } // The language service wants both the intermediate (bin\obj) and output (bin\debug)) paths // so that it can automatically hook up project-to-project references. It does this by matching the // bin output path with the another project's /reference argument, if they match, then it automatically // introduces a project reference between the two. We pass the intermediate path via the /out // command-line argument and set via one of the other handlers, where as the latter is calculate via // the TargetPath property and explictly set on the context. if (projectChange.Difference.ChangedProperties.Contains(ConfigurationGeneral.TargetPathProperty)) { _context.BinOutputPath = projectChange.After.Properties[ConfigurationGeneral.TargetPathProperty]; } return(Task.CompletedTask); }
public override async Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e, IProjectChangeDescription projectChange, IWorkspaceProjectContext context, bool isActiveContext) { Requires.NotNull(e, nameof(e)); Requires.NotNull(projectChange, nameof(projectChange)); IProjectChangeDiff diff = projectChange.Difference; foreach (string filePath in diff.RemovedItems) { RemoveSourceFile(filePath, context); } if (diff.AddedItems.Count > 0 || diff.RenamedItems.Count > 0 || diff.ChangedItems.Count > 0) { // Make sure the tree matches the same version of the evaluation that we're handling IProjectTreeServiceState treeState = await PublishTreeAsync(e).ConfigureAwait(true); // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 foreach (string filePath in diff.AddedItems) { AddSourceFile(filePath, context, isActiveContext, treeState); } foreach (KeyValuePair <string, string> filePaths in diff.RenamedItems) { RemoveSourceFile(filePaths.Key, context); AddSourceFile(filePaths.Value, context, isActiveContext, treeState); } foreach (string filePath in diff.ChangedItems) { // We add and then remove ChangedItems to handle Linked metadata changes RemoveSourceFile(filePath, context); AddSourceFile(filePath, context, isActiveContext); } } }
public override Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e, IProjectChangeDescription projectChange, IWorkspaceProjectContext context, bool isActiveContext) { Requires.NotNull(e, nameof(e)); Requires.NotNull(projectChange, nameof(projectChange)); if (!ProcessDesignTimeBuildFailure(projectChange, context)) { ProcessOptions(projectChange, context); ProcessItems(projectChange, context, isActiveContext); } return(Task.CompletedTask); }
internal void ProcessDataflowChanges(IProjectVersionedValue <ValueTuple <DesignTimeInputs, IProjectSubscriptionUpdate> > input) { DesignTimeInputs inputs = input.Value.Item1; IProjectChangeDescription configChanges = input.Value.Item2.ProjectChanges[ConfigurationGeneral.SchemaName]; // This can't change while we're running, but let's use a local so you don't have to take my word for it DesignTimeInputsDelta?previousState = _currentState; var changedInputs = new List <DesignTimeInputFileChange>(); // On the first call where we receive design time inputs we queue compilation of all of them, knowing that we'll only compile if the file write date requires it if (previousState == null) { AddAllInputsToQueue(false); } else { // If its not the first call... // If a new shared design time input is added, we need to recompile everything regardless of source file modified date // because it could be an old file that is being promoted to a shared input if (inputs.SharedInputs.Except(previousState.SharedInputs, StringComparers.Paths).Any()) { AddAllInputsToQueue(true); } // If the namespace or output path inputs have changed, then we recompile every file regardless of date else if (configChanges.Difference.ChangedProperties.Contains(ConfigurationGeneral.RootNamespaceProperty) || configChanges.Difference.ChangedProperties.Contains(ConfigurationGeneral.ProjectDirProperty) || configChanges.Difference.ChangedProperties.Contains(ConfigurationGeneral.IntermediateOutputPathProperty)) { AddAllInputsToQueue(true); } else { // Otherwise we just queue any new design time inputs, and still do date checks foreach (string file in inputs.Inputs.Except(previousState.Inputs, StringComparers.Paths)) { changedInputs.Add(new DesignTimeInputFileChange(file, ignoreFileWriteTime: false)); } } } string tempPEOutputPath; // Make sure we have the up to date output path string basePath = configChanges.After.Properties[ConfigurationGeneral.ProjectDirProperty]; string objPath = configChanges.After.Properties[ConfigurationGeneral.IntermediateOutputPathProperty]; try { tempPEOutputPath = Path.Combine(basePath, objPath, "TempPE"); } catch (ArgumentException) { // if the path is bad, then we presume we wouldn't be able to act on any files anyway // so we can just clear _latestDesignTimeInputs to ensure file changes aren't processed, and return. // If the path is ever fixed this block will trigger again and all will be right with the world. _currentState = null; return; } // This is our only update to current state, and data flow protects us from overlaps. File changes don't update state _currentState = new DesignTimeInputsDelta(inputs.Inputs, inputs.SharedInputs, changedInputs, tempPEOutputPath); PostToOutput(_currentState); void AddAllInputsToQueue(bool ignoreFileWriteTime) { foreach (string file in inputs.Inputs) { changedInputs.Add(new DesignTimeInputFileChange(file, ignoreFileWriteTime)); } } }
private IDependencyModel GetDependencyModel( string itemSpec, bool resolved, IImmutableDictionary <string, string> properties, IProjectChangeDescription projectChange, HashSet <string> unresolvedChanges, ITargetFramework targetFramework) { PackageDependencyMetadata metadata; bool isTopLevel = true; bool isTarget = false; if (resolved) { metadata = new PackageDependencyMetadata(itemSpec, properties); isTopLevel = metadata.IsImplicitlyDefined || (metadata.DependencyType == DependencyType.Package && unresolvedChanges != null && unresolvedChanges.Contains(metadata.Name)); isTarget = metadata.IsTarget; ITargetFramework packageTargetFramework = TargetFrameworkProvider.GetTargetFramework(metadata.Target); if (!(packageTargetFramework?.Equals(targetFramework) == true)) { return(null); } } else { metadata = CreateUnresolvedMetadata(itemSpec, properties); } if (isTarget) { return(null); } string originalItemSpec = itemSpec; if (resolved && isTopLevel) { originalItemSpec = metadata.Name; } IDependencyModel dependencyModel = null; switch (metadata.DependencyType) { case DependencyType.Package: dependencyModel = new PackageDependencyModel( ProviderType, itemSpec, originalItemSpec, metadata.Name, DependencyTreeFlags.NuGetSubTreeNodeFlags, metadata.Version, resolved, metadata.IsImplicitlyDefined, isTopLevel, !metadata.IsImplicitlyDefined /*visible*/, properties, metadata.DependenciesItemSpecs); break; case DependencyType.Assembly: case DependencyType.FrameworkAssembly: dependencyModel = new PackageAssemblyDependencyModel( ProviderType, itemSpec, originalItemSpec, metadata.Name, DependencyTreeFlags.NuGetSubTreeNodeFlags, resolved, properties, metadata.DependenciesItemSpecs); break; case DependencyType.AnalyzerAssembly: dependencyModel = new PackageAnalyzerAssemblyDependencyModel( ProviderType, itemSpec, originalItemSpec, metadata.Name, DependencyTreeFlags.NuGetSubTreeNodeFlags, resolved, properties, metadata.DependenciesItemSpecs); break; case DependencyType.Diagnostic: dependencyModel = new DiagnosticDependencyModel( ProviderType, itemSpec, metadata.Severity, metadata.DiagnosticCode, metadata.Name, DependencyTreeFlags.NuGetSubTreeNodeFlags, isVisible: true, properties: properties); break; default: dependencyModel = new PackageUnknownDependencyModel( ProviderType, itemSpec, originalItemSpec, metadata.Name, DependencyTreeFlags.NuGetSubTreeNodeFlags, resolved, properties, metadata.DependenciesItemSpecs); break; } return(dependencyModel); }
internal static IVsProjectRestoreInfo Build(IEnumerable <IProjectVersionedValue <IProjectSubscriptionUpdate> > updates) { Requires.NotNull(updates, nameof(updates)); // if none of the underlying subscriptions have any changes if (!updates.Any(u => u.Value.ProjectChanges.Any(c => c.Value.Difference.AnyChanges))) { return(null); } string msbuildProjectExtensionsPath = null; string originalTargetFrameworks = null; var targetFrameworks = ImmutableDictionary.Create <string, IVsTargetFrameworkInfo>(StringComparers.ItemNames); var toolReferences = ImmutableDictionary.Create <string, IVsReferenceItem>(StringComparers.ItemNames); foreach (IProjectVersionedValue <IProjectSubscriptionUpdate> update in updates) { IProjectChangeDescription nugetRestoreChanges = update.Value.ProjectChanges[NuGetRestore.SchemaName]; msbuildProjectExtensionsPath = msbuildProjectExtensionsPath ?? nugetRestoreChanges.After.Properties[NuGetRestore.MSBuildProjectExtensionsPathProperty]; originalTargetFrameworks = originalTargetFrameworks ?? nugetRestoreChanges.After.Properties[NuGetRestore.TargetFrameworksProperty]; bool noTargetFramework = !update.Value.ProjectConfiguration.Dimensions.TryGetValue(NuGetRestore.TargetFrameworkProperty, out string targetFramework) && !nugetRestoreChanges.After.Properties.TryGetValue(NuGetRestore.TargetFrameworkProperty, out targetFramework); if (noTargetFramework || string.IsNullOrEmpty(targetFramework)) { TraceUtilities.TraceWarning("Unable to find TargetFramework Property"); continue; } if (!targetFrameworks.ContainsKey(targetFramework)) { IProjectChangeDescription projectReferencesChanges = update.Value.ProjectChanges[ProjectReference.SchemaName]; IProjectChangeDescription packageReferencesChanges = update.Value.ProjectChanges[PackageReference.SchemaName]; targetFrameworks = targetFrameworks.Add(targetFramework, new TargetFrameworkInfo( targetFramework, RestoreBuilder.ToReferenceItems(projectReferencesChanges.After.Items), RestoreBuilder.ToReferenceItems(packageReferencesChanges.After.Items), RestoreBuilder.ToProjectProperties(nugetRestoreChanges.After.Properties) )); } IProjectChangeDescription toolReferencesChanges = update.Value.ProjectChanges[DotNetCliToolReference.SchemaName]; foreach (KeyValuePair <string, IImmutableDictionary <string, string> > item in toolReferencesChanges.After.Items) { if (!toolReferences.ContainsKey(item.Key)) { toolReferences = toolReferences.Add(item.Key, RestoreBuilder.ToReferenceItem(item.Key, item.Value)); } } } // return nominate restore information if any target framework entries are found return(targetFrameworks.Count > 0 ? new ProjectRestoreInfo( // NOTE: We pass MSBuildProjectExtensionsPath as BaseIntermediatePath instead of using // BaseIntermediateOutputPath. This is because NuGet switched from using BaseIntermediateOutputPath // to MSBuildProjectExtensionsPath, since the value of BaseIntermediateOutputPath is often set too // late (after *.g.props files would need to have been imported from it). Instead of modifying the // IVsProjectRestoreInfo interface or introducing something like IVsProjectRestoreInfo with an // MSBuildProjectExtensionsPath property, we opted to leave the interface the same but change the // meaning of its BaseIntermediatePath property. See // https://github.com/dotnet/project-system/issues/3466for for details. msbuildProjectExtensionsPath, originalTargetFrameworks, new TargetFrameworks(targetFrameworks.Values), new ReferenceItems(toolReferences.Values) ) : null); }