mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
This is an important refactor of the way documentation generation works
* Installs luarocks WITH it's executable (easy to install other rocks if necessary) * Use Lua supplied with luarocks * Create Utils/luadocumentor.bat, which works with RELATIVE PATH ! -> Everybody can generate the doc * Updated launch files accordingly
This commit is contained in:
873
Utils/luarocks/lua/luarocks/fs/lua.lua
Normal file
873
Utils/luarocks/lua/luarocks/fs/lua.lua
Normal file
@@ -0,0 +1,873 @@
|
||||
|
||||
--- Native Lua implementation of filesystem and platform abstractions,
|
||||
-- using LuaFileSystem, LZLib, MD5 and LuaCurl.
|
||||
-- module("luarocks.fs.lua")
|
||||
local fs_lua = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
|
||||
local cfg = require("luarocks.cfg")
|
||||
local dir = require("luarocks.dir")
|
||||
local util = require("luarocks.util")
|
||||
local path = require("luarocks.path")
|
||||
|
||||
local socket_ok, zip_ok, unzip_ok, lfs_ok, md5_ok, posix_ok, _
|
||||
local http, ftp, lrzip, luazip, lfs, md5, posix
|
||||
|
||||
if cfg.fs_use_modules then
|
||||
socket_ok, http = pcall(require, "socket.http")
|
||||
_, ftp = pcall(require, "socket.ftp")
|
||||
zip_ok, lrzip = pcall(require, "luarocks.tools.zip")
|
||||
unzip_ok, luazip = pcall(require, "zip"); _G.zip = nil
|
||||
lfs_ok, lfs = pcall(require, "lfs")
|
||||
md5_ok, md5 = pcall(require, "md5")
|
||||
posix_ok, posix = pcall(require, "posix")
|
||||
end
|
||||
|
||||
local patch = require("luarocks.tools.patch")
|
||||
|
||||
local dir_stack = {}
|
||||
|
||||
local dir_separator = "/"
|
||||
|
||||
--- Test is file/dir is writable.
|
||||
-- Warning: testing if a file/dir is writable does not guarantee
|
||||
-- that it will remain writable and therefore it is no replacement
|
||||
-- for checking the result of subsequent operations.
|
||||
-- @param file string: filename to test
|
||||
-- @return boolean: true if file exists, false otherwise.
|
||||
function fs_lua.is_writable(file)
|
||||
assert(file)
|
||||
file = dir.normalize(file)
|
||||
local result
|
||||
if fs.is_dir(file) then
|
||||
local file2 = dir.path(file, '.tmpluarockstestwritable')
|
||||
local fh = io.open(file2, 'wb')
|
||||
result = fh ~= nil
|
||||
if fh then fh:close() end
|
||||
os.remove(file2)
|
||||
else
|
||||
local fh = io.open(file, 'r+b')
|
||||
result = fh ~= nil
|
||||
if fh then fh:close() end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function quote_args(command, ...)
|
||||
local out = { command }
|
||||
for _, arg in ipairs({...}) do
|
||||
assert(type(arg) == "string")
|
||||
out[#out+1] = fs.Q(arg)
|
||||
end
|
||||
return table.concat(out, " ")
|
||||
end
|
||||
|
||||
--- Run the given command, quoting its arguments.
|
||||
-- The command is executed in the current directory in the dir stack.
|
||||
-- @param command string: The command to be executed. No quoting/escaping
|
||||
-- is applied.
|
||||
-- @param ... Strings containing additional arguments, which are quoted.
|
||||
-- @return boolean: true if command succeeds (status code 0), false
|
||||
-- otherwise.
|
||||
function fs_lua.execute(command, ...)
|
||||
assert(type(command) == "string")
|
||||
return fs.execute_string(quote_args(command, ...))
|
||||
end
|
||||
|
||||
--- Run the given command, quoting its arguments, silencing its output.
|
||||
-- The command is executed in the current directory in the dir stack.
|
||||
-- Silencing is omitted if 'verbose' mode is enabled.
|
||||
-- @param command string: The command to be executed. No quoting/escaping
|
||||
-- is applied.
|
||||
-- @param ... Strings containing additional arguments, which will be quoted.
|
||||
-- @return boolean: true if command succeeds (status code 0), false
|
||||
-- otherwise.
|
||||
function fs_lua.execute_quiet(command, ...)
|
||||
assert(type(command) == "string")
|
||||
if cfg.verbose then -- omit silencing output
|
||||
return fs.execute_string(quote_args(command, ...))
|
||||
else
|
||||
return fs.execute_string(fs.quiet(quote_args(command, ...)))
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if the given tool is available.
|
||||
-- The tool is executed using a flag, usually just to ask its version.
|
||||
-- @param tool_cmd string: The command to be used to check the tool's presence (e.g. hg in case of Mercurial)
|
||||
-- @param tool_name string: The actual name of the tool (e.g. Mercurial)
|
||||
-- @param arg string: The flag to pass to the tool. '--version' by default.
|
||||
function fs_lua.is_tool_available(tool_cmd, tool_name, arg)
|
||||
assert(type(tool_cmd) == "string")
|
||||
assert(type(tool_name) == "string")
|
||||
|
||||
arg = arg or "--version"
|
||||
assert(type(arg) == "string")
|
||||
|
||||
if not fs.execute_quiet(fs.Q(tool_cmd), arg) then
|
||||
local msg = "'%s' program not found. Make sure %s is installed and is available in your PATH " ..
|
||||
"(or you may want to edit the 'variables.%s' value in file '%s')"
|
||||
return nil, msg:format(tool_cmd, tool_name, tool_name:upper(), cfg.which_config().nearest)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Check the MD5 checksum for a file.
|
||||
-- @param file string: The file to be checked.
|
||||
-- @param md5sum string: The string with the expected MD5 checksum.
|
||||
-- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false + msg if not
|
||||
-- or if it could not perform the check for any reason.
|
||||
function fs_lua.check_md5(file, md5sum)
|
||||
file = dir.normalize(file)
|
||||
local computed, msg = fs.get_md5(file)
|
||||
if not computed then
|
||||
return false, msg
|
||||
end
|
||||
if computed:match("^"..md5sum) then
|
||||
return true
|
||||
else
|
||||
return false, "Mismatch MD5 hash for file "..file
|
||||
end
|
||||
end
|
||||
|
||||
--- List the contents of a directory.
|
||||
-- @param at string or nil: directory to list (will be the current
|
||||
-- directory if none is given).
|
||||
-- @return table: an array of strings with the filenames representing
|
||||
-- the contents of a directory.
|
||||
function fs_lua.list_dir(at)
|
||||
local result = {}
|
||||
for file in fs.dir(at) do
|
||||
result[#result+1] = file
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Iterate over the contents of a directory.
|
||||
-- @param at string or nil: directory to list (will be the current
|
||||
-- directory if none is given).
|
||||
-- @return function: an iterator function suitable for use with
|
||||
-- the for statement.
|
||||
function fs_lua.dir(at)
|
||||
if not at then
|
||||
at = fs.current_dir()
|
||||
end
|
||||
at = dir.normalize(at)
|
||||
if not fs.is_dir(at) then
|
||||
return function() end
|
||||
end
|
||||
return coroutine.wrap(function() fs.dir_iterator(at) end)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- LuaFileSystem functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
if lfs_ok then
|
||||
|
||||
--- Run the given command.
|
||||
-- The command is executed in the current directory in the dir stack.
|
||||
-- @param cmd string: No quoting/escaping is applied to the command.
|
||||
-- @return boolean: true if command succeeds (status code 0), false
|
||||
-- otherwise.
|
||||
function fs_lua.execute_string(cmd)
|
||||
local code = os.execute(cmd)
|
||||
return (code == 0 or code == true)
|
||||
end
|
||||
|
||||
--- Obtain current directory.
|
||||
-- Uses the module's internal dir stack.
|
||||
-- @return string: the absolute pathname of the current directory.
|
||||
function fs_lua.current_dir()
|
||||
return lfs.currentdir()
|
||||
end
|
||||
|
||||
--- Change the current directory.
|
||||
-- Uses the module's internal dir stack. This does not have exact
|
||||
-- semantics of chdir, as it does not handle errors the same way,
|
||||
-- but works well for our purposes for now.
|
||||
-- @param d string: The directory to switch to.
|
||||
function fs_lua.change_dir(d)
|
||||
table.insert(dir_stack, lfs.currentdir())
|
||||
d = dir.normalize(d)
|
||||
return lfs.chdir(d)
|
||||
end
|
||||
|
||||
--- Change directory to root.
|
||||
-- Allows leaving a directory (e.g. for deleting it) in
|
||||
-- a crossplatform way.
|
||||
function fs_lua.change_dir_to_root()
|
||||
local current = lfs.currentdir()
|
||||
if not current or current == "" then
|
||||
return false
|
||||
end
|
||||
table.insert(dir_stack, current)
|
||||
lfs.chdir("/") -- works on Windows too
|
||||
return true
|
||||
end
|
||||
|
||||
--- Change working directory to the previous in the dir stack.
|
||||
-- @return true if a pop ocurred, false if the stack was empty.
|
||||
function fs_lua.pop_dir()
|
||||
local d = table.remove(dir_stack)
|
||||
if d then
|
||||
lfs.chdir(d)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a directory if it does not already exist.
|
||||
-- If any of the higher levels in the path name do not exist
|
||||
-- too, they are created as well.
|
||||
-- @param directory string: pathname of directory to create.
|
||||
-- @return boolean or (boolean, string): true on success or (false, error message) on failure.
|
||||
function fs_lua.make_dir(directory)
|
||||
assert(type(directory) == "string")
|
||||
directory = dir.normalize(directory)
|
||||
local path = nil
|
||||
if directory:sub(2, 2) == ":" then
|
||||
path = directory:sub(1, 2)
|
||||
directory = directory:sub(4)
|
||||
else
|
||||
if directory:match("^/") then
|
||||
path = ""
|
||||
end
|
||||
end
|
||||
for d in directory:gmatch("([^"..dir.separator.."]+)"..dir.separator.."*") do
|
||||
path = path and path .. dir.separator .. d or d
|
||||
local mode = lfs.attributes(path, "mode")
|
||||
if not mode then
|
||||
local ok, err = lfs.mkdir(path)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
ok, err = fs.chmod(path, cfg.perm_exec)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
elseif mode ~= "directory" then
|
||||
return false, path.." is not a directory"
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param d string: pathname of directory to remove.
|
||||
function fs_lua.remove_dir_if_empty(d)
|
||||
assert(d)
|
||||
d = dir.normalize(d)
|
||||
lfs.rmdir(d)
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param d string: pathname of directory to remove.
|
||||
function fs_lua.remove_dir_tree_if_empty(d)
|
||||
assert(d)
|
||||
d = dir.normalize(d)
|
||||
for i=1,10 do
|
||||
lfs.rmdir(d)
|
||||
d = dir.dir_name(d)
|
||||
end
|
||||
end
|
||||
|
||||
--- Copy a file.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @param perms string or nil: Permissions for destination file,
|
||||
-- or nil to use the source filename permissions
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function fs_lua.copy(src, dest, perms)
|
||||
assert(src and dest)
|
||||
src = dir.normalize(src)
|
||||
dest = dir.normalize(dest)
|
||||
local destmode = lfs.attributes(dest, "mode")
|
||||
if destmode == "directory" then
|
||||
dest = dir.path(dest, dir.base_name(src))
|
||||
end
|
||||
if not perms then perms = fs.get_permissions(src) end
|
||||
local src_h, err = io.open(src, "rb")
|
||||
if not src_h then return nil, err end
|
||||
local dest_h, err = io.open(dest, "w+b")
|
||||
if not dest_h then src_h:close() return nil, err end
|
||||
while true do
|
||||
local block = src_h:read(8192)
|
||||
if not block then break end
|
||||
dest_h:write(block)
|
||||
end
|
||||
src_h:close()
|
||||
dest_h:close()
|
||||
fs.chmod(dest, perms)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Implementation function for recursive copy of directory contents.
|
||||
-- Assumes paths are normalized.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @param perms string or nil: Optional permissions.
|
||||
-- If not given, permissions of the source are copied over to the destination.
|
||||
-- @return boolean or (boolean, string): true on success, false on failure
|
||||
local function recursive_copy(src, dest, perms)
|
||||
local srcmode = lfs.attributes(src, "mode")
|
||||
|
||||
if srcmode == "file" then
|
||||
local ok = fs.copy(src, dest, perms)
|
||||
if not ok then return false end
|
||||
elseif srcmode == "directory" then
|
||||
local subdir = dir.path(dest, dir.base_name(src))
|
||||
local ok, err = fs.make_dir(subdir)
|
||||
if not ok then return nil, err end
|
||||
for file in lfs.dir(src) do
|
||||
if file ~= "." and file ~= ".." then
|
||||
local ok = recursive_copy(dir.path(src, file), subdir, perms)
|
||||
if not ok then return false end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Recursively copy the contents of a directory.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @param perms string or nil: Optional permissions.
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function fs_lua.copy_contents(src, dest, perms)
|
||||
assert(src and dest)
|
||||
src = dir.normalize(src)
|
||||
dest = dir.normalize(dest)
|
||||
assert(lfs.attributes(src, "mode") == "directory")
|
||||
|
||||
for file in lfs.dir(src) do
|
||||
if file ~= "." and file ~= ".." then
|
||||
local ok = recursive_copy(dir.path(src, file), dest, perms)
|
||||
if not ok then
|
||||
return false, "Failed copying "..src.." to "..dest
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Implementation function for recursive removal of directories.
|
||||
-- Assumes paths are normalized.
|
||||
-- @param name string: Pathname of file
|
||||
-- @return boolean or (boolean, string): true on success,
|
||||
-- or nil and an error message on failure.
|
||||
local function recursive_delete(name)
|
||||
local ok = os.remove(name)
|
||||
if ok then return true end
|
||||
local pok, ok, err = pcall(function()
|
||||
for file in lfs.dir(name) do
|
||||
if file ~= "." and file ~= ".." then
|
||||
local ok, err = recursive_delete(dir.path(name, file))
|
||||
if not ok then return nil, err end
|
||||
end
|
||||
end
|
||||
local ok, err = lfs.rmdir(name)
|
||||
return ok, (not ok) and err
|
||||
end)
|
||||
if pok then
|
||||
return ok, err
|
||||
else
|
||||
return pok, ok
|
||||
end
|
||||
end
|
||||
|
||||
--- Delete a file or a directory and all its contents.
|
||||
-- @param name string: Pathname of source
|
||||
-- @return nil
|
||||
function fs_lua.delete(name)
|
||||
name = dir.normalize(name)
|
||||
recursive_delete(name)
|
||||
end
|
||||
|
||||
--- Internal implementation function for fs.dir.
|
||||
-- Yields a filename on each iteration.
|
||||
-- @param at string: directory to list
|
||||
-- @return nil
|
||||
function fs_lua.dir_iterator(at)
|
||||
for file in lfs.dir(at) do
|
||||
if file ~= "." and file ~= ".." then
|
||||
coroutine.yield(file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Implementation function for recursive find.
|
||||
-- Assumes paths are normalized.
|
||||
-- @param cwd string: Current working directory in recursion.
|
||||
-- @param prefix string: Auxiliary prefix string to form pathname.
|
||||
-- @param result table: Array of strings where results are collected.
|
||||
local function recursive_find(cwd, prefix, result)
|
||||
for file in lfs.dir(cwd) do
|
||||
if file ~= "." and file ~= ".." then
|
||||
local item = prefix .. file
|
||||
table.insert(result, item)
|
||||
local pathname = dir.path(cwd, file)
|
||||
if lfs.attributes(pathname, "mode") == "directory" then
|
||||
recursive_find(pathname, item..dir_separator, result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Recursively scan the contents of a directory.
|
||||
-- @param at string or nil: directory to scan (will be the current
|
||||
-- directory if none is given).
|
||||
-- @return table: an array of strings with the filenames representing
|
||||
-- the contents of a directory.
|
||||
function fs_lua.find(at)
|
||||
assert(type(at) == "string" or not at)
|
||||
if not at then
|
||||
at = fs.current_dir()
|
||||
end
|
||||
at = dir.normalize(at)
|
||||
if not fs.is_dir(at) then
|
||||
return {}
|
||||
end
|
||||
local result = {}
|
||||
recursive_find(at, "", result)
|
||||
return result
|
||||
end
|
||||
|
||||
--- Test for existance of a file.
|
||||
-- @param file string: filename to test
|
||||
-- @return boolean: true if file exists, false otherwise.
|
||||
function fs_lua.exists(file)
|
||||
assert(file)
|
||||
file = dir.normalize(file)
|
||||
return type(lfs.attributes(file)) == "table"
|
||||
end
|
||||
|
||||
--- Test is pathname is a directory.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a directory, false otherwise.
|
||||
function fs_lua.is_dir(file)
|
||||
assert(file)
|
||||
file = dir.normalize(file)
|
||||
return lfs.attributes(file, "mode") == "directory"
|
||||
end
|
||||
|
||||
--- Test is pathname is a regular file.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a file, false otherwise.
|
||||
function fs_lua.is_file(file)
|
||||
assert(file)
|
||||
file = dir.normalize(file)
|
||||
return lfs.attributes(file, "mode") == "file"
|
||||
end
|
||||
|
||||
function fs_lua.set_time(file, time)
|
||||
file = dir.normalize(file)
|
||||
return lfs.touch(file, time)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- LuaZip functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
if zip_ok then
|
||||
|
||||
function fs_lua.zip(zipfile, ...)
|
||||
return lrzip.zip(zipfile, ...)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if unzip_ok then
|
||||
--- Uncompress files from a .zip archive.
|
||||
-- @param zipfile string: pathname of .zip archive to be extracted.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function fs_lua.unzip(zipfile)
|
||||
local zipfile, err = luazip.open(zipfile)
|
||||
if not zipfile then return nil, err end
|
||||
local files = zipfile:files()
|
||||
local file = files()
|
||||
repeat
|
||||
if file.filename:sub(#file.filename) == "/" then
|
||||
local ok, err = fs.make_dir(dir.path(fs.current_dir(), file.filename))
|
||||
if not ok then return nil, err end
|
||||
else
|
||||
local base = dir.dir_name(file.filename)
|
||||
if base ~= "" then
|
||||
base = dir.path(fs.current_dir(), base)
|
||||
if not fs.is_dir(base) then
|
||||
local ok, err = fs.make_dir(base)
|
||||
if not ok then return nil, err end
|
||||
end
|
||||
end
|
||||
local rf, err = zipfile:open(file.filename)
|
||||
if not rf then zipfile:close(); return nil, err end
|
||||
local contents = rf:read("*a")
|
||||
rf:close()
|
||||
local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb")
|
||||
if not wf then zipfile:close(); return nil, err end
|
||||
wf:write(contents)
|
||||
wf:close()
|
||||
end
|
||||
file = files()
|
||||
until not file
|
||||
zipfile:close()
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- LuaSocket functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
if socket_ok then
|
||||
|
||||
local ltn12 = require("ltn12")
|
||||
local luasec_ok, https = pcall(require, "ssl.https")
|
||||
|
||||
local redirect_protocols = {
|
||||
http = http,
|
||||
https = luasec_ok and https,
|
||||
}
|
||||
|
||||
local function request(url, method, http, loop_control)
|
||||
local result = {}
|
||||
|
||||
local proxy = cfg.http_proxy
|
||||
if type(proxy) ~= "string" then proxy = nil end
|
||||
-- LuaSocket's http.request crashes when given URLs missing the scheme part.
|
||||
if proxy and not proxy:find("://") then
|
||||
proxy = "http://" .. proxy
|
||||
end
|
||||
|
||||
if cfg.show_downloads then
|
||||
io.write(method.." "..url.." ...\n")
|
||||
end
|
||||
local dots = 0
|
||||
if cfg.connection_timeout and cfg.connection_timeout > 0 then
|
||||
http.TIMEOUT = cfg.connection_timeout
|
||||
end
|
||||
local res, status, headers, err = http.request {
|
||||
url = url,
|
||||
proxy = proxy,
|
||||
method = method,
|
||||
redirect = false,
|
||||
sink = ltn12.sink.table(result),
|
||||
step = cfg.show_downloads and function(...)
|
||||
io.write(".")
|
||||
io.flush()
|
||||
dots = dots + 1
|
||||
if dots == 70 then
|
||||
io.write("\n")
|
||||
dots = 0
|
||||
end
|
||||
return ltn12.pump.step(...)
|
||||
end,
|
||||
headers = {
|
||||
["user-agent"] = cfg.user_agent.." via LuaSocket"
|
||||
},
|
||||
}
|
||||
if cfg.show_downloads then
|
||||
io.write("\n")
|
||||
end
|
||||
if not res then
|
||||
return nil, status
|
||||
elseif status == 301 or status == 302 then
|
||||
local location = headers.location
|
||||
if location then
|
||||
local protocol, rest = dir.split_url(location)
|
||||
if redirect_protocols[protocol] then
|
||||
if not loop_control then
|
||||
loop_control = {}
|
||||
elseif loop_control[location] then
|
||||
return nil, "Redirection loop -- broken URL?"
|
||||
end
|
||||
loop_control[url] = true
|
||||
return request(location, method, redirect_protocols[protocol], loop_control)
|
||||
else
|
||||
return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support.", "https"
|
||||
end
|
||||
end
|
||||
return nil, err
|
||||
elseif status ~= 200 then
|
||||
return nil, err
|
||||
else
|
||||
return result, status, headers, err
|
||||
end
|
||||
end
|
||||
|
||||
local function http_request(url, http, cached)
|
||||
if cached then
|
||||
local tsfd = io.open(cached..".timestamp", "r")
|
||||
if tsfd then
|
||||
local timestamp = tsfd:read("*a")
|
||||
tsfd:close()
|
||||
local result, status, headers, err = request(url, "HEAD", http)
|
||||
if status == 200 and headers["last-modified"] == timestamp then
|
||||
return true
|
||||
end
|
||||
if not result then
|
||||
return nil, status, headers
|
||||
end
|
||||
end
|
||||
end
|
||||
local result, status, headers, err = request(url, "GET", http)
|
||||
if result then
|
||||
if cached and headers["last-modified"] then
|
||||
local tsfd = io.open(cached..".timestamp", "w")
|
||||
if tsfd then
|
||||
tsfd:write(headers["last-modified"])
|
||||
tsfd:close()
|
||||
end
|
||||
end
|
||||
return table.concat(result)
|
||||
else
|
||||
return nil, status, headers
|
||||
end
|
||||
end
|
||||
|
||||
local downloader_warning = false
|
||||
|
||||
--- Download a remote file.
|
||||
-- @param url string: URL to be fetched.
|
||||
-- @param filename string or nil: this function attempts to detect the
|
||||
-- resulting local filename of the remote file as the basename of the URL;
|
||||
-- if that is not correct (due to a redirection, for example), the local
|
||||
-- filename can be given explicitly as this second argument.
|
||||
-- @return (boolean, string): true and the filename on success,
|
||||
-- false and the error message on failure.
|
||||
function fs_lua.download(url, filename, cache)
|
||||
assert(type(url) == "string")
|
||||
assert(type(filename) == "string" or not filename)
|
||||
|
||||
filename = fs.absolute_name(filename or dir.base_name(url))
|
||||
|
||||
-- delegate to the configured downloader so we don't have to deal with whitelists
|
||||
if cfg.no_proxy then
|
||||
return fs.use_downloader(url, filename, cache)
|
||||
end
|
||||
|
||||
local content, err, https_err
|
||||
if util.starts_with(url, "http:") then
|
||||
content, err, https_err = http_request(url, http, cache and filename)
|
||||
elseif util.starts_with(url, "ftp:") then
|
||||
content, err = ftp.get(url)
|
||||
elseif util.starts_with(url, "https:") then
|
||||
-- skip LuaSec when proxy is enabled since it is not supported
|
||||
if luasec_ok and not cfg.https_proxy then
|
||||
content, err = http_request(url, https, cache and filename)
|
||||
else
|
||||
https_err = true
|
||||
end
|
||||
else
|
||||
err = "Unsupported protocol"
|
||||
end
|
||||
if https_err then
|
||||
if not downloader_warning then
|
||||
util.printerr("Warning: falling back to "..cfg.downloader.." - install luasec to get native HTTPS support")
|
||||
downloader_warning = true
|
||||
end
|
||||
return fs.use_downloader(url, filename, cache)
|
||||
end
|
||||
if cache and content == true then
|
||||
return true, filename
|
||||
end
|
||||
if not content then
|
||||
return false, tostring(err)
|
||||
end
|
||||
local file = io.open(filename, "wb")
|
||||
if not file then return false end
|
||||
file:write(content)
|
||||
file:close()
|
||||
return true, filename
|
||||
end
|
||||
|
||||
else --...if socket_ok == false then
|
||||
|
||||
function fs_lua.download(url, filename, cache)
|
||||
return fs.use_downloader(url, filename, cache)
|
||||
end
|
||||
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- MD5 functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
if md5_ok then
|
||||
|
||||
-- Support the interface of lmd5 by lhf in addition to md5 by Roberto
|
||||
-- and the keplerproject.
|
||||
if not md5.sumhexa and md5.digest then
|
||||
md5.sumhexa = function(msg)
|
||||
return md5.digest(msg)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the MD5 checksum for a file.
|
||||
-- @param file string: The file to be computed.
|
||||
-- @return string: The MD5 checksum or nil + error
|
||||
function fs_lua.get_md5(file)
|
||||
file = fs.absolute_name(file)
|
||||
local file_handler = io.open(file, "rb")
|
||||
if not file_handler then return nil, "Failed to open file for reading: "..file end
|
||||
local computed = md5.sumhexa(file_handler:read("*a"))
|
||||
file_handler:close()
|
||||
if computed then return computed end
|
||||
return nil, "Failed to compute MD5 hash for file "..file
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- POSIX functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
if posix_ok then
|
||||
|
||||
local octal_to_rwx = {
|
||||
["0"] = "---",
|
||||
["1"] = "--x",
|
||||
["2"] = "-w-",
|
||||
["3"] = "-wx",
|
||||
["4"] = "r--",
|
||||
["5"] = "r-x",
|
||||
["6"] = "rw-",
|
||||
["7"] = "rwx",
|
||||
}
|
||||
|
||||
function fs_lua.chmod(file, mode)
|
||||
-- LuaPosix (as of 5.1.15) does not support octal notation...
|
||||
if mode:sub(1,1) == "0" then
|
||||
local new_mode = {}
|
||||
for c in mode:sub(-3):gmatch(".") do
|
||||
table.insert(new_mode, octal_to_rwx[c])
|
||||
end
|
||||
mode = table.concat(new_mode)
|
||||
end
|
||||
local err = posix.chmod(file, mode)
|
||||
return err == 0
|
||||
end
|
||||
|
||||
function fs_lua.get_permissions(file)
|
||||
return posix.stat(file, "mode")
|
||||
end
|
||||
|
||||
--- Create a temporary directory.
|
||||
-- @param name string: name pattern to use for avoiding conflicts
|
||||
-- when creating temporary directory.
|
||||
-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure.
|
||||
function fs_lua.make_temp_dir(name)
|
||||
assert(type(name) == "string")
|
||||
name = dir.normalize(name)
|
||||
|
||||
return posix.mkdtemp((os.getenv("TMPDIR") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-XXXXXX")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Other functions
|
||||
---------------------------------------------------------------------
|
||||
|
||||
--- Apply a patch.
|
||||
-- @param patchname string: The filename of the patch.
|
||||
-- @param patchdata string or nil: The actual patch as a string.
|
||||
function fs_lua.apply_patch(patchname, patchdata)
|
||||
local p, all_ok = patch.read_patch(patchname, patchdata)
|
||||
if not all_ok then
|
||||
return nil, "Failed reading patch "..patchname
|
||||
end
|
||||
if p then
|
||||
return patch.apply_patch(p, 1)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move a file.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @param perms string or nil: Permissions for destination file,
|
||||
-- or nil to use the source filename permissions.
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function fs_lua.move(src, dest, perms)
|
||||
assert(src and dest)
|
||||
if fs.exists(dest) and not fs.is_dir(dest) then
|
||||
return false, "File already exists: "..dest
|
||||
end
|
||||
local ok, err = fs.copy(src, dest, perms)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
fs.delete(src)
|
||||
if fs.exists(src) then
|
||||
return false, "Failed move: could not delete "..src.." after copy."
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Check if user has write permissions for the command.
|
||||
-- Assumes the configuration variables under cfg have been previously set up.
|
||||
-- @param flags table: the flags table passed to run() drivers.
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function fs_lua.check_command_permissions(flags)
|
||||
local root_dir = path.root_dir(cfg.rocks_dir)
|
||||
local ok = true
|
||||
local err = ""
|
||||
for _, dir in ipairs { cfg.rocks_dir, root_dir } do
|
||||
if fs.exists(dir) and not fs.is_writable(dir) then
|
||||
ok = false
|
||||
err = "Your user does not have write permissions in " .. dir
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok and not fs.exists(root_dir) then
|
||||
local root = fs.root_of(root_dir)
|
||||
local parent = root_dir
|
||||
repeat
|
||||
parent = dir.dir_name(parent)
|
||||
if parent == "" then
|
||||
parent = root
|
||||
end
|
||||
until parent == root or fs.exists(parent)
|
||||
if not fs.is_writable(parent) then
|
||||
ok = false
|
||||
err = root_dir.." does not exist and your user does not have write permissions in " .. parent
|
||||
end
|
||||
end
|
||||
if ok then
|
||||
return true
|
||||
else
|
||||
if flags["local"] then
|
||||
err = err .. " \n-- please check your permissions."
|
||||
else
|
||||
err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local."
|
||||
end
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
--- Check whether a file is a Lua script
|
||||
-- When the file can be succesfully compiled by the configured
|
||||
-- Lua interpreter, it's considered to be a valid Lua file.
|
||||
-- @param name filename of file to check
|
||||
-- @return boolean true, if it is a Lua script, false otherwise
|
||||
function fs_lua.is_lua(name)
|
||||
name = name:gsub([[%\]],"/") -- normalize on fw slash to prevent escaping issues
|
||||
local lua = fs.Q(dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)) -- get lua interpreter configured
|
||||
-- execute on configured interpreter, might not be the same as the interpreter LR is run on
|
||||
local result = fs.execute_string(lua..[[ -e "if loadfile(']]..name..[[') then os.exit() else os.exit(1) end"]])
|
||||
return (result == true)
|
||||
end
|
||||
|
||||
return fs_lua
|
||||
156
Utils/luarocks/lua/luarocks/fs/tools.lua
Normal file
156
Utils/luarocks/lua/luarocks/fs/tools.lua
Normal file
@@ -0,0 +1,156 @@
|
||||
|
||||
--- Common fs operations implemented with third-party tools.
|
||||
local tools = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
local dir = require("luarocks.dir")
|
||||
local cfg = require("luarocks.cfg")
|
||||
|
||||
local vars = cfg.variables
|
||||
|
||||
local dir_stack = {}
|
||||
|
||||
--- Obtain current directory.
|
||||
-- Uses the module's internal directory stack.
|
||||
-- @return string: the absolute pathname of the current directory.
|
||||
function tools.current_dir()
|
||||
local current = cfg.cache_pwd
|
||||
if not current then
|
||||
local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD)))
|
||||
current = pipe:read("*l")
|
||||
pipe:close()
|
||||
cfg.cache_pwd = current
|
||||
end
|
||||
for _, directory in ipairs(dir_stack) do
|
||||
current = fs.absolute_name(directory, current)
|
||||
end
|
||||
return current
|
||||
end
|
||||
|
||||
--- Change the current directory.
|
||||
-- Uses the module's internal directory stack. This does not have exact
|
||||
-- semantics of chdir, as it does not handle errors the same way,
|
||||
-- but works well for our purposes for now.
|
||||
-- @param directory string: The directory to switch to.
|
||||
-- @return boolean or (nil, string): true if successful, (nil, error message) if failed.
|
||||
function tools.change_dir(directory)
|
||||
assert(type(directory) == "string")
|
||||
if fs.is_dir(directory) then
|
||||
table.insert(dir_stack, directory)
|
||||
return true
|
||||
end
|
||||
return nil, "directory not found: "..directory
|
||||
end
|
||||
|
||||
--- Change directory to root.
|
||||
-- Allows leaving a directory (e.g. for deleting it) in
|
||||
-- a crossplatform way.
|
||||
function tools.change_dir_to_root()
|
||||
table.insert(dir_stack, "/")
|
||||
end
|
||||
|
||||
--- Change working directory to the previous in the directory stack.
|
||||
function tools.pop_dir()
|
||||
local directory = table.remove(dir_stack)
|
||||
return directory ~= nil
|
||||
end
|
||||
|
||||
--- Run the given command.
|
||||
-- The command is executed in the current directory in the directory stack.
|
||||
-- @param cmd string: No quoting/escaping is applied to the command.
|
||||
-- @return boolean: true if command succeeds (status code 0), false
|
||||
-- otherwise.
|
||||
function tools.execute_string(cmd)
|
||||
local current = fs.current_dir()
|
||||
if not current then return false end
|
||||
cmd = fs.command_at(current, cmd)
|
||||
local code = os.execute(cmd)
|
||||
if code == 0 or code == true then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Internal implementation function for fs.dir.
|
||||
-- Yields a filename on each iteration.
|
||||
-- @param at string: directory to list
|
||||
-- @return nil
|
||||
function tools.dir_iterator(at)
|
||||
local pipe = io.popen(fs.command_at(at, fs.Q(vars.LS)))
|
||||
for file in pipe:lines() do
|
||||
if file ~= "." and file ~= ".." then
|
||||
coroutine.yield(file)
|
||||
end
|
||||
end
|
||||
pipe:close()
|
||||
end
|
||||
|
||||
--- Download a remote file.
|
||||
-- @param url string: URL to be fetched.
|
||||
-- @param filename string or nil: this function attempts to detect the
|
||||
-- resulting local filename of the remote file as the basename of the URL;
|
||||
-- if that is not correct (due to a redirection, for example), the local
|
||||
-- filename can be given explicitly as this second argument.
|
||||
-- @return (boolean, string): true and the filename on success,
|
||||
-- false and the error message on failure.
|
||||
function tools.use_downloader(url, filename, cache)
|
||||
assert(type(url) == "string")
|
||||
assert(type(filename) == "string" or not filename)
|
||||
|
||||
filename = fs.absolute_name(filename or dir.base_name(url))
|
||||
|
||||
local ok
|
||||
if cfg.downloader == "wget" then
|
||||
local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
|
||||
if cfg.connection_timeout and cfg.connection_timeout > 0 then
|
||||
wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
|
||||
end
|
||||
if cache then
|
||||
-- --timestamping is incompatible with --output-document,
|
||||
-- but that's not a problem for our use cases.
|
||||
fs.change_dir(dir.dir_name(filename))
|
||||
ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
|
||||
fs.pop_dir()
|
||||
elseif filename then
|
||||
ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
|
||||
else
|
||||
ok = fs.execute_quiet(wget_cmd, url)
|
||||
end
|
||||
elseif cfg.downloader == "curl" then
|
||||
local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
|
||||
if cfg.connection_timeout and cfg.connection_timeout > 0 then
|
||||
curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
|
||||
end
|
||||
ok = fs.execute_string(fs.quiet_stderr(curl_cmd..fs.Q(url).." > "..fs.Q(filename)))
|
||||
end
|
||||
if ok then
|
||||
return true, filename
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local md5_cmd = {
|
||||
md5sum = fs.Q(vars.MD5SUM),
|
||||
openssl = fs.Q(vars.OPENSSL).." md5",
|
||||
md5 = fs.Q(vars.MD5),
|
||||
}
|
||||
|
||||
--- Get the MD5 checksum for a file.
|
||||
-- @param file string: The file to be computed.
|
||||
-- @return string: The MD5 checksum or nil + message
|
||||
function tools.get_md5(file)
|
||||
local cmd = md5_cmd[cfg.md5checker]
|
||||
if not cmd then return nil, "no MD5 checker command configured" end
|
||||
local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
|
||||
local computed = pipe:read("*a")
|
||||
pipe:close()
|
||||
if computed then
|
||||
computed = computed:match("("..("%x"):rep(32)..")")
|
||||
end
|
||||
if computed then return computed end
|
||||
return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
|
||||
end
|
||||
|
||||
return tools
|
||||
135
Utils/luarocks/lua/luarocks/fs/unix.lua
Normal file
135
Utils/luarocks/lua/luarocks/fs/unix.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
--- Unix implementation of filesystem and platform abstractions.
|
||||
local unix = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
|
||||
local cfg = require("luarocks.cfg")
|
||||
local dir = require("luarocks.dir")
|
||||
local util = require("luarocks.util")
|
||||
|
||||
--- Annotate command string for quiet execution.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line, with silencing annotation.
|
||||
function unix.quiet(cmd)
|
||||
return cmd.." 1> /dev/null 2> /dev/null"
|
||||
end
|
||||
|
||||
--- Annotate command string for execution with quiet stderr.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line, with stderr silencing annotation.
|
||||
function unix.quiet_stderr(cmd)
|
||||
return cmd.." 2> /dev/null"
|
||||
end
|
||||
|
||||
--- Quote argument for shell processing.
|
||||
-- Adds single quotes and escapes.
|
||||
-- @param arg string: Unquoted argument.
|
||||
-- @return string: Quoted argument.
|
||||
function unix.Q(arg)
|
||||
assert(type(arg) == "string")
|
||||
return "'" .. arg:gsub("'", "'\\''") .. "'"
|
||||
end
|
||||
|
||||
--- Return an absolute pathname from a potentially relative one.
|
||||
-- @param pathname string: pathname to convert.
|
||||
-- @param relative_to string or nil: path to prepend when making
|
||||
-- pathname absolute, or the current dir in the dir stack if
|
||||
-- not given.
|
||||
-- @return string: The pathname converted to absolute.
|
||||
function unix.absolute_name(pathname, relative_to)
|
||||
assert(type(pathname) == "string")
|
||||
assert(type(relative_to) == "string" or not relative_to)
|
||||
|
||||
relative_to = relative_to or fs.current_dir()
|
||||
if pathname:sub(1,1) == "/" then
|
||||
return pathname
|
||||
else
|
||||
return relative_to .. "/" .. pathname
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the root directory for the given path.
|
||||
-- In Unix, root is always "/".
|
||||
-- @param pathname string: pathname to use.
|
||||
-- @return string: The root of the given pathname.
|
||||
function unix.root_of(_)
|
||||
return "/"
|
||||
end
|
||||
|
||||
--- Create a wrapper to make a script executable from the command-line.
|
||||
-- @param file string: Pathname of script to be made executable.
|
||||
-- @param dest string: Directory where to put the wrapper.
|
||||
-- @param name string: rock name to be used in loader context.
|
||||
-- @param version string: rock version to be used in loader context.
|
||||
-- @return boolean or (nil, string): True if succeeded, or nil and
|
||||
-- an error message.
|
||||
function unix.wrap_script(file, dest, name, version)
|
||||
assert(type(file) == "string")
|
||||
assert(type(dest) == "string")
|
||||
|
||||
local base = dir.base_name(file)
|
||||
local wrapname = fs.is_dir(dest) and dest.."/"..base or dest
|
||||
local lpath, lcpath = cfg.package_paths()
|
||||
local wrapper = io.open(wrapname, "w")
|
||||
if not wrapper then
|
||||
return nil, "Could not open "..wrapname.." for writing."
|
||||
end
|
||||
wrapper:write("#!/bin/sh\n\n")
|
||||
local lua = dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)
|
||||
local ppaths = "package.path="..util.LQ(lpath..";").."..package.path; package.cpath="..util.LQ(lcpath..";").."..package.cpath"
|
||||
local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")"
|
||||
wrapper:write('exec '..fs.Q(lua)..' -e '..fs.Q(ppaths)..' -e '..fs.Q(addctx)..' '..fs.Q(file)..' "$@"\n')
|
||||
wrapper:close()
|
||||
if fs.chmod(wrapname, cfg.perm_exec) then
|
||||
return true
|
||||
else
|
||||
return nil, "Could not make "..wrapname.." executable."
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if a file (typically inside path.bin_dir) is an actual binary
|
||||
-- or a Lua wrapper.
|
||||
-- @param filename string: the file name with full path.
|
||||
-- @return boolean: returns true if file is an actual binary
|
||||
-- (or if it couldn't check) or false if it is a Lua wrapper.
|
||||
function unix.is_actual_binary(filename)
|
||||
if filename:match("%.lua$") then
|
||||
return false
|
||||
end
|
||||
local file = io.open(filename)
|
||||
if not file then
|
||||
return true
|
||||
end
|
||||
local first = file:read(2)
|
||||
file:close()
|
||||
if not first then
|
||||
util.printerr("Warning: could not read "..filename)
|
||||
return true
|
||||
end
|
||||
return first ~= "#!"
|
||||
end
|
||||
|
||||
function unix.copy_binary(filename, dest)
|
||||
return fs.copy(filename, dest, cfg.perm_exec)
|
||||
end
|
||||
|
||||
--- Move a file on top of the other.
|
||||
-- The new file ceases to exist under its original name,
|
||||
-- and takes over the name of the old file.
|
||||
-- On Unix this is done through a single rename operation.
|
||||
-- @param old_file The name of the original file,
|
||||
-- which will be the new name of new_file.
|
||||
-- @param new_file The name of the new file,
|
||||
-- which will replace old_file.
|
||||
-- @return boolean or (nil, string): True if succeeded, or nil and
|
||||
-- an error message.
|
||||
function unix.replace_file(old_file, new_file)
|
||||
return os.rename(new_file, old_file)
|
||||
end
|
||||
|
||||
function unix.tmpname()
|
||||
return os.tmpname()
|
||||
end
|
||||
|
||||
return unix
|
||||
237
Utils/luarocks/lua/luarocks/fs/unix/tools.lua
Normal file
237
Utils/luarocks/lua/luarocks/fs/unix/tools.lua
Normal file
@@ -0,0 +1,237 @@
|
||||
|
||||
--- fs operations implemented with third-party tools for Unix platform abstractions.
|
||||
local tools = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
local dir = require("luarocks.dir")
|
||||
local cfg = require("luarocks.cfg")
|
||||
|
||||
local vars = cfg.variables
|
||||
|
||||
--- Adds prefix to command to make it run from a directory.
|
||||
-- @param directory string: Path to a directory.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line with prefix.
|
||||
function tools.command_at(directory, cmd)
|
||||
return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd
|
||||
end
|
||||
|
||||
--- Create a directory if it does not already exist.
|
||||
-- If any of the higher levels in the path name does not exist
|
||||
-- too, they are created as well.
|
||||
-- @param directory string: pathname of directory to create.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.make_dir(directory)
|
||||
assert(directory)
|
||||
local ok, err = fs.execute(vars.MKDIR.." -p", directory)
|
||||
if not ok then
|
||||
err = "failed making directory "..directory
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param directory string: pathname of directory to remove.
|
||||
function tools.remove_dir_if_empty(directory)
|
||||
assert(directory)
|
||||
fs.execute_quiet(vars.RMDIR, directory)
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param directory string: pathname of directory to remove.
|
||||
function tools.remove_dir_tree_if_empty(directory)
|
||||
assert(directory)
|
||||
fs.execute_quiet(vars.RMDIR, "-p", directory)
|
||||
end
|
||||
|
||||
--- Copy a file.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @param perm string or nil: Permissions for destination file,
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function tools.copy(src, dest, perm)
|
||||
assert(src and dest)
|
||||
if fs.execute(vars.CP, src, dest) then
|
||||
if perm then
|
||||
if fs.is_dir(dest) then
|
||||
dest = dir.path(dest, dir.base_name(src))
|
||||
end
|
||||
if fs.chmod(dest, perm) then
|
||||
return true
|
||||
else
|
||||
return false, "Failed setting permissions of "..dest
|
||||
end
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false, "Failed copying "..src.." to "..dest
|
||||
end
|
||||
end
|
||||
|
||||
--- Recursively copy the contents of a directory.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function tools.copy_contents(src, dest)
|
||||
assert(src and dest)
|
||||
if fs.execute_quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest)) then
|
||||
return true
|
||||
else
|
||||
return false, "Failed copying "..src.." to "..dest
|
||||
end
|
||||
end
|
||||
--- Delete a file or a directory and all its contents.
|
||||
-- For safety, this only accepts absolute paths.
|
||||
-- @param arg string: Pathname of source
|
||||
-- @return nil
|
||||
function tools.delete(arg)
|
||||
assert(arg)
|
||||
assert(arg:sub(1,1) == "/")
|
||||
fs.execute_quiet(vars.RM, "-rf", arg)
|
||||
end
|
||||
|
||||
--- Recursively scan the contents of a directory.
|
||||
-- @param at string or nil: directory to scan (will be the current
|
||||
-- directory if none is given).
|
||||
-- @return table: an array of strings with the filenames representing
|
||||
-- the contents of a directory.
|
||||
function tools.find(at)
|
||||
assert(type(at) == "string" or not at)
|
||||
if not at then
|
||||
at = fs.current_dir()
|
||||
end
|
||||
if not fs.is_dir(at) then
|
||||
return {}
|
||||
end
|
||||
local result = {}
|
||||
local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND.." *")))
|
||||
for file in pipe:lines() do
|
||||
table.insert(result, file)
|
||||
end
|
||||
pipe:close()
|
||||
return result
|
||||
end
|
||||
|
||||
--- Compress files in a .zip archive.
|
||||
-- @param zipfile string: pathname of .zip archive to be created.
|
||||
-- @param ... Filenames to be stored in the archive are given as
|
||||
-- additional arguments.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.zip(zipfile, ...)
|
||||
return fs.execute(vars.ZIP.." -r", zipfile, ...)
|
||||
end
|
||||
|
||||
--- Uncompress files from a .zip archive.
|
||||
-- @param zipfile string: pathname of .zip archive to be extracted.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.unzip(zipfile)
|
||||
assert(zipfile)
|
||||
return fs.execute_quiet(vars.UNZIP, zipfile)
|
||||
end
|
||||
|
||||
--- Test is file/directory exists
|
||||
-- @param file string: filename to test
|
||||
-- @return boolean: true if file exists, false otherwise.
|
||||
function tools.exists(file)
|
||||
assert(file)
|
||||
return fs.execute(vars.TEST, "-e", file)
|
||||
end
|
||||
|
||||
--- Test is pathname is a directory.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a directory, false otherwise.
|
||||
function tools.is_dir(file)
|
||||
assert(file)
|
||||
return fs.execute(vars.TEST, "-d", file)
|
||||
end
|
||||
|
||||
--- Test is pathname is a regular file.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a regular file, false otherwise.
|
||||
function tools.is_file(file)
|
||||
assert(file)
|
||||
return fs.execute(vars.TEST, "-f", file)
|
||||
end
|
||||
|
||||
function tools.chmod(pathname, mode)
|
||||
if mode then
|
||||
return fs.execute(vars.CHMOD, mode, pathname)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Unpack an archive.
|
||||
-- Extract the contents of an archive, detecting its format by
|
||||
-- filename extension.
|
||||
-- @param archive string: Filename of archive.
|
||||
-- @return boolean or (boolean, string): true on success, false and an error message on failure.
|
||||
function tools.unpack_archive(archive)
|
||||
assert(type(archive) == "string")
|
||||
|
||||
local pipe_to_tar = " | "..vars.TAR.." -xf -"
|
||||
|
||||
if not cfg.verbose then
|
||||
pipe_to_tar = " 2> /dev/null"..fs.quiet(pipe_to_tar)
|
||||
end
|
||||
|
||||
local ok
|
||||
if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then
|
||||
ok = fs.execute_string(vars.GUNZIP.." -c "..fs.Q(archive)..pipe_to_tar)
|
||||
elseif archive:match("%.tar%.bz2$") then
|
||||
ok = fs.execute_string(vars.BUNZIP2.." -c "..fs.Q(archive)..pipe_to_tar)
|
||||
elseif archive:match("%.zip$") then
|
||||
ok = fs.execute_quiet(vars.UNZIP, archive)
|
||||
elseif archive:match("%.lua$") or archive:match("%.c$") then
|
||||
-- Ignore .lua and .c files; they don't need to be extracted.
|
||||
return true
|
||||
else
|
||||
return false, "Couldn't extract archive "..archive..": unrecognized filename extension"
|
||||
end
|
||||
if not ok then
|
||||
return false, "Failed extracting "..archive
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function tools.get_permissions(filename)
|
||||
local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename))
|
||||
local ret = pipe:read("*l")
|
||||
pipe:close()
|
||||
return ret
|
||||
end
|
||||
|
||||
function tools.browser(url)
|
||||
return fs.execute(cfg.web_browser, url)
|
||||
end
|
||||
|
||||
function tools.set_time(file, time)
|
||||
file = dir.normalize(file)
|
||||
return fs.execute(vars.TOUCH, "-d", "@"..tostring(time), file)
|
||||
end
|
||||
|
||||
--- Create a temporary directory.
|
||||
-- @param name string: name pattern to use for avoiding conflicts
|
||||
-- when creating temporary directory.
|
||||
-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure.
|
||||
function tools.make_temp_dir(name)
|
||||
assert(type(name) == "string")
|
||||
name = dir.normalize(name)
|
||||
|
||||
local template = (os.getenv("TMPDIR") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-XXXXXX"
|
||||
local pipe = io.popen(vars.MKTEMP.." -d "..fs.Q(template))
|
||||
local dirname = pipe:read("*l")
|
||||
pipe:close()
|
||||
if dirname and dirname:match("^/") then
|
||||
return dirname
|
||||
end
|
||||
return nil, "Failed to create temporary directory "..tostring(dirname)
|
||||
end
|
||||
|
||||
return tools
|
||||
266
Utils/luarocks/lua/luarocks/fs/win32.lua
Normal file
266
Utils/luarocks/lua/luarocks/fs/win32.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--- Windows implementation of filesystem and platform abstractions.
|
||||
-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
|
||||
-- used by this module.
|
||||
local win32 = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
|
||||
local cfg = require("luarocks.cfg")
|
||||
local dir = require("luarocks.dir")
|
||||
local util = require("luarocks.util")
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
||||
-- Monkey patch io.popen and os.execute to make sure quoting
|
||||
-- works as expected.
|
||||
-- See http://lua-users.org/lists/lua-l/2013-11/msg00367.html
|
||||
local _prefix = "type NUL && "
|
||||
local _popen, _execute = io.popen, os.execute
|
||||
io.popen = function(cmd, ...) return _popen(_prefix..cmd, ...) end
|
||||
os.execute = function(cmd, ...) return _execute(_prefix..cmd, ...) end
|
||||
|
||||
--- Annotate command string for quiet execution.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line, with silencing annotation.
|
||||
function win32.quiet(cmd)
|
||||
return cmd.." 2> NUL 1> NUL"
|
||||
end
|
||||
|
||||
--- Annotate command string for execution with quiet stderr.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line, with stderr silencing annotation.
|
||||
function win32.quiet_stderr(cmd)
|
||||
return cmd.." 2> NUL"
|
||||
end
|
||||
|
||||
-- Split path into root and the rest.
|
||||
-- Root part consists of an optional drive letter (e.g. "C:")
|
||||
-- and an optional directory separator.
|
||||
local function split_root(path)
|
||||
local root = ""
|
||||
|
||||
if path:match("^.:") then
|
||||
root = path:sub(1, 2)
|
||||
path = path:sub(3)
|
||||
end
|
||||
|
||||
if path:match("^[\\/]") then
|
||||
root = path:sub(1, 1)
|
||||
path = path:sub(2)
|
||||
end
|
||||
|
||||
return root, path
|
||||
end
|
||||
|
||||
--- Quote argument for shell processing. Fixes paths on Windows.
|
||||
-- Adds double quotes and escapes.
|
||||
-- @param arg string: Unquoted argument.
|
||||
-- @return string: Quoted argument.
|
||||
function win32.Q(arg)
|
||||
assert(type(arg) == "string")
|
||||
-- Use Windows-specific directory separator for paths.
|
||||
-- Paths should be converted to absolute by now.
|
||||
if split_root(arg) ~= "" then
|
||||
arg = arg:gsub("/", "\\")
|
||||
end
|
||||
if arg == "\\" then
|
||||
return '\\' -- CHDIR needs special handling for root dir
|
||||
end
|
||||
-- URLs and anything else
|
||||
arg = arg:gsub('\\(\\*)"', '\\%1%1"')
|
||||
arg = arg:gsub('\\+$', '%0%0')
|
||||
arg = arg:gsub('"', '\\"')
|
||||
arg = arg:gsub('(\\*)%%', '%1%1"%%"')
|
||||
return '"' .. arg .. '"'
|
||||
end
|
||||
|
||||
--- Quote argument for shell processing in batch files.
|
||||
-- Adds double quotes and escapes.
|
||||
-- @param arg string: Unquoted argument.
|
||||
-- @return string: Quoted argument.
|
||||
function win32.Qb(arg)
|
||||
assert(type(arg) == "string")
|
||||
-- Use Windows-specific directory separator for paths.
|
||||
-- Paths should be converted to absolute by now.
|
||||
if split_root(arg) ~= "" then
|
||||
arg = arg:gsub("/", "\\")
|
||||
end
|
||||
if arg == "\\" then
|
||||
return '\\' -- CHDIR needs special handling for root dir
|
||||
end
|
||||
-- URLs and anything else
|
||||
arg = arg:gsub('\\(\\*)"', '\\%1%1"')
|
||||
arg = arg:gsub('\\+$', '%0%0')
|
||||
arg = arg:gsub('"', '\\"')
|
||||
arg = arg:gsub('%%', '%%%%')
|
||||
return '"' .. arg .. '"'
|
||||
end
|
||||
|
||||
--- Return an absolute pathname from a potentially relative one.
|
||||
-- @param pathname string: pathname to convert.
|
||||
-- @param relative_to string or nil: path to prepend when making
|
||||
-- pathname absolute, or the current dir in the dir stack if
|
||||
-- not given.
|
||||
-- @return string: The pathname converted to absolute.
|
||||
function win32.absolute_name(pathname, relative_to)
|
||||
assert(type(pathname) == "string")
|
||||
assert(type(relative_to) == "string" or not relative_to)
|
||||
|
||||
relative_to = relative_to or fs.current_dir()
|
||||
local root, rest = split_root(pathname)
|
||||
if root:match("[\\/]$") then
|
||||
-- It's an absolute path already.
|
||||
return pathname
|
||||
else
|
||||
-- It's a relative path, join it with base path.
|
||||
-- This drops drive letter from paths like "C:foo".
|
||||
return relative_to .. "/" .. rest
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the root directory for the given path.
|
||||
-- For example, for "c:\hello", returns "c:\"
|
||||
-- @param pathname string: pathname to use.
|
||||
-- @return string: The root of the given pathname.
|
||||
function win32.root_of(pathname)
|
||||
return (split_root(fs.absolute_name(pathname)))
|
||||
end
|
||||
|
||||
--- Create a wrapper to make a script executable from the command-line.
|
||||
-- @param file string: Pathname of script to be made executable.
|
||||
-- @param dest string: Directory where to put the wrapper.
|
||||
-- @param name string: rock name to be used in loader context.
|
||||
-- @param version string: rock version to be used in loader context.
|
||||
-- @return boolean or (nil, string): True if succeeded, or nil and
|
||||
-- an error message.
|
||||
function win32.wrap_script(file, dest, name, version)
|
||||
assert(type(file) == "string")
|
||||
assert(type(dest) == "string")
|
||||
|
||||
local base = dir.base_name(file)
|
||||
local wrapname = fs.is_dir(dest) and dest.."/"..base or dest
|
||||
wrapname = wrapname..".bat"
|
||||
local lpath, lcpath = cfg.package_paths()
|
||||
lpath = util.remove_path_dupes(lpath, ";")
|
||||
lcpath = util.remove_path_dupes(lcpath, ";")
|
||||
local wrapper = io.open(wrapname, "w")
|
||||
if not wrapper then
|
||||
return nil, "Could not open "..wrapname.." for writing."
|
||||
end
|
||||
wrapper:write("@echo off\n")
|
||||
local lua = dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)
|
||||
local ppaths = "package.path="..util.LQ(lpath..";").."..package.path; package.cpath="..util.LQ(lcpath..";").."..package.cpath"
|
||||
local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")"
|
||||
wrapper:write(fs.Qb(lua)..' -e '..fs.Qb(ppaths)..' -e '..fs.Qb(addctx)..' '..fs.Qb(file)..' %*\n')
|
||||
wrapper:write("exit /b %ERRORLEVEL%\n")
|
||||
wrapper:close()
|
||||
return true
|
||||
end
|
||||
|
||||
function win32.is_actual_binary(name)
|
||||
name = name:lower()
|
||||
if name:match("%.bat$") or name:match("%.exe$") then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function win32.copy_binary(filename, dest)
|
||||
local ok, err = fs.copy(filename, dest)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
local exe_pattern = "%.[Ee][Xx][Ee]$"
|
||||
local base = dir.base_name(filename)
|
||||
dest = dir.dir_name(dest)
|
||||
if base:match(exe_pattern) then
|
||||
base = base:gsub(exe_pattern, ".lua")
|
||||
local helpname = dest.."/"..base
|
||||
local helper = io.open(helpname, "w")
|
||||
if not helper then
|
||||
return nil, "Could not open "..helpname.." for writing."
|
||||
end
|
||||
helper:write('package.path=\"'..package.path:gsub("\\","\\\\")..';\"..package.path\n')
|
||||
helper:write('package.cpath=\"'..package.path:gsub("\\","\\\\")..';\"..package.cpath\n')
|
||||
helper:close()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function win32.chmod(filename, mode)
|
||||
return true
|
||||
end
|
||||
|
||||
function win32.get_permissions(filename)
|
||||
return ""
|
||||
end
|
||||
|
||||
--- Move a file on top of the other.
|
||||
-- The new file ceases to exist under its original name,
|
||||
-- and takes over the name of the old file.
|
||||
-- On Windows this is done by removing the original file and
|
||||
-- renaming the new file to its original name.
|
||||
-- @param old_file The name of the original file,
|
||||
-- which will be the new name of new_file.
|
||||
-- @param new_file The name of the new file,
|
||||
-- which will replace old_file.
|
||||
-- @return boolean or (nil, string): True if succeeded, or nil and
|
||||
-- an error message.
|
||||
function win32.replace_file(old_file, new_file)
|
||||
os.remove(old_file)
|
||||
return os.rename(new_file, old_file)
|
||||
end
|
||||
|
||||
--- Test is file/dir is writable.
|
||||
-- Warning: testing if a file/dir is writable does not guarantee
|
||||
-- that it will remain writable and therefore it is no replacement
|
||||
-- for checking the result of subsequent operations.
|
||||
-- @param file string: filename to test
|
||||
-- @return boolean: true if file exists, false otherwise.
|
||||
function win32.is_writable(file)
|
||||
assert(file)
|
||||
file = dir.normalize(file)
|
||||
local result
|
||||
local tmpname = 'tmpluarockstestwritable.deleteme'
|
||||
if fs.is_dir(file) then
|
||||
local file2 = dir.path(file, tmpname)
|
||||
local fh = io.open(file2, 'wb')
|
||||
result = fh ~= nil
|
||||
if fh then fh:close() end
|
||||
if result then
|
||||
-- the above test might give a false positive when writing to
|
||||
-- c:\program files\ because of VirtualStore redirection on Vista and up
|
||||
-- So check whether it's really there
|
||||
result = fs.exists(file2)
|
||||
end
|
||||
os.remove(file2)
|
||||
else
|
||||
local fh = io.open(file, 'r+b')
|
||||
result = fh ~= nil
|
||||
if fh then fh:close() end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Create a temporary directory.
|
||||
-- @param name string: name pattern to use for avoiding conflicts
|
||||
-- when creating temporary directory.
|
||||
-- @return string or (nil, string): name of temporary directory or (nil, error message) on failure.
|
||||
function win32.make_temp_dir(name)
|
||||
assert(type(name) == "string")
|
||||
name = dir.normalize(name)
|
||||
|
||||
local temp_dir = os.getenv("TMP") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000))
|
||||
local ok, err = fs.make_dir(temp_dir)
|
||||
if ok then
|
||||
return temp_dir
|
||||
else
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
function win32.tmpname()
|
||||
return os.getenv("TMP")..os.tmpname()
|
||||
end
|
||||
|
||||
return win32
|
||||
227
Utils/luarocks/lua/luarocks/fs/win32/tools.lua
Normal file
227
Utils/luarocks/lua/luarocks/fs/win32/tools.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
|
||||
--- fs operations implemented with third-party tools for Windows platform abstractions.
|
||||
-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
|
||||
-- used by this module.
|
||||
local tools = {}
|
||||
|
||||
local fs = require("luarocks.fs")
|
||||
local dir = require("luarocks.dir")
|
||||
local cfg = require("luarocks.cfg")
|
||||
|
||||
local vars = cfg.variables
|
||||
|
||||
--- Adds prefix to command to make it run from a directory.
|
||||
-- @param directory string: Path to a directory.
|
||||
-- @param cmd string: A command-line string.
|
||||
-- @return string: The command-line with prefix.
|
||||
function tools.command_at(directory, cmd)
|
||||
local drive = directory:match("^([A-Za-z]:)")
|
||||
cmd = "cd " .. fs.Q(directory) .. " & " .. cmd
|
||||
if drive then
|
||||
cmd = drive .. " & " .. cmd
|
||||
end
|
||||
return cmd
|
||||
end
|
||||
|
||||
--- Create a directory if it does not already exist.
|
||||
-- If any of the higher levels in the path name does not exist
|
||||
-- too, they are created as well.
|
||||
-- @param directory string: pathname of directory to create.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.make_dir(directory)
|
||||
assert(directory)
|
||||
directory = dir.normalize(directory)
|
||||
fs.execute_quiet(fs.Q(vars.MKDIR).." -p ", directory)
|
||||
if not fs.is_dir(directory) then
|
||||
return false, "failed making directory "..directory
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param directory string: pathname of directory to remove.
|
||||
function tools.remove_dir_if_empty(directory)
|
||||
assert(directory)
|
||||
fs.execute_quiet(fs.Q(vars.RMDIR), directory)
|
||||
end
|
||||
|
||||
--- Remove a directory if it is empty.
|
||||
-- Does not return errors (for example, if directory is not empty or
|
||||
-- if already does not exist)
|
||||
-- @param directory string: pathname of directory to remove.
|
||||
function tools.remove_dir_tree_if_empty(directory)
|
||||
assert(directory)
|
||||
fs.execute_quiet(fs.Q(vars.RMDIR), directory)
|
||||
end
|
||||
|
||||
--- Copy a file.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function tools.copy(src, dest)
|
||||
assert(src and dest)
|
||||
if dest:match("[/\\]$") then dest = dest:sub(1, -2) end
|
||||
local ok = fs.execute(fs.Q(vars.CP), src, dest)
|
||||
if ok then
|
||||
return true
|
||||
else
|
||||
return false, "Failed copying "..src.." to "..dest
|
||||
end
|
||||
end
|
||||
|
||||
--- Recursively copy the contents of a directory.
|
||||
-- @param src string: Pathname of source
|
||||
-- @param dest string: Pathname of destination
|
||||
-- @return boolean or (boolean, string): true on success, false on failure,
|
||||
-- plus an error message.
|
||||
function tools.copy_contents(src, dest)
|
||||
assert(src and dest)
|
||||
if fs.execute_quiet(fs.Q(vars.CP), "-dR", src.."\\*.*", dest) then
|
||||
return true
|
||||
else
|
||||
return false, "Failed copying "..src.." to "..dest
|
||||
end
|
||||
end
|
||||
|
||||
--- Delete a file or a directory and all its contents.
|
||||
-- For safety, this only accepts absolute paths.
|
||||
-- @param arg string: Pathname of source
|
||||
-- @return nil
|
||||
function tools.delete(arg)
|
||||
assert(arg)
|
||||
assert(arg:match("^[a-zA-Z]?:?[\\/]"))
|
||||
fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )")
|
||||
end
|
||||
|
||||
--- Recursively scan the contents of a directory.
|
||||
-- @param at string or nil: directory to scan (will be the current
|
||||
-- directory if none is given).
|
||||
-- @return table: an array of strings with the filenames representing
|
||||
-- the contents of a directory. Paths are returned with forward slashes.
|
||||
function tools.find(at)
|
||||
assert(type(at) == "string" or not at)
|
||||
if not at then
|
||||
at = fs.current_dir()
|
||||
end
|
||||
if not fs.is_dir(at) then
|
||||
return {}
|
||||
end
|
||||
local result = {}
|
||||
local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(fs.Q(vars.FIND))))
|
||||
for file in pipe:lines() do
|
||||
-- Windows find is a bit different
|
||||
local first_two = file:sub(1,2)
|
||||
if first_two == ".\\" or first_two == "./" then file=file:sub(3) end
|
||||
if file ~= "." then
|
||||
table.insert(result, (file:gsub("\\", "/")))
|
||||
end
|
||||
end
|
||||
pipe:close()
|
||||
return result
|
||||
end
|
||||
|
||||
--- Compress files in a .zip archive.
|
||||
-- @param zipfile string: pathname of .zip archive to be created.
|
||||
-- @param ... Filenames to be stored in the archive are given as
|
||||
-- additional arguments.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.zip(zipfile, ...)
|
||||
return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa a -tzip", zipfile, ...)
|
||||
end
|
||||
|
||||
--- Uncompress files from a .zip archive.
|
||||
-- @param zipfile string: pathname of .zip archive to be extracted.
|
||||
-- @return boolean: true on success, false on failure.
|
||||
function tools.unzip(zipfile)
|
||||
assert(zipfile)
|
||||
return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", zipfile)
|
||||
end
|
||||
|
||||
--- Test is pathname is a directory.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a directory, false otherwise.
|
||||
function tools.is_dir(file)
|
||||
assert(file)
|
||||
return fs.execute_quiet("if not exist " .. fs.Q(file.."\\").." invalidcommandname")
|
||||
end
|
||||
|
||||
--- Test is pathname is a regular file.
|
||||
-- @param file string: pathname to test
|
||||
-- @return boolean: true if it is a regular file, false otherwise.
|
||||
function tools.is_file(file)
|
||||
assert(file)
|
||||
return fs.execute(fs.Q(vars.TEST).." -f", file)
|
||||
end
|
||||
|
||||
--- Strip the last extension of a filename.
|
||||
-- Example: "foo.tar.gz" becomes "foo.tar".
|
||||
-- If filename has no dots, returns it unchanged.
|
||||
-- @param filename string: The file name to strip.
|
||||
-- @return string: The stripped name.
|
||||
local function strip_extension(filename)
|
||||
assert(type(filename) == "string")
|
||||
return (filename:gsub("%.[^.]+$", "")) or filename
|
||||
end
|
||||
|
||||
--- Uncompress gzip file.
|
||||
-- @param archive string: Filename of archive.
|
||||
-- @return boolean : success status
|
||||
local function gunzip(archive)
|
||||
return fs.execute_quiet(fs.Q(vars.SEVENZ).." -aoa x", archive)
|
||||
end
|
||||
|
||||
--- Unpack an archive.
|
||||
-- Extract the contents of an archive, detecting its format by
|
||||
-- filename extension.
|
||||
-- @param archive string: Filename of archive.
|
||||
-- @return boolean or (boolean, string): true on success, false and an error message on failure.
|
||||
function tools.unpack_archive(archive)
|
||||
assert(type(archive) == "string")
|
||||
|
||||
local ok
|
||||
local sevenzx = fs.Q(vars.SEVENZ).." -aoa x"
|
||||
if archive:match("%.tar%.gz$") then
|
||||
ok = gunzip(archive)
|
||||
if ok then
|
||||
ok = fs.execute_quiet(sevenzx, strip_extension(archive))
|
||||
end
|
||||
elseif archive:match("%.tgz$") then
|
||||
ok = gunzip(archive)
|
||||
if ok then
|
||||
ok = fs.execute_quiet(sevenzx, strip_extension(archive)..".tar")
|
||||
end
|
||||
elseif archive:match("%.tar%.bz2$") then
|
||||
ok = fs.execute_quiet(sevenzx, archive)
|
||||
if ok then
|
||||
ok = fs.execute_quiet(sevenzx, strip_extension(archive))
|
||||
end
|
||||
elseif archive:match("%.zip$") then
|
||||
ok = fs.execute_quiet(sevenzx, archive)
|
||||
elseif archive:match("%.lua$") or archive:match("%.c$") then
|
||||
-- Ignore .lua and .c files; they don't need to be extracted.
|
||||
return true
|
||||
else
|
||||
return false, "Couldn't extract archive "..archive..": unrecognized filename extension"
|
||||
end
|
||||
if not ok then
|
||||
return false, "Failed extracting "..archive
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Test for existance of a file.
|
||||
-- @param file string: filename to test
|
||||
-- @return boolean: true if file exists, false otherwise.
|
||||
function tools.exists(file)
|
||||
assert(file)
|
||||
return fs.execute_quiet("if not exist " .. fs.Q(file) .. " invalidcommandname")
|
||||
end
|
||||
|
||||
function tools.browser(url)
|
||||
return fs.execute(cfg.web_browser..' "Starting docs..." '..fs.Q(url))
|
||||
end
|
||||
|
||||
return tools
|
||||
Reference in New Issue
Block a user