178 lines
5.1 KiB
Lua
178 lines
5.1 KiB
Lua
local _M = {}
|
|
|
|
_M.isWin = package.config:sub(1, 1) == '\\'
|
|
|
|
--- Echo a command, run it, and return the file handle
|
|
--- @param cmd string The command to execute
|
|
--- @param workdir string The working directory
|
|
--- @param env table The environment variables
|
|
function _M.popenCmd(cmd, workdir, env)
|
|
local cmdParts = {}
|
|
if workdir ~= nil then
|
|
if _M.isWin then
|
|
table.insert(cmdParts, 'cd /d "'..workdir..'" &&')
|
|
else
|
|
table.insert(cmdParts, 'cd "'..workdir..'" &&')
|
|
end
|
|
end
|
|
if env ~= nil then
|
|
for k,v in pairs(env) do
|
|
if _M.isWin then
|
|
table.insert(cmdParts, string.format("set %s=%s&&", k, v))
|
|
else
|
|
table.insert(cmdParts, string.format("%s='%s'", k, v))
|
|
end
|
|
end
|
|
end
|
|
table.insert(cmdParts, cmd)
|
|
local fullCmd = table.concat(cmdParts, " ")
|
|
print(fullCmd)
|
|
|
|
--[[ local dummy = "/dev/null"
|
|
if isWin then
|
|
dummy = "NUL"
|
|
end
|
|
return io.open(dummy, 'r') ]]
|
|
return io.popen(fullCmd, 'r')
|
|
end
|
|
|
|
--- Echo a command, run it, and handle any errors
|
|
--- @return string string The stdout
|
|
function _M.doCmd(...)
|
|
return _M.scrapeCmd('*a', ...)
|
|
end
|
|
|
|
--- Create a directory
|
|
--- @return string dir The directory to create
|
|
function _M.mkdir(dir)
|
|
if _M.isWin then
|
|
return _M.doCmd('if not exist "'..dir..'" mkdir "'..dir..'"')
|
|
else
|
|
return _M.doCmd("mkdir '"..dir.."'")
|
|
end
|
|
end
|
|
|
|
--- Run a command and get the output
|
|
--- @param formats table|string|number List or single io.read() specifier
|
|
--- @return table table List of results based on read specifiers
|
|
function _M.scrapeCmd(formats, ...)
|
|
local poppet = _M.popenCmd(...)
|
|
local outputs = nil
|
|
if type(formats) ~= 'table' then
|
|
outputs = poppet:read(formats)
|
|
else
|
|
outputs = {}
|
|
for i=1,#formats,1 do
|
|
table.insert(outputs, poppet:read(formats[i]))
|
|
end
|
|
end
|
|
_M.closeCmd(poppet)
|
|
return outputs
|
|
end
|
|
|
|
--- Check the command's exit code and throw a Lua error if it isn't right
|
|
--- @param handle file* The handle of the command
|
|
function _M.closeCmd(handle)
|
|
local ok, state, code = handle:close()
|
|
if state ~= "exit" then
|
|
return
|
|
end
|
|
if code ~= 0 then
|
|
error("The last command failed")
|
|
end
|
|
end
|
|
|
|
function _M.waitForChange(filenames, count, wild)
|
|
if type(filenames) == 'string' then
|
|
if wild == nil then
|
|
wild = filenames
|
|
end
|
|
|
|
filenames = {filenames}
|
|
end
|
|
|
|
if count == nil then
|
|
count = #filenames
|
|
end
|
|
|
|
if _M.isWin then
|
|
local sec, usec = utime()
|
|
print(string.format('Starting watching file at %d', sec * 1000000 + usec))
|
|
|
|
local poppet = _M.popenCmd([[powershell "$filename = ']]..wild..
|
|
[[' ; $targetCount = ]]..count..[[ ; $count = 0 ; $action = { $count += 1 ; if ( $count -ge $targetCount ) { [Environment]::Exit(0) } } ; (Register-ObjectEvent (New-Object IO.FileSystemWatcher (Split-Path $filename), (Split-Path -Leaf $filename) -Property @{ IncludeSubdirectories = $false ; NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}) -EventName Changed -SourceIdentifier RunnerDataChanged -Action $action).Name ; while($true) { Start-Sleep -Seconds 5 }"]])
|
|
|
|
while poppet:read('*l'):sub(1, 17) ~= 'RunnerDataChanged' do
|
|
end
|
|
|
|
return poppet
|
|
else
|
|
local watchCmd = ''
|
|
if count == 1 then
|
|
watchCmd = [[which inotifywait >/dev/null && { inotifywait -q -e close_write ']]..filenames[1]..[[' || exit 0 ; }]]
|
|
else
|
|
watchCmd = [[bash <<'EOF'
|
|
COUNT=]]..count..[[
|
|
FILENAMES=(']]..table.concat(filenames, "' '")..[[')
|
|
declare -A SEEN
|
|
((I = 0))
|
|
set -m
|
|
which inotifywait >/dev/null
|
|
( inotifywait -q -m -e close_write "${FILENAMES[@]}" | while read LINE ; do
|
|
SEEN["$LINE"]=1
|
|
TOTAL=${#SEEN[@]}
|
|
if ((TOTAL == COUNT)) ; then
|
|
kill -s TERM 0
|
|
fi
|
|
done ) &
|
|
wait
|
|
EOF]]
|
|
end
|
|
return _M.popenCmd(watchCmd)
|
|
end
|
|
end
|
|
|
|
function _M.table_to_string(tbl)
|
|
local result = "{"
|
|
local keys = {}
|
|
for k in pairs(tbl) do
|
|
table.insert(keys, k)
|
|
end
|
|
table.sort(keys)
|
|
for _, k in ipairs(keys) do
|
|
local v = tbl[k]
|
|
if type(v) == "number" and v == 0 then
|
|
--goto continue
|
|
end
|
|
|
|
-- Check the key type (ignore any numerical keys - assume its an array)
|
|
if type(k) == "string" then
|
|
result = result.."[\""..k.."\"]".."="
|
|
end
|
|
|
|
-- Check the value type
|
|
if type(v) == "table" then
|
|
result = result.._M.table_to_string(v)
|
|
elseif type(v) == "boolean" then
|
|
result = result..tostring(v)
|
|
elseif type(v) == "number" and v >= 0 then
|
|
result = result..string.format("%x", v)
|
|
else
|
|
result = result.."\""..v.."\""
|
|
end
|
|
result = result..",\n"
|
|
::continue::
|
|
end
|
|
-- Remove leading commas from the result
|
|
if result ~= "" then
|
|
result = result:sub(1, result:len()-1)
|
|
end
|
|
return result.."}"
|
|
end
|
|
|
|
function _M.file_exists(name)
|
|
local f=io.open(name,"r")
|
|
if f~=nil then io.close(f) return true else return false end
|
|
end
|
|
|
|
return _M
|