1 /** 2 ... 3 4 Copyright: © 2012 Matthias Dondorff 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Matthias Dondorff 7 */ 8 module dub.internal.utils; 9 10 import dub.internal.std.process; 11 import dub.internal.vibecompat.core.file; 12 import dub.internal.vibecompat.core.log; 13 import dub.internal.vibecompat.data.json; 14 import dub.internal.vibecompat.inet.url; 15 import dub.version_; 16 17 // todo: cleanup imports. 18 import std.algorithm : startsWith; 19 import std.array; 20 import std.conv; 21 import std.exception; 22 import std.file; 23 import std.net.curl; 24 import std.string; 25 import std.typecons; 26 import std.zip; 27 28 29 Path getTempDir() 30 { 31 auto tmp = environment.get("TEMP"); 32 if( !tmp.length ) tmp = environment.get("TMP"); 33 if( !tmp.length ){ 34 version(Posix) tmp = "/tmp/"; 35 else tmp = "./"; 36 } 37 return Path(tmp); 38 } 39 40 bool isEmptyDir(Path p) { 41 foreach(DirEntry e; dirEntries(p.toNativeString(), SpanMode.shallow)) 42 return false; 43 return true; 44 } 45 46 Json jsonFromFile(Path file, bool silent_fail = false) { 47 if( silent_fail && !existsFile(file) ) return Json.EmptyObject; 48 auto f = openFile(file.toNativeString(), FileMode.Read); 49 scope(exit) f.close(); 50 auto text = stripUTF8Bom(cast(string)f.readAll()); 51 return parseJson(text); 52 } 53 54 Json jsonFromZip(Path zip, string filename) { 55 auto f = openFile(zip, FileMode.Read); 56 ubyte[] b = new ubyte[cast(size_t)f.size]; 57 f.rawRead(b); 58 f.close(); 59 auto archive = new ZipArchive(b); 60 auto text = stripUTF8Bom(cast(string)archive.expand(archive.directory[filename])); 61 return parseJson(text); 62 } 63 64 void writeJsonFile(Path path, Json json) 65 { 66 auto f = openFile(path, FileMode.CreateTrunc); 67 scope(exit) f.close(); 68 f.writePrettyJsonString(json); 69 } 70 71 bool isPathFromZip(string p) { 72 enforce(p.length > 0); 73 return p[$-1] == '/'; 74 } 75 76 bool existsDirectory(Path path) { 77 if( !existsFile(path) ) return false; 78 auto fi = getFileInfo(path); 79 return fi.isDirectory; 80 } 81 82 void runCommands(string[] commands, string[string] env = null) 83 { 84 foreach(cmd; commands){ 85 logDiagnostic("Running %s", cmd); 86 Pid pid; 87 if( env !is null ) pid = spawnShell(cmd, env); 88 else pid = spawnShell(cmd); 89 auto exitcode = pid.wait(); 90 enforce(exitcode == 0, "Command failed with exit code "~to!string(exitcode)); 91 } 92 } 93 94 /** 95 Downloads a file from the specified URL. 96 97 Any redirects will be followed until the actual file resource is reached or if the redirection 98 limit of 10 is reached. Note that only HTTP(S) is currently supported. 99 */ 100 void download(string url, string filename) 101 { 102 auto conn = setupHTTPClient(); 103 logDebug("Storing %s...", url); 104 std.net.curl.download(url, filename, conn); 105 } 106 /// ditto 107 void download(Url url, Path filename) 108 { 109 download(url.toString(), filename.toNativeString()); 110 } 111 /// ditto 112 char[] download(string url) 113 { 114 auto conn = setupHTTPClient(); 115 logDebug("Getting %s...", url); 116 return get(url, conn); 117 } 118 /// ditto 119 char[] download(Url url) 120 { 121 return download(url.toString()); 122 } 123 124 private HTTP setupHTTPClient() 125 { 126 auto conn = HTTP(); 127 static if( is(typeof(&conn.verifyPeer)) ) 128 conn.verifyPeer = false; 129 130 // convert version string to valid SemVer format 131 auto verstr = dubVersion; 132 if (verstr.startsWith("v")) verstr = verstr[1 .. $]; 133 auto idx = verstr.indexOf("-"); 134 if (idx >= 0) verstr = verstr[0 .. idx] ~ "+" ~ verstr[idx+1 .. $].split("-").join("."); 135 136 conn.addRequestHeader("User-Agent", "dub/"~verstr~" (std.net.curl; +https://github.com/rejectedsoftware/dub)"); 137 return conn; 138 } 139 140 private string stripUTF8Bom(string str) 141 { 142 if( str.length >= 3 && str[0 .. 3] == [0xEF, 0xBB, 0xBF] ) 143 return str[3 ..$]; 144 return str; 145 }