1 module api.proc; 2 3 import lumars, std.process, std.typecons, std.format; 4 5 struct ShellResult 6 { 7 string output; 8 int status; 9 } 10 11 void registerProcApi(LuaState* lua) 12 { 13 lua.register!( 14 "execute", doExec!(execute, pipeProcess), 15 "executeShell", doExec!(executeShell, pipeShell), 16 "executeEnforceZero", (LuaState* lua, string command, LuaValue[] args) { 17 auto t = doExec!(executeShell, pipeShell)(lua, command, args); 18 if(t.status != 0) 19 throw new Exception("Command failed with status %s: %s".format(t.status, t.output)); 20 return t; 21 }, 22 "userShell", userShell 23 )("sh.proc"); 24 25 lua.doString(` 26 local shmeta = {} 27 28 -- Enable sh:COMMAND shorthand 29 function shmeta.__index(_,idx) 30 return function(...) 31 local args = {...} 32 if #args == 0 or args[1] ~= sh then 33 error("Please use sh:NAME syntax instead of sh.NAME syntax when using the sh.proc.execute shorthand") 34 end 35 table.remove(args, 1) 36 37 local ret = { 38 __lumarsh_pipe_to_stdin = sh.proc.executeEnforceZero(idx, args).output 39 } 40 ret.output = ret.__lumarsh_pipe_to_stdin 41 setmetatable(ret, { 42 __tostring = function(t) 43 return t.output 44 end, 45 46 __index = function(me,idx) 47 return function(_,...) 48 return sh[idx](sh, me, ...) 49 end 50 end 51 }) 52 53 return ret 54 end 55 end 56 57 sh = setmetatable(sh, shmeta) 58 `); 59 } 60 61 private: 62 63 ShellResult doExec(alias Func, alias PipeFunc)(LuaState* lua, string command, LuaValue[] args) 64 { 65 import std.conv; 66 string[] actualArgs; 67 string pipeData; 68 69 void put(LuaValue arg) 70 { 71 if(arg.isText) 72 actualArgs ~= arg.textValue; 73 else if(arg.isNumber) 74 actualArgs ~= arg.numberValue.to!string; 75 else if(arg.isBoolean) 76 actualArgs ~= arg.booleanValue.to!string; 77 else if(arg.isNil) 78 actualArgs ~= "nil"; 79 else if(arg.isTable) 80 { 81 auto t = &arg.tableValue(); 82 t.pushElement("__lumarsh_pipe_to_stdin"); 83 scope(exit) lua.pop(1); 84 if(lua.type(-1) != LuaValue.Kind.nil) 85 pipeData = lua.get!string(-1); 86 else 87 { 88 t.pairs!(string, LuaValue, (key, value){ 89 if(value.isBoolean) 90 { 91 if(value.booleanValue) 92 actualArgs ~= (key.length == 1 ? "-" : "--")~key; 93 else 94 actualArgs ~= (key.length == 1 ? "-" : "--")~key~"=false"; 95 } 96 else 97 { 98 put(value); 99 actualArgs[$-1] = (key.length == 1 ? "-" : "--")~key~"="~actualArgs[$-1]; 100 } 101 }); 102 } 103 } 104 else 105 actualArgs ~= "<FUNCTION(probably)>"; 106 } 107 108 foreach(arg; args) 109 put(arg); 110 111 const commString = escapeShellCommand(command~actualArgs); 112 113 if(!pipeData) 114 { 115 const res = Func(commString); 116 return ShellResult(res.output, res.status); 117 } 118 else 119 { 120 const addition = escapeShellCommand("echo", pipeData); 121 const res = Func(addition~" | "~commString, null, Config(Config.Flags.retainStderr | Config.Flags.retainStdout)); 122 return ShellResult(res.output, res.status); 123 } 124 }