1 module exec.stupidlocal; 2 3 import exec.iexecprovider; 4 5 import vibe.core.core: sleep, runTask; 6 import core.time : msecs; 7 import vibe.core.log : logInfo; 8 9 import std.process; 10 import std.typecons: Tuple; 11 import std.file: exists, remove, tempDir; 12 import std.stdio: File; 13 import std.random: uniform; 14 import std..string: stripRight, format; 15 16 // searches the local system for valid D compilers 17 private string findDCompiler() 18 { 19 string dCompiler = "dmd"; 20 foreach (compiler; ["dmd", "ldmd", "ldmd2", "gdmd"]) 21 { 22 try { 23 if (execute([compiler, "--version"]).status == 0) 24 { 25 dCompiler = compiler; 26 break; 27 } 28 } catch (ProcessException) {} 29 } 30 return dCompiler; 31 } 32 33 /++ 34 Stupid local executor which just runs rdmd and passes the source to it 35 and outputs the executes binary's output. 36 37 Warning: 38 UNSAFE BECUASE CODE IS RUN UNFILTERED AND NOT IN A SANDBOX 39 +/ 40 class StupidLocal: IExecProvider 41 { 42 string dCompiler = "dmd"; 43 this() { 44 dCompiler = findDCompiler(); 45 logInfo("Selected %s as D compiler", dCompiler); 46 } 47 48 private File getTempFile() 49 { 50 auto tempdir = tempDir().stripRight("/"); // dub has issues with // in path 51 52 static string randomName() 53 { 54 enum Length = 10; 55 char[Length] res; 56 foreach (ref c; res) { 57 c = cast(char)('a' + uniform(0, 'z'-'a')); 58 } 59 return res.idup; 60 } 61 62 string tempname; 63 do { 64 tempname = "%s/temp_dlang_tour_%s.d".format(tempdir, randomName()); 65 } while (exists(tempname)); 66 return File(tempname, "wb"); 67 } 68 69 Tuple!(string, "output", bool, "success") compileAndExecute(RunInput input) 70 { 71 import std.array : join, split; 72 import std.algorithm.searching : canFind; 73 typeof(return) result; 74 auto task = runTask(() { 75 auto tmpfile = getTempFile(); 76 scope(exit) tmpfile.name.remove; 77 78 tmpfile.write(input.source); 79 tmpfile.close(); 80 81 const isDub = input.source.canFind("dub.sdl", "dub.json"); 82 string[] args; 83 84 typeof(args.execute) res; 85 // support execution of dub single file packages 86 if (isDub) 87 { 88 string dubCompiler; 89 switch (dCompiler) 90 { 91 case "dmd": 92 dubCompiler = "dmd"; 93 break; 94 case "ldmd": 95 dubCompiler = "ldc"; 96 break; 97 case "ldmd2": 98 dubCompiler = "ldc2"; 99 break; 100 case "gdmd", "gdmd2": 101 dubCompiler = "gdc"; 102 break; 103 default: 104 assert(0, "Unknown compiler found."); 105 } 106 107 args = ["dub", "-q", "--compiler=" ~ dubCompiler, "--single", tmpfile.name]; 108 res = args.execute; 109 } 110 else 111 { 112 args = [dCompiler]; 113 args ~= input.args.split(" "); 114 args ~= "-color=" ~ (input.color ? "on " : "off "); 115 args ~= "-run"; 116 args ~= tmpfile.name; 117 args ~= input.runtimeArgs.split(" "); 118 119 // DMD requires a TTY for colored output 120 auto env = [ 121 "TERM": "dtour" 122 ]; 123 auto fakeTty = ` 124 faketty () { script -qfc "$(printf "%q " "$@")" /dev/null ; } 125 faketty ` ~ args.join(" ") ~ ` | cat | sed 's/\r$//'`; 126 127 res = fakeTty.executeShell(env); 128 } 129 result.success = res.status == 0; 130 result.output = res.output; 131 }); 132 133 while (task.running) 134 sleep(10.msecs); 135 136 return result; 137 } 138 139 Package[] installedPackages() 140 { 141 return null; 142 } 143 }