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
local path = require("tools.lua.path")
local process = {}
local function parse_elapsed_seconds(s)
if not s then return nil end
local parts = {}
for part in tostring(s):gmatch("[^:]+") do
parts[#parts + 1] = tonumber(part)
end
if #parts == 3 then
return parts[1] * 3600 + parts[2] * 60 + parts[3]
elseif #parts == 2 then
return parts[1] * 60 + parts[2]
elseif #parts == 1 then
return parts[1]
end
return nil
end
local function normalize_status(a, b, c)
if type(a) == "boolean" then
return a and 0 or (c or 1)
end
if type(a) == "number" then
if a == 0 then return 0 end
return a
end
return 1
end
function process.capture(cmd)
local f = assert(io.popen(cmd))
local out = f:read("*a")
local a, b, c = f:close()
return out, normalize_status(a, b, c)
end
function process.run(cmd)
local a, b, c = os.execute(cmd)
return normalize_status(a, b, c)
end
function process.with_cwd(root, cmd)
if path.is_windows then
return "cd /d " .. path.shell_quote(root) .. " && " .. cmd
end
return "cd " .. path.shell_quote(root) .. " && " .. cmd
end
function process.env_prefix(env)
local keys = {}
for k, _ in pairs(env or {}) do keys[#keys + 1] = k end
table.sort(keys)
if #keys == 0 then return "" end
if path.is_windows then
local parts = {}
for _, k in ipairs(keys) do
parts[#parts + 1] = "set " .. k .. "=" .. tostring(env[k]) .. "&&"
end
return table.concat(parts, " ") .. " "
end
local parts = {}
for _, k in ipairs(keys) do
parts[#parts + 1] = k .. "=" .. path.shell_quote(env[k])
end
return table.concat(parts, " ") .. " "
end
function process.command_exists(name)
local cmd
if path.is_windows then
cmd = "where " .. path.shell_quote(name) .. " >NUL 2>NUL"
else
cmd = "command -v " .. path.shell_quote(name) .. " >/dev/null 2>&1"
end
return process.run(cmd) == 0
end
function process.uname()
if path.is_windows then return "Windows" end
local out = process.capture("uname -s 2>/dev/null")
return (out or ""):match("([^\r\n]+)") or "Unix"
end
function process.read_time_v(pathname)
if not pathname or not path.exists(pathname) then return {} end
local text = path.read_file(pathname)
local out = {}
out.user_seconds = tonumber(text:match("User time %(seconds%):%s*([%d%.]+)"))
out.system_seconds = tonumber(text:match("System time %(seconds%):%s*([%d%.]+)"))
out.max_rss_kib = tonumber(text:match("Maximum resident set size %(kbytes%):%s*(%d+)"))
out.elapsed = text:match("Elapsed %(wall clock%) time.-%):%s*([^\n]+)")
out.elapsed_seconds = parse_elapsed_seconds(out.elapsed)
if not out.max_rss_kib then
local rss_bytes = tonumber(text:match("maximum resident set size:%s*(%d+)"))
if rss_bytes then
out.max_rss_kib = math.floor(rss_bytes / 1024)
end
end
return out
end
process.parse_elapsed_seconds = parse_elapsed_seconds
return process