public ITargetFramework GetProjectFramework(ProjectConfiguration projectConfiguration) { if (projectConfiguration.IsCrossTargeting()) { string targetFrameworkMoniker = projectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]; return(_targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker)); } else { return(TargetFrameworks.Length > 1 ? null : TargetFrameworks[0]); } }
private void OnSubtreeProviderDependenciesChanged(object sender, DependenciesChangedEventArgs e) { if (IsDisposing || IsDisposed || !e.Changes.AnyChanges()) { return; } ITargetFramework targetFramework = string.IsNullOrEmpty(e.TargetShortOrFullName) || TargetFramework.Any.Equals(e.TargetShortOrFullName) ? TargetFramework.Any : _targetFrameworkProvider.GetTargetFramework(e.TargetShortOrFullName) ?? TargetFramework.Any; ImmutableDictionary <ITargetFramework, IDependenciesChanges> changes = ImmutableDictionary <ITargetFramework, IDependenciesChanges> .Empty.Add(targetFramework, e.Changes); UpdateDependenciesSnapshot(changes, catalogs: null, activeTargetFramework: null, e.Token); }
private void OnSubtreeProviderDependenciesChanged(object sender, DependenciesChangedEventArgs e) { if (IsDisposing || IsDisposed || !e.Changes.AnyChanges()) { return; } // TODO remove ! when https://github.com/dotnet/roslyn/issues/36018 is fixed ITargetFramework targetFramework = string.IsNullOrEmpty(e.TargetShortOrFullName) || TargetFramework.Any.Equals(e.TargetShortOrFullName !) ? TargetFramework.Any : _targetFrameworkProvider.GetTargetFramework(e.TargetShortOrFullName) ?? TargetFramework.Any; ImmutableDictionary <ITargetFramework, IDependenciesChanges> changes = ImmutableDictionary <ITargetFramework, IDependenciesChanges> .Empty.Add(targetFramework, e.Changes); UpdateDependenciesSnapshot(changes, catalogs: null, activeTargetFramework: null, e.Token); }
/// <summary> /// Ensures that <see cref="_currentAggregateProjectContext"/> is updated for the latest TargetFrameworks from the project properties /// and returns this value. /// </summary> private async Task <AggregateCrossTargetProjectContext> UpdateProjectContextAsync() { // Ensure that only single thread is attempting to create a project context. AggregateCrossTargetProjectContext previousContextToDispose = null; return(await ExecuteWithinLockAsync(async() => { // Check if we have already computed the project context. if (_currentAggregateProjectContext != null) { // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed. // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project. // If not, we create a new one and dispose the current one. var projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(false); if (!_currentAggregateProjectContext.IsCrossTargeting) { var newTargetFramework = _targetFrameworkProvider.GetTargetFramework((string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false)); if (_currentAggregateProjectContext.ActiveProjectContext.TargetFramework.Equals(newTargetFramework)) { return _currentAggregateProjectContext; } } else { var targetFrameworks = (string)await projectProperties.TargetFrameworks.GetValueAsync().ConfigureAwait(false); // Check if the current project context is up-to-date for the current active and known project configurations. var activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; var knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync().ConfigureAwait(false); if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) && _currentAggregateProjectContext.HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations)) { return _currentAggregateProjectContext; } } previousContextToDispose = _currentAggregateProjectContext; } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync().ConfigureAwait(false); // Dispose the old project context, if one exists. if (previousContextToDispose != null) { await DisposeAggregateProjectContextAsync(previousContextToDispose).ConfigureAwait(false); } // Create new project context. _currentAggregateProjectContext = await _contextProvider.Value.CreateProjectContextAsync().ConfigureAwait(false); OnAggregateContextChanged(previousContextToDispose, _currentAggregateProjectContext); return _currentAggregateProjectContext; }).ConfigureAwait(false)); }
protected override async Task InitializeCoreAsync(CancellationToken cancellationToken) { await UpdateProjectContextAndSubscriptionsAsync(); lock (_lock) { if (_isDisposed) { throw new ObjectDisposedException(nameof(DependenciesSnapshotProvider)); } _commonServices.Project.ProjectUnloading += OnUnconfiguredProjectUnloadingAsync; foreach (Lazy <IProjectDependenciesSubTreeProvider, IOrderPrecedenceMetadataView> provider in _subTreeProviders) { provider.Value.DependenciesChanged += OnSubtreeProviderDependenciesChanged; } _disposables.Add( new DisposableDelegate( () => { _commonServices.Project.ProjectUnloading -= OnUnconfiguredProjectUnloadingAsync; foreach (Lazy <IProjectDependenciesSubTreeProvider, IOrderPrecedenceMetadataView> provider in _subTreeProviders) { provider.Value.DependenciesChanged -= OnSubtreeProviderDependenciesChanged; } })); } return; Task OnUnconfiguredProjectUnloadingAsync(object?sender, EventArgs args) { // If our project unloads, we have no more work to do DisposeCore(); return(Task.CompletedTask); } void OnSubtreeProviderDependenciesChanged(object?sender, DependenciesChangedEventArgs e) { if (IsDisposing || IsDisposed || !e.Changes.AnyChanges()) { return; } ITargetFramework targetFramework = Strings.IsNullOrEmpty(e.TargetShortOrFullName) || TargetFramework.Any.Equals(e.TargetShortOrFullName) ? TargetFramework.Any : _targetFrameworkProvider.GetTargetFramework(e.TargetShortOrFullName) ?? TargetFramework.Any; UpdateDependenciesSnapshot(targetFramework, e.Changes, catalogs: null, targetFrameworks: default, activeTargetFramework: null, e.Token);
public TargetFramework?GetProjectFramework(ProjectConfiguration projectConfiguration) { if (projectConfiguration.Dimensions.TryGetValue(ConfigurationGeneral.TargetFrameworkProperty, out string targetFrameworkMoniker)) { return(_targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker)); } else { return(TargetFrameworks.Length > 1 ? null : TargetFrameworks[0]); } }
private async Task <ITargetFramework> GetTargetFrameworkAsync( string shortOrFullName, ConfigurationGeneral configurationGeneralProperties) { if (string.IsNullOrEmpty(shortOrFullName)) { object?targetObject = await configurationGeneralProperties.TargetFramework.GetValueAsync(); if (targetObject == null) { return(TargetFramework.Empty); } shortOrFullName = targetObject.ToString(); } return(_targetFrameworkProvider.GetTargetFramework(shortOrFullName) ?? TargetFramework.Empty); }
private async Task <TargetFramework> GetTargetFrameworkAsync( string shortOrFullName, ConfiguredProject configuredProject) { if (string.IsNullOrEmpty(shortOrFullName)) { ProjectProperties projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>(); ConfigurationGeneral configurationGeneralProperties = await projectProperties.GetConfigurationGeneralPropertiesAsync(); object?targetObject = await configurationGeneralProperties.TargetFramework.GetValueAsync(); if (targetObject == null) { return(TargetFramework.Empty); } shortOrFullName = targetObject.ToString(); } return(_targetFrameworkProvider.GetTargetFramework(shortOrFullName) ?? TargetFramework.Empty); }
private bool TryCreatePackageDependencyModel( string itemSpec, bool isResolved, IImmutableDictionary <string, string> properties, Func <string, bool>?isEvaluatedItemSpec, ITargetFramework targetFramework, [NotNullWhen(returnValue: true)] out PackageDependencyModel?dependencyModel) { Requires.NotNullOrEmpty(itemSpec, nameof(itemSpec)); Requires.NotNull(properties, nameof(properties)); bool isImplicitlyDefined = properties.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined) ?? false; if (isResolved) { // We have design-time build data Requires.NotNull(targetFramework, nameof(targetFramework)); Requires.NotNull(isEvaluatedItemSpec !, nameof(isEvaluatedItemSpec)); string?name = properties.GetStringProperty(ProjectItemMetadata.Name); string?dependencyType = properties.GetStringProperty(ProjectItemMetadata.Type); if (dependencyType != null) { // LEGACY MODE // // In 16.7 (SDK 3.1.4xx) the format of ResolvedPackageReference items was changed in task PreprocessPackageDependenciesDesignTime. // // If we observe "Type" metadata then we are running with an older SDK and need to preserve some // legacy behaviour to avoid breaking the dependencies node too much. Transitive dependencies will // not be displayed, but we should be able to provide an equivalent experience for top-level items. if (!StringComparers.PropertyLiteralValues.Equals(dependencyType, "Package")) { // Legacy behaviour included items of various types. We now only accept "Package". dependencyModel = null; return(false); } // Legacy behaviour was to return packages for all targets, even though we have a build per-target. // The package's target was prefixed to its ItemSpec (for example: ".NETFramework,Version=v4.8/MetadataExtractor/2.3.0"). // We would then filter out items for the wrong target here. // // From 16.7 we no longer return items from other target frameworks during DTB, and we remove the target prefix from ItemSpec. // // This code preserves filtering logic when processing legacy items. int slashIndex = itemSpec.IndexOf('/'); if (slashIndex != -1) { string targetFrameworkName = s_targetFrameworkInternPool.Intern(itemSpec.Substring(0, slashIndex)); if (_targetFrameworkProvider.GetTargetFramework(targetFrameworkName)?.Equals(targetFramework) != true) { // Item is not for the correct target dependencyModel = null; return(false); } } // Name metadata is required in 16.7. Legacy behaviour uses ItemSpec as a fallback. name ??= itemSpec; } else { if (Strings.IsNullOrEmpty(name)) { // This should not happen as Name is required in PreprocessPackageDependenciesDesignTime from 16.7 dependencyModel = null; return(false); } } bool isTopLevel = isImplicitlyDefined || isEvaluatedItemSpec(name); if (!isTopLevel) { // We no longer accept non-top-level dependencies from DTB data. See note above about legacy mode support. dependencyModel = null; return(false); } dependencyModel = new PackageDependencyModel( originalItemSpec: name, version: properties.GetStringProperty(ProjectItemMetadata.Version) ?? string.Empty, isResolved: true, isImplicitlyDefined, isVisible: !isImplicitlyDefined, properties); } else { // We only have evaluation data System.Diagnostics.Debug.Assert(itemSpec.IndexOf('/') == -1); dependencyModel = new PackageDependencyModel( originalItemSpec: itemSpec, version: properties.GetStringProperty(ProjectItemMetadata.Version) ?? string.Empty, isResolved: false, isImplicitlyDefined, isVisible: !isImplicitlyDefined, properties); } return(true); }
public static bool TryGetMetadata( string itemSpec, bool isResolved, IImmutableDictionary <string, string> properties, HashSet <string> unresolvedChanges, ITargetFramework targetFramework, ITargetFrameworkProvider targetFrameworkProvider, out PackageDependencyMetadata metadata) { Requires.NotNull(itemSpec, nameof(itemSpec)); Requires.NotNull(properties, nameof(properties)); // unresolvedChanges can be null Requires.NotNull(targetFramework, nameof(targetFramework)); Requires.NotNull(targetFrameworkProvider, nameof(targetFrameworkProvider)); bool isTopLevel; string target = GetTargetFromDependencyId(itemSpec); DependencyType dependencyType = properties.GetEnumProperty <DependencyType>(ProjectItemMetadata.Type) ?? (isResolved ? DependencyType.Unknown : DependencyType.Package); string name = properties.GetStringProperty(ProjectItemMetadata.Name) ?? itemSpec; bool isImplicitlyDefined = properties.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined) ?? false; if (isResolved) { isTopLevel = isImplicitlyDefined || (dependencyType == DependencyType.Package && unresolvedChanges?.Contains(name) == true); bool isTarget = itemSpec.IndexOf('/') == -1; if (isTarget) { metadata = default; return(false); } ITargetFramework packageTargetFramework = targetFrameworkProvider.GetTargetFramework(target); if (packageTargetFramework?.Equals(targetFramework) != true) { metadata = default; return(false); } } else { isTopLevel = true; } string originalItemSpec = isResolved && isTopLevel ? name : itemSpec; metadata = new PackageDependencyMetadata( dependencyType, target, itemSpec, originalItemSpec, name, isResolved, isImplicitlyDefined, isTopLevel, properties); return(true);
public async Task <AggregateCrossTargetProjectContext?> TryUpdateCurrentAggregateProjectContextAsync() { AggregateCrossTargetProjectContext?previousContext = Current; // Check if we have already computed the project context. if (previousContext != null) { // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed. // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project. // If not, we create a new one and dispose the current one. ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync(); if (!previousContext.IsCrossTargeting) { string?newTargetFrameworkName = (string?)await projectProperties.TargetFrameworkMoniker.GetValueAsync(); if (string.IsNullOrEmpty(newTargetFrameworkName) && TargetFramework.Empty.Equals(previousContext.ActiveTargetFramework)) { // No change return(null); } TargetFramework?newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName); if (previousContext.ActiveTargetFramework.Equals(newTargetFramework)) { // No change return(null); } } else { // Check if the current project context is up-to-date for the current active and known project configurations. Assumes.Present(_commonServices.Project.Services.ProjectConfigurationsService); ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration; IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync(); if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) && HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations)) { // No change return(null); } } } // Force refresh the CPS active project configuration (needs UI thread). await _commonServices.ThreadingService.SwitchToUIThread(); await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync(); // Create new project context. AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync(); Current = newContext; return(newContext); bool HasMatchingTargetFrameworks( ProjectConfiguration activeProjectConfiguration, IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations) { Assumes.NotNull(previousContext); Assumes.True(activeProjectConfiguration.IsCrossTargeting()); TargetFramework?activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]); if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework)) { // Active target framework is different. return(false); } var targetFrameworkMonikers = knownProjectConfigurations .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]) .Distinct() .ToList(); if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length) { // Different number of target frameworks. return(false); } foreach (string targetFrameworkMoniker in targetFrameworkMonikers) { TargetFramework?targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker); if (targetFramework == null || !previousContext.TargetFrameworks.Contains(targetFramework)) { // Differing TargetFramework return(false); } } return(true); } }
public static bool TryGetMetadata( string itemSpec, bool isResolved, IImmutableDictionary <string, string> properties, Func <string, bool>?isEvaluatedItemSpec, ITargetFramework targetFramework, ITargetFrameworkProvider targetFrameworkProvider, out PackageDependencyMetadata metadata) { Requires.NotNullOrEmpty(itemSpec, nameof(itemSpec)); Requires.NotNull(properties, nameof(properties)); bool isImplicitlyDefined = properties.GetBoolProperty(ProjectItemMetadata.IsImplicitlyDefined) ?? false; if (isResolved) { // We have design-time build data Requires.NotNull(targetFramework, nameof(targetFramework)); Requires.NotNull(targetFrameworkProvider, nameof(targetFrameworkProvider)); Requires.NotNull(isEvaluatedItemSpec !, nameof(isEvaluatedItemSpec)); DependencyType dependencyType = properties.GetEnumProperty <DependencyType>(ProjectItemMetadata.Type) ?? DependencyType.Unknown; if (dependencyType == DependencyType.Target) { // Disregard items of type 'Target' from design-time build metadata = default; return(false); } int slashIndex = itemSpec.IndexOf('/'); string?targetFrameworkName = slashIndex == -1 ? null : s_targetFrameworkInternPool.Intern(itemSpec.Substring(0, slashIndex)); if (targetFrameworkName == null || targetFrameworkProvider.GetTargetFramework(targetFrameworkName)?.Equals(targetFramework) != true) { metadata = default; return(false); } string name = properties.GetStringProperty(ProjectItemMetadata.Name) ?? itemSpec; bool isTopLevel = isImplicitlyDefined || (dependencyType == DependencyType.Package && isEvaluatedItemSpec(name)); string originalItemSpec = isTopLevel ? name : itemSpec; metadata = new PackageDependencyMetadata( dependencyType, targetFrameworkName, itemSpec, originalItemSpec, name, isResolved: true, isImplicitlyDefined, isTopLevel, properties); } else { // We only have evaluation data System.Diagnostics.Debug.Assert(itemSpec.IndexOf('/') == -1); metadata = new PackageDependencyMetadata( dependencyType: DependencyType.Package, targetFrameworkName: null, itemSpec, originalItemSpec: itemSpec, name: itemSpec, isResolved: false, isImplicitlyDefined, isTopLevel: true, properties); } return(true); }