Example #1
0
        static List <RemotePackage> FindDependencies(IDictionary <string, List <PackageDependency> > discoveredDependencies, Package[] packages, params List <RemotePackage>[] listsOfPackages)
        {
            var  found          = new List <RemotePackage>();
            var  packageIds     = packages.Select(p => p.Id);
            bool throwIfMissing = (discoveredDependencies == null);             // if this is null, then we're not recursing

            // TODO this should be pulled out into its own method that JUST returns a list of PackageDependency for us to find
            //
            // get ALL of the dependencies for these packages, grouped by package Id
            // eg. { "log4net" => ["log4net > 2.0", "log4net < 2.5"] }
            var allDependencies = new Dictionary <string, List <PackageDependency> >();

            foreach (var package in packages)
            {
                foreach (var packageDependency in package.Dependencies)
                {
                    if (packageIds.Contains(packageDependency.PackageId))
                    {
                        continue;
                    }
                    if (!allDependencies.ContainsKey(packageDependency.PackageId))
                    {
                        allDependencies[packageDependency.PackageId] = new List <PackageDependency>();
                    }
                    if (!allDependencies[packageDependency.PackageId].Contains(packageDependency))
                    {
                        allDependencies[packageDependency.PackageId].Add(packageDependency);
                    }
                }
            }

            // add these packages' dependencies into discoveredDependencies.
            // we track these to know whether or not we're missing any dependencies for any of the packages found.
            if (discoveredDependencies == null)
            {
                discoveredDependencies = new Dictionary <string, List <PackageDependency> >();
            }
            foreach (var packageDependency in allDependencies)
            {
                var dependencyId = packageDependency.Key;
                var dependencies = packageDependency.Value.ToArray();
                if (!discoveredDependencies.ContainsKey(dependencyId))
                {
                    discoveredDependencies[dependencyId] = new List <PackageDependency>();
                }
                foreach (var dependency in dependencies)
                {
                    if (!discoveredDependencies[dependencyId].Contains(dependency))
                    {
                        discoveredDependencies[dependencyId].Add(dependency);
                    }
                }
            }

            foreach (var packageDependency in allDependencies)
            {
                var dependencyId = packageDependency.Key;
                var dependencies = packageDependency.Value.ToArray();

                // go through all sources and get the *latest* version of this dependency (that matches)
                RemotePackage dependencyPackage = null;
                foreach (var sourcePackages in listsOfPackages)
                {
                    var match = sourcePackages.Where(pkg => pkg.Id == dependencyId && PackageDependency.MatchesAll(pkg.Version, dependencies)).OrderBy(pkg => pkg.Version).Reverse().FirstOrDefault();

                    if (match != null)
                    {
                        if (dependencyPackage == null || dependencyPackage.Version < match.Version)
                        {
                            dependencyPackage = match;
                        }
                    }
                }

                if (dependencyPackage != null)
                {
                    found.Add(dependencyPackage);
                    if (dependencyPackage.Dependencies.Any())
                    {
                        found.AddRange(Package.FindDependencies(discoveredDependencies, new Package[] { dependencyPackage }, listsOfPackages));                        // <--- recurse!
                    }
                }
                else
                {
                    Console.WriteLine("Could not find dependency: {0}", dependencyId);
                }
            }

            // throw a MissingDependencyException if any of the discovered dependencies were not found
            if (throwIfMissing)
            {
                var foundIds = found.Select(pkg => pkg.Id);
                var missing  = new List <PackageDependency>();

                foreach (var dependencyPackage in discoveredDependencies)
                {
                    if (!foundIds.Contains(dependencyPackage.Key))
                    {
                        missing.AddRange(dependencyPackage.Value);
                    }
                }

                if (missing.Count > 0)
                {
                    throw new MissingDependencyException(missing);
                }
            }

            // TODO instead of just doing a Distinct(), we need to actually inspect the dependencies ...

            // do not include any of the packages that were passed in as dependencies
            return(found.Where(pkg => !packageIds.Contains(pkg.Id)).Distinct().ToList());
        }
Example #2
0
        static RemotePackage PackageFromFeedEntry(XmlElement entry)
        {
            var package = new RemotePackage();

            foreach (XmlNode node in entry.ChildNodes)
            {
                switch (node.Name.ToLower())
                {
                case "id": break;

                case "pkg:packageid": package.Id = node.InnerText; break;

                case "pkg:version":   package.VersionText = node.InnerText; break;

                case "pkg:language":  package.Language = node.InnerText; break;

                case "title":         package.Title = node.InnerText; break;

                case "content":       package.Description = node.InnerText; break;

                case "author":        package.Authors.Add(node.InnerText);    break;

                case "owner":         package.Owners.Add(node.InnerText);     break;

                case "published":     package.Created = DateTime.Parse(node.InnerText); break;

                case "updated":       package.Modified = DateTime.Parse(node.InnerText); break;

                case "category":
                    var term = node.Attributes["term"].Value;
                    if (!package.Tags.Contains(term))
                    {
                        package.Tags.Add(term);
                    }
                    break;

                case "pkg:requirelicenseacceptance":
                    package.RequireLicenseAcceptance = bool.Parse(node.InnerText); break;

                case "pkg:keywords":
                    // if there is 1 <string>, split it on spaces
                    // else if there are many, each element is a tag
                    var tagNodes = node.ChildNodes;
                    if (tagNodes.Count == 1)
                    {
                        foreach (var tag in tagNodes[0].InnerText.Split(' '))
                        {
                            if (!package.Tags.Contains(tag.Trim()))
                            {
                                package.Tags.Add(tag.Trim());
                            }
                        }
                    }
                    else
                    {
                        foreach (XmlNode tagString in tagNodes)
                        {
                            if (!package.Tags.Contains(tagString.InnerText.Trim()))
                            {
                                package.Tags.Add(tagString.InnerText.Trim());
                            }
                        }
                    }
                    break;

                case "link":
                    switch (node.Attributes["rel"].Value)
                    {
                    case "enclosure":
                        package.DownloadUrl = node.Attributes["href"].Value; break;

                    case "license":
                        package.LicenseUrl = node.Attributes["href"].Value; break;

                    case "project":
                        package.ProjectUrl = node.Attributes["href"].Value; break;

                    case "icon":
                        package.IconUrl = node.Attributes["href"].Value; break;

                    default:
                        Console.WriteLine("Unsupported <link> rel: {0}", node.Attributes["rel"].Value); break;
                    }
                    break;

                case "pkg:dependencies":
                    foreach (XmlNode dependencyNode in node.ChildNodes)
                    {
                        var dependency = new PackageDependency();
                        foreach (XmlNode depNode in dependencyNode.ChildNodes)
                        {
                            switch (depNode.Name.ToLower())
                            {
                            case "pkg:id":         dependency.Id = depNode.InnerText; break;

                            case "pkg:version":    dependency.VersionText = depNode.InnerText; break;

                            case "pkg:minversion": dependency.MinVersionText = depNode.InnerText; break;

                            case "pkg:maxversion": dependency.MaxVersionText = depNode.InnerText; break;

                            default:
                                Console.WriteLine("Unknown dependency node: {0}", depNode.Name);
                                break;
                            }
                        }
                        package.Dependencies.Add(dependency);
                    }
                    break;

                default:
                    Console.WriteLine("Unsupported <entry> element: {0} \"{1}\"", node.Name, node.InnerText);
                    break;
                }
            }

            return(package);
        }