Resolver.vala 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. namespace Usm {
  4. public class Resolver {
  5. private Dictionary<Repository, RepositoryListing> listings = new Dictionary<Repository, RepositoryListing>();
  6. private Set<AbstractPackage> supplied = new HashSet<AbstractPackage>();
  7. private Enumerable<AbstractPackage> available_packages() {
  8. return
  9. supplied.concat(listings
  10. .select_many<Pair<Repository, RepositoryListingEntry>>(l => l.value.entries.select_pairs<Repository, RepositoryListingEntry>(e => l.key, e => e))
  11. .select<AbstractPackage>(p => new AbstractPackage.from_repository(p.value1, p.value2)));
  12. }
  13. public void load_listing(Repository repo, RepositoryListing listing) {
  14. listings.set(repo, listing);
  15. }
  16. public void supply_package(string path) throws Error {
  17. supplied.add(new AbstractPackage.from_package(path));
  18. }
  19. public void load_cache(Paths paths) throws Error {
  20. var state = new SystemState(paths);
  21. foreach (var package in state.get_cached_packages()) {
  22. supply_package(package.package_path);
  23. }
  24. }
  25. public AbstractPackage? find_package(string search) {
  26. return available_packages()
  27. .first_or_default(p => p.manifest.name == search);
  28. }
  29. public AbstractPackage? find_resource(ResourceRef resource) {
  30. return available_packages()
  31. .first_or_default(p => p.manifest.provides.any(r => resource.satisfied_by(r.key)));
  32. }
  33. public void solve_dependencies_for(PackageSet package_set) {
  34. var queue = new Fifo<AbstractPackage>();
  35. package_set.iterate(i => queue.push(i));
  36. foreach (var item in queue) {
  37. var dependencies = item.manifest.dependencies.build
  38. .concat(item.manifest.dependencies.manage)
  39. .concat(item.manifest.dependencies.runtime);
  40. foreach (var dep in dependencies) {
  41. if(package_set.provides(dep) || dep.is_satisfied()) {
  42. continue;
  43. }
  44. var provider = find_resource(dep);
  45. if(provider == null) {
  46. error(@"Could not solve dependency $dep");
  47. }
  48. package_set.add(provider);
  49. queue.push(provider);
  50. }
  51. }
  52. }
  53. }
  54. public class PackageSet : HashSet<AbstractPackage> {
  55. public void add_from_file(string path) throws Error {
  56. add(new AbstractPackage.from_package(path));
  57. }
  58. public void add_from_repo(Repository repository, RepositoryListingEntry entry) throws Error {
  59. add(new AbstractPackage.from_repository(repository, entry));
  60. }
  61. public bool is_satisfied() {
  62. return all(check_satisfied);
  63. }
  64. private bool check_satisfied(AbstractPackage package) {
  65. return package.manifest.dependencies.build.all(d => provides(d) || d.is_satisfied()) &&
  66. package.manifest.dependencies.manage.all(d => provides(d) || d.is_satisfied()) &&
  67. package.manifest.dependencies.runtime.all(d => provides(d) || d.is_satisfied());
  68. }
  69. public bool provides(ResourceRef resource) {
  70. return any(p => p.manifest.provides.any(r => resource.satisfied_by(r.key)));
  71. }
  72. }
  73. public class AbstractPackage {
  74. public Manifest manifest { get; set; }
  75. public Repository? repository { get; set; }
  76. public RepositoryListingEntry? repository_entry { get; set; }
  77. public string? package_path { get; set; }
  78. public CachedPackage? cached_package { get; set; }
  79. public AbstractPackage.from_package(string path) throws Error {
  80. package_path = path;
  81. manifest = new Manifest.from_file(path);
  82. }
  83. public AbstractPackage.from_repository(Repository repository, RepositoryListingEntry entry) {
  84. this.repository = repository;
  85. this.repository_entry = entry;
  86. this.manifest = entry.manifest;
  87. }
  88. }
  89. }