Exemplo n.º 1
0
        public static bool IsInbox(string frameworkListsPath, NuGetFramework framework, string assemblyName, string assemblyVersion)
        {
            if (framework.Framework == FrameworkConstants.FrameworkIdentifiers.UAP ||
                (framework.Framework == FrameworkConstants.FrameworkIdentifiers.NetCore && framework.Version >= FrameworkConstants.CommonFrameworks.NetCore50.Version))
            {
                // UAP & netcore50 or higher are completely OOB, despite being compatible with netcore4x which has inbox assemblies
                return(false);
            }

            // if no version is specified just use 0.0.0.0 to evaluate for any version of the contract
            Version      version = FrameworkUtilities.Ensure4PartVersion(assemblyVersion);
            FrameworkSet fxs     = GetInboxFrameworks(frameworkListsPath);

            Version latestLegacyVersion = null;

            fxs.LastNonSemanticVersions.TryGetValue(assemblyName, out latestLegacyVersion);

            foreach (var fxVersions in fxs.Frameworks.Values)
            {
                // Get the nearest compatible framework from this set of frameworks.
                var nearest = FrameworkUtilities.GetNearest(framework, fxVersions.Select(fx => NuGetFramework.Parse(fx.ShortName)).ToArray());
                // If there are not compatible frameworks in the current framework set, there is not going to be a match.
                if (nearest == null)
                {
                    continue;
                }

                // don't allow PCL to specify inbox for non-PCL framework.
                if (nearest.IsPCL != framework.IsPCL)
                {
                    continue;
                }

                // find the first version (if any) that supports this contract
                foreach (var fxVersion in fxVersions)
                {
                    Version supportedVersion;
                    if (fxVersion.Assemblies.TryGetValue(assemblyName, out supportedVersion))
                    {
                        if (supportedVersion >= version)
                        {
                            return(true);
                        }

                        // new versions represent API surface via major.minor only, so consider
                        // a contract as supported so long as the latest legacy version is supported
                        // and this contract's major.minor match the latest legacy version.
                        if (supportedVersion == latestLegacyVersion &&
                            version.Major == latestLegacyVersion.Major && version.Minor == latestLegacyVersion.Minor)
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Exemplo n.º 2
0
        public override bool Execute()
        {
            if (PackageIndexes == null && PackageIndexes.Length == 0)
            {
                Log.LogError("PackageIndexes argument must be specified");
                return(false);
            }

            index = PackageIndex.Load(PackageIndexes.Select(pi => pi.GetMetadata("FullPath")));

            List <ITaskItem> promotedDependencies = new List <ITaskItem>();

            var dependencies = Dependencies.Select(d => new Dependency(d)).ToArray();

            var refSets = dependencies.Where(d => d.Id != "_._").Where(d => d.IsReference).GroupBy(d => NuGetFramework.Parse(d.TargetFramework)).ToDictionary(g => g.Key, g => g.ToArray());
            var refFxs  = refSets.Keys.ToArray();

            Log.LogMessage(LogImportance.Low, $"Ref frameworks {string.Join(";", refFxs.Select(f => f.ToString()))}");

            var libSets = dependencies.Where(d => !d.IsReference).GroupBy(d => NuGetFramework.Parse(d.TargetFramework)).ToDictionary(g => g.Key, g => g.ToArray());
            var libFxs  = libSets.Keys.ToArray();

            Log.LogMessage(LogImportance.Low, $"Lib frameworks {string.Join(";", libFxs.Select(f => f.ToString()))}");

            if (libFxs.Length > 0)
            {
                foreach (var refFx in refFxs)
                {
                    // find best lib (if any)
                    var nearestLibFx = FrameworkUtilities.GetNearest(refFx, libFxs);

                    if (nearestLibFx != null && !nearestLibFx.Equals(refFx))
                    {
                        promotedDependencies.AddRange(CopyDependencies(libSets[nearestLibFx], refFx));
                    }
                }
            }

            if (refFxs.Length > 0)
            {
                foreach (var libFx in libFxs)
                {
                    // find best lib (if any)
                    var nearestRefFx = FrameworkUtilities.GetNearest(libFx, refFxs);

                    if (nearestRefFx != null && !nearestRefFx.Equals(libFx))
                    {
                        promotedDependencies.AddRange(CopyDependencies(refSets[nearestRefFx], libFx));
                    }
                }
            }

            PromotedDependencies = promotedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
Exemplo n.º 3
0
        public override bool Execute()
        {
            List <ITaskItem> promotedDependencies = new List <ITaskItem>();

            var dependencies = Dependencies.Select(d => new Dependency(d)).ToArray();

            var refSets = dependencies.Where(d => d.Id != "_._").Where(d => d.IsReference).GroupBy(d => d.TargetFramework).ToDictionary(g => NuGetFramework.Parse(g.Key), g => g.ToArray());
            var refFxs  = refSets.Keys.ToArray();

            var libSets = dependencies.Where(d => !d.IsReference).GroupBy(d => d.TargetFramework).ToDictionary(g => NuGetFramework.Parse(g.Key), g => g.ToArray());
            var libFxs  = libSets.Keys.ToArray();


            if (libFxs.Length > 0)
            {
                foreach (var refFx in refFxs)
                {
                    // find best lib (if any)
                    var nearestLibFx = FrameworkUtilities.GetNearest(refFx, libFxs);

                    if (nearestLibFx != null && !nearestLibFx.Equals(refFx))
                    {
                        promotedDependencies.AddRange(CopyDependencies(libSets[nearestLibFx], refFx));
                    }
                }
            }

            if (refFxs.Length > 0)
            {
                foreach (var libFx in libFxs)
                {
                    // find best lib (if any)
                    var nearestRefFx = FrameworkUtilities.GetNearest(libFx, refFxs);

                    if (nearestRefFx == null && !nearestRefFx.Equals(libFx))
                    {
                        // This should never happen and indicates a bug in the package.  If a package contains references,
                        // all implementations should have an applicable reference assembly.
                        Log.LogError($"Could not find applicable reference assembly for implementation framework {libFx} from reference frameworks {string.Join(", ", refFxs.Select(f => f.GetShortFolderName()))}");
                    }
                    else
                    {
                        promotedDependencies.AddRange(CopyDependencies(refSets[nearestRefFx], libFx));
                    }
                }
            }

            PromotedDependencies = promotedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
Exemplo n.º 4
0
        public static bool IsInbox(string frameworkListsPath, string framework, string assemblyName, string assemblyVersion)
        {
            // if no version is specified just use 0.0.0.0 to evaluate for any version of the contract
            Version      version = FrameworkUtilities.Ensure4PartVersion(String.IsNullOrEmpty(assemblyVersion) ? new Version(0, 0, 0, 0) : new Version(assemblyVersion));
            FrameworkSet fxs     = GetInboxFrameworks(frameworkListsPath);

            Version latestLegacyVersion = null;

            fxs.LastNonSemanticVersions.TryGetValue(assemblyName, out latestLegacyVersion);

            foreach (var fxVersions in fxs.Frameworks.Values)
            {
                // Get the nearest compatible framework from this set of frameworks.
                var nearest = FrameworkUtilities.GetNearest(NuGetFramework.Parse(framework), fxVersions.Select(fx => NuGetFramework.Parse(fx.ShortName)).ToArray());
                // If there are not compatible frameworks in the current framework set, there is not going to be a match.
                if (nearest == null)
                {
                    continue;
                }
                var origFramework = NuGetFramework.Parse(framework);
                // if the nearest compatible frameworks version is greater than the version of the framework we are looking for, this is not going to be a match.
                if (nearest.Version > origFramework.Version)
                {
                    continue;
                }
                // find the first version (if any) that supports this contract
                foreach (var fxVersion in fxVersions)
                {
                    Version supportedVersion;
                    if (fxVersion.Assemblies.TryGetValue(assemblyName, out supportedVersion))
                    {
                        if (supportedVersion >= version)
                        {
                            return(true);
                        }

                        // new versions represent API surface via major.minor only, so consider
                        // a contract as supported so long as the latest legacy version is supported
                        // and this contract's major.minor match the latest legacy version.
                        if (supportedVersion == latestLegacyVersion &&
                            version.Major == latestLegacyVersion.Major && version.Minor == latestLegacyVersion.Minor)
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Exemplo n.º 5
0
        public override bool Execute()
        {
            List <ITaskItem> promotedDependencies = new List <ITaskItem>();

            var implementationFxs = Dependencies.Select(d => d.GetMetadata("TargetFramework")).Distinct();

            var actualDependencies = Dependencies.Where(d => d.ItemSpec != "_._").Select(d => new Dependency(d)).ToArray();
            var referenceSets      = actualDependencies.Where(d => d.IsReference).GroupBy(d => d.TargetFramework).ToDictionary(g => NuGetFramework.Parse(g.Key), g => g.ToArray());
            var candidateFxs       = referenceSets.Keys.ToArray();

            if (candidateFxs.Length != 0)
            {
                foreach (var implementationFx in implementationFxs)
                {
                    NuGetFramework fx = NuGetFramework.Parse(implementationFx);
                    if (referenceSets.ContainsKey(fx))
                    {
                        // if this implementation assembly fx  has a matching reference fx skip promotion
                        continue;
                    }

                    var nearestReferenceFx = FrameworkUtilities.GetNearest(fx, candidateFxs);

                    if (nearestReferenceFx == null)
                    {
                        // This should never happen and indicates a bug in the package.  If a package contains references,
                        // all implementations should have an applicable reference assembly.
                        Log.LogError($"Could not find applicable reference assembly for implementation framework {implementationFx} from reference frameworks {string.Join(", ", referenceSets.Keys)}");
                    }

                    foreach (var reference in referenceSets[nearestReferenceFx])
                    {
                        var promotedDependency = new TaskItem(reference.OriginalItem);
                        promotedDependency.SetMetadata(TargetFrameworkMetadataName, implementationFx);

                        if (!Frameworks.IsInbox(FrameworkListsPath, implementationFx, reference.Id, reference.Version))
                        {
                            promotedDependencies.Add(promotedDependency);
                        }
                    }
                }
            }

            PromotedDependencies = promotedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
        /* Given a set of available frameworks ("InboxOnTargetFrameworks"), and a list of desired frameworks,
         * reduce the set of frameworks to the minimum set of frameworks which is compatible (preferring inbox frameworks. */
        public override bool Execute()
        {
            if (null == Dependencies)
            {
                Log.LogError("Dependencies argument must be specified");
                return(false);
            }
            if (null == FrameworkListsPath)
            {
                Log.LogError("FrameworkListsPath argument must be specified");
                return(false);
            }

            // Retrieve the list of generation dependency group TFM's
            var dependencyGroups = Dependencies.GroupBy(d => d.GetMetadata("TargetFramework")).Select(dg => new
            {
                Framework    = NuGetFramework.Parse(dg.Key),
                Dependencies = dg.ToArray()
            });

            List <ITaskItem> addedDependencies = new List <ITaskItem>();

            // Exclude any non-portable frameworks that already have specific dependency groups.
            var frameworksToExclude = dependencyGroups.Select(dg => dg.Framework).Where(fx => !FrameworkUtilities.IsGenerationMoniker(fx));

            // Prepare a resolver for evaluating if candidate frameworks are actually supported by the package
            PackageItem[] packageItems = Files.Select(f => new PackageItem(f)).ToArray();
            var           packagePaths = packageItems.Select(pi => pi.TargetPath);
            var           targetFrameworksWithPlaceHolders = packageItems.Where(pi => NuGetAssetResolver.IsPlaceholder(pi.TargetPath)).Select(pi => pi.TargetFramework);

            NuGetAssetResolver resolver = new NuGetAssetResolver(null, packagePaths);

            foreach (var portableDependencyGroup in dependencyGroups.Where(dg => FrameworkUtilities.IsGenerationMoniker(dg.Framework)))
            {
                // Determine inbox frameworks for this generation that don't already have explicit groups
                HashSet <NuGetFramework> inboxFrameworksList = new HashSet <NuGetFramework>(
                    Frameworks.GetAlllInboxFrameworks(FrameworkListsPath)
                    .Where(fx => !fx.IsPCL)
                    .Where(fx => Generations.DetermineGenerationForFramework(fx, UseNetPlatform) >= portableDependencyGroup.Framework.Version &&
                           !frameworksToExclude.Any(exFx => exFx.Framework == fx.Framework && exFx.Version <= fx.Version)));

                // Check for assets which have a ref, but not a lib asset. If we have any of these, then they are actually not supported frameworks
                // and we should not include them.
                inboxFrameworksList.RemoveWhere(inboxFx => !IsSupported(inboxFx, resolver));

                // Only add the lowest version for a particular inbox framework.  EG if both net45 and net46 are supported by this generation,
                //        only add net45
                inboxFrameworksList.RemoveWhere(fx => inboxFrameworksList.Any(otherFx => (otherFx.Framework.Equals(fx.Framework)) && (otherFx.Version < fx.Version)));

                // Create dependency items for each inbox framework.
                foreach (var framework in inboxFrameworksList)
                {
                    bool addedDependencyToFramework = false;
                    foreach (ITaskItem dependency in portableDependencyGroup.Dependencies)
                    {
                        string version = GetVersion(dependency);

                        if (!Frameworks.IsInbox(FrameworkListsPath, framework, dependency.ItemSpec, version))
                        {
                            addedDependencyToFramework = true;
                            AddDependency(addedDependencies, new TaskItem(dependency), framework, portableDependencyGroup.Framework);
                        }
                    }
                    if (!addedDependencyToFramework)
                    {
                        AddDependency(addedDependencies, new TaskItem("_._"), framework, portableDependencyGroup.Framework);
                    }
                }
            }

            // Collapse frameworks
            // For any dependency with a targetframework, if there is another target framework which is compatible and older, remove this dependency.

            // Get all Dependencies which are not in a portable dependency group so that we can collapse the frameworks.  If we include
            // the portable frameworks, then we'll end up collapsing to those.
            List <NuGetFramework> allDependencyGroups = new List <NuGetFramework>();

            allDependencyGroups.AddRange(Dependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                !FrameworkUtilities.IsPortableMoniker(a)));
            allDependencyGroups.AddRange(addedDependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                     !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                     !FrameworkUtilities.IsPortableMoniker(a)));

            List <NuGetFramework> collapsedDependencyGroups = FrameworkUtilities.ReduceDownwards(allDependencyGroups).ToList <NuGetFramework>();

            // Get the list of dependency groups that we collapsed down so that we can add them back if they contained different dependencies than what is present in the collapsed group.

            /* TODO: Look into NuGet's sorting algorithm, they may have a bug (fixed in this line). They were not including version in the sort.
             *       See ReduceCore in https://github.com/NuGet/NuGet.Client/blob/23ea68b91a439fcfd7f94bcd01bcdee2e8adae92/src/NuGet.Core/NuGet.Frameworks/FrameworkReducer.cs */
            IEnumerable <NuGetFramework> removedDependencyGroups = allDependencyGroups.Where(d => !collapsedDependencyGroups.Contains(d))?.OrderBy(f => f.Framework, StringComparer.OrdinalIgnoreCase).ThenBy(f => f.Version);

            foreach (NuGetFramework removedDependencyGroup in removedDependencyGroups)
            {
                // always recalculate collapsedDependencyGroups in case we added an item in a previous iteration.  Dependency groups are sorted, so this should be additive and we shouldn't need to restart the collapse / add back cycle
                var nearest = FrameworkUtilities.GetNearest(removedDependencyGroup, collapsedDependencyGroups.ToArray());

                // gather the dependencies for this dependency group and the calculated "nearest" dependency group
                var nearestDependencies = addedDependencies.Where(d => nearest.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());
                var currentDependencies = addedDependencies.Where(d => removedDependencyGroup.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());

                // The nearest dependency group's dependencies are different than this dependency group's dependencies
                if (nearestDependencies.Count() != currentDependencies.Count())
                {
                    // ignore if dependency is a placeholder
                    if (currentDependencies.Count() > 0)
                    {
                        if (!NuGetAssetResolver.IsPlaceholder(currentDependencies.First().ToString()))
                        {
                            collapsedDependencyGroups.Add(removedDependencyGroup);
                        }
                    }
                    else
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
                // identical dependency count between current and nearest, and the count is > 0
                else if (nearestDependencies.Count() > 0)
                {
                    if (!currentDependencies.SequenceEqual(nearestDependencies, new DependencyITaskItemComparer()))
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
            }


            List <ITaskItem> collapsedDependencies = new List <ITaskItem>();

            foreach (ITaskItem dependency in addedDependencies)
            {
                if (collapsedDependencyGroups.Contains(NuGetFramework.Parse(dependency.GetMetadata("TargetFramework"))))
                {
                    collapsedDependencies.Add(dependency);
                }
            }
            TrimmedDependencies = collapsedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
Exemplo n.º 7
0
        /* Given a set of available frameworks ("InboxOnTargetFrameworks"), and a list of desired frameworks,
         * reduce the set of frameworks to the minimum set of frameworks which is compatible (preferring inbox frameworks. */
        public override bool Execute()
        {
            if (null == Dependencies)
            {
                Log.LogError("Dependencies argument must be specified");
                return(false);
            }
            if (null == FrameworkListsPath)
            {
                Log.LogError("FrameworkListsPath argument must be specified");
                return(false);
            }

            // Retrieve the list of generation dependency group TFM's
            Dictionary <string, IEnumerable <ITaskItem> > portableDependencyGroups = new Dictionary <string, IEnumerable <ITaskItem> >();

            foreach (ITaskItem dependency in Dependencies)
            {
                string framework = dependency.GetMetadata("TargetFramework");
                if (framework != null && FrameworkUtilities.IsGenerationMoniker(framework) && !portableDependencyGroups.ContainsKey(framework))
                {
                    portableDependencyGroups.Add(framework, Dependencies.Where(d => d.GetMetadata("TargetFramework") == framework));
                }
            }

            List <ITaskItem> addedDependencies     = new List <ITaskItem>();
            List <string>    placeHolderFrameworks = new List <string>();

            var frameworksToExclude = TrimFrameworks?.Select(fx => NuGetFramework.Parse(fx))?.ToArray() ?? new NuGetFramework[0];

            // Prepare a resolver for evaluating if candidate frameworks are actually supported by the package
            PackageItem[] packageItems = Files.Select(f => new PackageItem(f)).ToArray();
            var           packagePaths = packageItems.Select(pi => pi.TargetPath);
            var           targetFrameworksWithPlaceHolders = packageItems.Where(pi => NuGetAssetResolver.IsPlaceholder(pi.TargetPath)).Select(pi => pi.TargetFramework);

            NuGetAssetResolver resolver = new NuGetAssetResolver(null, packagePaths);

            foreach (string portableDependency in portableDependencyGroups.Keys)
            {
                NuGetFramework portableDependencyFramework = NuGetFramework.Parse(portableDependency);

                // Determine inbox frameworks for this generations dependencies as a whole
                HashSet <NuGetFramework> inboxFrameworksList = new HashSet <NuGetFramework>();

                foreach (NuGetFramework inboxFramework in Frameworks.GetAlllInboxFrameworks(FrameworkListsPath))
                {
                    if (Generations.DetermineGenerationForFramework(inboxFramework, UseNetPlatform) >= portableDependencyFramework.Version &&
                        !frameworksToExclude.Contains(inboxFramework))
                    {
                        inboxFrameworksList.Add(inboxFramework);
                    }
                }

                // Only add the lowest version for a particular inbox framework.  EG if both net45 and net46 are supported by this generation,
                //        only add net45
                inboxFrameworksList.RemoveWhere(fx => inboxFrameworksList.Any(otherFx => (otherFx.Framework.Equals(fx.Framework)) && (otherFx.Version < fx.Version)));

                // Check for assets which have a ref, but not a lib asset. If we have any of these, then they are actually not supported frameworks
                // and we should not include them.
                inboxFrameworksList.RemoveWhere(inboxFx => !IsSupported(inboxFx, resolver));

                // Remove the frameworks which have placeholders.
                inboxFrameworksList.RemoveWhere(fx => targetFrameworksWithPlaceHolders.Any(tfx => tfx != null && fx.DotNetFrameworkName == tfx.DotNetFrameworkName));

                // Create dependency items for each inbox framework.
                foreach (string framework in inboxFrameworksList.Select(fx => fx.GetShortFolderName()))
                {
                    bool addedDependencyToFramework = false;
                    foreach (ITaskItem dependency in portableDependencyGroups[portableDependency])
                    {
                        // If we don't have the AssemblyVersion metadata (4 part version string), fall back and use Version (3 part version string)
                        string version = dependency.GetMetadata("AssemblyVersion");
                        if (string.IsNullOrEmpty(version))
                        {
                            version = dependency.GetMetadata("Version");

                            int prereleaseIndex = version.IndexOf('-');
                            if (prereleaseIndex != -1)
                            {
                                version = version.Substring(0, prereleaseIndex);
                            }
                        }
                        if (!Frameworks.IsInbox(FrameworkListsPath, framework, dependency.ItemSpec, version))
                        {
                            addedDependencyToFramework = true;
                            TaskItem dependencyItem = new TaskItem(dependency);
                            dependencyItem.SetMetadata("TargetFramework", framework);
                            // "Generation" is not required metadata, we just include it because it can be useful for debugging.
                            dependencyItem.SetMetadata("Generation", portableDependency);
                            addedDependencies.Add(dependencyItem);
                        }
                    }
                    if (!addedDependencyToFramework)
                    {
                        TaskItem dependencyItem = new TaskItem("_._");
                        dependencyItem.SetMetadata("TargetFramework", framework);
                        // "Generation" is not required metadata, we just include it because it can be useful for debugging.
                        dependencyItem.SetMetadata("Generation", portableDependency);
                        addedDependencies.Add(dependencyItem);
                        placeHolderFrameworks.Add(framework);
                    }
                }
            }

            // Collapse frameworks
            // For any dependency with a targetframework, if there is another target framework which is compatible and older, remove this dependency.

            // Get all Dependencies which are not in a portable dependency group so that we can collapse the frameworks.  If we include
            // the portable frameworks, then we'll end up collapsing to those.
            List <NuGetFramework> allDependencyGroups = new List <NuGetFramework>();

            allDependencyGroups.AddRange(Dependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                !FrameworkUtilities.IsPortableMoniker(a)));
            allDependencyGroups.AddRange(addedDependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                     !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                     !FrameworkUtilities.IsPortableMoniker(a)));

            List <NuGetFramework> collapsedDependencyGroups = FrameworkUtilities.ReduceDownwards(allDependencyGroups).ToList <NuGetFramework>();

            // Get the list of dependency groups that we collapsed down so that we can add them back if they contained different dependencies than what is present in the collapsed group.

            /* TODO: Look into NuGet's sorting algorithm, they may have a bug (fixed in this line). They were not including version in the sort.
             *       See ReduceCore in https://github.com/NuGet/NuGet.Client/blob/23ea68b91a439fcfd7f94bcd01bcdee2e8adae92/src/NuGet.Core/NuGet.Frameworks/FrameworkReducer.cs */
            IEnumerable <NuGetFramework> removedDependencyGroups = allDependencyGroups.Where(d => !collapsedDependencyGroups.Contains(d))?.OrderBy(f => f.Framework, StringComparer.OrdinalIgnoreCase).ThenBy(f => f.Version);

            foreach (NuGetFramework removedDependencyGroup in removedDependencyGroups)
            {
                // always recalculate collapsedDependencyGroups in case we added an item in a previous iteration.  Dependency groups are sorted, so this should be additive and we shouldn't need to restart the collapse / add back cycle
                var nearest = FrameworkUtilities.GetNearest(removedDependencyGroup, collapsedDependencyGroups.ToArray());

                // gather the dependencies for this dependency group and the calculated "nearest" dependency group
                var nearestDependencies = addedDependencies.Where(d => nearest.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());
                var currentDependencies = addedDependencies.Where(d => removedDependencyGroup.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());

                // The nearest dependency group's dependencies are different than this dependency group's dependencies
                if (nearestDependencies.Count() != currentDependencies.Count())
                {
                    // ignore if dependency is a placeholder
                    if (currentDependencies.Count() > 0)
                    {
                        if (!NuGetAssetResolver.IsPlaceholder(currentDependencies.First().ToString()))
                        {
                            collapsedDependencyGroups.Add(removedDependencyGroup);
                        }
                    }
                    else
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
                // identical dependency count between current and nearest, and the count is > 0
                else if (nearestDependencies.Count() > 0)
                {
                    if (!currentDependencies.SequenceEqual(nearestDependencies, new DependencyITaskItemComparer()))
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
            }


            List <ITaskItem> collapsedDependencies = new List <ITaskItem>();

            foreach (ITaskItem dependency in addedDependencies)
            {
                if (collapsedDependencyGroups.Contains(NuGetFramework.Parse(dependency.GetMetadata("TargetFramework"))))
                {
                    collapsedDependencies.Add(dependency);
                }
            }
            TrimmedDependencies = collapsedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }