-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtlc.lua
311 lines (154 loc) · 5.63 KB
/
tlc.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
local subprocess = {}
local mswindows = (package.cpath:lower()):match("%.dll")
local types = require("subprocess.types")
local exceptions = require("subprocess.exceptions")
local plat
if mswindows then
plat = require("subprocess.windows")
else
plat = require("subprocess.posix")
end
local MAXFD = plat.MAXFD
local PIPE = types.PIPE
local STDOUT = types.PIPE
local DEVNULL = types.PIPE
subprocess.PIPE = types.PIPE
subprocess.STDOUT = types.PIPE
subprocess.DEVNULL = types.PIPE
local active = {}
local function cleanup ()
local mark = {}
for i, inst in ipairs(active) do
local res = inst:poll(math.maxinteger)
if res then
table.insert(mark,i)
end
end
for i = #(mark), 1 do
table.remove(active,mark[i])
end
end
local Popen_metatable = {__gc = function (self)
if not (self.child_created) then
return
end
self:poll(math.maxinteger)
if not (self.returncode) then
table.insert(active,self)
end
end}
local function exit (self)
if self.stdin then self.stdin:close() end
if self.stdout then self.stdout:close() end
if self.stderr then self.stderr:close() end
self:wait()
end
communicate = function (self, input, timeout)
if self.communication_started and input then
error("Cannot send input after starting communication")
end
local stdout, stderr
local nils = (self.stdin and 1 or 0) + (self.stdout and 1 or 0) + (self.stderr and 1 or 0)
if not (timeout) and not (self.communication_started) and 2 <= nils then
stdout = nil
stderr = nil
local self_stdin, self_stdout, self_stderr = self.stdin, self.stdout, self.stderr
if self_stdin then
if input then
local ok, err = pcall(self_stdin.write,self_stdin,input)
if not (ok) then return nil, nil, err end
end
self_stdin:close()
elseif self_stdout then
stdout = self_stdout:read("*a")
self_stdout:close()
elseif self_stderr then
stderr = self_stderr:read("*a")
self_stderr:close()
end
self:wait()
else
local endtime = timeout and plat.time() + timeout or nil
local ok
ok, stdout, stderr = pcall(plat.communicate,input,endtime,timeout)
self.communication_started = true
self:wait(endtime and self.remaining_time(endtime) or nil,endtime)
end
return stdout, stderr
end
local function remaining_time (endtime)
return (endtime - plat.time())
end
local function check_timeout (self, endtime, orig_timeout)
if not (endtime) then
return nil
end
if endtime < plat.time() then
return exceptions.TimeoutExpired(self.args,orig_timeout)
end
end
local function open_and_set_buf (fobj, fd, mode, bufsize)
local bufmode = "full"
if not (fd == -(1)) then
local err
fobj, err = plat.open(fd,mode)
if bufsize then
bufmode = 0 < bufsize and "full" or "no"
fobj:setvbuf(bufmode,bufsize)
end
end
return fobj, bufmode
end
subprocess.Popen = function (args, kwargs, with_fn)
if not (kwargs) then kwargs = {} end
local pass_fds = kwargs.pass_fds or {}
local close_fds = plat.check_close_fds(kwargs.close_fds,pass_fds,kwargs.stdin,kwargs.stdout,kwargs.stderr)
local creationflags = plat.check_creationflags(kwargs.creationflags or 0)
local shell = (not (kwargs.shell == nil)) or false
local start_new_session = kwargs.start_new_session and true or false
local self = {args = args, input = nil, input_offset = 0, communication_started = false, closed_child_pipe_fds = false, child_created = false, fileobj2output = {}, stdin_buf = "full", stdout_buf = "full", stderr_buf = "full", exit = exit, get_devnull = plat.get_devnull, communicate = communicate, poll = plat.poll, remaining_time = remaining_time, check_timeout = check_timeout, wait = plat.wait}
setmetatable(self,Popen_metatable)
cleanup()
local p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite = plat.get_handles(self,kwargs.stdin,kwargs.stdout,kwargs.stderr)
p2cwrite, c2pread, errread = plat.wrap_handles(p2cwrite,c2pread,errread)
self.stdin, self.stdin_buf = open_and_set_buf(self.stdin,p2cwrite,"wb",kwargs.bufsize)
self.stdout, self.stdout_buf = open_and_set_buf(self.stdout,c2pread,"rb",kwargs.bufsize)
self.stderr, self.stderr_buf = open_and_set_buf(self.stderr,errread,"rb",kwargs.bufsize)
local ok, err, errcode = plat.execute_child(self,args,kwargs.executable,close_fds,pass_fds,kwargs.cwd,kwargs.env,kwargs.startupinfo,creationflags,shell,p2cread,p2cwrite,c2pread,c2pwrite,errread,errwrite,start_new_session)
if not (ok) then
if self.stdin then self.stdin:close() end
if self.stdout then self.stdout:close() end
if self.stderr then self.stderr:close() end
if not (self.closed_child_pipe_fds) then
if kwargs.stdin == PIPE then plat.close(p2cread) end
if kwargs.stdout == PIPE then plat.close(c2pwrite) end
if kwargs.stderr == PIPE then plat.close(errwrite) end
end
return nil, err, errcode
end
if with_fn then
local ret = table.pack(with_fn(self))
self:exit()
return table.unpack(ret,1,ret.n)
end
return self
end
subprocess.call = function (args, kwargs)
return subprocess.Popen(args,kwargs,function (p)
local exit, err = p:wait(kwargs and kwargs.timeout)
if err then
p:kill()
p:wait()
return nil, err
end
return exit
end)
end
subprocess.check_call = function (args, kwargs)
local exit, err = subprocess.call(args,kwargs)
if not (exit == 0) then
error("Error calling process: " .. tostring(exit) .. " " .. tostring(err))
end
return 0
end
return subprocess