From 4f15619eabf3b47853406bbb5b52f5878121df44 Mon Sep 17 00:00:00 2001 From: hisham Date: Thu, 16 Apr 2009 22:17:48 +0000 Subject: Greatly simplified the LuaRocks fs abstractions system git-svn-id: http://luarocks.org/svn/luarocks/trunk@8 9ca3f7c1-7366-0410-b1a3-b5c78f85698c --- src/luarocks/cfg.lua | 4 +- src/luarocks/fs.lua | 43 +++-- src/luarocks/fs/lua.lua | 119 ++++--------- src/luarocks/fs/unix.lua | 415 ++++---------------------------------------- src/luarocks/fs/win32.lua | 267 +--------------------------- src/luarocks/manif_core.lua | 1 + src/luarocks/tools/zip.lua | 6 +- 7 files changed, 98 insertions(+), 757 deletions(-) diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua index 71efea47..b667f8e7 100644 --- a/src/luarocks/cfg.lua +++ b/src/luarocks/cfg.lua @@ -1,6 +1,6 @@ -local rawset, next, table, pairs, print, require, io, os, setmetatable = - rawset, next, table, pairs, print, require, io, os, setmetatable +local rawset, next, table, pairs, print, require, io, os, setmetatable, program_version = + rawset, next, table, pairs, print, require, io, os, setmetatable, program_version --- Configuration for LuaRocks. -- Tries to load the user's configuration file and diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua index a905755d..d2cb3ddb 100644 --- a/src/luarocks/fs.lua +++ b/src/luarocks/fs.lua @@ -1,5 +1,5 @@ -local rawset = rawset +local pairs = pairs --- Proxy module for filesystem and platform abstractions. -- All code using "fs" code should require "luarocks.fs", @@ -10,33 +10,30 @@ module("luarocks.fs", package.seeall) local cfg = require("luarocks.cfg") -local fs_impl = nil -for _, platform in ipairs(cfg.platforms) do - local ok, result = pcall(require, "luarocks.fs."..platform) - if ok then - fs_impl = result - if fs_impl then - break +local function load_fns(fs_table) + for name, fn in pairs(fs_table) do + if not _M[name] then + _M[name] = fn end end end -local fs_lua = require("luarocks.fs.lua") -local fs_unix = require("luarocks.fs.unix") - -local fs_mt = { - __index = function(t, k) - local impl = fs_lua[k] or fs_impl[k] or fs_unix[k] - rawset(t, k, impl) - return impl +-- Load platform-specific functions +local loaded_platform = nil +for _, platform in ipairs(cfg.platforms) do + local ok, fs_plat = pcall(require, "luarocks.fs."..platform) + if ok and fs_plat then + loaded_platform = platform + load_fns(fs_plat) + break end -} +end -setmetatable(luarocks.fs, fs_mt) +-- Load platform-independent pure-Lua functionality +local fs_lua = require("luarocks.fs.lua") +load_fns(fs_lua) -fs_lua.init_fs_functions(luarocks.fs) -fs_unix.init_fs_functions(luarocks.fs) -if fs_impl then - fs_impl.init_fs_functions(luarocks.fs) -end +-- Load platform-specific fallbacks for missing Lua modules +local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") +if ok and fs_plat_tools then load_fns(fs_plat_tools) end diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 7d411e49..9f9a4b63 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -6,6 +6,8 @@ local assert, type, table, io, package, math, os, ipairs = -- using LuaFileSystem, LZLib, MD5 and LuaCurl. module("luarocks.fs.lua", package.seeall) +local fs = require("luarocks.fs") + local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") @@ -23,36 +25,6 @@ math.randomseed(os.time()) dir_separator = "/" -local fs_absolute_name, - fs_copy, - fs_current_dir, - fs_dir_stack, - fs_execute, - fs_execute_string, - fs_exists, - fs_find, - fs_is_dir, - fs_is_file, - fs_make_dir, - fs_set_time, - fs_Q - -function init_fs_functions(impl) - fs_absolute_name = impl.absolute_name - fs_copy = impl.copy - fs_current_dir = impl.current_dir - fs_dir_stack = impl.dir_stack - fs_execute = impl.execute - fs_execute_string = impl.execute_string - fs_exists = impl.exists - fs_find = impl.find - fs_is_dir = impl.is_dir - fs_is_file = impl.is_file - fs_make_dir = impl.make_dir - fs_set_time = impl.set_time - fs_Q = impl.Q -end - --- Quote argument for shell processing. -- Adds single quotes and escapes. -- @param arg string: Unquoted argument. @@ -73,7 +45,7 @@ end function is_writable(file) assert(file) local result - if fs_is_dir(file) then + if fs.is_dir(file) then local file2 = file .. '/.tmpluarockstestwritable' local fh = io.open(file2, 'w') result = fh ~= nil @@ -95,31 +67,13 @@ function make_temp_dir(name) assert(type(name) == "string") local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) - if fs_make_dir(temp_dir) then + if fs.make_dir(temp_dir) then return temp_dir else return nil end 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 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 - --- Split protocol and path from an URL or local pathname. -- URLs should be in the "protocol://path" format. -- For local pathnames, "file" is returned as the protocol. @@ -134,11 +88,28 @@ function split_url(url) pathname = url end if protocol == "file" then - pathname = fs_absolute_name(pathname) + pathname = fs.absolute_name(pathname) end return protocol, pathname 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 execute(command, ...) + assert(type(command) == "string") + + for _, arg in ipairs({...}) do + assert(type(arg) == "string") + command = command .. " " .. fs.Q(arg) + end + return fs.execute_string(command) +end + --------------------------------------------------------------------- -- LuaFileSystem functions --------------------------------------------------------------------- @@ -158,23 +129,6 @@ function execute_string(cmd) end 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 execute(command, ...) - assert(type(command) == "string") - - for _, arg in ipairs({...}) do - assert(type(arg) == "string") - command = command .. " " .. fs_Q(arg) - end - return fs_execute_string(command) -end - --- Obtain current directory. -- Uses the module's internal dir stack. -- @return string: the absolute pathname of the current directory. @@ -190,7 +144,6 @@ end function change_dir(d) table.insert(dir_stack, lfs.currentdir()) lfs.chdir(d) ---local x="CHDIR: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) end --- Change directory to root. @@ -200,14 +153,12 @@ function change_dir_to_root() table.insert(dir_stack, lfs.currentdir()) -- TODO Does this work on Windows? lfs.chdir("/") ---local x="CHDIR ROOT: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) end --- Change working directory to the previous in the dir stack. -- @return true if a pop ocurred, false if the stack was empty. function pop_dir() local d = table.remove(dir_stack) ---local x="POP DIR: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) if d then lfs.chdir(d) return true @@ -280,11 +231,11 @@ local function recursive_copy(src, dest) local srcmode = lfs.attributes(src, "mode") if srcmode == "file" then - local ok = fs_copy(src, dest) + local ok = fs.copy(src, dest) if not ok then return false end elseif srcmode == "directory" then local subdir = dir.path(dest, dir.base_name(src)) - fs_make_dir(subdir) + fs.make_dir(subdir) for file in lfs.dir(src) do if file ~= "." and file ~= ".." then local ok = recursive_copy(dir.path(src, file), subdir) @@ -354,9 +305,9 @@ end function list_dir(at) assert(type(at) == "string" or not at) if not at then - at = fs_current_dir() + at = fs.current_dir() end - if not fs_is_dir(at) then + if not fs.is_dir(at) then return {} end local result = {} @@ -392,9 +343,9 @@ end function find(at) assert(type(at) == "string" or not at) if not at then - at = fs_current_dir() + at = fs.current_dir() end - if not fs_is_dir(at) then + if not fs.is_dir(at) then return {} end local result = {} @@ -448,7 +399,7 @@ end function unzip(zipfile) assert(zipfile) -- FIXME!!!! - return fs_execute("unzip", zipfile) + return fs.execute("unzip", zipfile) end end @@ -506,7 +457,7 @@ if md5_ok then -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not -- or if it could not perform the check for any reason. function check_md5(file, md5sum) - file = fs_absolute_name(file) + file = fs.absolute_name(file) local file = io.open(file, "r") if not file then return false end local computed = md5.sumhexa(file:read("*a")) @@ -545,13 +496,13 @@ function unpack_archive(archive) local ok if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then - -- ok = fs_execute("tar zxvpf ", archive) - ok = fs_execute_string("gunzip -c "..archive.."|tar -xf -") + -- ok = fs.execute("tar zxvpf ", archive) + ok = fs.execute_string("gunzip -c "..archive.."|tar -xf -") elseif archive:match("%.tar%.bz2$") then - -- ok = fs_execute("tar jxvpf ", archive) - ok = fs_execute_string("bunzip2 -c "..archive.."|tar -xf -") + -- ok = fs.execute("tar jxvpf ", archive) + ok = fs.execute_string("bunzip2 -c "..archive.."|tar -xf -") elseif archive:match("%.zip$") then - ok = fs_execute("unzip ", archive) + ok = fs.execute("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 diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua index 1f8411c9..dba152ef 100644 --- a/src/luarocks/fs/unix.lua +++ b/src/luarocks/fs/unix.lua @@ -5,389 +5,14 @@ local assert, type, table, io, package, math, os, ipairs = --- Unix implementation of filesystem and platform abstractions. module("luarocks.fs.unix", package.seeall) +local fs = require("luarocks.fs") + local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") +local fs = require("luarocks.fs") math.randomseed(os.time()) -dir_stack = {} - -local fs_absolute_name, - fs_copy, - fs_current_dir, - fs_dir_stack, - fs_execute, - fs_execute_string, - fs_is_dir, - fs_is_file, - fs_make_dir, - fs_exists, - fs_find, - fs_Q - -function init_fs_functions(impl) - fs_absolute_name = impl.absolute_name - fs_copy = impl.copy - fs_current_dir = impl.current_dir - fs_dir_stack = impl.dir_stack - fs_execute = impl.execute - fs_execute_string = impl.execute_string - fs_is_dir = impl.is_dir - fs_is_file = impl.is_file - fs_make_dir = impl.make_dir - fs_exists = impl.exists - fs_find = impl.find - fs_Q = impl.Q -end - ---- Quote argument for shell processing. --- Adds single quotes and escapes. --- @param arg string: Unquoted argument. --- @return string: Quoted argument. -function Q(arg) - assert(type(arg) == "string") - - return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'" -end - ---- Obtain current directory. --- Uses the module's internal dir stack. --- @return string: the absolute pathname of the current directory. -function current_dir() - local current = os.getenv("PWD") - if not current then - local pipe = io.popen("pwd") - current = pipe:read("*l") - pipe:close() - end - for _, d in ipairs(fs_dir_stack) do - current = fs_absolute_name(d, current) - end - return current -end - ---- 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 execute_string(cmd) - if os.execute("cd " .. fs_Q(fs_current_dir()) .. " && " .. cmd) == 0 then - return true - else - return false - end -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 execute(command, ...) - assert(type(command) == "string") - - for _, arg in ipairs({...}) do - assert(type(arg) == "string") - command = command .. " " .. fs_Q(arg) - end - return fs_execute_string(command) -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 change_dir(d) - assert(type(d) == "string") - table.insert(fs_dir_stack, d) -end - ---- Change directory to root. --- Allows leaving a directory (e.g. for deleting it) in --- a crossplatform way. -function change_dir_to_root() - table.insert(fs_dir_stack, "/") -end - ---- Change working directory to the previous in the dir stack. -function pop_dir() - local d = table.remove(fs_dir_stack) - return d ~= nil -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 d string: pathname of directory to create. --- @return boolean: true on success, false on failure. -function make_dir(d) - assert(d) - return fs_execute("mkdir -p", 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 dir string: pathname of directory to remove. -function remove_dir_if_empty(d) - assert(d) - fs_execute_string("rmdir "..fs_Q(d).." 1> /dev/null 2> /dev/null") -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 copy(src, dest) - assert(src and dest) - if fs_execute("cp", src, dest) 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 copy_contents(src, dest) - assert(src and dest) - if fs_execute_string("cp -pPR "..fs_Q(src).."/* "..fs_Q(dest).." 1> /dev/null 2>/dev/null") 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 boolean: true on success, false on failure. -function delete(arg) - assert(arg) - assert(arg:sub(1,1) == "/") - return fs_execute_string("rm -rf " .. fs_Q(arg) .. " 1> /dev/null 2>/dev/null") -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 list_dir(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("cd "..fs_Q(at).." && ls") - for file in pipe:lines() do - table.insert(result, file) - end - pipe:close() - return result -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 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("cd "..fs_Q(at).." && find * 2>/dev/null") - 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 zip(zipfile, ...) - return fs_execute("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 unzip(zipfile) - assert(zipfile) - return fs_execute("unzip", zipfile) -end - ---- Test for existance of a file. --- @param file string: filename to test --- @return boolean: true if file exists, false otherwise. -function exists(file) - assert(file) - return fs_execute("test -r", file) -end - ---- Test is file/dir is writable. --- @param file string: filename to test --- @return boolean: true if file exists, false otherwise. -function is_writable(file) - assert(file) - return fs_execute("test -w", 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 is_dir(file) - assert(file) - return fs_execute("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 is_file(file) - assert(file) - return fs_execute("test -f", file) -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: true on success, false on failure. -function download(url, filename) - assert(type(url) == "string") - assert(type(filename) == "string" or not filename) - - if cfg.downloader == "wget" then - local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " - if filename then - return fs_execute(wget_cmd.." --output-document ", filename, url) - else - return fs_execute(wget_cmd, url) - end - elseif cfg.downloader == "curl" then - filename = filename or dir.base_name(url) - return fs_execute_string("curl --user-agent "..cfg.user_agent.." "..fs_Q(url).." 2> /dev/null 1> "..fs_Q(filename)) - end -end - ---- Create a temporary directory. --- @param name string: name pattern to use for avoiding conflicts --- when creating temporary directory. --- @return string or nil: name of temporary directory or nil on failure. -function make_temp_dir(name) - assert(type(name) == "string") - - local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) - if fs_make_dir(temp_dir) then - return temp_dir - else - return nil - end -end - -function chmod(pathname, mode) - return fs_execute("chmod "..mode, pathname) -end - ---- Apply a patch. --- @param patchname string: The filename of the patch. -function apply_patch(patchname) - return fs_execute("patch -p1 -f -i ", patchname) -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 unpack_archive(archive) - assert(type(archive) == "string") - - local ok - if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then - -- ok = fs_execute("tar zxvpf ", archive) - ok = fs_execute_string("gunzip -c "..archive.."|tar -xf -") - elseif archive:match("%.tar%.bz2$") then - -- ok = fs_execute("tar jxvpf ", archive) - ok = fs_execute_string("bunzip2 -c "..archive.."|tar -xf -") - elseif archive:match("%.zip$") then - ok = fs_execute("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 - local ext = archive:match(".*(%..*)") - return false, "Unrecognized filename extension "..(ext or "") - end - if not ok then - return false, "Failed extracting "..archive - end - return true -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 if not --- or if it could not perform the check for any reason. -function check_md5(file, md5sum) - file = fs_absolute_name(file) - local computed - if cfg.md5checker == "md5sum" then - local pipe = io.popen("md5sum "..file) - computed = pipe:read("*l"):gsub("[^%x]+", "") - pipe:close() - if computed then - computed = computed:sub(1,32) - end - elseif cfg.md5checker == "openssl" then - local pipe = io.popen("openssl md5 "..file) - computed = pipe:read("*l") - pipe:close() - if computed then - computed = computed:sub(-32) - end - elseif cfg.md5checker == "md5" then - local pipe = io.popen("md5 "..file) - computed = pipe:read("*l") - pipe:close() - if computed then - computed = computed:sub(-32) - end - end - if not computed then - return false - end - if computed:match("^"..md5sum) then - return true - else - return false - end -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 @@ -398,7 +23,7 @@ function 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() + relative_to = relative_to or fs.current_dir() if pathname:sub(1,1) == "/" then return pathname else @@ -420,7 +45,7 @@ function split_url(url) pathname = url end if protocol == "file" then - pathname = fs_absolute_name(pathname) + pathname = fs.absolute_name(pathname) end return protocol, pathname end @@ -446,7 +71,7 @@ function wrap_script(file, dest) wrapper:write('export LUA_PATH LUA_CPATH\n') wrapper:write('exec "'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.require "'..file..'" "$@"\n') wrapper:close() - if fs_execute("chmod +x",wrapname) then + if fs.execute("chmod +x",wrapname) then return true else return nil, "Could not make "..wrapname.." executable." @@ -487,7 +112,33 @@ function is_actual_binary(filename) return false end +function is_actual_binary(filename) + if filename:match("%.lua$") then + return false + end + local file = io.open(filename) + if file then + local found = false + local first = file:read() + if first:match("#!.*lua") then + file:close() + return true + elseif first:match("#!/bin/sh") then + local line = file:read() + line = file:read() + if not(line and line:match("LUA_PATH")) then + file:close() + return true + end + end + file:close() + else + return true + end + return false +end + function copy_binary(filename, dest) - return fs_copy(filename, dest) + return fs.copy(filename, dest) end diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index da9b7d60..d005781e 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -3,25 +3,11 @@ -- used by this module. module("luarocks.fs.win32", package.seeall) +local fs = require("luarocks.fs") + local cfg = require("luarocks.cfg") local dir = require("luarocks.dir") -local fs_copy, - fs_current_dir, - fs_execute, - fs_execute_string, - fs_is_dir, - fs_Q - -function init_fs_functions(impl) - fs_copy = impl.copy - fs_current_dir = impl.current_dir - fs_execute = impl.execute - fs_execute_string = impl.execute_string - fs_is_dir = impl.is_dir - fs_Q = impl.Q -end - --- Quote argument for shell processing. Fixes paths on Windows. -- Adds single quotes and escapes. -- @param arg string: Unquoted argument. @@ -36,202 +22,6 @@ function Q(arg) return '"' .. arg:gsub('"', '\\"') .. '"' end -local function 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 - ---- 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 execute_string(cmd) - if os.execute(command_at(fs_current_dir(), cmd)) == 0 then - return true - else - return false - end -end - ---- Test for existance of a file. --- @param file string: filename to test --- @return boolean: true if file exists, false otherwise. -function exists(file) - assert(file) - return fs_execute("if not exist " .. fs_Q(file) .. - " invalidcommandname 2>NUL 1>NUL") -end - ---- Test is pathname is a directory. --- @param file string: pathname to test --- @return boolean: true if it is a directory, false otherwise. -function is_dir(file) - assert(file) - return fs_execute("chdir /D " .. fs_Q(file) .. " 2>NUL 1>NUL") -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 is_dir(file) - assert(file) - return fs_execute("test -d" .. fs_Q(file) .. " 2>NUL 1>NUL") -end - ---- Test is file/dir is writable. --- @param file string: filename to test --- @return boolean: true if file exists, false otherwise. -function is_writable(file) - assert(file) - local result - if is_dir(file) then - local file2 = file .. '/.tmpluarockstestwritable' - local fh = io.open(file2, 'w') - result = fh ~= nil - if fh then fh:close() end - os.remove(file2) - else - local fh = io.open(file, 'r+') - result = fh ~= nil - if fh then fh:close() end - end - return result -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 d string: pathname of directory to create. --- @return boolean: true on success, false on failure. -function make_dir(d) - assert(d) - fs_execute("mkdir "..fs_Q(d).." 1> NUL 2> NUL") - return 1 -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 remove_dir_if_empty(d) - assert(d) - fs_execute_string("rmdir "..fs_Q(d).." 1> NUL 2> NUL") -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 copy(src, dest) - assert(src and dest) - if dest:match("[/\\]$") then dest = dest:sub(1, -2) end - if fs_execute("cp", src, dest) 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 copy_contents(src, dest) - assert(src and dest) - if fs_execute_string("cp -a "..src.."\\*.* "..fs_Q(dest).." 1> NUL 2> NUL") 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 boolean: true on success, false on failure. -function delete(arg) - assert(arg) - assert(arg:match("^[\a-zA-Z]?:?[\\/]")) - fs_execute("chmod a+rw -R ", arg) - return fs_execute_string("rm -rf " .. fs_Q(arg) .. " 1> NUL 2> NUL") -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 list_dir(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(command_at(at, "ls")) - for file in pipe:lines() do - table.insert(result, file) - end - pipe:close() - - return result -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 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(command_at(at, "find 2> NUL")) - for file in pipe:lines() do - -- Windows find is a bit different - if file:sub(1,2)==".\\" then file=file:sub(3) end - if file ~= "." then - table.insert(result, (file:gsub("\\", "/"))) - end - end - return result -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: true on success, false on failure. -function download(url, filename) - assert(type(url) == "string") - assert(type(filename) == "string" or not filename) - local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " - - if filename then - return fs_execute(wget_cmd.." --output-document ", filename, url) - else - return fs_execute(wget_cmd, url) - end -end - --- Strip the last extension of a filename. -- Example: "foo.tar.gz" becomes "foo.tar". -- If filename has no dots, returns it unchanged. @@ -243,55 +33,6 @@ local function strip_extension(filename) return (filename:gsub("%.[^.]+$", "")) or filename end ---- Uncompress gzip file. --- @param archive string: Filename of archive. --- @return boolean : success status -local function gunzip(archive) - local cmd = fs_execute("gunzip -h 1>NUL 2>NUL") and 'gunzip' or - fs_execute("gzip -h 1>NUL 2>NUL") and 'gzip -d' - local ok = fs_execute(cmd, archive) - return ok -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 unpack_archive(archive) - assert(type(archive) == "string") - - local ok - if archive:match("%.tar%.gz$") then - ok = gunzip(archive) - if ok then - ok = fs_execute("tar -xf ", strip_extension(archive)) - end - elseif archive:match("%.tgz$") then - ok = gunzip(archive) - if ok then - ok = fs_execute("tar -xf ", strip_extension(archive)..".tar") - end - elseif archive:match("%.tar%.bz2$") then - ok = fs_execute("bunzip2 ", archive) - if ok then - ok = fs_execute("tar -xf ", strip_extension(archive)) - end - elseif archive:match("%.zip$") then - ok = fs_execute("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 - local ext = archive:match(".*(%..*)") - return false, "Unrecognized filename extension "..(ext or "") - end - if not ok then - return false, "Failed extracting "..archive - end - return true -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 @@ -302,7 +43,7 @@ function 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() + relative_to = relative_to or fs.current_dir() if pathname:match("^[\.a-zA-Z]?:?[\\/]") then return pathname else @@ -344,7 +85,7 @@ function is_actual_binary(name) end function copy_binary(filename, dest) - local ok, err = fs_copy(filename, dest) + local ok, err = fs.copy(filename, dest) if not ok then return nil, err end diff --git a/src/luarocks/manif_core.lua b/src/luarocks/manif_core.lua index 941c569d..d1eb4ebb 100644 --- a/src/luarocks/manif_core.lua +++ b/src/luarocks/manif_core.lua @@ -1,5 +1,6 @@ --- Core functions for querying manifest files. +-- This module requires no specific 'fs' functionality. module("luarocks.manif_core", package.seeall) local persist = require("luarocks.persist") diff --git a/src/luarocks/tools/zip.lua b/src/luarocks/tools/zip.lua index 621beae1..18ad967e 100644 --- a/src/luarocks/tools/zip.lua +++ b/src/luarocks/tools/zip.lua @@ -209,9 +209,9 @@ function zip(zipfile, ...) local ok, err for _, file in pairs({...}) do - if fs_is_dir(file) then - for _, file in pairs(fs_find(file)) do - if fs_is_file(file) then + if fs.is_dir(file) then + for _, file in pairs(fs.find(file)) do + if fs.is_file(file) then ok, err = add_to_zip(file) if not ok then break end end -- cgit v1.2.3-55-g6feb