1 module reggae.dub.interop.fetch; 2 3 4 import reggae.from; 5 6 7 package void dubFetch(O)( 8 auto ref O output, 9 ref from!"reggae.dub.interop.dublib".Dub dub, 10 in from!"reggae.options".Options options, 11 in string dubSelectionsJson) 12 @trusted 13 { 14 import reggae.dub.interop.exec: callDub, dubEnvArgs; 15 import reggae.io: log; 16 import std.array: replace; 17 import std.json: parseJSON, JSONType; 18 import std.file: readText; 19 import std.parallelism: parallel; 20 21 const(VersionedPackage)[] pkgsToFetch; 22 23 const json = parseJSON(readText(dubSelectionsJson)); 24 25 foreach(dubPackageName, versionJson; json["versions"].object) { 26 27 // skip the ones with a defined path 28 if(versionJson.type != JSONType..string) continue; 29 30 // versions are usually `==1.2.3`, so strip the equals sign 31 const version_ = versionJson.str.replace("==", ""); 32 const pkg = VersionedPackage(dubPackageName, version_); 33 34 if(needDubFetch(dub, pkg)) pkgsToFetch ~= pkg; 35 } 36 37 output.log("Fetching dub packages"); 38 foreach(pkg; pkgsToFetch.parallel) { 39 const cmd = ["dub", "fetch", pkg.name, "--version=" ~ pkg.version_] ~ dubEnvArgs; 40 callDub(output, options, cmd); 41 } 42 43 dub.reinit; 44 } 45 46 47 private struct VersionedPackage { 48 string name; 49 string version_; 50 } 51 52 53 private bool needDubFetch( 54 ref from!"reggae.dub.interop.dublib".Dub dub, 55 in VersionedPackage pkg) 56 @safe 57 { 58 // first check the file system explicitly 59 if(pkgExistsOnFS(pkg)) return false; 60 // next ask dub (this is slower) 61 if(dub.getPackage(pkg.name, pkg.version_)) return false; 62 63 return true; 64 } 65 66 67 // dub fetch can sometimes take >10s (!) despite the package already being 68 // on disk 69 private bool pkgExistsOnFS(in VersionedPackage pkg) @safe { 70 import reggae.path: dubPackagesDir; 71 import std.path: buildPath; 72 import std.file: exists; 73 import std.string: replace; 74 75 // Some versions include a `+` and that becomes `_` in the path 76 const version_ = pkg.version_.replace("+", "_"); 77 78 return buildPath( 79 dubPackagesDir, 80 pkg.name ~ "-" ~ version_, 81 pkg.name ~ ".lock" 82 ).exists; 83 }