Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        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"));
        }
Ejemplo n.º 7
0
        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]);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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;
            }
        }
Ejemplo n.º 12
0
        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;
                }
            }
        }
Ejemplo n.º 14
0
        /// <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);
            }
        }