1 module dub.packagesuppliers.packagesupplier; 2 3 public import dub.dependency : Dependency, Version; 4 public import dub.internal.vibecompat.core.file : NativePath; 5 public import dub.internal.vibecompat.data.json : Json; 6 7 /** 8 Base interface for remote package suppliers. 9 10 Provides functionality necessary to query package versions, recipes and 11 contents. 12 */ 13 interface PackageSupplier { 14 /// Represents a single package search result. 15 static struct SearchResult { string name, description, version_; } 16 17 /// Returns a human-readable representation of the package supplier. 18 @property string description(); 19 20 /** Retrieves a list of all available versions(/branches) of a package. 21 22 Throws: Throws an exception if the package name is not known, or if 23 an error occurred while retrieving the version list. 24 */ 25 Version[] getVersions(string package_id); 26 27 /** Downloads a package and stores it as a ZIP file. 28 29 Params: 30 path = Absolute path of the target ZIP file 31 package_id = Name of the package to retrieve 32 dep: Version constraint to match against 33 pre_release: If true, matches the latest pre-release version. 34 Otherwise prefers stable versions. 35 */ 36 void fetchPackage(NativePath path, string package_id, Dependency dep, bool pre_release); 37 38 /** Retrieves only the recipe of a particular package. 39 40 Params: 41 package_id = Name of the package of which to retrieve the recipe 42 dep: Version constraint to match against 43 pre_release: If true, matches the latest pre-release version. 44 Otherwise prefers stable versions. 45 */ 46 Json fetchPackageRecipe(string package_id, Dependency dep, bool pre_release); 47 48 /** Searches for packages matching the given search query term. 49 50 Search queries are currently a simple list of words separated by 51 white space. Results will get ordered from best match to worst. 52 */ 53 SearchResult[] searchPackages(string query); 54 } 55 56 // TODO: Could drop the "best package" behavior and let retrievePackage/ 57 // getPackageDescription take a Version instead of Dependency. But note 58 // this means that two requests to the registry are necessary to retrieve 59 // a package recipe instead of one (first get version list, then the 60 // package recipe) 61 62 package Json getBestPackage(Json metadata, string packageId, Dependency dep, bool pre_release) 63 { 64 import std.exception : enforce; 65 if (metadata.type == Json.Type.null_) 66 return metadata; 67 Json best = null; 68 Version bestver; 69 foreach (json; metadata["versions"]) { 70 auto cur = Version(json["version"].get!string); 71 if (!dep.matches(cur)) continue; 72 if (best == null) best = json; 73 else if (pre_release) { 74 if (cur > bestver) best = json; 75 } else if (bestver.isPreRelease) { 76 if (!cur.isPreRelease || cur > bestver) best = json; 77 } else if (!cur.isPreRelease && cur > bestver) best = json; 78 bestver = Version(cast(string)best["version"]); 79 } 80 enforce(best != null, "No package candidate found for "~packageId~" "~dep.toString()); 81 return best; 82 }