/// <summary> /// Returns a value indicating whether the specified flags indicates that /// the file or folder is missing on disk. /// </summary> public static bool IsMissingOnDisk(this ProjectTreeFlags flags) { return(!flags.HasFlag(ProjectTreeFlags.Common.FileSystemEntity)); }
public void Matches_MultipleFlags(string s, bool expected) { var detector = new FlagsStringMatcher(ProjectTreeFlags.Create("APPLE") + ProjectTreeFlags.Create("BANANA")); Assert.Equal(expected, detector.Matches(s)); }
private IProjectTree CreateOrUpdateNode( IProjectTree node, IDependencyViewModel viewModel, IRule rule, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } string filePath = viewModel.OriginalModel != null && viewModel.OriginalModel.TopLevel && viewModel.OriginalModel.Resolved ? viewModel.OriginalModel.GetTopLevelId() : viewModel.FilePath; ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { // For IProjectTree remove ProjectTreeFlags.Common.Reference flag, otherwise CPS would fail to // map this node to graph node and GraphProvider would be never called. // Only IProjectItemTree can have this flag filteredFlags = filteredFlags.Except(DependencyTreeFlags.BaseReferenceFlags); return(_treeServices.CreateTree( caption: viewModel.Caption, filePath, browseObjectProperties: rule, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: filePath, itemType: viewModel.SchemaItemType, itemName: filePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: rule, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: rule, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }
public IProjectTree SetFlags(ProjectTreeFlags flags) { throw new NotImplementedException(); }
public async Task WhenMultipleTargetSnapshotsWithExistingDependencies_ShouldApplyChanges() { var dependencyModelRootXxx = new TestDependencyModel { ProviderType = "Xxx", Id = "XxxDependencyRoot", Name = "XxxDependencyRoot", Caption = "XxxDependencyRoot", Resolved = true }; var dependencyXxx1 = new TestDependency { ProviderType = "Xxx", Id = "xxx\\dependency1", Path = "dependencyxxxpath", Name = "dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true, TargetFramework = _tfm1 }; var dependencyModelRootYyy = new TestDependencyModel { ProviderType = "Yyy", Id = "YyyDependencyRoot", Name = "YyyDependencyRoot", Caption = "YyyDependencyRoot" }; var dependencyYyy1 = new TestDependency { ProviderType = "Yyy", Id = "yyy\\dependency1", Path = "dependencyyyypath", Name = "dependency1", Caption = "Dependency1", SchemaItemType = "Yyy", Resolved = true, TargetFramework = _tfm1 }; var dependencyYyyExisting = new TestDependency { ProviderType = "Yyy", Id = "yyy\\dependencyExisting", Path = "dependencyyyyExistingpath", Name = "dependencyExisting", Caption = "DependencyExisting", SchemaItemType = "Yyy", Resolved = true, TargetFramework = _tfm1 }; var dependencyModelRootZzz = new TestDependencyModel { ProviderType = "Zzz", Id = "ZzzDependencyRoot", Name = "ZzzDependencyRoot", Caption = "ZzzDependencyRoot", Resolved = true, Flags = ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp) }; var dependencyAny1 = new TestDependency { ProviderType = "Zzz", Id = "ZzzDependencyAny1", Path = "ZzzDependencyAny1path", Name = "ZzzDependencyAny1", Caption = "ZzzDependencyAny1", TargetFramework = TargetFramework.Any }; var dependenciesRoot = new TestProjectTree { Caption = "MyDependencies", Children = { new TestProjectTree { Caption = "OldRootChildToBeRemoved" }, new TestProjectTree { Caption = "YyyDependencyRoot", FilePath = "YyyDependencyRoot", Children = { new TestProjectTree { Caption = "DependencyExisting", FilePath = "yyy\\dependencyExisting" } } } } }; var targetModel1 = new TestDependencyModel { Id = "tfm1", Name = "tfm1", Caption = "tfm1" }; var targetModel2 = new TestDependencyModel { Id = "tfm2", Name = "tfm2", Caption = "tfm2" }; var provider = CreateProvider( rootModels: new[] { dependencyModelRootXxx, dependencyModelRootYyy, dependencyModelRootZzz }, targetModels: new[] { targetModel1, targetModel2 }); var snapshot = GetSnapshot( (_tfm1, new[] { dependencyXxx1, dependencyYyy1, dependencyYyyExisting }), (_tfm2, new[] { dependencyXxx1, dependencyYyy1, dependencyYyyExisting }), (TargetFramework.Any, new[] { dependencyAny1 })); // Act var resultTree = await provider.BuildTreeAsync(dependenciesRoot, snapshot); // Assert var expectedFlatHierarchy = @"Caption=MyDependencies, FilePath=, IconHash=325248080, ExpandedIconHash=325248080, Rule=, IsProjectItem=False, CustomTag= Caption=ZzzDependencyRoot, FilePath=ZzzDependencyRoot, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag= Caption=ZzzDependencyAny1, FilePath=ZzzDependencyAny1, IconHash=325248665, ExpandedIconHash=325248817, Rule=, IsProjectItem=False, CustomTag= Caption=tfm2, FilePath=tfm2, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag=, BubbleUpFlag=True Caption=XxxDependencyRoot, FilePath=XxxDependencyRoot, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag= Caption=Dependency1, FilePath=tfm1\Xxx\dependencyxxxpath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=False, CustomTag= Caption=YyyDependencyRoot, FilePath=YyyDependencyRoot, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag= Caption=Dependency1, FilePath=tfm1\Yyy\dependencyyyypath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=False, CustomTag= Caption=DependencyExisting, FilePath=tfm1\Yyy\dependencyyyyExistingpath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=False, CustomTag= Caption=tfm1, FilePath=tfm1, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag=, BubbleUpFlag=True Caption=XxxDependencyRoot, FilePath=XxxDependencyRoot, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag= Caption=Dependency1, FilePath=tfm1\Xxx\dependencyxxxpath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=True, CustomTag= Caption=YyyDependencyRoot, FilePath=YyyDependencyRoot, IconHash=0, ExpandedIconHash=0, Rule=, IsProjectItem=False, CustomTag= Caption=Dependency1, FilePath=tfm1\Yyy\dependencyyyypath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=True, CustomTag= Caption=DependencyExisting, FilePath=tfm1\Yyy\dependencyyyyExistingpath, IconHash=325248088, ExpandedIconHash=325248260, Rule=, IsProjectItem=True, CustomTag="; Assert.Equal(expectedFlatHierarchy, ToTestDataString((TestProjectTree)resultTree)); }
/// <summary> /// Returns a value indicating whether the specified flags has the specified flag. /// </summary> public static bool HasFlag(this ProjectTreeFlags flags, ProjectTreeFlags.Common flag) { return(flags.Contains(flag)); }
/// <summary> /// Returns a value indicating whether the specified flags indicates that /// the node is a folder. /// </summary> public static bool IsFolder(this ProjectTreeFlags flags) { return(flags.HasFlag(ProjectTreeFlags.Common.Folder)); }
/// <summary> /// Returns a value indicating whether the specified property context represents the candidate special folder. /// </summary> protected abstract bool IsCandidateSpecialFolder(IProjectTreeCustomizablePropertyContext propertyContext, ProjectTreeFlags flags);
private bool IsCandidateSpecialFolderItem(IProjectTreeCustomizablePropertyContext propertyContext, ProjectTreeFlags flags) { // We're a special folder item if our parent is the special folder. We rely on // the fact that "VisibleOnlyInShowAllFiles" is transitive; that is, if a parent // is marked with it, its children are also implicitly marked with it. if (propertyContext.ParentNodeFlags.Contains(FolderFlags)) { return(flags.IsIncludedInProject()); } return(false); }
/// <summary> /// Builds all available sub trees under root: target framework or Dependencies node /// when there is only one target. /// </summary> private async Task <IProjectTree> BuildSubTreesAsync( IProjectTree rootNode, ITargetFramework activeTarget, TargetedDependenciesSnapshot targetedSnapshot, Func <IProjectTree, HashSet <IProjectTree>, IProjectTree> syncFunc) { var groupedByProviderType = new Dictionary <string, List <IDependency> >(StringComparers.DependencyProviderTypes); foreach (IDependency dependency in targetedSnapshot.TopLevelDependencies) { if (!dependency.Visible) { // If a dependency is not visible we will still register a top-level group if it // has the ShowEmptyProviderRootNode flag. if (!dependency.Flags.Contains(DependencyTreeFlags.ShowEmptyProviderRootNode)) { // No such flag, so skip it completely. continue; } } if (!groupedByProviderType.TryGetValue(dependency.ProviderType, out List <IDependency> dependencies)) { dependencies = new List <IDependency>(); groupedByProviderType.Add(dependency.ProviderType, dependencies); } // Only add visible dependencies. See note above. if (dependency.Visible) { dependencies.Add(dependency); } } var currentNodes = new HashSet <IProjectTree>(capacity: groupedByProviderType.Count); bool isActiveTarget = targetedSnapshot.TargetFramework.Equals(activeTarget); foreach ((string providerType, List <IDependency> dependencies) in groupedByProviderType) { IDependencyViewModel?subTreeViewModel = _viewModelFactory.CreateRootViewModel( providerType, targetedSnapshot.CheckForUnresolvedDependencies(providerType)); if (subTreeViewModel == null) { // In theory this should never happen, as it means we have a dependency model of a type // that no provider claims. https://github.com/dotnet/project-system/issues/3653 continue; } IProjectTree?subTreeNode = rootNode.FindChildWithCaption(subTreeViewModel.Caption); bool isNewSubTreeNode = subTreeNode == null; ProjectTreeFlags excludedFlags = targetedSnapshot.TargetFramework.Equals(TargetFramework.Any) ? ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp) : ProjectTreeFlags.Empty; subTreeNode = CreateOrUpdateNode( subTreeNode, subTreeViewModel, browseObjectProperties: null, isProjectItem: false, excludedFlags: excludedFlags); subTreeNode = await BuildSubTreeAsync( subTreeNode, targetedSnapshot, dependencies, isActiveTarget, shouldCleanup : !isNewSubTreeNode); currentNodes.Add(subTreeNode); rootNode = isNewSubTreeNode ? rootNode.Add(subTreeNode).Parent ! : subTreeNode.Parent !; Assumes.NotNull(rootNode); } return(syncFunc(rootNode, currentNodes)); }
/// <inheritdoc /> public async Task <IProjectTree> BuildTreeAsync( IProjectTree dependenciesTree, DependenciesSnapshot snapshot, CancellationToken cancellationToken = default) { // Keep a reference to the original tree to return in case we are cancelled. IProjectTree originalTree = dependenciesTree; bool hasSingleTarget = snapshot.DependenciesByTargetFramework.Count(x => !x.Key.Equals(TargetFramework.Any)) == 1; var currentTopLevelNodes = new HashSet <IProjectTree>(); if (hasSingleTarget) { await BuildSingleTargetTreeAsync(); } else { await BuildMultiTargetTreeAsync(); } if (cancellationToken.IsCancellationRequested) { return(originalTree); } dependenciesTree = CleanupOldNodes(dependenciesTree, currentTopLevelNodes); ProjectImageMoniker rootIcon = _viewModelFactory.GetDependenciesRootIcon(snapshot.HasReachableVisibleUnresolvedDependency).ToProjectSystemType(); return(dependenciesTree.SetProperties(icon: rootIcon, expandedIcon: rootIcon)); async Task BuildSingleTargetTreeAsync() { foreach ((ITargetFramework _, TargetedDependenciesSnapshot targetedSnapshot) in snapshot.DependenciesByTargetFramework) { if (cancellationToken.IsCancellationRequested) { return; } dependenciesTree = await BuildSubTreesAsync( rootNode : dependenciesTree, snapshot.ActiveTargetFramework, targetedSnapshot, RememberNewNodes); } } async Task BuildMultiTargetTreeAsync() { foreach ((ITargetFramework targetFramework, TargetedDependenciesSnapshot targetedSnapshot) in snapshot.DependenciesByTargetFramework) { if (cancellationToken.IsCancellationRequested) { return; } if (targetFramework.Equals(TargetFramework.Any)) { dependenciesTree = await BuildSubTreesAsync( rootNode : dependenciesTree, snapshot.ActiveTargetFramework, targetedSnapshot, RememberNewNodes); } else { IProjectTree? node = dependenciesTree.FindChildWithCaption(targetFramework.FriendlyName); bool shouldAddTargetNode = node == null; IDependencyViewModel targetViewModel = _viewModelFactory.CreateTargetViewModel(targetedSnapshot); node = CreateOrUpdateNode( node, targetViewModel, browseObjectProperties: null, isProjectItem: false, additionalFlags: ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp)); node = await BuildSubTreesAsync( rootNode : node, snapshot.ActiveTargetFramework, targetedSnapshot, CleanupOldNodes); dependenciesTree = shouldAddTargetNode ? dependenciesTree.Add(node).Parent ! : node.Parent !; Assumes.NotNull(dependenciesTree); currentTopLevelNodes.Add(node); } } } IProjectTree RememberNewNodes(IProjectTree rootNode, IEnumerable <IProjectTree> currentNodes) { if (currentNodes != null) { currentTopLevelNodes.AddRange(currentNodes); } return(rootNode); } }
/// <summary> /// Generates the original references directory tree. /// </summary> protected override void Initialize() { #pragma warning disable RS0030 // symbol LoadedProject is banned using (UnconfiguredProjectAsynchronousTasksService.LoadedProject()) #pragma warning restore RS0030 // symbol LoadedProject is banned { base.Initialize(); // this.IsApplicable may take a project lock, so we can't do it inline with this method // which is holding a private lock. It turns out that doing it asynchronously isn't a problem anyway, // so long as we guard against races with the Dispose method. #pragma warning disable RS0030 // symbol LoadedProjectAsync is banned UnconfiguredProjectAsynchronousTasksService.LoadedProjectAsync( #pragma warning restore RS0030 // symbol LoadedProjectAsync is banned async delegate { await TaskScheduler.Default.SwitchTo(alwaysYield: true); UnconfiguredProjectAsynchronousTasksService .UnloadCancellationToken.ThrowIfCancellationRequested(); lock (SyncObject) { Verify.NotDisposed(this); // Issue this token before hooking the SnapshotChanged event to prevent a race // where a snapshot tree is replaced by the initial, empty tree created below. // The handler will cancel this token before submitting its update. CancellationToken initialTreeCancellationToken = _treeUpdateCancellationSeries.CreateNext(); _ = SubmitTreeUpdateAsync( delegate { IProjectTree dependenciesNode = CreateDependenciesNode(); return(Task.FromResult(new TreeUpdateResult(dependenciesNode))); }, initialTreeCancellationToken); ITargetBlock <SnapshotChangedEventArgs> actionBlock = DataflowBlockFactory.CreateActionBlock <SnapshotChangedEventArgs>( OnDependenciesSnapshotChangedAsync, _project, nameFormat: "DependenciesProjectTreeProviderSource {1}", skipIntermediateInputData: true); _snapshotEventListener = _dependenciesSnapshotProvider.SnapshotChangedSource.LinkTo(actionBlock, DataflowOption.PropagateCompletion); } }, registerFaultHandler: true); } IProjectTree CreateDependenciesNode() { var values = new ReferencesProjectTreeCustomizablePropertyValues { Caption = Resources.DependenciesNodeName, Icon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), ExpandedIcon = ManagedImageMonikers.ReferenceGroup.ToProjectSystemType(), Flags = ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp) + ProjectTreeFlags.Create(ProjectTreeFlags.Common.ReferencesFolder) + ProjectTreeFlags.Create(ProjectTreeFlags.Common.VirtualFolder) + DependencyTreeFlags.DependenciesRootNode }; // Allow property providers to perform customization. // These are ordered from lowest priority to highest, allowing higher priority // providers to override lower priority providers. foreach (IProjectTreePropertiesProvider provider in _projectTreePropertiesProviders.ExtensionValues()) { provider.CalculatePropertyValues(ProjectTreeCustomizablePropertyContext.Instance, values); } // Note that all the parameters are specified so we can force this call to an // overload of NewTree available prior to 15.5 versions of CPS. Once a 15.5 build // is publicly available we can move this to an overload with default values for // most of the parameters, and we'll only need to pass the interesting ones. return(NewTree( caption: values.Caption, filePath: null, browseObjectProperties: null, icon: values.Icon, expandedIcon: values.ExpandedIcon, visible: true, flags: values.Flags)); } }
protected AssetsFileTopLevelDependenciesCollectionSourceProvider(ProjectTreeFlags flags) : base(flags) { }
private IProjectTree CreateOrUpdateNode( IProjectTree?node, IDependencyViewModel viewModel, IRule?browseObjectProperties, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } string?filePath = viewModel.Dependency != null && viewModel.Dependency.Resolved ? viewModel.Dependency.GetTopLevelId() : viewModel.FilePath; ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { return(_treeServices.CreateTree( caption: viewModel.Caption, filePath, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { Assumes.NotNull(filePath); var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: filePath, itemType: viewModel.SchemaItemType, itemName: filePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node !.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: browseObjectProperties, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }
/// <summary> /// Builds Dependencies tree for given dependencies snapshot /// </summary> public override async Task <IProjectTree> BuildTreeAsync( IProjectTree dependenciesTree, IDependenciesSnapshot snapshot, CancellationToken cancellationToken = default(CancellationToken)) { var originalTree = dependenciesTree; var currentTopLevelNodes = new List <IProjectTree>(); Func <IProjectTree, IEnumerable <IProjectTree>, IProjectTree> rememberNewNodes = (rootNode, currentNodes) => { if (currentNodes != null) { currentTopLevelNodes.AddRange(currentNodes); } return(rootNode); }; if (snapshot.Targets.Where(x => !x.Key.Equals(TargetFramework.Any)).Count() == 1) { foreach (var target in snapshot.Targets) { if (cancellationToken.IsCancellationRequested) { return(originalTree); } dependenciesTree = await BuildSubTreesAsync( dependenciesTree, snapshot.ActiveTarget, target.Value, target.Value.Catalogs, rememberNewNodes).ConfigureAwait(false); } } else { foreach (var target in snapshot.Targets) { if (cancellationToken.IsCancellationRequested) { return(originalTree); } if (target.Key.Equals(TargetFramework.Any)) { dependenciesTree = await BuildSubTreesAsync(dependenciesTree, snapshot.ActiveTarget, target.Value, target.Value.Catalogs, rememberNewNodes).ConfigureAwait(false); } else { var node = dependenciesTree.FindNodeByCaption(target.Key.FriendlyName); var shouldAddTargetNode = node == null; var targetViewModel = ViewModelFactory.CreateTargetViewModel(target.Value); node = CreateOrUpdateNode(node, targetViewModel, rule: null, isProjectItem: false, additionalFlags: ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp)); node = await BuildSubTreesAsync(node, snapshot.ActiveTarget, target.Value, target.Value.Catalogs, CleanupOldNodes).ConfigureAwait(false); if (shouldAddTargetNode) { dependenciesTree = dependenciesTree.Add(node).Parent; } else { dependenciesTree = node.Parent; } currentTopLevelNodes.Add(node); } } } dependenciesTree = CleanupOldNodes(dependenciesTree, currentTopLevelNodes); // now update root Dependencies node status var rootIcon = ViewModelFactory.GetDependenciesRootIcon(snapshot.HasUnresolvedDependency).ToProjectSystemType(); return(dependenciesTree.SetProperties(icon: rootIcon, expandedIcon: rootIcon)); }
protected DependencyModel( string caption, string?path, string originalItemSpec, ProjectTreeFlags flags, bool isResolved, bool isImplicit, IImmutableDictionary <string, string>?properties, bool isVisible = true) { Requires.NotNullOrEmpty(caption, nameof(caption)); // IDependencyModel allows original item spec to be null, but we can satisfy a // more strict requirement for the dependency types produced internally. // External providers may not have a meaningful value, but do not use this type. Requires.NotNullOrEmpty(originalItemSpec, nameof(originalItemSpec)); Path = path; OriginalItemSpec = originalItemSpec; Properties = properties ?? ImmutableStringDictionary <string> .EmptyOrdinal; Caption = caption; Flags = flags; if (Properties.TryGetBoolProperty(ProjectItemMetadata.Visible, out bool visibleProperty)) { isVisible = visibleProperty; } DiagnosticLevel diagnosticLevel = DiagnosticLevel.None; if (Properties.TryGetStringProperty(ProjectItemMetadata.DiagnosticLevel, out string?levelString)) { diagnosticLevel = levelString switch { "Warning" => DiagnosticLevel.Warning, "Error" => DiagnosticLevel.Error, _ => DiagnosticLevel.None }; } if (diagnosticLevel == DiagnosticLevel.None && !isResolved) { // Treat unresolved state as a warning diagnostic diagnosticLevel = DiagnosticLevel.Warning; } DependencyFlags depFlags = 0; if (isResolved) { depFlags |= DependencyFlags.Resolved; } if (isVisible) { depFlags |= DependencyFlags.Visible; } if (isImplicit) { depFlags |= DependencyFlags.Implicit; } _flags = depFlags; DiagnosticLevel = diagnosticLevel; }
/// <summary> /// Returns a value indicating whether the specified flags has the flag <see cref="ProjectTreeFlags.Common.ProjectRoot"/>. /// </summary> public static bool IsProjectRoot(this ProjectTreeFlags flags) { return(flags.HasFlag(ProjectTreeFlags.Common.ProjectRoot)); }
protected DependenciesAttachedCollectionSourceProviderBase(ProjectTreeFlags flags) => _flagsStringMatcher = new FlagsStringMatcher(flags);
/// <summary> /// Returns a value indicating whether the specified flags indicates that /// the node is included as part of the project. /// </summary> public static bool IsIncludedInProject(this ProjectTreeFlags flags) { return(!flags.HasFlag(ProjectTreeFlags.Common.IncludeInProjectCandidate)); }
public IProjectTree SetFlags(ProjectTreeFlags flags) { return(null); }
/// <summary> /// Returns a value indicating whether the specified flags exist. /// </summary> public static bool Contains(this ProjectTreeFlags source, ProjectTreeFlags flags) { ProjectTreeFlags newFlags = source.Except(flags); return((source.Count - newFlags.Count) == flags.Count); }
public static ProjectTreeFlags CreateNewProjectRoot() => ProjectTreeFlags.Create(ProjectTreeFlags.Common.ProjectRoot);
protected sealed override bool IsCandidateSpecialFolder(IProjectTreeCustomizablePropertyContext propertyContext, ProjectTreeFlags flags) { if (propertyContext.ParentNodeFlags.IsProjectRoot() && flags.IsFolder() && flags.IsIncludedInProject()) { string folderName = propertyContext.ProjectTreeSettings[AppDesigner.FolderNameProperty]; return(StringComparers.Paths.Equals(folderName, propertyContext.ItemName)); } return(false); }
IProjectItemTree IProjectItemTree.SetFlags(ProjectTreeFlags flags) { throw new NotImplementedException(); }
public void Matches_SingleFlag_CaseInsensitive(string s, bool expected) { var detector = new FlagsStringMatcher(ProjectTreeFlags.Create("APPLE"), RegexOptions.IgnoreCase); Assert.Equal(expected, detector.Matches(s)); }
public IProjectTree SetFlags(ProjectTreeFlags flags) { Flags = flags; return(this); }
/// <summary> /// Builds all available sub trees under root: target framework or Dependencies node /// when there is only one target. /// </summary> private async Task <IProjectTree> BuildSubTreesAsync( IProjectTree rootNode, ITargetFramework activeTarget, ITargetedDependenciesSnapshot targetedSnapshot, Func <IProjectTree, IEnumerable <IProjectTree>, IProjectTree> syncFunc) { var groupedByProviderType = new Dictionary <string, List <IDependency> >(StringComparers.DependencyProviderTypes); foreach (IDependency dependency in targetedSnapshot.TopLevelDependencies) { if (!dependency.Visible) { if (dependency.Flags.Contains(DependencyTreeFlags.ShowEmptyProviderRootNode)) { // if provider sends special invisible node with flag ShowEmptyProviderRootNode, we // need to show provider node even if it does not have any dependencies. groupedByProviderType.Add(dependency.ProviderType, new List <IDependency>()); } continue; } if (!groupedByProviderType.TryGetValue(dependency.ProviderType, out List <IDependency> dependencies)) { dependencies = new List <IDependency>(); groupedByProviderType.Add(dependency.ProviderType, dependencies); } dependencies.Add(dependency); } var currentNodes = new List <IProjectTree>(capacity: groupedByProviderType.Count); bool isActiveTarget = targetedSnapshot.TargetFramework.Equals(activeTarget); foreach ((string providerType, List <IDependency> dependencies) in groupedByProviderType) { IDependencyViewModel subTreeViewModel = _viewModelFactory.CreateRootViewModel( providerType, targetedSnapshot.CheckForUnresolvedDependencies(providerType)); if (subTreeViewModel == null) { // In theory this should never happen, as it means we have a dependency model of a type // that no provider claims. https://github.com/dotnet/project-system/issues/3653 continue; } IProjectTree subTreeNode = rootNode.FindChildWithCaption(subTreeViewModel.Caption); bool isNewSubTreeNode = subTreeNode == null; ProjectTreeFlags excludedFlags = targetedSnapshot.TargetFramework.Equals(TargetFramework.Any) ? ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp) : ProjectTreeFlags.Empty; subTreeNode = CreateOrUpdateNode( subTreeNode, subTreeViewModel, rule: null, isProjectItem: false, excludedFlags: excludedFlags); subTreeNode = await BuildSubTreeAsync( subTreeNode, targetedSnapshot, dependencies, isActiveTarget, shouldCleanup : !isNewSubTreeNode); currentNodes.Add(subTreeNode); rootNode = isNewSubTreeNode ? rootNode.Add(subTreeNode).Parent : subTreeNode.Parent; } return(syncFunc(rootNode, currentNodes)); }
/// <summary> /// Builds all available sub trees under root: target framework or Dependencies node /// when there is only one target. /// </summary> private async Task <IProjectTree> BuildSubTreesAsync( IProjectTree rootNode, ITargetFramework activeTarget, ITargetedDependenciesSnapshot targetedSnapshot, IProjectCatalogSnapshot catalogs, Func <IProjectTree, IEnumerable <IProjectTree>, IProjectTree> syncFunc) { var currentNodes = new List <IProjectTree>(); var grouppedByProviderType = new Dictionary <string, List <IDependency> >(StringComparer.OrdinalIgnoreCase); foreach (var dependency in targetedSnapshot.TopLevelDependencies) { if (!dependency.Visible) { if (dependency.Flags.Contains(DependencyTreeFlags.ShowEmptyProviderRootNode)) { // if provider sends special invisible node with flag ShowEmptyProviderRootNode, we // need to show provider node even if it does not have any dependencies. grouppedByProviderType.Add(dependency.ProviderType, new List <IDependency>()); } continue; } if (!grouppedByProviderType.TryGetValue(dependency.ProviderType, out List <IDependency> dependencies)) { dependencies = new List <IDependency>(); grouppedByProviderType.Add(dependency.ProviderType, dependencies); } dependencies.Add(dependency); } var isActiveTarget = targetedSnapshot.TargetFramework.Equals(activeTarget); foreach (var dependencyGroup in grouppedByProviderType) { var subTreeViewModel = ViewModelFactory.CreateRootViewModel( dependencyGroup.Key, targetedSnapshot.CheckForUnresolvedDependencies(dependencyGroup.Key)); var subTreeNode = rootNode.FindNodeByCaption(subTreeViewModel.Caption); var isNewSubTreeNode = subTreeNode == null; var excludedFlags = ProjectTreeFlags.Empty; if (targetedSnapshot.TargetFramework.Equals(TargetFramework.Any)) { excludedFlags = ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp); } subTreeNode = CreateOrUpdateNode( subTreeNode, subTreeViewModel, rule: null, isProjectItem: false, excludedFlags: excludedFlags); subTreeNode = await BuildSubTreeAsync( subTreeNode, targetedSnapshot, dependencyGroup.Value, catalogs, isActiveTarget, shouldCleanup : !isNewSubTreeNode).ConfigureAwait(false); currentNodes.Add(subTreeNode); if (isNewSubTreeNode) { rootNode = rootNode.Add(subTreeNode).Parent; } else { rootNode = subTreeNode.Parent; } } return(syncFunc(rootNode, currentNodes)); }
/// <inheritdoc /> public async Task <IProjectTree> BuildTreeAsync( IProjectTree dependenciesTree, IDependenciesSnapshot snapshot, CancellationToken cancellationToken = default) { IProjectTree originalTree = dependenciesTree; var currentTopLevelNodes = new List <IProjectTree>(); if (snapshot.Targets.Count(x => !x.Key.Equals(TargetFramework.Any)) == 1) { foreach ((ITargetFramework _, ITargetedDependenciesSnapshot targetedSnapshot) in snapshot.Targets) { if (cancellationToken.IsCancellationRequested) { return(originalTree); } dependenciesTree = await BuildSubTreesAsync( rootNode : dependenciesTree, snapshot.ActiveTarget, targetedSnapshot, RememberNewNodes); } } else { foreach ((ITargetFramework targetFramework, ITargetedDependenciesSnapshot targetedSnapshot) in snapshot.Targets) { if (cancellationToken.IsCancellationRequested) { return(originalTree); } if (targetFramework.Equals(TargetFramework.Any)) { dependenciesTree = await BuildSubTreesAsync( rootNode : dependenciesTree, snapshot.ActiveTarget, targetedSnapshot, RememberNewNodes); } else { IProjectTree node = dependenciesTree.FindChildWithCaption(targetFramework.FriendlyName); bool shouldAddTargetNode = node == null; IDependencyViewModel targetViewModel = _viewModelFactory.CreateTargetViewModel(targetedSnapshot); node = CreateOrUpdateNode( node, targetViewModel, rule: null, isProjectItem: false, additionalFlags: ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp)); node = await BuildSubTreesAsync( rootNode : node, snapshot.ActiveTarget, targetedSnapshot, CleanupOldNodes); dependenciesTree = shouldAddTargetNode ? dependenciesTree.Add(node).Parent : node.Parent; currentTopLevelNodes.Add(node); } } } dependenciesTree = CleanupOldNodes(dependenciesTree, currentTopLevelNodes); // now update root Dependencies node status ProjectImageMoniker rootIcon = _viewModelFactory.GetDependenciesRootIcon(snapshot.HasUnresolvedDependency).ToProjectSystemType(); return(dependenciesTree.SetProperties(icon: rootIcon, expandedIcon: rootIcon)); IProjectTree RememberNewNodes(IProjectTree rootNode, IEnumerable <IProjectTree> currentNodes) { if (currentNodes != null) { currentTopLevelNodes.AddRange(currentNodes); } return(rootNode); } }
public DependencyFlagCache(ProjectTreeFlags resolved, ProjectTreeFlags unresolved, ProjectTreeFlags remove = default) { // The 'isResolved' dimension determines whether we start with generic resolved or unresolved dependency flags. // We then add (union) and remove (except) any other flags as instructed. ProjectTreeFlags combinedResolved = DependencyTreeFlags.ResolvedDependencyFlags.Union(resolved).Except(remove); ProjectTreeFlags combinedUnresolved = DependencyTreeFlags.UnresolvedDependencyFlags.Union(unresolved).Except(remove); // The 'isImplicit' dimension only enforces, when true, that the dependency cannot be removed. _lookup = new ProjectTreeFlags[4]; _lookup[Index(isResolved: true, isImplicit: false)] = combinedResolved; _lookup[Index(isResolved: true, isImplicit: true)] = combinedResolved.Except(DependencyTreeFlags.SupportsRemove); _lookup[Index(isResolved: false, isImplicit: false)] = combinedUnresolved; _lookup[Index(isResolved: false, isImplicit: true)] = combinedUnresolved.Except(DependencyTreeFlags.SupportsRemove); }