public static DependenciesSnapshot FromChanges( string projectPath, DependenciesSnapshot previousSnapshot, ImmutableDictionary <ITargetFramework, IDependenciesChanges> changes, IProjectCatalogSnapshot catalogs, ITargetFramework activeTargetFramework, IEnumerable <IDependenciesSnapshotFilter> snapshotFilters, out bool anyChanges) { var newSnapshot = new DependenciesSnapshot(projectPath, activeTargetFramework, previousSnapshot); anyChanges = newSnapshot.MergeChanges(changes, catalogs, snapshotFilters); return(newSnapshot); }
public void SetTargets_SameMembers_SameActive() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; ITargetFramework tfm1 = new TargetFramework("tfm1"); ITargetFramework tfm2 = new TargetFramework("tfm2"); var before = DependenciesSnapshot.CreateEmpty(projectPath) .SetTargets(ImmutableArray.Create(tfm1, tfm2), tfm1); var after = before.SetTargets(ImmutableArray.Create(tfm1, tfm2), tfm1); Assert.Same(before, after); }
public void FromChanges_WithDependenciesChanges() { const string previousProjectPath = @"c:\somefolder\someproject\a.csproj"; const string newProjectPath = @"c:\somefolder\someproject\b.csproj"; var catalogs = IProjectCatalogSnapshotFactory.Create(); var targetFramework = new TargetFramework("tfm1"); var dependenciesByTargetFramework = CreateDependenciesByTargetFramework(previousProjectPath, catalogs, targetFramework); var previousSnapshot = new DependenciesSnapshot( previousProjectPath, activeTargetFramework: targetFramework, dependenciesByTargetFramework); var targetChanges = new DependenciesChangesBuilder(); var model = new TestDependencyModel { ProviderType = "Xxx", Id = "dependency1", TopLevel = true }; targetChanges.Added(model); var snapshot = DependenciesSnapshot.FromChanges( newProjectPath, previousSnapshot, targetFramework, targetChanges.TryBuildChanges() !, catalogs, targetFrameworks: ImmutableArray.Create <ITargetFramework>(targetFramework), activeTargetFramework: targetFramework, ImmutableArray <IDependenciesSnapshotFilter> .Empty, new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(newProjectPath, snapshot.ProjectPath); Assert.Same(targetFramework, snapshot.ActiveTargetFramework); Assert.NotSame(previousSnapshot.DependenciesByTargetFramework, snapshot.DependenciesByTargetFramework); var(actualTfm, targetedSnapshot) = Assert.Single(snapshot.DependenciesByTargetFramework); Assert.Same(targetFramework, actualTfm); var dependency = Assert.Single(targetedSnapshot.TopLevelDependencies); Assert.Equal(@"tfm1\Xxx\dependency1", dependency.Id); Assert.Equal("Xxx", dependency.ProviderType); Assert.Same(dependency, targetedSnapshot.DependenciesWorld.Single().Value); }
public void SetTargets_FromEmpty() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; ITargetFramework tfm1 = new TargetFramework("tfm1"); ITargetFramework tfm2 = new TargetFramework("tfm2"); var snapshot = DependenciesSnapshot.CreateEmpty(projectPath) .SetTargets(ImmutableArray.Create(tfm1, tfm2), tfm1); Assert.Same(tfm1, snapshot.ActiveTargetFramework); Assert.Equal(2, snapshot.DependenciesByTargetFramework.Count); Assert.True(snapshot.DependenciesByTargetFramework.ContainsKey(tfm1)); Assert.True(snapshot.DependenciesByTargetFramework.ContainsKey(tfm2)); }
public void SetTargets_SameMembers_DifferentActive() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; ITargetFramework tfm1 = new TargetFramework("tfm1"); ITargetFramework tfm2 = new TargetFramework("tfm2"); var before = DependenciesSnapshot.CreateEmpty(projectPath) .SetTargets(new[] { tfm1, tfm2 }.ToImmutableArray(), tfm1); var after = before.SetTargets(new[] { tfm1, tfm2 }.ToImmutableArray(), tfm2); Assert.Same(tfm2, after.ActiveTargetFramework); Assert.Same(before.DependenciesByTargetFramework, after.DependenciesByTargetFramework); }
public void Constructor() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; var activeTarget = new TargetFramework("tfm1"); var snapshot = new DependenciesSnapshot( projectPath, activeTarget, ImmutableDictionary <ITargetFramework, ITargetedDependenciesSnapshot> .Empty); Assert.Same(projectPath, snapshot.ProjectPath); Assert.Same(activeTarget, snapshot.ActiveTarget); Assert.Empty(snapshot.Targets); Assert.False(snapshot.HasUnresolvedDependency); Assert.Null(snapshot.FindDependency("foo")); }
public void FromChanges_ProjectPathChange() { const string previousProjectPath = @"c:\somefolder\someproject\a.csproj"; const string newProjectPath = @"c:\somefolder\someproject\b.csproj"; var catalogs = IProjectCatalogSnapshotFactory.Create(); var targetFramework = new TargetFramework("tfm1"); var dependenciesByTargetFramework = CreateDependenciesByTargetFramework(previousProjectPath, catalogs, targetFramework); var previousSnapshot = new DependenciesSnapshot( previousProjectPath, activeTargetFramework: targetFramework, dependenciesByTargetFramework); var targetChanges = new DependenciesChangesBuilder(); var changes = new Dictionary <ITargetFramework, IDependenciesChanges> { [targetFramework] = targetChanges.Build() }; var snapshot = DependenciesSnapshot.FromChanges( newProjectPath, previousSnapshot, changes.ToImmutableDictionary(), catalogs, targetFrameworks: ImmutableArray <ITargetFramework> .Empty.Add(targetFramework), activeTargetFramework: targetFramework, ImmutableArray <IDependenciesSnapshotFilter> .Empty, new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(newProjectPath, snapshot.ProjectPath); Assert.Same(targetFramework, snapshot.ActiveTargetFramework); Assert.NotSame(previousSnapshot.DependenciesByTargetFramework, snapshot.DependenciesByTargetFramework); var targetedSnapshot = snapshot.DependenciesByTargetFramework.Single().Value; Assert.Equal(newProjectPath, targetedSnapshot.ProjectPath); Assert.Equal(targetFramework, targetedSnapshot.TargetFramework); Assert.Empty(targetedSnapshot.TopLevelDependencies); Assert.Empty(targetedSnapshot.DependenciesWorld); Assert.Same(catalogs, targetedSnapshot.Catalogs); Assert.Same( dependenciesByTargetFramework.Single().Value.DependenciesWorld, targetedSnapshot.DependenciesWorld); }
public void Constructor() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; var catalogs = IProjectCatalogSnapshotFactory.Create(); var targetFramework = new TargetFramework("tfm1"); var dependenciesByTargetFramework = CreateDependenciesByTargetFramework(projectPath, catalogs, targetFramework); var snapshot = new DependenciesSnapshot( projectPath, activeTargetFramework: targetFramework, dependenciesByTargetFramework); Assert.Same(projectPath, snapshot.ProjectPath); Assert.Same(targetFramework, snapshot.ActiveTargetFramework); Assert.Same(dependenciesByTargetFramework, snapshot.DependenciesByTargetFramework); Assert.False(snapshot.HasReachableVisibleUnresolvedDependency); Assert.Null(snapshot.FindDependency("foo")); }
public void SetTargets_DifferentMembers_DifferentActive() { const string projectPath = @"c:\somefolder\someproject\a.csproj"; ITargetFramework tfm1 = new TargetFramework("tfm1"); ITargetFramework tfm2 = new TargetFramework("tfm2"); ITargetFramework tfm3 = new TargetFramework("tfm3"); var before = DependenciesSnapshot.CreateEmpty(projectPath) .SetTargets(ImmutableArray.Create(tfm1, tfm2), tfm1); var after = before.SetTargets(ImmutableArray.Create(tfm2, tfm3), tfm3); Assert.Same(tfm3, after.ActiveTargetFramework); Assert.Equal(2, after.DependenciesByTargetFramework.Count); Assert.True(after.DependenciesByTargetFramework.ContainsKey(tfm2)); Assert.True(after.DependenciesByTargetFramework.ContainsKey(tfm3)); Assert.Same(before.DependenciesByTargetFramework[tfm2], after.DependenciesByTargetFramework[tfm2]); }
public void FromChanges_ProjectPathAndTargetChange() { const string previousProjectPath = @"c:\somefolder\someproject\a.csproj"; const string newProjectPath = @"c:\somefolder\someproject\b.csproj"; var catalogs = IProjectCatalogSnapshotFactory.Create(); var targetFramework = new TargetFramework("tfm1"); var dependenciesByTargetFramework = CreateDependenciesByTargetFramework(previousProjectPath, catalogs, targetFramework); var previousSnapshot = new DependenciesSnapshot( previousProjectPath, activeTargetFramework: targetFramework, dependenciesByTargetFramework); var targetChanges = new DependenciesChangesBuilder(); var model = new TestDependencyModel { ProviderType = "Xxx", Id = "dependency1" }; targetChanges.Added(model); var changes = new Dictionary <ITargetFramework, IDependenciesChanges> { [targetFramework] = targetChanges.Build() }; var snapshot = DependenciesSnapshot.FromChanges( newProjectPath, previousSnapshot, changes.ToImmutableDictionary(), catalogs, targetFrameworks: ImmutableArray <ITargetFramework> .Empty.Add(targetFramework), activeTargetFramework: targetFramework, ImmutableArray <IDependenciesSnapshotFilter> .Empty, new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(newProjectPath, snapshot.ProjectPath); Assert.Same(targetFramework, snapshot.ActiveTargetFramework); Assert.NotSame(previousSnapshot.DependenciesByTargetFramework, snapshot.DependenciesByTargetFramework); Assert.Equal(@"tfm1\Xxx\dependency1", snapshot.DependenciesByTargetFramework[targetFramework].DependenciesWorld.First().Value.Id); }
private DependenciesSnapshot(string projectPath, ITargetFramework activeTarget = null, DependenciesSnapshot previousSnapshot = null) { Requires.NotNullOrEmpty(projectPath, nameof(projectPath)); ProjectPath = projectPath; ActiveTarget = activeTarget; if (previousSnapshot != null) { _targets = previousSnapshot._targets; if (ActiveTarget == null) { ActiveTarget = previousSnapshot.ActiveTarget; } } if (ActiveTarget == null) { ActiveTarget = TargetFramework.Empty; } }
public void FromChanges_Empty_ProjectPathAndActiveTargetChange() { const string previousProjectPath = @"c:\somefolder\someproject\a.csproj"; const string newProjectPath = @"c:\somefolder\someproject\b.csproj"; var catalogs = IProjectCatalogSnapshotFactory.Create(); var previousActiveTarget = new TargetFramework("tfm1"); var newActiveTarget = new TargetFramework("tfm2"); var previousSnapshot = new DependenciesSnapshot( previousProjectPath, previousActiveTarget, ImmutableDictionary <ITargetFramework, ITargetedDependenciesSnapshot> .Empty); var targetChanges = new DependenciesChangesBuilder(); var changes = new Dictionary <ITargetFramework, IDependenciesChanges> { [previousActiveTarget] = targetChanges.Build(), [newActiveTarget] = targetChanges.Build() }; var snapshot = DependenciesSnapshot.FromChanges( newProjectPath, previousSnapshot, changes.ToImmutableDictionary(), catalogs, newActiveTarget, ImmutableArray <IDependenciesSnapshotFilter> .Empty, new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(newProjectPath, snapshot.ProjectPath); Assert.Same(newActiveTarget, snapshot.ActiveTarget); Assert.Same(previousSnapshot.Targets, snapshot.Targets); }
/// <summary> /// Updates the <see cref="TargetedDependenciesSnapshot"/> corresponding to <paramref name="changedTargetFramework"/>, /// returning either: /// <list type="bullet"> /// <item>An updated <see cref="DependenciesSnapshot"/> object, or</item> /// <item>the immutable <paramref name="previousSnapshot"/> if no changes were made.</item> /// </list> /// </summary> /// <remarks> /// As part of the update, each <see cref="IDependenciesSnapshotFilter"/> in <paramref name="snapshotFilters"/> /// is given a chance to influence the addition and removal of dependency data in the returned snapshot. /// </remarks> /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occured.</returns> public static DependenciesSnapshot FromChanges( string projectPath, DependenciesSnapshot previousSnapshot, ITargetFramework changedTargetFramework, IDependenciesChanges?changes, IProjectCatalogSnapshot?catalogs, ImmutableArray <ITargetFramework> targetFrameworks, ITargetFramework?activeTargetFramework, ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters, IReadOnlyDictionary <string, IProjectDependenciesSubTreeProvider> subTreeProviderByProviderType, IImmutableSet <string>?projectItemSpecs) { Requires.NotNullOrWhiteSpace(projectPath, nameof(projectPath)); Requires.NotNull(previousSnapshot, nameof(previousSnapshot)); Requires.NotNull(changedTargetFramework, nameof(changedTargetFramework)); Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default."); Requires.NotNull(subTreeProviderByProviderType, nameof(subTreeProviderByProviderType)); var builder = previousSnapshot.DependenciesByTargetFramework.ToBuilder(); if (!builder.TryGetValue(changedTargetFramework, out TargetedDependenciesSnapshot previousTargetedSnapshot)) { previousTargetedSnapshot = TargetedDependenciesSnapshot.CreateEmpty(projectPath, changedTargetFramework, catalogs); } bool builderChanged = false; var newTargetedSnapshot = TargetedDependenciesSnapshot.FromChanges( projectPath, previousTargetedSnapshot, changes, catalogs, snapshotFilters, subTreeProviderByProviderType, projectItemSpecs); if (!ReferenceEquals(previousTargetedSnapshot, newTargetedSnapshot)) { builder[changedTargetFramework] = newTargetedSnapshot; builderChanged = true; } SyncTargetFrameworks(); activeTargetFramework ??= previousSnapshot.ActiveTargetFramework; if (builderChanged) { // Dependencies-by-target-framework has changed return(new DependenciesSnapshot( projectPath, activeTargetFramework, builder.ToImmutable())); } if (!activeTargetFramework.Equals(previousSnapshot.ActiveTargetFramework)) { // The active target framework changed return(new DependenciesSnapshot( projectPath, activeTargetFramework, previousSnapshot.DependenciesByTargetFramework)); } if (projectPath != previousSnapshot.ProjectPath) { // The project path changed return(new DependenciesSnapshot( projectPath, activeTargetFramework, previousSnapshot.DependenciesByTargetFramework)); } // Nothing has changed, so return the same snapshot return(previousSnapshot); void SyncTargetFrameworks() { // Only sync if a the full list of target frameworks has been provided if (targetFrameworks.IsDefault) { return; } // This is a long-winded way of doing this that minimises allocations // Ensure all required target frameworks are present foreach (ITargetFramework targetFramework in targetFrameworks) { if (!builder.ContainsKey(targetFramework)) { builder.Add(targetFramework, TargetedDependenciesSnapshot.CreateEmpty(projectPath, targetFramework, catalogs)); builderChanged = true; } } // Remove any extra target frameworks if (builder.Count != targetFrameworks.Length) { IEnumerable <ITargetFramework> targetFrameworksToRemove = builder.Keys.Except(targetFrameworks); foreach (ITargetFramework targetFramework in targetFrameworksToRemove) { builder.Remove(targetFramework); } builderChanged = true; } } }
/// <summary> /// For each target framework in <paramref name="changes"/>, applies the corresponding /// <see cref="IDependenciesChanges"/> to <paramref name="previousSnapshot"/> in order to produce /// and return an updated <see cref="DependenciesSnapshot"/> object. /// If no changes are made, <paramref name="previousSnapshot"/> is returned unmodified. /// </summary> /// <remarks> /// As part of the update, each <see cref="IDependenciesSnapshotFilter"/> in <paramref name="snapshotFilters"/> /// is given a chance to influence the addition and removal of dependency data in the returned snapshot. /// </remarks> /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occured.</returns> public static DependenciesSnapshot FromChanges( string projectPath, DependenciesSnapshot previousSnapshot, ImmutableDictionary <ITargetFramework, IDependenciesChanges> changes, IProjectCatalogSnapshot catalogs, ITargetFramework activeTargetFramework, ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters, IReadOnlyDictionary <string, IProjectDependenciesSubTreeProvider> subTreeProviderByProviderType, IImmutableSet <string> projectItemSpecs) { Requires.NotNullOrWhiteSpace(projectPath, nameof(projectPath)); Requires.NotNull(previousSnapshot, nameof(previousSnapshot)); Requires.NotNull(changes, nameof(changes)); // catalogs can be null Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default."); Requires.NotNull(subTreeProviderByProviderType, nameof(subTreeProviderByProviderType)); // projectItemSpecs can be null var builder = previousSnapshot.Targets.ToBuilder(); bool targetChanged = false; foreach ((ITargetFramework targetFramework, IDependenciesChanges dependenciesChanges) in changes) { if (!builder.TryGetValue(targetFramework, out ITargetedDependenciesSnapshot previousTargetedSnapshot)) { previousTargetedSnapshot = TargetedDependenciesSnapshot.CreateEmpty(projectPath, targetFramework, catalogs); } ITargetedDependenciesSnapshot newTargetedSnapshot = TargetedDependenciesSnapshot.FromChanges( projectPath, previousTargetedSnapshot, dependenciesChanges, catalogs, snapshotFilters, subTreeProviderByProviderType, projectItemSpecs); if (!ReferenceEquals(previousTargetedSnapshot, newTargetedSnapshot)) { builder[targetFramework] = newTargetedSnapshot; targetChanged = true; } } targetChanged |= RemoveTargetFrameworksWithNoDependencies(); ITargetFramework activeTarget = activeTargetFramework ?? previousSnapshot.ActiveTarget; if (targetChanged) { // Targets have changed return(new DependenciesSnapshot( previousSnapshot.ProjectPath, activeTarget, builder.ToImmutable())); } if (!activeTarget.Equals(previousSnapshot.ActiveTarget)) { // The active target changed return(new DependenciesSnapshot( previousSnapshot.ProjectPath, activeTarget, previousSnapshot.Targets)); } // Nothing has changed, so return the same snapshot return(previousSnapshot); // Active target differs bool RemoveTargetFrameworksWithNoDependencies() { // This is a long-winded way of doing this that minimises allocations List <ITargetFramework> emptyFrameworks = null; bool anythingRemoved = false; foreach ((ITargetFramework targetFramework, ITargetedDependenciesSnapshot targetedSnapshot) in builder) { if (targetedSnapshot.DependenciesWorld.Count == 0) { if (emptyFrameworks == null) { anythingRemoved = true; emptyFrameworks = new List <ITargetFramework>(builder.Count); } emptyFrameworks.Add(targetFramework); } } if (emptyFrameworks != null) { foreach (ITargetFramework framework in emptyFrameworks) { builder.Remove(framework); } } return(anythingRemoved); } }