diff options
| author | Hisham Muhammad <hisham@gobolinux.org> | 2025-12-28 19:22:31 -0300 |
|---|---|---|
| committer | Hisham Muhammad <hisham@gobolinux.org> | 2025-12-28 19:22:31 -0300 |
| commit | ed96305bc55cd27b7efc191724f29786a7a34026 (patch) | |
| tree | a44d0ec90a5a8fbbd772a9e58bc7f3950b39ba01 | |
| parent | f22578d60941e3206ab6a2a0c80aabb70e91731b (diff) | |
| download | luarocks-ed96305bc55cd27b7efc191724f29786a7a34026.tar.gz luarocks-ed96305bc55cd27b7efc191724f29786a7a34026.tar.bz2 luarocks-ed96305bc55cd27b7efc191724f29786a7a34026.zip | |
fs: remove external-tool-based modules
| -rw-r--r-- | src/luarocks/fs/tools.lua | 222 | ||||
| -rw-r--r-- | src/luarocks/fs/unix/tools.lua | 365 | ||||
| -rw-r--r-- | src/luarocks/fs/win32/tools.lua | 331 | ||||
| -rw-r--r-- | vendor/lua-zlib/lua-zlib-1.2-0.rockspec (renamed from vendor/lua-zlib/lua-zlib-1.1-0.rockspec) | 0 |
4 files changed, 0 insertions, 918 deletions
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua deleted file mode 100644 index b7d03759..00000000 --- a/src/luarocks/fs/tools.lua +++ /dev/null | |||
| @@ -1,222 +0,0 @@ | |||
| 1 | |||
| 2 | --- Common fs operations implemented with third-party tools. | ||
| 3 | local tools = {} | ||
| 4 | |||
| 5 | local fs = require("luarocks.fs") | ||
| 6 | local dir = require("luarocks.dir") | ||
| 7 | local cfg = require("luarocks.core.cfg") | ||
| 8 | |||
| 9 | local vars = setmetatable({}, { __index = function(_,k) return cfg.variables[k] end }) | ||
| 10 | |||
| 11 | local dir_stack = {} | ||
| 12 | |||
| 13 | do | ||
| 14 | local tool_cache = {} | ||
| 15 | |||
| 16 | local tool_options = { | ||
| 17 | downloader = { | ||
| 18 | desc = "downloader", | ||
| 19 | { var = "WGET", name = "wget" }, | ||
| 20 | { var = "CURL", name = "curl" }, | ||
| 21 | }, | ||
| 22 | md5checker = { | ||
| 23 | desc = "MD5 checker", | ||
| 24 | { var = "MD5SUM", name = "md5sum" }, | ||
| 25 | { var = "OPENSSL", name = "openssl", cmdarg = "md5" }, | ||
| 26 | { var = "MD5", name = "md5" }, | ||
| 27 | }, | ||
| 28 | } | ||
| 29 | |||
| 30 | function tools.which_tool(tooltype) | ||
| 31 | local tool = tool_cache[tooltype] | ||
| 32 | local names = {} | ||
| 33 | if not tool then | ||
| 34 | for _, opt in ipairs(tool_options[tooltype]) do | ||
| 35 | table.insert(names, opt.name) | ||
| 36 | if fs.is_tool_available(vars[opt.var], opt.name) then | ||
| 37 | tool = opt | ||
| 38 | tool_cache[tooltype] = opt | ||
| 39 | break | ||
| 40 | end | ||
| 41 | end | ||
| 42 | end | ||
| 43 | if not tool then | ||
| 44 | local tool_names = table.concat(names, ", ", 1, #names - 1) .. " or " .. names[#names] | ||
| 45 | return nil, "no " .. tool_options[tooltype].desc .. " tool available," .. " please install " .. tool_names .. " in your system" | ||
| 46 | end | ||
| 47 | return tool.name, vars[tool.var] .. (tool.cmdarg and " "..tool.cmdarg or "") | ||
| 48 | end | ||
| 49 | end | ||
| 50 | |||
| 51 | local current_dir_with_cache | ||
| 52 | do | ||
| 53 | local cache_pwd | ||
| 54 | |||
| 55 | current_dir_with_cache = function() | ||
| 56 | local current = cache_pwd | ||
| 57 | if not current then | ||
| 58 | local pipe = io.popen(fs.quiet_stderr(vars.PWD)) | ||
| 59 | current = pipe:read("*a"):gsub("^%s*", ""):gsub("%s*$", "") | ||
| 60 | pipe:close() | ||
| 61 | cache_pwd = current | ||
| 62 | end | ||
| 63 | for _, directory in ipairs(dir_stack) do | ||
| 64 | current = fs.absolute_name(directory, current) | ||
| 65 | end | ||
| 66 | return current, cache_pwd | ||
| 67 | end | ||
| 68 | |||
| 69 | --- Obtain current directory. | ||
| 70 | -- Uses the module's internal directory stack. | ||
| 71 | -- @return string: the absolute pathname of the current directory. | ||
| 72 | function tools.current_dir() | ||
| 73 | return (current_dir_with_cache()) -- drop second return | ||
| 74 | end | ||
| 75 | end | ||
| 76 | |||
| 77 | --- Change the current directory. | ||
| 78 | -- Uses the module's internal directory stack. This does not have exact | ||
| 79 | -- semantics of chdir, as it does not handle errors the same way, | ||
| 80 | -- but works well for our purposes for now. | ||
| 81 | -- @param directory string: The directory to switch to. | ||
| 82 | -- @return boolean or (nil, string): true if successful, (nil, error message) if failed. | ||
| 83 | function tools.change_dir(directory) | ||
| 84 | assert(type(directory) == "string") | ||
| 85 | if fs.is_dir(directory) then | ||
| 86 | table.insert(dir_stack, directory) | ||
| 87 | return true | ||
| 88 | end | ||
| 89 | return nil, "directory not found: "..directory | ||
| 90 | end | ||
| 91 | |||
| 92 | --- Change directory to root. | ||
| 93 | -- Allows leaving a directory (e.g. for deleting it) in | ||
| 94 | -- a crossplatform way. | ||
| 95 | function tools.change_dir_to_root() | ||
| 96 | local curr_dir = fs.current_dir() | ||
| 97 | if not curr_dir or not fs.is_dir(curr_dir) then | ||
| 98 | return false | ||
| 99 | end | ||
| 100 | table.insert(dir_stack, "/") | ||
| 101 | return true | ||
| 102 | end | ||
| 103 | |||
| 104 | --- Change working directory to the previous in the directory stack. | ||
| 105 | function tools.pop_dir() | ||
| 106 | local directory = table.remove(dir_stack) | ||
| 107 | return directory ~= nil | ||
| 108 | end | ||
| 109 | |||
| 110 | --- Run the given command. | ||
| 111 | -- The command is executed in the current directory in the directory stack. | ||
| 112 | -- @param cmd string: No quoting/escaping is applied to the command. | ||
| 113 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 114 | -- otherwise. | ||
| 115 | function tools.execute_string(cmd) | ||
| 116 | local current, cache_pwd = current_dir_with_cache() | ||
| 117 | if not current then return false end | ||
| 118 | if current ~= cache_pwd then | ||
| 119 | cmd = fs.command_at(current, cmd) | ||
| 120 | end | ||
| 121 | local code = os.execute(cmd) | ||
| 122 | if code == 0 or code == true then | ||
| 123 | return true | ||
| 124 | else | ||
| 125 | return false | ||
| 126 | end | ||
| 127 | end | ||
| 128 | |||
| 129 | --- Internal implementation function for fs.dir. | ||
| 130 | -- Yields a filename on each iteration. | ||
| 131 | -- @param at string: directory to list | ||
| 132 | -- @return nil | ||
| 133 | function tools.dir_iterator(at) | ||
| 134 | local pipe = io.popen(fs.command_at(at, vars.LS, true)) | ||
| 135 | for file in pipe:lines() do | ||
| 136 | if file ~= "." and file ~= ".." then | ||
| 137 | coroutine.yield(file) | ||
| 138 | end | ||
| 139 | end | ||
| 140 | pipe:close() | ||
| 141 | end | ||
| 142 | |||
| 143 | --- Download a remote file. | ||
| 144 | -- @param url string: URL to be fetched. | ||
| 145 | -- @param filename string or nil: this function attempts to detect the | ||
| 146 | -- resulting local filename of the remote file as the basename of the URL; | ||
| 147 | -- if that is not correct (due to a redirection, for example), the local | ||
| 148 | -- filename can be given explicitly as this second argument. | ||
| 149 | -- @param cache boolean: compare remote timestamps via HTTP HEAD prior to | ||
| 150 | -- re-downloading the file. | ||
| 151 | -- @return (string, string, string): filename on success, | ||
| 152 | -- false and the error message and code on failure. | ||
| 153 | function tools.use_downloader(url, filename, cache) | ||
| 154 | assert(type(url) == "string") | ||
| 155 | assert(type(filename) == "string" or not filename) | ||
| 156 | |||
| 157 | filename = fs.absolute_name(filename or dir.base_name(url)) | ||
| 158 | |||
| 159 | local downloader, err = fs.which_tool("downloader") | ||
| 160 | if not downloader then | ||
| 161 | return nil, err, "downloader" | ||
| 162 | end | ||
| 163 | |||
| 164 | local ok = false | ||
| 165 | if downloader == "wget" then | ||
| 166 | local wget_cmd = vars.WGET.." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet " | ||
| 167 | if cfg.connection_timeout and cfg.connection_timeout > 0 then | ||
| 168 | wget_cmd = wget_cmd .. "--timeout="..tostring(cfg.connection_timeout).." --tries=1 " | ||
| 169 | end | ||
| 170 | if cache then | ||
| 171 | -- --timestamping is incompatible with --output-document, | ||
| 172 | -- but that's not a problem for our use cases. | ||
| 173 | fs.delete(filename .. ".unixtime") | ||
| 174 | fs.change_dir(dir.dir_name(filename)) | ||
| 175 | ok = fs.execute_quiet(wget_cmd.." --timestamping ", url) | ||
| 176 | fs.pop_dir() | ||
| 177 | elseif filename then | ||
| 178 | ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url) | ||
| 179 | else | ||
| 180 | ok = fs.execute_quiet(wget_cmd, url) | ||
| 181 | end | ||
| 182 | elseif downloader == "curl" then | ||
| 183 | local curl_cmd = vars.CURL.." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" " | ||
| 184 | if cfg.connection_timeout and cfg.connection_timeout > 0 then | ||
| 185 | curl_cmd = curl_cmd .. "--connect-timeout "..tostring(cfg.connection_timeout).." " | ||
| 186 | end | ||
| 187 | if cache then | ||
| 188 | curl_cmd = curl_cmd .. " -R -z \"" .. filename .. "\" " | ||
| 189 | end | ||
| 190 | ok = fs.execute_string(fs.quiet_stderr(curl_cmd..fs.Q(url).." --output "..fs.Q(filename))) | ||
| 191 | end | ||
| 192 | if ok then | ||
| 193 | return filename | ||
| 194 | else | ||
| 195 | os.remove(filename) | ||
| 196 | return nil, "failed downloading " .. url, "network" | ||
| 197 | end | ||
| 198 | end | ||
| 199 | |||
| 200 | --- Get the MD5 checksum for a file. | ||
| 201 | -- @param file string: The file to be computed. | ||
| 202 | -- @return string: The MD5 checksum or nil + message | ||
| 203 | function tools.get_md5(file) | ||
| 204 | local ok, md5checker = fs.which_tool("md5checker") | ||
| 205 | if not ok then | ||
| 206 | return false, md5checker | ||
| 207 | end | ||
| 208 | |||
| 209 | local pipe = io.popen(md5checker.." "..fs.Q(fs.absolute_name(file))) | ||
| 210 | local computed = pipe:read("*l") | ||
| 211 | pipe:close() | ||
| 212 | if computed then | ||
| 213 | computed = computed:match("("..("%x"):rep(32)..")") | ||
| 214 | end | ||
| 215 | if computed then | ||
| 216 | return computed | ||
| 217 | else | ||
| 218 | return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file)) | ||
| 219 | end | ||
| 220 | end | ||
| 221 | |||
| 222 | return tools | ||
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua deleted file mode 100644 index 2127aed6..00000000 --- a/src/luarocks/fs/unix/tools.lua +++ /dev/null | |||
| @@ -1,365 +0,0 @@ | |||
| 1 | |||
| 2 | --- fs operations implemented with third-party tools for Unix platform abstractions. | ||
| 3 | local tools = {} | ||
| 4 | |||
| 5 | local fs = require("luarocks.fs") | ||
| 6 | local dir = require("luarocks.dir") | ||
| 7 | local cfg = require("luarocks.core.cfg") | ||
| 8 | |||
| 9 | local vars = setmetatable({}, { __index = function(_,k) return cfg.variables[k] end }) | ||
| 10 | |||
| 11 | --- Adds prefix to command to make it run from a directory. | ||
| 12 | -- @param directory string: Path to a directory. | ||
| 13 | -- @param cmd string: A command-line string. | ||
| 14 | -- @return string: The command-line with prefix. | ||
| 15 | function tools.command_at(directory, cmd) | ||
| 16 | return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd | ||
| 17 | end | ||
| 18 | |||
| 19 | --- Create a directory if it does not already exist. | ||
| 20 | -- If any of the higher levels in the path name does not exist | ||
| 21 | -- too, they are created as well. | ||
| 22 | -- @param directory string: pathname of directory to create. | ||
| 23 | -- @return boolean: true on success, false on failure. | ||
| 24 | function tools.make_dir(directory) | ||
| 25 | assert(directory) | ||
| 26 | local ok, err = fs.execute(vars.MKDIR.." -p", directory) | ||
| 27 | if not ok then | ||
| 28 | err = "failed making directory "..directory | ||
| 29 | end | ||
| 30 | return ok, err | ||
| 31 | end | ||
| 32 | |||
| 33 | --- Remove a directory if it is empty. | ||
| 34 | -- Does not return errors (for example, if directory is not empty or | ||
| 35 | -- if already does not exist) | ||
| 36 | -- @param directory string: pathname of directory to remove. | ||
| 37 | function tools.remove_dir_if_empty(directory) | ||
| 38 | assert(directory) | ||
| 39 | fs.execute_quiet(vars.RMDIR, directory) | ||
| 40 | end | ||
| 41 | |||
| 42 | --- Remove a directory if it is empty. | ||
| 43 | -- Does not return errors (for example, if directory is not empty or | ||
| 44 | -- if already does not exist) | ||
| 45 | -- @param directory string: pathname of directory to remove. | ||
| 46 | function tools.remove_dir_tree_if_empty(directory) | ||
| 47 | assert(directory) | ||
| 48 | fs.execute_quiet(vars.RMDIR, "-p", directory) | ||
| 49 | end | ||
| 50 | |||
| 51 | --- Copy a file. | ||
| 52 | -- @param src string: Pathname of source | ||
| 53 | -- @param dest string: Pathname of destination | ||
| 54 | -- @param perm string ("read" or "exec") or nil: Permissions for destination | ||
| 55 | -- file or nil to use the source permissions | ||
| 56 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 57 | -- plus an error message. | ||
| 58 | function tools.copy(src, dest, perm) | ||
| 59 | assert(src and dest) | ||
| 60 | if fs.execute(vars.CP, src, dest) then | ||
| 61 | if perm then | ||
| 62 | if fs.is_dir(dest) then | ||
| 63 | dest = dir.path(dest, dir.base_name(src)) | ||
| 64 | end | ||
| 65 | if fs.set_permissions(dest, perm, "all") then | ||
| 66 | return true | ||
| 67 | else | ||
| 68 | return false, "Failed setting permissions of "..dest | ||
| 69 | end | ||
| 70 | end | ||
| 71 | return true | ||
| 72 | else | ||
| 73 | return false, "Failed copying "..src.." to "..dest | ||
| 74 | end | ||
| 75 | end | ||
| 76 | |||
| 77 | --- Recursively copy the contents of a directory. | ||
| 78 | -- @param src string: Pathname of source | ||
| 79 | -- @param dest string: Pathname of destination | ||
| 80 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 81 | -- plus an error message. | ||
| 82 | function tools.copy_contents(src, dest) | ||
| 83 | assert(src and dest) | ||
| 84 | if not fs.is_dir(src) then | ||
| 85 | return false, src .. " is not a directory" | ||
| 86 | end | ||
| 87 | if fs.make_dir(dest) and fs.execute_quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest)) then | ||
| 88 | return true | ||
| 89 | else | ||
| 90 | return false, "Failed copying "..src.." to "..dest | ||
| 91 | end | ||
| 92 | end | ||
| 93 | --- Delete a file or a directory and all its contents. | ||
| 94 | -- For safety, this only accepts absolute paths. | ||
| 95 | -- @param pathname string: Pathname of source | ||
| 96 | -- @return true on success, nil and an error on failure | ||
| 97 | function tools.delete(pathname) | ||
| 98 | assert(pathname) | ||
| 99 | assert(pathname:sub(1,1) == "/") | ||
| 100 | if fs.execute_quiet(vars.RM, "-rf", pathname) then | ||
| 101 | return true | ||
| 102 | else | ||
| 103 | return nil, "failed deleting " .. pathname | ||
| 104 | end | ||
| 105 | end | ||
| 106 | |||
| 107 | --- Recursively scan the contents of a directory. | ||
| 108 | -- @param at string or nil: directory to scan (will be the current | ||
| 109 | -- directory if none is given). | ||
| 110 | -- @return table: an array of strings with the filenames representing | ||
| 111 | -- the contents of a directory. | ||
| 112 | function tools.find(at) | ||
| 113 | assert(type(at) == "string" or not at) | ||
| 114 | if not at then | ||
| 115 | at = fs.current_dir() | ||
| 116 | end | ||
| 117 | if not fs.is_dir(at) then | ||
| 118 | return {} | ||
| 119 | end | ||
| 120 | local result = {} | ||
| 121 | local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND.." *"))) | ||
| 122 | for file in pipe:lines() do | ||
| 123 | table.insert(result, file) | ||
| 124 | end | ||
| 125 | pipe:close() | ||
| 126 | return result | ||
| 127 | end | ||
| 128 | |||
| 129 | --- Compress files in a .zip archive. | ||
| 130 | -- @param zipfile string: pathname of .zip archive to be created. | ||
| 131 | -- @param ... Filenames to be stored in the archive are given as | ||
| 132 | -- additional arguments. | ||
| 133 | -- @return boolean: true on success, nil and error message on failure. | ||
| 134 | function tools.zip(zipfile, ...) | ||
| 135 | local ok, err = fs.is_tool_available(vars.ZIP, "zip") | ||
| 136 | if not ok then | ||
| 137 | return nil, err | ||
| 138 | end | ||
| 139 | if fs.execute_quiet(vars.ZIP.." -r", zipfile, ...) then | ||
| 140 | return true | ||
| 141 | else | ||
| 142 | return nil, "failed compressing " .. zipfile | ||
| 143 | end | ||
| 144 | end | ||
| 145 | |||
| 146 | --- Uncompress files from a .zip archive. | ||
| 147 | -- @param zipfile string: pathname of .zip archive to be extracted. | ||
| 148 | -- @return boolean: true on success, nil and error message on failure. | ||
| 149 | function tools.unzip(zipfile) | ||
| 150 | assert(zipfile) | ||
| 151 | local ok, err = fs.is_tool_available(vars.UNZIP, "unzip") | ||
| 152 | if not ok then | ||
| 153 | return nil, err | ||
| 154 | end | ||
| 155 | if fs.execute_quiet(vars.UNZIP, zipfile) then | ||
| 156 | return true | ||
| 157 | else | ||
| 158 | return nil, "failed extracting " .. zipfile | ||
| 159 | end | ||
| 160 | end | ||
| 161 | |||
| 162 | local function uncompress(default_ext, program, infile, outfile) | ||
| 163 | assert(type(infile) == "string") | ||
| 164 | assert(outfile == nil or type(outfile) == "string") | ||
| 165 | if not outfile then | ||
| 166 | outfile = infile:gsub("%."..default_ext.."$", "") | ||
| 167 | end | ||
| 168 | if fs.execute(fs.Q(program).." -c "..fs.Q(infile).." > "..fs.Q(outfile)) then | ||
| 169 | return true | ||
| 170 | else | ||
| 171 | return nil, "failed extracting " .. infile | ||
| 172 | end | ||
| 173 | end | ||
| 174 | |||
| 175 | --- Uncompresses a .gz file. | ||
| 176 | -- @param infile string: pathname of .gz file to be extracted. | ||
| 177 | -- @param outfile string or nil: pathname of output file to be produced. | ||
| 178 | -- If not given, name is derived from input file. | ||
| 179 | -- @return boolean: true on success; nil and error message on failure. | ||
| 180 | function tools.gunzip(infile, outfile) | ||
| 181 | return uncompress("gz", "gunzip", infile, outfile) | ||
| 182 | end | ||
| 183 | |||
| 184 | --- Uncompresses a .bz2 file. | ||
| 185 | -- @param infile string: pathname of .bz2 file to be extracted. | ||
| 186 | -- @param outfile string or nil: pathname of output file to be produced. | ||
| 187 | -- If not given, name is derived from input file. | ||
| 188 | -- @return boolean: true on success; nil and error message on failure. | ||
| 189 | function tools.bunzip2(infile, outfile) | ||
| 190 | return uncompress("bz2", "bunzip2", infile, outfile) | ||
| 191 | end | ||
| 192 | |||
| 193 | do | ||
| 194 | local function rwx_to_octal(rwx) | ||
| 195 | return (rwx:match "r" and 4 or 0) | ||
| 196 | + (rwx:match "w" and 2 or 0) | ||
| 197 | + (rwx:match "x" and 1 or 0) | ||
| 198 | end | ||
| 199 | local umask_cache | ||
| 200 | function tools._unix_umask() | ||
| 201 | if umask_cache then | ||
| 202 | return umask_cache | ||
| 203 | end | ||
| 204 | local fd = assert(io.popen("umask -S")) | ||
| 205 | local umask = assert(fd:read("*a")) | ||
| 206 | fd:close() | ||
| 207 | local u, g, o = umask:match("u=([rwx]*),g=([rwx]*),o=([rwx]*)") | ||
| 208 | if not u then | ||
| 209 | error("invalid umask result") | ||
| 210 | end | ||
| 211 | umask_cache = string.format("%d%d%d", | ||
| 212 | 7 - rwx_to_octal(u), | ||
| 213 | 7 - rwx_to_octal(g), | ||
| 214 | 7 - rwx_to_octal(o)) | ||
| 215 | return umask_cache | ||
| 216 | end | ||
| 217 | end | ||
| 218 | |||
| 219 | --- Set permissions for file or directory | ||
| 220 | -- @param filename string: filename whose permissions are to be modified | ||
| 221 | -- @param mode string ("read" or "exec"): permissions to set | ||
| 222 | -- @param scope string ("user" or "all"): the user(s) to whom the permission applies | ||
| 223 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 224 | -- plus an error message | ||
| 225 | function tools.set_permissions(filename, mode, scope) | ||
| 226 | assert(filename and mode and scope) | ||
| 227 | |||
| 228 | local perms, err = fs._unix_mode_scope_to_perms(mode, scope) | ||
| 229 | if err then | ||
| 230 | return false, err | ||
| 231 | end | ||
| 232 | |||
| 233 | return fs.execute(vars.CHMOD, perms, filename) | ||
| 234 | end | ||
| 235 | |||
| 236 | function tools.browser(url) | ||
| 237 | return fs.execute(cfg.web_browser, url) | ||
| 238 | end | ||
| 239 | |||
| 240 | -- Set access and modification times for a file. | ||
| 241 | -- @param filename File to set access and modification times for. | ||
| 242 | -- @param time may be a string or number containing the format returned | ||
| 243 | -- by os.time, or a table ready to be processed via os.time; if | ||
| 244 | -- nil, current time is assumed. | ||
| 245 | function tools.set_time(file, time) | ||
| 246 | assert(time == nil or type(time) == "table" or type(time) == "number") | ||
| 247 | file = dir.normalize(file) | ||
| 248 | local flag = "" | ||
| 249 | if type(time) == "number" then | ||
| 250 | time = os.date("*t", time) | ||
| 251 | end | ||
| 252 | if type(time) == "table" then | ||
| 253 | flag = ("-t %04d%02d%02d%02d%02d.%02d"):format(time.year, time.month, time.day, time.hour, time.min, time.sec) | ||
| 254 | end | ||
| 255 | return fs.execute(vars.TOUCH .. " " .. flag, file) | ||
| 256 | end | ||
| 257 | |||
| 258 | --- Create a temporary directory. | ||
| 259 | -- @param name_pattern string: name pattern to use for avoiding conflicts | ||
| 260 | -- when creating temporary directory. | ||
| 261 | -- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. | ||
| 262 | function tools.make_temp_dir(name_pattern) | ||
| 263 | assert(type(name_pattern) == "string") | ||
| 264 | name_pattern = dir.normalize(name_pattern) | ||
| 265 | |||
| 266 | local template = (os.getenv("TMPDIR") or "/tmp") .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-XXXXXX" | ||
| 267 | local pipe = io.popen(vars.MKTEMP.." -d "..fs.Q(template)) | ||
| 268 | local dirname = pipe:read("*l") | ||
| 269 | pipe:close() | ||
| 270 | if dirname and dirname:match("^/") then | ||
| 271 | return dirname | ||
| 272 | end | ||
| 273 | return nil, "Failed to create temporary directory "..tostring(dirname) | ||
| 274 | end | ||
| 275 | |||
| 276 | --- Test is file/directory exists | ||
| 277 | -- @param file string: filename to test | ||
| 278 | -- @return boolean: true if file exists, false otherwise. | ||
| 279 | function tools.exists(file) | ||
| 280 | assert(file) | ||
| 281 | return fs.execute(vars.TEST, "-e", file) | ||
| 282 | end | ||
| 283 | |||
| 284 | --- Test is pathname is a directory. | ||
| 285 | -- @param file string: pathname to test | ||
| 286 | -- @return boolean: true if it is a directory, false otherwise. | ||
| 287 | function tools.is_dir(file) | ||
| 288 | assert(file) | ||
| 289 | return fs.execute(vars.TEST, "-d", file) | ||
| 290 | end | ||
| 291 | |||
| 292 | --- Test is pathname is a regular file. | ||
| 293 | -- @param file string: pathname to test | ||
| 294 | -- @return boolean: true if it is a regular file, false otherwise. | ||
| 295 | function tools.is_file(file) | ||
| 296 | assert(file) | ||
| 297 | return fs.execute(vars.TEST, "-f", file) | ||
| 298 | end | ||
| 299 | |||
| 300 | function tools.current_user() | ||
| 301 | local user = os.getenv("USER") | ||
| 302 | if user then | ||
| 303 | return user | ||
| 304 | end | ||
| 305 | local pd = io.popen("whoami", "r") | ||
| 306 | if not pd then | ||
| 307 | return "" | ||
| 308 | end | ||
| 309 | user = pd:read("*l") | ||
| 310 | pd:close() | ||
| 311 | return user | ||
| 312 | end | ||
| 313 | |||
| 314 | function tools.is_superuser() | ||
| 315 | return fs.current_user() == "root" | ||
| 316 | end | ||
| 317 | |||
| 318 | local lock_mt = { | ||
| 319 | __gc = function(lock) | ||
| 320 | fs.unlock_access(lock) | ||
| 321 | end | ||
| 322 | } | ||
| 323 | |||
| 324 | function tools.lock_access(dirname, force) | ||
| 325 | local ok, err = fs.make_dir(dirname) | ||
| 326 | if not ok then | ||
| 327 | return nil, err | ||
| 328 | end | ||
| 329 | |||
| 330 | local tempfile = dir.path(dirname, ".lock.tmp." .. tostring(math.random(100000000))) | ||
| 331 | |||
| 332 | local fd, fderr = io.open(tempfile, "w") | ||
| 333 | if not fd then | ||
| 334 | return nil, "failed opening temp file " .. tempfile .. " for locking: " .. fderr | ||
| 335 | end | ||
| 336 | |||
| 337 | local ok, werr = fd:write("lock file for " .. dirname) | ||
| 338 | if not ok then | ||
| 339 | return nil, "failed writing temp file " .. tempfile .. " for locking: " .. werr | ||
| 340 | end | ||
| 341 | |||
| 342 | fd:close() | ||
| 343 | |||
| 344 | local lockfile = dir.path(dirname, "lockfile.lfs") | ||
| 345 | |||
| 346 | local force_flag = force and " -f" or "" | ||
| 347 | |||
| 348 | if fs.execute(vars.LN .. force_flag, tempfile, lockfile) then | ||
| 349 | local lock = { | ||
| 350 | tempfile = tempfile, | ||
| 351 | lockfile = lockfile, | ||
| 352 | } | ||
| 353 | setmetatable(lock, lock_mt) | ||
| 354 | return lock | ||
| 355 | else | ||
| 356 | return nil, "File exists" -- same message as luafilesystem | ||
| 357 | end | ||
| 358 | end | ||
| 359 | |||
| 360 | function tools.unlock_access(lock) | ||
| 361 | os.remove(lock.lockfile) | ||
| 362 | os.remove(lock.tempfile) | ||
| 363 | end | ||
| 364 | |||
| 365 | return tools | ||
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua deleted file mode 100644 index 56f04b19..00000000 --- a/src/luarocks/fs/win32/tools.lua +++ /dev/null | |||
| @@ -1,331 +0,0 @@ | |||
| 1 | |||
| 2 | --- fs operations implemented with third-party tools for Windows platform abstractions. | ||
| 3 | -- Download http://unxutils.sourceforge.net/ for Windows GNU utilities | ||
| 4 | -- used by this module. | ||
| 5 | local tools = {} | ||
| 6 | |||
| 7 | local fs = require("luarocks.fs") | ||
| 8 | local dir = require("luarocks.dir") | ||
| 9 | local cfg = require("luarocks.core.cfg") | ||
| 10 | |||
| 11 | local vars = setmetatable({}, { __index = function(_,k) return cfg.variables[k] end }) | ||
| 12 | |||
| 13 | local dir_sep = package.config:sub(1, 1) | ||
| 14 | |||
| 15 | --- Adds prefix to command to make it run from a directory. | ||
| 16 | -- @param directory string: Path to a directory. | ||
| 17 | -- @param cmd string: A command-line string. | ||
| 18 | -- @param exit_on_error bool: Exits immediately if entering the directory failed. | ||
| 19 | -- @return string: The command-line with prefix. | ||
| 20 | function tools.command_at(directory, cmd, exit_on_error) | ||
| 21 | local drive = directory:match("^([A-Za-z]:)") | ||
| 22 | local op = " & " | ||
| 23 | if exit_on_error then | ||
| 24 | op = " && " | ||
| 25 | end | ||
| 26 | local cmd_prefixed = "cd " .. fs.Q(directory) .. op .. cmd | ||
| 27 | if drive then | ||
| 28 | cmd_prefixed = drive .. " & " .. cmd_prefixed | ||
| 29 | end | ||
| 30 | return cmd_prefixed | ||
| 31 | end | ||
| 32 | |||
| 33 | --- Create a directory if it does not already exist. | ||
| 34 | -- If any of the higher levels in the path name does not exist | ||
| 35 | -- too, they are created as well. | ||
| 36 | -- @param directory string: pathname of directory to create. | ||
| 37 | -- @return boolean: true on success, false on failure. | ||
| 38 | function tools.make_dir(directory) | ||
| 39 | assert(directory) | ||
| 40 | directory = dir.normalize(directory) | ||
| 41 | fs.execute_quiet(vars.MKDIR, directory) | ||
| 42 | if not fs.is_dir(directory) then | ||
| 43 | return false, "failed making directory "..directory | ||
| 44 | end | ||
| 45 | return true | ||
| 46 | end | ||
| 47 | |||
| 48 | --- Remove a directory if it is empty. | ||
| 49 | -- Does not return errors (for example, if directory is not empty or | ||
| 50 | -- if already does not exist) | ||
| 51 | -- @param directory string: pathname of directory to remove. | ||
| 52 | function tools.remove_dir_if_empty(directory) | ||
| 53 | assert(directory) | ||
| 54 | fs.execute_quiet(vars.RMDIR, directory) | ||
| 55 | end | ||
| 56 | |||
| 57 | --- Remove a directory if it is empty. | ||
| 58 | -- Does not return errors (for example, if directory is not empty or | ||
| 59 | -- if already does not exist) | ||
| 60 | -- @param directory string: pathname of directory to remove. | ||
| 61 | function tools.remove_dir_tree_if_empty(directory) | ||
| 62 | assert(directory) | ||
| 63 | while true do | ||
| 64 | fs.execute_quiet(vars.RMDIR, directory) | ||
| 65 | local parent = dir.dir_name(directory) | ||
| 66 | if parent ~= directory then | ||
| 67 | directory = parent | ||
| 68 | else | ||
| 69 | break | ||
| 70 | end | ||
| 71 | end | ||
| 72 | end | ||
| 73 | |||
| 74 | --- Copy a file. | ||
| 75 | -- @param src string: Pathname of source | ||
| 76 | -- @param dest string: Pathname of destination | ||
| 77 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 78 | -- plus an error message. | ||
| 79 | function tools.copy(src, dest) | ||
| 80 | assert(src and dest) | ||
| 81 | if dest:match("[/\\]$") then dest = dest:sub(1, -2) end | ||
| 82 | local ok = fs.execute(vars.CP, src, dest) | ||
| 83 | if ok then | ||
| 84 | return true | ||
| 85 | else | ||
| 86 | return false, "Failed copying "..src.." to "..dest | ||
| 87 | end | ||
| 88 | end | ||
| 89 | |||
| 90 | --- Recursively copy the contents of a directory. | ||
| 91 | -- @param src string: Pathname of source | ||
| 92 | -- @param dest string: Pathname of destination | ||
| 93 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 94 | -- plus an error message. | ||
| 95 | function tools.copy_contents(src, dest) | ||
| 96 | assert(src and dest) | ||
| 97 | if not fs.is_dir(src) then | ||
| 98 | return false, src .. " is not a directory" | ||
| 99 | end | ||
| 100 | if fs.make_dir(dest) and fs.execute_quiet(vars.CP, "-dR", src.."\\*.*", dest) then | ||
| 101 | return true | ||
| 102 | else | ||
| 103 | return false, "Failed copying "..src.." to "..dest | ||
| 104 | end | ||
| 105 | end | ||
| 106 | |||
| 107 | --- Delete a file or a directory and all its contents. | ||
| 108 | -- For safety, this only accepts absolute paths. | ||
| 109 | -- @param arg string: Pathname of source | ||
| 110 | -- @return nil | ||
| 111 | function tools.delete(arg) | ||
| 112 | assert(arg) | ||
| 113 | assert(arg:match("^[a-zA-Z]?:?[\\/]")) | ||
| 114 | fs.execute_quiet("if exist "..fs.Q(arg.."\\*").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )") | ||
| 115 | end | ||
| 116 | |||
| 117 | --- Recursively scan the contents of a directory. | ||
| 118 | -- @param at string or nil: directory to scan (will be the current | ||
| 119 | -- directory if none is given). | ||
| 120 | -- @return table: an array of strings with the filenames representing | ||
| 121 | -- the contents of a directory. Paths are returned with forward slashes. | ||
| 122 | function tools.find(at) | ||
| 123 | assert(type(at) == "string" or not at) | ||
| 124 | if not at then | ||
| 125 | at = fs.current_dir() | ||
| 126 | end | ||
| 127 | if not fs.is_dir(at) then | ||
| 128 | return {} | ||
| 129 | end | ||
| 130 | local result = {} | ||
| 131 | local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND), true)) | ||
| 132 | for file in pipe:lines() do | ||
| 133 | -- Windows find is a bit different | ||
| 134 | local file = file | ||
| 135 | local first_two = file:sub(1,2) | ||
| 136 | if first_two == ".\\" or first_two == "./" then file=file:sub(3) end | ||
| 137 | if file ~= "." then | ||
| 138 | table.insert(result, (file:gsub("[\\/]", dir_sep))) | ||
| 139 | end | ||
| 140 | end | ||
| 141 | pipe:close() | ||
| 142 | return result | ||
| 143 | end | ||
| 144 | |||
| 145 | --- Compress files in a .zip archive. | ||
| 146 | -- @param zipfile string: pathname of .zip archive to be created. | ||
| 147 | -- @param ... Filenames to be stored in the archive are given as | ||
| 148 | -- additional arguments. | ||
| 149 | -- @return boolean: true on success, nil and error message on failure. | ||
| 150 | function tools.zip(zipfile, ...) | ||
| 151 | if fs.execute_quiet(vars.SEVENZ.." -aoa a -tzip", zipfile, ...) then | ||
| 152 | return true | ||
| 153 | else | ||
| 154 | return nil, "failed compressing " .. zipfile | ||
| 155 | end | ||
| 156 | end | ||
| 157 | |||
| 158 | --- Uncompress files from a .zip archive. | ||
| 159 | -- @param zipfile string: pathname of .zip archive to be extracted. | ||
| 160 | -- @return boolean: true on success, nil and error message on failure. | ||
| 161 | function tools.unzip(zipfile) | ||
| 162 | assert(zipfile) | ||
| 163 | if fs.execute_quiet(vars.SEVENZ.." -aoa x", zipfile) then | ||
| 164 | return true | ||
| 165 | else | ||
| 166 | return nil, "failed extracting " .. zipfile | ||
| 167 | end | ||
| 168 | end | ||
| 169 | |||
| 170 | local function sevenz(default_ext, infile, outfile) | ||
| 171 | assert(type(infile) == "string") | ||
| 172 | assert(outfile == nil or type(outfile) == "string") | ||
| 173 | |||
| 174 | local dropext = infile:gsub("%."..default_ext.."$", "") | ||
| 175 | local outdir = dir.dir_name(dropext) | ||
| 176 | |||
| 177 | infile = fs.absolute_name(infile) | ||
| 178 | |||
| 179 | local cmdline = vars.SEVENZ.." -aoa -t* -o"..fs.Q(outdir).." x "..fs.Q(infile) | ||
| 180 | local ok, err = fs.execute_quiet(cmdline) | ||
| 181 | if not ok then | ||
| 182 | return nil, "failed extracting " .. infile | ||
| 183 | end | ||
| 184 | |||
| 185 | if outfile then | ||
| 186 | outfile = fs.absolute_name(outfile) | ||
| 187 | dropext = fs.absolute_name(dropext) | ||
| 188 | ok, err = os.rename(dropext, outfile) | ||
| 189 | if not ok then | ||
| 190 | return nil, "failed creating new file " .. outfile | ||
| 191 | end | ||
| 192 | end | ||
| 193 | |||
| 194 | return true | ||
| 195 | end | ||
| 196 | |||
| 197 | --- Uncompresses a .gz file. | ||
| 198 | -- @param infile string: pathname of .gz file to be extracted. | ||
| 199 | -- @param outfile string or nil: pathname of output file to be produced. | ||
| 200 | -- If not given, name is derived from input file. | ||
| 201 | -- @return boolean: true on success; nil and error message on failure. | ||
| 202 | function tools.gunzip(infile, outfile) | ||
| 203 | return sevenz("gz", infile, outfile) | ||
| 204 | end | ||
| 205 | |||
| 206 | --- Uncompresses a .bz2 file. | ||
| 207 | -- @param infile string: pathname of .bz2 file to be extracted. | ||
| 208 | -- @param outfile string or nil: pathname of output file to be produced. | ||
| 209 | -- If not given, name is derived from input file. | ||
| 210 | -- @return boolean: true on success; nil and error message on failure. | ||
| 211 | function tools.bunzip2(infile, outfile) | ||
| 212 | return sevenz("bz2", infile, outfile) | ||
| 213 | end | ||
| 214 | |||
| 215 | --- Helper function for fs.set_permissions | ||
| 216 | -- @return table: an array of all system users | ||
| 217 | local function get_system_users() | ||
| 218 | local exclude = { | ||
| 219 | [""] = true, | ||
| 220 | ["Name"] = true, | ||
| 221 | ["\128\164\172\168\173\168\225\226\224\160\226\174\224"] = true, -- Administrator in cp866 | ||
| 222 | ["Administrator"] = true, | ||
| 223 | } | ||
| 224 | local result = {} | ||
| 225 | local fd = assert(io.popen("wmic UserAccount get name")) | ||
| 226 | for user in fd:lines() do | ||
| 227 | local user = user:gsub("%s+$", "") | ||
| 228 | if not exclude[user] then | ||
| 229 | table.insert(result, user) | ||
| 230 | end | ||
| 231 | end | ||
| 232 | return result | ||
| 233 | end | ||
| 234 | |||
| 235 | --- Set permissions for file or directory | ||
| 236 | -- @param filename string: filename whose permissions are to be modified | ||
| 237 | -- @param mode string ("read" or "exec"): permission to set | ||
| 238 | -- @param scope string ("user" or "all"): the user(s) to whom the permission applies | ||
| 239 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 240 | -- plus an error message | ||
| 241 | function tools.set_permissions(filename, mode, scope) | ||
| 242 | assert(filename and mode and scope) | ||
| 243 | |||
| 244 | if scope == "user" then | ||
| 245 | local perms | ||
| 246 | if mode == "read" then | ||
| 247 | perms = "(R,W,M)" | ||
| 248 | elseif mode == "exec" then | ||
| 249 | perms = "(F)" | ||
| 250 | end | ||
| 251 | |||
| 252 | local ok | ||
| 253 | -- Take ownership of the given file | ||
| 254 | ok = fs.execute_quiet("takeown /f " .. fs.Q(filename)) | ||
| 255 | if not ok then | ||
| 256 | return false, "Could not take ownership of the given file" | ||
| 257 | end | ||
| 258 | local username = os.getenv('USERNAME') | ||
| 259 | -- Grant the current user the proper rights | ||
| 260 | ok = fs.execute_quiet(vars.ICACLS .. " " .. fs.Q(filename) .. " /inheritance:d /grant:r " .. fs.Q(username) .. ":" .. perms) | ||
| 261 | if not ok then | ||
| 262 | return false, "Failed setting permission " .. mode .. " for " .. scope | ||
| 263 | end | ||
| 264 | -- Finally, remove all the other users from the ACL in order to deny them access to the file | ||
| 265 | for _, user in pairs(get_system_users()) do | ||
| 266 | if username ~= user then | ||
| 267 | local ok = fs.execute_quiet(vars.ICACLS .. " " .. fs.Q(filename) .. " /remove " .. fs.Q(user)) | ||
| 268 | if not ok then | ||
| 269 | return false, "Failed setting permission " .. mode .. " for " .. scope | ||
| 270 | end | ||
| 271 | end | ||
| 272 | end | ||
| 273 | elseif scope == "all" then | ||
| 274 | local my_perms, others_perms | ||
| 275 | if mode == "read" then | ||
| 276 | my_perms = "(R,W,M)" | ||
| 277 | others_perms = "(R)" | ||
| 278 | elseif mode == "exec" then | ||
| 279 | my_perms = "(F)" | ||
| 280 | others_perms = "(RX)" | ||
| 281 | end | ||
| 282 | |||
| 283 | local ok | ||
| 284 | -- Grant permissions available to all users | ||
| 285 | ok = fs.execute_quiet(vars.ICACLS .. " " .. fs.Q(filename) .. " /inheritance:d /grant:r *S-1-1-0:" .. others_perms) | ||
| 286 | if not ok then | ||
| 287 | return false, "Failed setting permission " .. mode .. " for " .. scope | ||
| 288 | end | ||
| 289 | |||
| 290 | -- Grant permissions available only to the current user | ||
| 291 | ok = fs.execute_quiet(vars.ICACLS .. " " .. fs.Q(filename) .. " /inheritance:d /grant \"%USERNAME%\":" .. my_perms) | ||
| 292 | |||
| 293 | -- This may not be necessary if the above syntax is correct, | ||
| 294 | -- but I couldn't really test the extra quotes above, so if that | ||
| 295 | -- fails we try again with the syntax used in previous releases | ||
| 296 | -- just to be on the safe side | ||
| 297 | if not ok then | ||
| 298 | ok = fs.execute_quiet(vars.ICACLS .. " " .. fs.Q(filename) .. " /inheritance:d /grant %USERNAME%:" .. my_perms) | ||
| 299 | end | ||
| 300 | |||
| 301 | if not ok then | ||
| 302 | return false, "Failed setting permission " .. mode .. " for " .. scope | ||
| 303 | end | ||
| 304 | end | ||
| 305 | |||
| 306 | return true | ||
| 307 | end | ||
| 308 | |||
| 309 | function tools.browser(url) | ||
| 310 | return fs.execute(cfg.web_browser..' "Starting docs..." '..fs.Q(url)) | ||
| 311 | end | ||
| 312 | |||
| 313 | -- Set access and modification times for a file. | ||
| 314 | -- @param filename File to set access and modification times for. | ||
| 315 | -- @param time may be a string or number containing the format returned | ||
| 316 | -- by os.time, or a table ready to be processed via os.time; if | ||
| 317 | -- nil, current time is assumed. | ||
| 318 | function tools.set_time(filename, time) | ||
| 319 | return true -- FIXME | ||
| 320 | end | ||
| 321 | |||
| 322 | function tools.lock_access(dirname) | ||
| 323 | -- NYI | ||
| 324 | return {} | ||
| 325 | end | ||
| 326 | |||
| 327 | function tools.unlock_access(lock) | ||
| 328 | -- NYI | ||
| 329 | end | ||
| 330 | |||
| 331 | return tools | ||
diff --git a/vendor/lua-zlib/lua-zlib-1.1-0.rockspec b/vendor/lua-zlib/lua-zlib-1.2-0.rockspec index 7927d6ce..7927d6ce 100644 --- a/vendor/lua-zlib/lua-zlib-1.1-0.rockspec +++ b/vendor/lua-zlib/lua-zlib-1.2-0.rockspec | |||
