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.io: log; 15 import dub.dub: Dub, FetchOptions; 16 import dub.dependency: Dependency; 17 import dub.project: PlacementLocation; 18 import std.array: replace; 19 import std.json: parseJSON, JSONType; 20 import std.file: readText, getcwd; 21 import std.parallelism: parallel; 22 23 const(VersionedPackage)[] pkgsToFetch; 24 25 const json = parseJSON(readText(dubSelectionsJson)); 26 27 foreach(dubPackageName, versionJson; json["versions"].object) { 28 29 // skip the ones with a defined path 30 if(versionJson.type != JSONType..string) continue; 31 32 const version_ = versionJson.str.replace("==", ""); 33 const pkg = VersionedPackage(dubPackageName, version_); 34 35 if(needDubFetch(dub, pkg)) pkgsToFetch ~= pkg; 36 } 37 38 output.log("Creating dub object"); 39 auto dubObj = new Dub(getcwd()); 40 41 42 output.log("Fetching dub packages"); 43 foreach(pkg; pkgsToFetch.parallel) { 44 dubObj.fetch( 45 pkg.name, 46 Dependency("==" ~ pkg.version_), 47 PlacementLocation.user, 48 FetchOptions.none, 49 ); 50 } 51 output.log("Fetched dub packages"); 52 53 dub.reinit; 54 } 55 56 57 private struct VersionedPackage { 58 string name; 59 string version_; 60 } 61 62 63 private bool needDubFetch( 64 ref from!"reggae.dub.interop.dublib".Dub dub, 65 in VersionedPackage pkg) 66 @safe 67 { 68 // first check the file system explicitly 69 if(pkgExistsOnFS(pkg)) return false; 70 // next ask dub (this is slower) 71 if(dub.getPackage(pkg.name, pkg.version_)) return false; 72 73 return true; 74 } 75 76 77 // dub fetch can sometimes take >10s (!) despite the package already being 78 // on disk 79 private bool pkgExistsOnFS(in VersionedPackage pkg) @safe { 80 import reggae.path: buildPath, dubPackagesDir; 81 import std.file: exists; 82 import std..string: replace; 83 84 // Some versions include a `+` and that becomes `_` in the path 85 const version_ = pkg.version_.replace("+", "_"); 86 87 return buildPath( 88 dubPackagesDir, 89 pkg.name ~ "-" ~ version_, 90 pkg.name ~ ".lock" 91 ).exists; 92 }