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 auto res = pipes.pid.wait; 38 context.log("%s exit %s".format(pid, res)); 39 context.logExec("%s exit %s".format(pid, res)); 40 }catch(Throwable t) 41 writeln(t); 42 }; 43 task(dg).executeInNewThread; 44 } 45 46 47 void openFile(string context, string path){ 48 context.openPath(path, "file"); 49 } 50 51 52 void openDir(string context, string path){ 53 context.openPath(path, "directory"); 54 } 55 56 57 void openPath(string context, string path, string type){ 58 auto command = `exo-open "%s" || xdg-open "%s"`.format(path,path); 59 context.execute(type, path, command); 60 } 61 62 63 string[] bangSplit(string text){ 64 return text.split(regex(`(?<!\\)\!`)).map!`a.replace("\\!", "!")`.array; 65 } 66 67 string bangJoin(string[] parts){ 68 return parts.map!`a.replace("!", "\\!")`.join("!"); 69 } 70 71 72 string formatExec(long pid, string type, string serialized, string parameter){ 73 return "%s exec %s!%s!%s".format(pid, type, serialized, parameter); 74 } 75 76 77 string unixEscape(string path){ 78 return path 79 .replace(" ", "\\ ") 80 .replace("(", "\\(") 81 .replace(")", "\\)"); 82 } 83 84 string unixClean(string path){ 85 return path 86 .replace("\\ ", " ") 87 .replace("\\(", "(") 88 .replace("\\)", ")"); 89 } 90 91 92 __gshared private Mutex logMutex; 93 94 shared static this(){ 95 logMutex = new Mutex; 96 } 97 98 void log(string context, string text){ 99 synchronized(logMutex){ 100 auto path = context ~ ".log"; 101 if(path.exists) 102 path.append(text ~ '\n'); 103 else 104 std.file.write(path, text ~ '\n'); 105 } 106 } 107 108 void logExec(string context, string text){ 109 context.log(text); 110 synchronized(logMutex){ 111 auto path = context ~ ".exec"; 112 if(path.exists) 113 path.append(text ~ '\n'); 114 else 115 std.file.write(path, text ~ '\n'); 116 } 117 } 118