using Invercargill; using Invercargill.DataStructures; namespace Usm { public class Resolver { private Dictionary listings = new Dictionary(); private Set supplied = new HashSet(); private Enumerable available_packages() { return supplied.concat(listings .select_many>(l => l.value.entries.select_pairs(e => l.key, e => e)) .select(p => new AbstractPackage.from_repository(p.value1, p.value2))); } public void load_listing(Repository repo, RepositoryListing listing) { listings.set(repo, listing); } public void supply_package(string path) throws Error { supplied.add(new AbstractPackage.from_package(path)); } public void load_cache(Paths paths) throws Error { var state = new SystemState(paths); foreach (var package in state.get_cached_packages()) { supply_package(package.package_path); } } public AbstractPackage? find_package(string search) { return available_packages() .first_or_default(p => p.manifest.name == search); } public AbstractPackage? find_resource(ResourceRef resource) { return available_packages() .first_or_default(p => p.manifest.provides.any(r => resource.satisfied_by(r.key))); } public void solve_dependencies_for(PackageSet package_set) { var queue = new Fifo(); package_set.iterate(i => queue.push(i)); foreach (var item in queue) { var dependencies = item.manifest.dependencies.build .concat(item.manifest.dependencies.manage) .concat(item.manifest.dependencies.runtime); foreach (var dep in dependencies) { if(package_set.provides(dep) || dep.is_satisfied()) { continue; } var provider = find_resource(dep); if(provider == null) { error(@"Could not solve dependency $dep"); } package_set.add(provider); queue.push(provider); } } } } public class PackageSet : HashSet { public void add_from_file(string path) throws Error { add(new AbstractPackage.from_package(path)); } public void add_from_repo(Repository repository, RepositoryListingEntry entry) throws Error { add(new AbstractPackage.from_repository(repository, entry)); } public bool is_satisfied() { return all(check_satisfied); } private bool check_satisfied(AbstractPackage package) { return package.manifest.dependencies.build.all(d => provides(d) || d.is_satisfied()) && package.manifest.dependencies.manage.all(d => provides(d) || d.is_satisfied()) && package.manifest.dependencies.runtime.all(d => provides(d) || d.is_satisfied()); } public bool provides(ResourceRef resource) { return any(p => p.manifest.provides.any(r => resource.satisfied_by(r.key))); } } public class AbstractPackage { public Manifest manifest { get; set; } public Repository? repository { get; set; } public RepositoryListingEntry? repository_entry { get; set; } public string? package_path { get; set; } public CachedPackage? cached_package { get; set; } public AbstractPackage.from_package(string path) throws Error { package_path = path; manifest = new Manifest.from_file(path); } public AbstractPackage.from_repository(Repository repository, RepositoryListingEntry entry) { this.repository = repository; this.repository_entry = entry; this.manifest = entry.manifest; } } }