/// <summary> /// Gets an IRule to attach to a project item so that browse object properties will be displayed. /// </summary> private IRule GetRuleForUnresolvableReference(IProjectPropertiesContext unresolvedContext, IProjectCatalogSnapshot catalogs, ConfiguredProjectExports configuredProjectExports) { Requires.NotNull(unresolvedContext, nameof(unresolvedContext)); Requires.NotNull(configuredProjectExports, nameof(configuredProjectExports)); var namedCatalogs = GetNamedCatalogs(catalogs); var schemas = GetSchemaForReference(unresolvedContext.ItemType, false, namedCatalogs).ToList(); if (schemas.Count == 1) { Requires.NotNull(namedCatalogs, nameof(namedCatalogs)); var browseObjectCatalog = namedCatalogs[PropertyPageContexts.BrowseObject]; return(browseObjectCatalog.BindToContext(schemas[0].Name, unresolvedContext)); } if (schemas.Count > 1) { TraceUtilities.TraceWarning( "Too many rule schemas ({0}) in the BrowseObject context were found. Only 1 is allowed.", schemas.Count); } // Since we have no browse object, we still need to create *something* so that standard property // pages can pop up. var emptyRule = RuleExtensions.SynthesizeEmptyRule(unresolvedContext.ItemType); return(configuredProjectExports.PropertyPagesDataModelProvider.GetRule( emptyRule, unresolvedContext.File, unresolvedContext.ItemType, unresolvedContext.ItemName)); }
/// <summary> /// Gets an IRule to attach to a project item so that browse object properties will be displayed. /// </summary> private IRule GetRuleForResolvableReference( IProjectPropertiesContext unresolvedContext, KeyValuePair <string, IImmutableDictionary <string, string> > resolvedReference, IProjectCatalogSnapshot catalogs, ConfiguredProjectExports configuredProjectExports, bool isGenericDependency = true) { Requires.NotNull(unresolvedContext, nameof(unresolvedContext)); var namedCatalogs = GetNamedCatalogs(catalogs); var schemas = GetSchemaForReference(unresolvedContext.ItemType, isGenericDependency, namedCatalogs).ToList(); if (schemas.Count == 1) { IRule rule = configuredProjectExports.RuleFactory.CreateResolvedReferencePageRule( schemas[0], unresolvedContext, resolvedReference.Key, resolvedReference.Value); return(rule); } else { if (schemas.Count > 1) { TraceUtilities.TraceWarning( "Too many rule schemas ({0}) in the BrowseObject context were found. Only 1 is allowed.", schemas.Count); } // Since we have no browse object, we still need to create *something* so that standard property // pages can pop up. var emptyRule = RuleExtensions.SynthesizeEmptyRule(unresolvedContext.ItemType); return(configuredProjectExports.PropertyPagesDataModelProvider.GetRule( emptyRule, unresolvedContext.File, unresolvedContext.ItemType, unresolvedContext.ItemName)); } }
private async Task HandleFileChangedAsync(CancellationToken cancellationToken = default) { try { // Only notify the project if the contents of the watched file have changed. // In the case if we fail to read the contents, we will opt to notify the project. byte[] newHash = GetFileHashOrNull(_fileBeingWatched); if (newHash == null || _previousContentsHash == null || !newHash.SequenceEqual(_previousContentsHash)) { TraceUtilities.TraceVerbose("{0} changed on disk. Marking project dirty", _fileBeingWatched); _previousContentsHash = newHash; cancellationToken.ThrowIfCancellationRequested(); await _projectServices.Project.Services.ProjectAsynchronousTasks.LoadedProjectAsync(async() => { await _projectServices.ProjectAccessor.EnterWriteLockAsync(async(collection, token) => { // notify all the loaded configured projects IEnumerable <ConfiguredProject> currentProjects = _projectServices.Project.LoadedConfiguredProjects; foreach (ConfiguredProject configuredProject in currentProjects) { await _projectServices.ProjectAccessor.OpenProjectForWriteAsync(configuredProject, project => { project.MarkDirty(); configuredProject.NotifyProjectChange(); }, cancellationToken).ConfigureAwait(true); // Stay on same thread that took lock } }, cancellationToken).ConfigureAwait(true); // Stay on same thread that took lock }); } else { TraceUtilities.TraceWarning("{0} changed on disk, but has no actual content change.", _fileBeingWatched); } } catch (OperationCanceledException) { // Project is already unloaded } }
private async Task HandleFileChangedAsync(CancellationToken cancellationToken = default(CancellationToken)) { try { // Only notify the project if the contents of the watched file have changed. // In the case if we fail to read the contents, we will opt to notify the project. byte[] newHash = GetFileHashOrNull(_fileBeingWatched); if (newHash == null || _previousContentsHash == null || !newHash.SequenceEqual(_previousContentsHash)) { TraceUtilities.TraceVerbose("{0} changed on disk. Marking project dirty", _fileBeingWatched); _previousContentsHash = newHash; cancellationToken.ThrowIfCancellationRequested(); await _projectServices.Project.Services.ProjectAsynchronousTasks.LoadedProjectAsync(async() => { using (var access = await _projectServices.ProjectLockService.WriteLockAsync(cancellationToken)) { // notify all the loaded configured projects var currentProjects = _projectServices.Project.LoadedConfiguredProjects; foreach (var configuredProject in currentProjects) { // Inside a write lock, we should get back to the same thread. var project = await access.GetProjectAsync(configuredProject, cancellationToken).ConfigureAwait(true); project.MarkDirty(); configuredProject.NotifyProjectChange(); } } }); } else { TraceUtilities.TraceWarning("{0} changed on disk, but has no actual content change.", _fileBeingWatched); } } catch (OperationCanceledException) { // Project is already unloaded } }
internal static IVsProjectRestoreInfo Build(IEnumerable <IProjectVersionedValue <IProjectSubscriptionUpdate> > updates, UnconfiguredProject project) { Requires.NotNull(updates, nameof(updates)); Requires.NotNull(project, nameof(project)); // 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 baseIntermediatePath = null; string originalTargetFrameworks = null; var targetFrameworks = new TargetFrameworks(); var toolReferences = new ReferenceItems(); foreach (IProjectVersionedValue <IProjectSubscriptionUpdate> update in updates) { var nugetRestoreChanges = update.Value.ProjectChanges[NuGetRestore.SchemaName]; baseIntermediatePath = baseIntermediatePath ?? nugetRestoreChanges.After.Properties[NuGetRestore.BaseIntermediateOutputPathProperty]; 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.Contains(targetFramework)) { var projectReferencesChanges = update.Value.ProjectChanges[ProjectReference.SchemaName]; var packageReferencesChanges = update.Value.ProjectChanges[PackageReference.SchemaName]; targetFrameworks.Add(new TargetFrameworkInfo { TargetFrameworkMoniker = targetFramework, ProjectReferences = GetProjectReferences(projectReferencesChanges.After.Items, project), PackageReferences = GetReferences(packageReferencesChanges.After.Items), Properties = GetProperties(nugetRestoreChanges.After.Properties) }); } var toolReferencesChanges = update.Value.ProjectChanges[DotNetCliToolReference.SchemaName]; foreach (var item in toolReferencesChanges.After.Items) { if (!toolReferences.Contains(item.Key)) { toolReferences.Add(GetReferenceItem(item)); } } } // return nominate restore information if any target framework entries are found return(targetFrameworks.Any() ? new ProjectRestoreInfo { BaseIntermediatePath = baseIntermediatePath, OriginalTargetFrameworks = originalTargetFrameworks, TargetFrameworks = targetFrameworks, ToolReferences = toolReferences } : null); }
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); }