1 module dub.packagesuppliers.filesystem; 2 3 import dub.packagesuppliers.packagesupplier; 4 5 /** 6 File system based package supplier. 7 8 This package supplier searches a certain directory for files with names of 9 the form "[package name]-[version].zip". 10 */ 11 class FileSystemPackageSupplier : PackageSupplier { 12 import dub.internal.vibecompat.core.log; 13 version (Have_vibe_core) import dub.internal.vibecompat.inet.path : toNativeString; 14 import std.exception : enforce; 15 private { 16 NativePath m_path; 17 } 18 19 this(NativePath root) { m_path = root; } 20 21 override @property string description() { return "file repository at "~m_path.toNativeString(); } 22 23 Version[] getVersions(string package_id) 24 { 25 import std.algorithm.sorting : sort; 26 import std.file : dirEntries, DirEntry, SpanMode; 27 import std.conv : to; 28 Version[] ret; 29 foreach (DirEntry d; dirEntries(m_path.toNativeString(), package_id~"*", SpanMode.shallow)) { 30 NativePath p = NativePath(d.name); 31 logDebug("Entry: %s", p); 32 enforce(to!string(p.head)[$-4..$] == ".zip"); 33 auto vers = p.head.name[package_id.length+1..$-4]; 34 logDebug("Version: %s", vers); 35 ret ~= Version(vers); 36 } 37 ret.sort(); 38 return ret; 39 } 40 41 void fetchPackage(NativePath path, string packageId, Dependency dep, bool pre_release) 42 { 43 import dub.internal.vibecompat.core.file : copyFile, existsFile; 44 enforce(path.absolute); 45 logInfo("Storing package '"~packageId~"', version requirements: %s", dep); 46 auto filename = bestPackageFile(packageId, dep, pre_release); 47 enforce(existsFile(filename)); 48 copyFile(filename, path); 49 } 50 51 Json fetchPackageRecipe(string packageId, Dependency dep, bool pre_release) 52 { 53 import std.array : split; 54 import std.path : stripExtension; 55 import dub.internal.utils : packageInfoFileFromZip; 56 import dub.recipe.io : parsePackageRecipe; 57 import dub.recipe.json : toJson; 58 59 auto filePath = bestPackageFile(packageId, dep, pre_release); 60 string packageFileName; 61 string packageFileContent = packageInfoFileFromZip(filePath, packageFileName); 62 auto recipe = parsePackageRecipe(packageFileContent, packageFileName); 63 Json json = toJson(recipe); 64 json["version"] = filePath.toNativeString().split("-")[$-1].stripExtension(); 65 return json; 66 } 67 68 SearchResult[] searchPackages(string query) 69 { 70 // TODO! 71 return null; 72 } 73 74 private NativePath bestPackageFile(string packageId, Dependency dep, bool pre_release) 75 { 76 import std.algorithm.iteration : filter; 77 import std.array : array; 78 import std.format : format; 79 NativePath toPath(Version ver) { 80 return m_path ~ (packageId ~ "-" ~ ver.toString() ~ ".zip"); 81 } 82 auto versions = getVersions(packageId).filter!(v => dep.matches(v)).array; 83 enforce(versions.length > 0, format("No package %s found matching %s", packageId, dep)); 84 foreach_reverse (ver; versions) { 85 if (pre_release || !ver.isPreRelease) 86 return toPath(ver); 87 } 88 return toPath(versions[$-1]); 89 } 90 }