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: format; 15 16 // searches the local system for valid D compilers 17 private string findDCompiler() 18 { 19 string dCompiler = "dmd"; 20 foreach (compiler; ["dmd", "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(); 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 args = ["dub", "-q", "--compiler=" ~ dCompiler, "--single", tmpfile.name]; 89 res = args.execute; 90 } 91 else 92 { 93 args = [dCompiler]; 94 args ~= input.args.split(" "); 95 args ~= "-color=" ~ (input.color ? "on " : "off "); 96 args ~= "-run"; 97 args ~= tmpfile.name; 98 99 // DMD requires a TTY for colored output 100 auto env = [ 101 "TERM": "dtour" 102 ]; 103 auto fakeTty = ` 104 faketty () { script -qfc "$(printf "%q " "$@")" /dev/null ; } 105 faketty ` ~ args.join(" ") ~ ` | cat | sed 's/\r$//'`; 106 107 res = fakeTty.executeShell(env); 108 } 109 result.success = res.status == 0; 110 result.output = res.output; 111 }); 112 113 while (task.running) 114 sleep(10.msecs); 115 116 return result; 117 } 118 119 Package[] installedPackages() 120 { 121 return null; 122 } 123 }