1 module ws.context; 2 3 4 import 5 core.sync.mutex, 6 std.string, 7 std.stdio, 8 std.process, 9 std.parallelism, 10 std.regex, 11 std.algorithm, 12 std.array, 13 std.file; 14 15 16 void execute(string context, string type, string serialized, string command, string parameter=""){ 17 auto dg = { 18 try{ 19 string command = (command.strip ~ ' ' ~ parameter).strip; 20 if(!serialized.length) 21 serialized = command; 22 "running: \"%s\" in %s".format(command, context).writeln; 23 auto pipes = pipeShell(command); 24 auto pid = pipes.pid.processID; 25 context.logExec(formatExec(pid, type, serialized, parameter)); 26 auto reader = task({ 27 foreach(line; pipes.stdout.byLine){ 28 if(line.length) 29 context.log("%s stdout %s".format(pid, line)); 30 } 31 }); 32 reader.executeInNewThread; 33 foreach(line; pipes.stderr.byLine){ 34 if(line.length) 35 context.log("%s stderr %s".format(pid, line)); 36 } 37 reader.yieldForce; 38 auto res = pipes.pid.wait; 39 context.log("%s exit %s".format(pid, res)); 40 context.logExec("%s exit %s".format(pid, res)); 41 }catch(Throwable t) 42 writeln(t); 43 }; 44 task(dg).executeInNewThread; 45 } 46 47 48 void openFile(string context, string path){ 49 context.openPath(path, "file"); 50 } 51 52 53 void openDir(string context, string path){ 54 context.openPath(path, "directory"); 55 } 56 57 58 void openPath(string context, string path, string type){ 59 auto command = `exo-open "%s" || xdg-open "%s"`.format(path,path); 60 context.execute(type, path, command); 61 } 62 63 64 string[] bangSplit(string text){ 65 return text.split(regex(`(?<!\\)\!`)).map!`a.replace("\\!", "!")`.array; 66 } 67 68 string bangJoin(string[] parts){ 69 return parts.map!`a.replace("!", "\\!")`.join("!"); 70 } 71 72 73 string formatExec(long pid, string type, string serialized, string parameter){ 74 return "%s exec %s!%s!%s".format(pid, type, serialized, parameter); 75 } 76 77 78 string unixEscape(string path){ 79 return path 80 .replace(" ", "\\ ") 81 .replace("(", "\\(") 82 .replace(")", "\\)"); 83 } 84 85 string unixClean(string path){ 86 return path 87 .replace("\\ ", " ") 88 .replace("\\(", "(") 89 .replace("\\)", ")"); 90 } 91 92 93 __gshared private Mutex logMutex; 94 95 shared static this(){ 96 logMutex = new Mutex; 97 } 98 99 void log(string context, string text){ 100 synchronized(logMutex){ 101 auto path = context ~ ".log"; 102 if(path.exists) 103 path.append(text ~ '\n'); 104 else 105 std.file.write(path, text ~ '\n'); 106 } 107 } 108 109 void logExec(string context, string text){ 110 context.log(text); 111 synchronized(logMutex){ 112 auto path = context ~ ".exec"; 113 if(path.exists) 114 path.append(text ~ '\n'); 115 else 116 std.file.write(path, text ~ '\n'); 117 } 118 } 119