示例#1
0
        private Possible <Unit> ValidateUniquenes(out Dictionary <string, INugetPackage> idToPackageMap, out Dictionary <string, INugetPackage> idPlusVersionToPackageMap)
        {
            // TODO: the overall uniquness/aliasing thing should be improved.
            // Today the following case will lead to weird results:
            // package1: id: n1, alias: n2
            // package2: id: n2, alias: n1
            // This will work, but it is not clear what the expected semantic should be.
            // When the user requests 'n1' which package should be used?

            idToPackageMap = idPlusVersionToPackageMap = null;

            // Packages should have unique (id or alias)
            // And (id + version) -- regardless of the alias.
            var duplicateNames         = new HashSet <string>();
            var duplicateIdPlusVersion = new HashSet <string>();

            var localIdToPackageMap            = new Dictionary <string, INugetPackage>(m_packages.Count);
            var localIdPlusVersionToPackageMap = new Dictionary <string, INugetPackage>(m_packages.Count);

            foreach (var package in m_packages)
            {
                // Track id+version first
                string idPlusVersion = package.Id + "." + package.Version;
                if (!localIdPlusVersionToPackageMap.TryAdd(idPlusVersion, package))
                {
                    duplicateIdPlusVersion.Add(package.Id);
                }

                // Then track id or alias
                if (!localIdToPackageMap.TryAdd(package.Id, package))
                {
                    // A package with the same id is already in the map.
                    if (string.IsNullOrEmpty(package.Alias) || localIdToPackageMap.ContainsKey(package.Alias))
                    {
                        duplicateNames.Add(package.Alias ?? package.Id);
                    }
                    else
                    {
                        // This allows us to have the same package id coexist in our workspace as long as it defines a unique alias.
                        localIdToPackageMap.Add(package.Alias, package);
                    }
                }
            }

            if (duplicateNames.Count != 0)
            {
                return(NugetFailure.DuplicatedPackagesWithTheSameIdOrAlias(duplicateNames.ToList()));
            }

            if (duplicateIdPlusVersion.Count != 0)
            {
                return(NugetFailure.DuplicatedPackagesWithTheSameIdAndVersion(duplicateIdPlusVersion.ToList()));
            }

            idToPackageMap            = localIdToPackageMap;
            idPlusVersionToPackageMap = localIdPlusVersionToPackageMap;
            return(Unit.Void);
        }
示例#2
0
        /// <summary>
        /// Sorts analyzedPackages into sortedPackages such that given a package A in sortedPackages, its dependencies are always in the
        /// tail of A.
        /// </summary>
        /// <returns>
        /// Returns true if the packages were successfully sorted, and in that case failure is null. An unsuccessfull sort is always due
        /// to a cycle in the package references. In that case, failure contains one package involved in the cycle.
        /// TODO: Consider enhancing the failure case with information about the whole cycle, for better diagnostics
        /// </returns>
        private static bool TryToposortPackages(
            IDictionary <string, NugetAnalyzedPackage> analyzedPackages, out List <NugetAnalyzedPackage> sortedPackages, out NugetFailure failure)
        {
            sortedPackages = new List <NugetAnalyzedPackage>(analyzedPackages.Count);

            // All packages start as unmarked, and none as temporary marked. We loop until all packages are marked
            var unmarkedPackages        = new HashSet <NugetAnalyzedPackage>(analyzedPackages.Values);
            var temporaryMarkedPackages = new HashSet <NugetAnalyzedPackage>();

            while (unmarkedPackages.Any())
            {
                var aPackage = unmarkedPackages.First();
                if (!TryVisit(analyzedPackages, unmarkedPackages, temporaryMarkedPackages, aPackage, sortedPackages))
                {
                    sortedPackages = null;
                    failure        = new NugetFailure(aPackage.PackageOnDisk.Package, NugetFailure.FailureType.CyclicPackageDependency);
                    return(false);
                }
            }

            failure = null;
            return(true);
        }
示例#3
0
        private Possible <Unit> TryValidatePackagesConfiguration()
        {
            var invalidPackages = m_packages.Where(pkg => !ValidatePackageConfiguration(pkg)).Select(pkg => pkg.Alias ?? pkg.Id).ToList();

            return(invalidPackages.Count == 0 ? (Possible <Unit>)Unit.Void : NugetFailure.InvalidConfiguration(invalidPackages));
        }
示例#4
0
        /// <summary>
        /// Given a dictionary of packageID -> NugetAnalyzedPackage that is closed under dependencies (if a nuget package A depends on B, if
        /// A is in the dictionary then B is in the dictionary), updates the set of supported target frameworks for each package considering its package
        /// dependencies.
        /// </summary>
        /// <remarks>
        /// The way the patch works is as follows:
        /// - For a managed package, the set of supported frameworks is explicit given the package directory structure, so it is left as is
        /// - For a non-managed package, the patched set of supported frameworks is the union of the supported frameworks of all its dependencies, considering
        /// that all its dependencies were already patched
        /// </remarks>
        public static bool TryPatchSupportedTargetFrameworksForPackageExtent(NugetFrameworkMonikers nugetFrameworkMonikers, IDictionary <string, NugetAnalyzedPackage> packageExtent, out NugetFailure failure)
        {
            // We topo sort the list of packages, where dependents are always after their dependencies
            if (!TryToposortPackages(packageExtent, out List <NugetAnalyzedPackage> sortedAnalyzedPackages, out failure))
            {
                return(false);
            }

            // We traverse the list from head to tail, so when we retrieve a dependency, it is already patched
            foreach (var analyzedPackage in sortedAnalyzedPackages)
            {
                var targetFrameworkWithFallBacks = analyzedPackage.TargetFrameworkWithFallbacks;

                // If the package is managed, the qualifier space is already the right one
                if (analyzedPackage.IsManagedPackage)
                {
                    /*
                     *  TODO:Nuget: Another workaround to make Nuget packages that are already exposing .NET Standard targets compatible to .NET Framework 452 qualifiers,
                     *  unfortunately we have many of those in use with BuildXL already e.g. ProtocolReader. This makes coercing between .NETStandard1.1 packages and
                     *  .NET Framework 4.5.1 work, until we have proper support built in. If we encounter more packages with different .NETStandard this would
                     *  at least be the only place we introduce more special casing.
                     */
                    if (targetFrameworkWithFallBacks.Count == 1)
                    {
                        if (targetFrameworkWithFallBacks.Keys.FirstOrDefault().Equals(nugetFrameworkMonikers.NetStandard10) ||
                            targetFrameworkWithFallBacks.Keys.FirstOrDefault().Equals(nugetFrameworkMonikers.NetStandard11))
                        {
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net472);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net462);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net461);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net46);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net452);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net451);
                            targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net45);
                        }
                    }

                    continue;
                }

                // Otherwise, we compute the union of the qualifier spaces of its dependencies
                foreach (var dependency in analyzedPackage.Dependencies)
                {
                    Contract.Assert(packageExtent.Keys.Contains(dependency.GetPackageIdentity()));
                    var analyzedDependency = packageExtent[dependency.GetPackageIdentity()];
                    CombineTargetFrameworksForUnmanagedPackage(targetFrameworkWithFallBacks, analyzedDependency.TargetFrameworkWithFallbacks);
                }
            }

            return(true);
        }