diff options
| author | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-16 22:17:48 +0000 |
|---|---|---|
| committer | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-16 22:17:48 +0000 |
| commit | 4f15619eabf3b47853406bbb5b52f5878121df44 (patch) | |
| tree | 3ed033d2aae9b17b030e8389a945d598ba506404 | |
| parent | f994a726c346fc1df003debd071a79fa109141f0 (diff) | |
| download | luarocks-4f15619eabf3b47853406bbb5b52f5878121df44.tar.gz luarocks-4f15619eabf3b47853406bbb5b52f5878121df44.tar.bz2 luarocks-4f15619eabf3b47853406bbb5b52f5878121df44.zip | |
Greatly simplified the LuaRocks fs abstractions system
git-svn-id: http://luarocks.org/svn/luarocks/trunk@8 9ca3f7c1-7366-0410-b1a3-b5c78f85698c
| -rw-r--r-- | src/luarocks/cfg.lua | 4 | ||||
| -rw-r--r-- | src/luarocks/fs.lua | 43 | ||||
| -rw-r--r-- | src/luarocks/fs/lua.lua | 119 | ||||
| -rw-r--r-- | src/luarocks/fs/unix.lua | 415 | ||||
| -rw-r--r-- | src/luarocks/fs/win32.lua | 267 | ||||
| -rw-r--r-- | src/luarocks/manif_core.lua | 1 | ||||
| -rw-r--r-- | 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 @@ | |||
| 1 | 1 | ||
| 2 | local rawset, next, table, pairs, print, require, io, os, setmetatable = | 2 | local rawset, next, table, pairs, print, require, io, os, setmetatable, program_version = |
| 3 | rawset, next, table, pairs, print, require, io, os, setmetatable | 3 | rawset, next, table, pairs, print, require, io, os, setmetatable, program_version |
| 4 | 4 | ||
| 5 | --- Configuration for LuaRocks. | 5 | --- Configuration for LuaRocks. |
| 6 | -- Tries to load the user's configuration file and | 6 | -- 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 @@ | |||
| 1 | 1 | ||
| 2 | local rawset = rawset | 2 | local pairs = pairs |
| 3 | 3 | ||
| 4 | --- Proxy module for filesystem and platform abstractions. | 4 | --- Proxy module for filesystem and platform abstractions. |
| 5 | -- All code using "fs" code should require "luarocks.fs", | 5 | -- All code using "fs" code should require "luarocks.fs", |
| @@ -10,33 +10,30 @@ module("luarocks.fs", package.seeall) | |||
| 10 | 10 | ||
| 11 | local cfg = require("luarocks.cfg") | 11 | local cfg = require("luarocks.cfg") |
| 12 | 12 | ||
| 13 | local fs_impl = nil | 13 | local function load_fns(fs_table) |
| 14 | for _, platform in ipairs(cfg.platforms) do | 14 | for name, fn in pairs(fs_table) do |
| 15 | local ok, result = pcall(require, "luarocks.fs."..platform) | 15 | if not _M[name] then |
| 16 | if ok then | 16 | _M[name] = fn |
| 17 | fs_impl = result | ||
| 18 | if fs_impl then | ||
| 19 | break | ||
| 20 | end | 17 | end |
| 21 | end | 18 | end |
| 22 | end | 19 | end |
| 23 | 20 | ||
| 24 | local fs_lua = require("luarocks.fs.lua") | 21 | -- Load platform-specific functions |
| 25 | local fs_unix = require("luarocks.fs.unix") | 22 | local loaded_platform = nil |
| 26 | 23 | for _, platform in ipairs(cfg.platforms) do | |
| 27 | local fs_mt = { | 24 | local ok, fs_plat = pcall(require, "luarocks.fs."..platform) |
| 28 | __index = function(t, k) | 25 | if ok and fs_plat then |
| 29 | local impl = fs_lua[k] or fs_impl[k] or fs_unix[k] | 26 | loaded_platform = platform |
| 30 | rawset(t, k, impl) | 27 | load_fns(fs_plat) |
| 31 | return impl | 28 | break |
| 32 | end | 29 | end |
| 33 | } | 30 | end |
| 34 | 31 | ||
| 35 | setmetatable(luarocks.fs, fs_mt) | 32 | -- Load platform-independent pure-Lua functionality |
| 33 | local fs_lua = require("luarocks.fs.lua") | ||
| 34 | load_fns(fs_lua) | ||
| 36 | 35 | ||
| 37 | fs_lua.init_fs_functions(luarocks.fs) | 36 | -- Load platform-specific fallbacks for missing Lua modules |
| 38 | fs_unix.init_fs_functions(luarocks.fs) | 37 | local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") |
| 39 | if fs_impl then | 38 | if ok and fs_plat_tools then load_fns(fs_plat_tools) end |
| 40 | fs_impl.init_fs_functions(luarocks.fs) | ||
| 41 | end | ||
| 42 | 39 | ||
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 = | |||
| 6 | -- using LuaFileSystem, LZLib, MD5 and LuaCurl. | 6 | -- using LuaFileSystem, LZLib, MD5 and LuaCurl. |
| 7 | module("luarocks.fs.lua", package.seeall) | 7 | module("luarocks.fs.lua", package.seeall) |
| 8 | 8 | ||
| 9 | local fs = require("luarocks.fs") | ||
| 10 | |||
| 9 | local cfg = require("luarocks.cfg") | 11 | local cfg = require("luarocks.cfg") |
| 10 | local dir = require("luarocks.dir") | 12 | local dir = require("luarocks.dir") |
| 11 | 13 | ||
| @@ -23,36 +25,6 @@ math.randomseed(os.time()) | |||
| 23 | 25 | ||
| 24 | dir_separator = "/" | 26 | dir_separator = "/" |
| 25 | 27 | ||
| 26 | local fs_absolute_name, | ||
| 27 | fs_copy, | ||
| 28 | fs_current_dir, | ||
| 29 | fs_dir_stack, | ||
| 30 | fs_execute, | ||
| 31 | fs_execute_string, | ||
| 32 | fs_exists, | ||
| 33 | fs_find, | ||
| 34 | fs_is_dir, | ||
| 35 | fs_is_file, | ||
| 36 | fs_make_dir, | ||
| 37 | fs_set_time, | ||
| 38 | fs_Q | ||
| 39 | |||
| 40 | function init_fs_functions(impl) | ||
| 41 | fs_absolute_name = impl.absolute_name | ||
| 42 | fs_copy = impl.copy | ||
| 43 | fs_current_dir = impl.current_dir | ||
| 44 | fs_dir_stack = impl.dir_stack | ||
| 45 | fs_execute = impl.execute | ||
| 46 | fs_execute_string = impl.execute_string | ||
| 47 | fs_exists = impl.exists | ||
| 48 | fs_find = impl.find | ||
| 49 | fs_is_dir = impl.is_dir | ||
| 50 | fs_is_file = impl.is_file | ||
| 51 | fs_make_dir = impl.make_dir | ||
| 52 | fs_set_time = impl.set_time | ||
| 53 | fs_Q = impl.Q | ||
| 54 | end | ||
| 55 | |||
| 56 | --- Quote argument for shell processing. | 28 | --- Quote argument for shell processing. |
| 57 | -- Adds single quotes and escapes. | 29 | -- Adds single quotes and escapes. |
| 58 | -- @param arg string: Unquoted argument. | 30 | -- @param arg string: Unquoted argument. |
| @@ -73,7 +45,7 @@ end | |||
| 73 | function is_writable(file) | 45 | function is_writable(file) |
| 74 | assert(file) | 46 | assert(file) |
| 75 | local result | 47 | local result |
| 76 | if fs_is_dir(file) then | 48 | if fs.is_dir(file) then |
| 77 | local file2 = file .. '/.tmpluarockstestwritable' | 49 | local file2 = file .. '/.tmpluarockstestwritable' |
| 78 | local fh = io.open(file2, 'w') | 50 | local fh = io.open(file2, 'w') |
| 79 | result = fh ~= nil | 51 | result = fh ~= nil |
| @@ -95,31 +67,13 @@ function make_temp_dir(name) | |||
| 95 | assert(type(name) == "string") | 67 | assert(type(name) == "string") |
| 96 | 68 | ||
| 97 | local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) | 69 | local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) |
| 98 | if fs_make_dir(temp_dir) then | 70 | if fs.make_dir(temp_dir) then |
| 99 | return temp_dir | 71 | return temp_dir |
| 100 | else | 72 | else |
| 101 | return nil | 73 | return nil |
| 102 | end | 74 | end |
| 103 | end | 75 | end |
| 104 | 76 | ||
| 105 | --- Return an absolute pathname from a potentially relative one. | ||
| 106 | -- @param pathname string: pathname to convert. | ||
| 107 | -- @param relative_to string or nil: path to prepend when making | ||
| 108 | -- pathname absolute, or the current dir in the dir stack if | ||
| 109 | -- not given. | ||
| 110 | -- @return string: The pathname converted to absolute. | ||
| 111 | function absolute_name(pathname, relative_to) | ||
| 112 | assert(type(pathname) == "string") | ||
| 113 | assert(type(relative_to) == "string" or not relative_to) | ||
| 114 | |||
| 115 | relative_to = relative_to or fs_current_dir() | ||
| 116 | if pathname:sub(1,1) == "/" then | ||
| 117 | return pathname | ||
| 118 | else | ||
| 119 | return relative_to .. "/" .. pathname | ||
| 120 | end | ||
| 121 | end | ||
| 122 | |||
| 123 | --- Split protocol and path from an URL or local pathname. | 77 | --- Split protocol and path from an URL or local pathname. |
| 124 | -- URLs should be in the "protocol://path" format. | 78 | -- URLs should be in the "protocol://path" format. |
| 125 | -- For local pathnames, "file" is returned as the protocol. | 79 | -- For local pathnames, "file" is returned as the protocol. |
| @@ -134,11 +88,28 @@ function split_url(url) | |||
| 134 | pathname = url | 88 | pathname = url |
| 135 | end | 89 | end |
| 136 | if protocol == "file" then | 90 | if protocol == "file" then |
| 137 | pathname = fs_absolute_name(pathname) | 91 | pathname = fs.absolute_name(pathname) |
| 138 | end | 92 | end |
| 139 | return protocol, pathname | 93 | return protocol, pathname |
| 140 | end | 94 | end |
| 141 | 95 | ||
| 96 | --- Run the given command, quoting its arguments. | ||
| 97 | -- The command is executed in the current directory in the dir stack. | ||
| 98 | -- @param command string: The command to be executed. No quoting/escaping | ||
| 99 | -- is applied. | ||
| 100 | -- @param ... Strings containing additional arguments, which are quoted. | ||
| 101 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 102 | -- otherwise. | ||
| 103 | function execute(command, ...) | ||
| 104 | assert(type(command) == "string") | ||
| 105 | |||
| 106 | for _, arg in ipairs({...}) do | ||
| 107 | assert(type(arg) == "string") | ||
| 108 | command = command .. " " .. fs.Q(arg) | ||
| 109 | end | ||
| 110 | return fs.execute_string(command) | ||
| 111 | end | ||
| 112 | |||
| 142 | --------------------------------------------------------------------- | 113 | --------------------------------------------------------------------- |
| 143 | -- LuaFileSystem functions | 114 | -- LuaFileSystem functions |
| 144 | --------------------------------------------------------------------- | 115 | --------------------------------------------------------------------- |
| @@ -158,23 +129,6 @@ function execute_string(cmd) | |||
| 158 | end | 129 | end |
| 159 | end | 130 | end |
| 160 | 131 | ||
| 161 | --- Run the given command, quoting its arguments. | ||
| 162 | -- The command is executed in the current directory in the dir stack. | ||
| 163 | -- @param command string: The command to be executed. No quoting/escaping | ||
| 164 | -- is applied. | ||
| 165 | -- @param ... Strings containing additional arguments, which are quoted. | ||
| 166 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 167 | -- otherwise. | ||
| 168 | function execute(command, ...) | ||
| 169 | assert(type(command) == "string") | ||
| 170 | |||
| 171 | for _, arg in ipairs({...}) do | ||
| 172 | assert(type(arg) == "string") | ||
| 173 | command = command .. " " .. fs_Q(arg) | ||
| 174 | end | ||
| 175 | return fs_execute_string(command) | ||
| 176 | end | ||
| 177 | |||
| 178 | --- Obtain current directory. | 132 | --- Obtain current directory. |
| 179 | -- Uses the module's internal dir stack. | 133 | -- Uses the module's internal dir stack. |
| 180 | -- @return string: the absolute pathname of the current directory. | 134 | -- @return string: the absolute pathname of the current directory. |
| @@ -190,7 +144,6 @@ end | |||
| 190 | function change_dir(d) | 144 | function change_dir(d) |
| 191 | table.insert(dir_stack, lfs.currentdir()) | 145 | table.insert(dir_stack, lfs.currentdir()) |
| 192 | lfs.chdir(d) | 146 | lfs.chdir(d) |
| 193 | --local x="CHDIR: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) | ||
| 194 | end | 147 | end |
| 195 | 148 | ||
| 196 | --- Change directory to root. | 149 | --- Change directory to root. |
| @@ -200,14 +153,12 @@ function change_dir_to_root() | |||
| 200 | table.insert(dir_stack, lfs.currentdir()) | 153 | table.insert(dir_stack, lfs.currentdir()) |
| 201 | -- TODO Does this work on Windows? | 154 | -- TODO Does this work on Windows? |
| 202 | lfs.chdir("/") | 155 | lfs.chdir("/") |
| 203 | --local x="CHDIR ROOT: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) | ||
| 204 | end | 156 | end |
| 205 | 157 | ||
| 206 | --- Change working directory to the previous in the dir stack. | 158 | --- Change working directory to the previous in the dir stack. |
| 207 | -- @return true if a pop ocurred, false if the stack was empty. | 159 | -- @return true if a pop ocurred, false if the stack was empty. |
| 208 | function pop_dir() | 160 | function pop_dir() |
| 209 | local d = table.remove(dir_stack) | 161 | local d = table.remove(dir_stack) |
| 210 | --local x="POP DIR: " for _,d in ipairs(dir_stack) do x=x.." "..d end print(x) | ||
| 211 | if d then | 162 | if d then |
| 212 | lfs.chdir(d) | 163 | lfs.chdir(d) |
| 213 | return true | 164 | return true |
| @@ -280,11 +231,11 @@ local function recursive_copy(src, dest) | |||
| 280 | local srcmode = lfs.attributes(src, "mode") | 231 | local srcmode = lfs.attributes(src, "mode") |
| 281 | 232 | ||
| 282 | if srcmode == "file" then | 233 | if srcmode == "file" then |
| 283 | local ok = fs_copy(src, dest) | 234 | local ok = fs.copy(src, dest) |
| 284 | if not ok then return false end | 235 | if not ok then return false end |
| 285 | elseif srcmode == "directory" then | 236 | elseif srcmode == "directory" then |
| 286 | local subdir = dir.path(dest, dir.base_name(src)) | 237 | local subdir = dir.path(dest, dir.base_name(src)) |
| 287 | fs_make_dir(subdir) | 238 | fs.make_dir(subdir) |
| 288 | for file in lfs.dir(src) do | 239 | for file in lfs.dir(src) do |
| 289 | if file ~= "." and file ~= ".." then | 240 | if file ~= "." and file ~= ".." then |
| 290 | local ok = recursive_copy(dir.path(src, file), subdir) | 241 | local ok = recursive_copy(dir.path(src, file), subdir) |
| @@ -354,9 +305,9 @@ end | |||
| 354 | function list_dir(at) | 305 | function list_dir(at) |
| 355 | assert(type(at) == "string" or not at) | 306 | assert(type(at) == "string" or not at) |
| 356 | if not at then | 307 | if not at then |
| 357 | at = fs_current_dir() | 308 | at = fs.current_dir() |
| 358 | end | 309 | end |
| 359 | if not fs_is_dir(at) then | 310 | if not fs.is_dir(at) then |
| 360 | return {} | 311 | return {} |
| 361 | end | 312 | end |
| 362 | local result = {} | 313 | local result = {} |
| @@ -392,9 +343,9 @@ end | |||
| 392 | function find(at) | 343 | function find(at) |
| 393 | assert(type(at) == "string" or not at) | 344 | assert(type(at) == "string" or not at) |
| 394 | if not at then | 345 | if not at then |
| 395 | at = fs_current_dir() | 346 | at = fs.current_dir() |
| 396 | end | 347 | end |
| 397 | if not fs_is_dir(at) then | 348 | if not fs.is_dir(at) then |
| 398 | return {} | 349 | return {} |
| 399 | end | 350 | end |
| 400 | local result = {} | 351 | local result = {} |
| @@ -448,7 +399,7 @@ end | |||
| 448 | function unzip(zipfile) | 399 | function unzip(zipfile) |
| 449 | assert(zipfile) | 400 | assert(zipfile) |
| 450 | -- FIXME!!!! | 401 | -- FIXME!!!! |
| 451 | return fs_execute("unzip", zipfile) | 402 | return fs.execute("unzip", zipfile) |
| 452 | end | 403 | end |
| 453 | 404 | ||
| 454 | end | 405 | end |
| @@ -506,7 +457,7 @@ if md5_ok then | |||
| 506 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not | 457 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not |
| 507 | -- or if it could not perform the check for any reason. | 458 | -- or if it could not perform the check for any reason. |
| 508 | function check_md5(file, md5sum) | 459 | function check_md5(file, md5sum) |
| 509 | file = fs_absolute_name(file) | 460 | file = fs.absolute_name(file) |
| 510 | local file = io.open(file, "r") | 461 | local file = io.open(file, "r") |
| 511 | if not file then return false end | 462 | if not file then return false end |
| 512 | local computed = md5.sumhexa(file:read("*a")) | 463 | local computed = md5.sumhexa(file:read("*a")) |
| @@ -545,13 +496,13 @@ function unpack_archive(archive) | |||
| 545 | 496 | ||
| 546 | local ok | 497 | local ok |
| 547 | if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then | 498 | if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then |
| 548 | -- ok = fs_execute("tar zxvpf ", archive) | 499 | -- ok = fs.execute("tar zxvpf ", archive) |
| 549 | ok = fs_execute_string("gunzip -c "..archive.."|tar -xf -") | 500 | ok = fs.execute_string("gunzip -c "..archive.."|tar -xf -") |
| 550 | elseif archive:match("%.tar%.bz2$") then | 501 | elseif archive:match("%.tar%.bz2$") then |
| 551 | -- ok = fs_execute("tar jxvpf ", archive) | 502 | -- ok = fs.execute("tar jxvpf ", archive) |
| 552 | ok = fs_execute_string("bunzip2 -c "..archive.."|tar -xf -") | 503 | ok = fs.execute_string("bunzip2 -c "..archive.."|tar -xf -") |
| 553 | elseif archive:match("%.zip$") then | 504 | elseif archive:match("%.zip$") then |
| 554 | ok = fs_execute("unzip ", archive) | 505 | ok = fs.execute("unzip ", archive) |
| 555 | elseif archive:match("%.lua$") or archive:match("%.c$") then | 506 | elseif archive:match("%.lua$") or archive:match("%.c$") then |
| 556 | -- Ignore .lua and .c files; they don't need to be extracted. | 507 | -- Ignore .lua and .c files; they don't need to be extracted. |
| 557 | return true | 508 | 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 = | |||
| 5 | --- Unix implementation of filesystem and platform abstractions. | 5 | --- Unix implementation of filesystem and platform abstractions. |
| 6 | module("luarocks.fs.unix", package.seeall) | 6 | module("luarocks.fs.unix", package.seeall) |
| 7 | 7 | ||
| 8 | local fs = require("luarocks.fs") | ||
| 9 | |||
| 8 | local cfg = require("luarocks.cfg") | 10 | local cfg = require("luarocks.cfg") |
| 9 | local dir = require("luarocks.dir") | 11 | local dir = require("luarocks.dir") |
| 12 | local fs = require("luarocks.fs") | ||
| 10 | 13 | ||
| 11 | math.randomseed(os.time()) | 14 | math.randomseed(os.time()) |
| 12 | 15 | ||
| 13 | dir_stack = {} | ||
| 14 | |||
| 15 | local fs_absolute_name, | ||
| 16 | fs_copy, | ||
| 17 | fs_current_dir, | ||
| 18 | fs_dir_stack, | ||
| 19 | fs_execute, | ||
| 20 | fs_execute_string, | ||
| 21 | fs_is_dir, | ||
| 22 | fs_is_file, | ||
| 23 | fs_make_dir, | ||
| 24 | fs_exists, | ||
| 25 | fs_find, | ||
| 26 | fs_Q | ||
| 27 | |||
| 28 | function init_fs_functions(impl) | ||
| 29 | fs_absolute_name = impl.absolute_name | ||
| 30 | fs_copy = impl.copy | ||
| 31 | fs_current_dir = impl.current_dir | ||
| 32 | fs_dir_stack = impl.dir_stack | ||
| 33 | fs_execute = impl.execute | ||
| 34 | fs_execute_string = impl.execute_string | ||
| 35 | fs_is_dir = impl.is_dir | ||
| 36 | fs_is_file = impl.is_file | ||
| 37 | fs_make_dir = impl.make_dir | ||
| 38 | fs_exists = impl.exists | ||
| 39 | fs_find = impl.find | ||
| 40 | fs_Q = impl.Q | ||
| 41 | end | ||
| 42 | |||
| 43 | --- Quote argument for shell processing. | ||
| 44 | -- Adds single quotes and escapes. | ||
| 45 | -- @param arg string: Unquoted argument. | ||
| 46 | -- @return string: Quoted argument. | ||
| 47 | function Q(arg) | ||
| 48 | assert(type(arg) == "string") | ||
| 49 | |||
| 50 | return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'" | ||
| 51 | end | ||
| 52 | |||
| 53 | --- Obtain current directory. | ||
| 54 | -- Uses the module's internal dir stack. | ||
| 55 | -- @return string: the absolute pathname of the current directory. | ||
| 56 | function current_dir() | ||
| 57 | local current = os.getenv("PWD") | ||
| 58 | if not current then | ||
| 59 | local pipe = io.popen("pwd") | ||
| 60 | current = pipe:read("*l") | ||
| 61 | pipe:close() | ||
| 62 | end | ||
| 63 | for _, d in ipairs(fs_dir_stack) do | ||
| 64 | current = fs_absolute_name(d, current) | ||
| 65 | end | ||
| 66 | return current | ||
| 67 | end | ||
| 68 | |||
| 69 | --- Run the given command. | ||
| 70 | -- The command is executed in the current directory in the dir stack. | ||
| 71 | -- @param cmd string: No quoting/escaping is applied to the command. | ||
| 72 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 73 | -- otherwise. | ||
| 74 | function execute_string(cmd) | ||
| 75 | if os.execute("cd " .. fs_Q(fs_current_dir()) .. " && " .. cmd) == 0 then | ||
| 76 | return true | ||
| 77 | else | ||
| 78 | return false | ||
| 79 | end | ||
| 80 | end | ||
| 81 | |||
| 82 | --- Run the given command, quoting its arguments. | ||
| 83 | -- The command is executed in the current directory in the dir stack. | ||
| 84 | -- @param command string: The command to be executed. No quoting/escaping | ||
| 85 | -- is applied. | ||
| 86 | -- @param ... Strings containing additional arguments, which are quoted. | ||
| 87 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 88 | -- otherwise. | ||
| 89 | function execute(command, ...) | ||
| 90 | assert(type(command) == "string") | ||
| 91 | |||
| 92 | for _, arg in ipairs({...}) do | ||
| 93 | assert(type(arg) == "string") | ||
| 94 | command = command .. " " .. fs_Q(arg) | ||
| 95 | end | ||
| 96 | return fs_execute_string(command) | ||
| 97 | end | ||
| 98 | |||
| 99 | --- Change the current directory. | ||
| 100 | -- Uses the module's internal dir stack. This does not have exact | ||
| 101 | -- semantics of chdir, as it does not handle errors the same way, | ||
| 102 | -- but works well for our purposes for now. | ||
| 103 | -- @param d string: The directory to switch to. | ||
| 104 | function change_dir(d) | ||
| 105 | assert(type(d) == "string") | ||
| 106 | table.insert(fs_dir_stack, d) | ||
| 107 | end | ||
| 108 | |||
| 109 | --- Change directory to root. | ||
| 110 | -- Allows leaving a directory (e.g. for deleting it) in | ||
| 111 | -- a crossplatform way. | ||
| 112 | function change_dir_to_root() | ||
| 113 | table.insert(fs_dir_stack, "/") | ||
| 114 | end | ||
| 115 | |||
| 116 | --- Change working directory to the previous in the dir stack. | ||
| 117 | function pop_dir() | ||
| 118 | local d = table.remove(fs_dir_stack) | ||
| 119 | return d ~= nil | ||
| 120 | end | ||
| 121 | |||
| 122 | --- Create a directory if it does not already exist. | ||
| 123 | -- If any of the higher levels in the path name does not exist | ||
| 124 | -- too, they are created as well. | ||
| 125 | -- @param d string: pathname of directory to create. | ||
| 126 | -- @return boolean: true on success, false on failure. | ||
| 127 | function make_dir(d) | ||
| 128 | assert(d) | ||
| 129 | return fs_execute("mkdir -p", d) | ||
| 130 | end | ||
| 131 | |||
| 132 | --- Remove a directory if it is empty. | ||
| 133 | -- Does not return errors (for example, if directory is not empty or | ||
| 134 | -- if already does not exist) | ||
| 135 | -- @param dir string: pathname of directory to remove. | ||
| 136 | function remove_dir_if_empty(d) | ||
| 137 | assert(d) | ||
| 138 | fs_execute_string("rmdir "..fs_Q(d).." 1> /dev/null 2> /dev/null") | ||
| 139 | end | ||
| 140 | |||
| 141 | --- Copy a file. | ||
| 142 | -- @param src string: Pathname of source | ||
| 143 | -- @param dest string: Pathname of destination | ||
| 144 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 145 | -- plus an error message. | ||
| 146 | function copy(src, dest) | ||
| 147 | assert(src and dest) | ||
| 148 | if fs_execute("cp", src, dest) then | ||
| 149 | return true | ||
| 150 | else | ||
| 151 | return false, "Failed copying "..src.." to "..dest | ||
| 152 | end | ||
| 153 | end | ||
| 154 | |||
| 155 | --- Recursively copy the contents of a directory. | ||
| 156 | -- @param src string: Pathname of source | ||
| 157 | -- @param dest string: Pathname of destination | ||
| 158 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 159 | -- plus an error message. | ||
| 160 | function copy_contents(src, dest) | ||
| 161 | assert(src and dest) | ||
| 162 | if fs_execute_string("cp -pPR "..fs_Q(src).."/* "..fs_Q(dest).." 1> /dev/null 2>/dev/null") then | ||
| 163 | return true | ||
| 164 | else | ||
| 165 | return false, "Failed copying "..src.." to "..dest | ||
| 166 | end | ||
| 167 | end | ||
| 168 | |||
| 169 | --- Delete a file or a directory and all its contents. | ||
| 170 | -- For safety, this only accepts absolute paths. | ||
| 171 | -- @param arg string: Pathname of source | ||
| 172 | -- @return boolean: true on success, false on failure. | ||
| 173 | function delete(arg) | ||
| 174 | assert(arg) | ||
| 175 | assert(arg:sub(1,1) == "/") | ||
| 176 | return fs_execute_string("rm -rf " .. fs_Q(arg) .. " 1> /dev/null 2>/dev/null") | ||
| 177 | end | ||
| 178 | |||
| 179 | --- List the contents of a directory. | ||
| 180 | -- @param at string or nil: directory to list (will be the current | ||
| 181 | -- directory if none is given). | ||
| 182 | -- @return table: an array of strings with the filenames representing | ||
| 183 | -- the contents of a directory. | ||
| 184 | function list_dir(at) | ||
| 185 | assert(type(at) == "string" or not at) | ||
| 186 | if not at then | ||
| 187 | at = fs_current_dir() | ||
| 188 | end | ||
| 189 | if not fs_is_dir(at) then | ||
| 190 | return {} | ||
| 191 | end | ||
| 192 | local result = {} | ||
| 193 | local pipe = io.popen("cd "..fs_Q(at).." && ls") | ||
| 194 | for file in pipe:lines() do | ||
| 195 | table.insert(result, file) | ||
| 196 | end | ||
| 197 | pipe:close() | ||
| 198 | return result | ||
| 199 | end | ||
| 200 | |||
| 201 | --- Recursively scan the contents of a directory. | ||
| 202 | -- @param at string or nil: directory to scan (will be the current | ||
| 203 | -- directory if none is given). | ||
| 204 | -- @return table: an array of strings with the filenames representing | ||
| 205 | -- the contents of a directory. | ||
| 206 | function find(at) | ||
| 207 | assert(type(at) == "string" or not at) | ||
| 208 | if not at then | ||
| 209 | at = fs_current_dir() | ||
| 210 | end | ||
| 211 | if not fs_is_dir(at) then | ||
| 212 | return {} | ||
| 213 | end | ||
| 214 | local result = {} | ||
| 215 | local pipe = io.popen("cd "..fs_Q(at).." && find * 2>/dev/null") | ||
| 216 | for file in pipe:lines() do | ||
| 217 | table.insert(result, file) | ||
| 218 | end | ||
| 219 | pipe:close() | ||
| 220 | return result | ||
| 221 | end | ||
| 222 | |||
| 223 | --- Compress files in a .zip archive. | ||
| 224 | -- @param zipfile string: pathname of .zip archive to be created. | ||
| 225 | -- @param ... Filenames to be stored in the archive are given as | ||
| 226 | -- additional arguments. | ||
| 227 | -- @return boolean: true on success, false on failure. | ||
| 228 | function zip(zipfile, ...) | ||
| 229 | return fs_execute("zip -r", zipfile, ...) | ||
| 230 | end | ||
| 231 | |||
| 232 | --- Uncompress files from a .zip archive. | ||
| 233 | -- @param zipfile string: pathname of .zip archive to be extracted. | ||
| 234 | -- @return boolean: true on success, false on failure. | ||
| 235 | function unzip(zipfile) | ||
| 236 | assert(zipfile) | ||
| 237 | return fs_execute("unzip", zipfile) | ||
| 238 | end | ||
| 239 | |||
| 240 | --- Test for existance of a file. | ||
| 241 | -- @param file string: filename to test | ||
| 242 | -- @return boolean: true if file exists, false otherwise. | ||
| 243 | function exists(file) | ||
| 244 | assert(file) | ||
| 245 | return fs_execute("test -r", file) | ||
| 246 | end | ||
| 247 | |||
| 248 | --- Test is file/dir is writable. | ||
| 249 | -- @param file string: filename to test | ||
| 250 | -- @return boolean: true if file exists, false otherwise. | ||
| 251 | function is_writable(file) | ||
| 252 | assert(file) | ||
| 253 | return fs_execute("test -w", file) | ||
| 254 | end | ||
| 255 | |||
| 256 | --- Test is pathname is a directory. | ||
| 257 | -- @param file string: pathname to test | ||
| 258 | -- @return boolean: true if it is a directory, false otherwise. | ||
| 259 | function is_dir(file) | ||
| 260 | assert(file) | ||
| 261 | return fs_execute("test -d", file) | ||
| 262 | end | ||
| 263 | |||
| 264 | --- Test is pathname is a regular file. | ||
| 265 | -- @param file string: pathname to test | ||
| 266 | -- @return boolean: true if it is a regular file, false otherwise. | ||
| 267 | function is_file(file) | ||
| 268 | assert(file) | ||
| 269 | return fs_execute("test -f", file) | ||
| 270 | end | ||
| 271 | |||
| 272 | --- Download a remote file. | ||
| 273 | -- @param url string: URL to be fetched. | ||
| 274 | -- @param filename string or nil: this function attempts to detect the | ||
| 275 | -- resulting local filename of the remote file as the basename of the URL; | ||
| 276 | -- if that is not correct (due to a redirection, for example), the local | ||
| 277 | -- filename can be given explicitly as this second argument. | ||
| 278 | -- @return boolean: true on success, false on failure. | ||
| 279 | function download(url, filename) | ||
| 280 | assert(type(url) == "string") | ||
| 281 | assert(type(filename) == "string" or not filename) | ||
| 282 | |||
| 283 | if cfg.downloader == "wget" then | ||
| 284 | local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " | ||
| 285 | if filename then | ||
| 286 | return fs_execute(wget_cmd.." --output-document ", filename, url) | ||
| 287 | else | ||
| 288 | return fs_execute(wget_cmd, url) | ||
| 289 | end | ||
| 290 | elseif cfg.downloader == "curl" then | ||
| 291 | filename = filename or dir.base_name(url) | ||
| 292 | return fs_execute_string("curl --user-agent "..cfg.user_agent.." "..fs_Q(url).." 2> /dev/null 1> "..fs_Q(filename)) | ||
| 293 | end | ||
| 294 | end | ||
| 295 | |||
| 296 | --- Create a temporary directory. | ||
| 297 | -- @param name string: name pattern to use for avoiding conflicts | ||
| 298 | -- when creating temporary directory. | ||
| 299 | -- @return string or nil: name of temporary directory or nil on failure. | ||
| 300 | function make_temp_dir(name) | ||
| 301 | assert(type(name) == "string") | ||
| 302 | |||
| 303 | local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) | ||
| 304 | if fs_make_dir(temp_dir) then | ||
| 305 | return temp_dir | ||
| 306 | else | ||
| 307 | return nil | ||
| 308 | end | ||
| 309 | end | ||
| 310 | |||
| 311 | function chmod(pathname, mode) | ||
| 312 | return fs_execute("chmod "..mode, pathname) | ||
| 313 | end | ||
| 314 | |||
| 315 | --- Apply a patch. | ||
| 316 | -- @param patchname string: The filename of the patch. | ||
| 317 | function apply_patch(patchname) | ||
| 318 | return fs_execute("patch -p1 -f -i ", patchname) | ||
| 319 | end | ||
| 320 | |||
| 321 | --- Unpack an archive. | ||
| 322 | -- Extract the contents of an archive, detecting its format by | ||
| 323 | -- filename extension. | ||
| 324 | -- @param archive string: Filename of archive. | ||
| 325 | -- @return boolean or (boolean, string): true on success, false and an error message on failure. | ||
| 326 | function unpack_archive(archive) | ||
| 327 | assert(type(archive) == "string") | ||
| 328 | |||
| 329 | local ok | ||
| 330 | if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then | ||
| 331 | -- ok = fs_execute("tar zxvpf ", archive) | ||
| 332 | ok = fs_execute_string("gunzip -c "..archive.."|tar -xf -") | ||
| 333 | elseif archive:match("%.tar%.bz2$") then | ||
| 334 | -- ok = fs_execute("tar jxvpf ", archive) | ||
| 335 | ok = fs_execute_string("bunzip2 -c "..archive.."|tar -xf -") | ||
| 336 | elseif archive:match("%.zip$") then | ||
| 337 | ok = fs_execute("unzip ", archive) | ||
| 338 | elseif archive:match("%.lua$") or archive:match("%.c$") then | ||
| 339 | -- Ignore .lua and .c files; they don't need to be extracted. | ||
| 340 | return true | ||
| 341 | else | ||
| 342 | local ext = archive:match(".*(%..*)") | ||
| 343 | return false, "Unrecognized filename extension "..(ext or "") | ||
| 344 | end | ||
| 345 | if not ok then | ||
| 346 | return false, "Failed extracting "..archive | ||
| 347 | end | ||
| 348 | return true | ||
| 349 | end | ||
| 350 | |||
| 351 | --- Check the MD5 checksum for a file. | ||
| 352 | -- @param file string: The file to be checked. | ||
| 353 | -- @param md5sum string: The string with the expected MD5 checksum. | ||
| 354 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not | ||
| 355 | -- or if it could not perform the check for any reason. | ||
| 356 | function check_md5(file, md5sum) | ||
| 357 | file = fs_absolute_name(file) | ||
| 358 | local computed | ||
| 359 | if cfg.md5checker == "md5sum" then | ||
| 360 | local pipe = io.popen("md5sum "..file) | ||
| 361 | computed = pipe:read("*l"):gsub("[^%x]+", "") | ||
| 362 | pipe:close() | ||
| 363 | if computed then | ||
| 364 | computed = computed:sub(1,32) | ||
| 365 | end | ||
| 366 | elseif cfg.md5checker == "openssl" then | ||
| 367 | local pipe = io.popen("openssl md5 "..file) | ||
| 368 | computed = pipe:read("*l") | ||
| 369 | pipe:close() | ||
| 370 | if computed then | ||
| 371 | computed = computed:sub(-32) | ||
| 372 | end | ||
| 373 | elseif cfg.md5checker == "md5" then | ||
| 374 | local pipe = io.popen("md5 "..file) | ||
| 375 | computed = pipe:read("*l") | ||
| 376 | pipe:close() | ||
| 377 | if computed then | ||
| 378 | computed = computed:sub(-32) | ||
| 379 | end | ||
| 380 | end | ||
| 381 | if not computed then | ||
| 382 | return false | ||
| 383 | end | ||
| 384 | if computed:match("^"..md5sum) then | ||
| 385 | return true | ||
| 386 | else | ||
| 387 | return false | ||
| 388 | end | ||
| 389 | end | ||
| 390 | |||
| 391 | --- Return an absolute pathname from a potentially relative one. | 16 | --- Return an absolute pathname from a potentially relative one. |
| 392 | -- @param pathname string: pathname to convert. | 17 | -- @param pathname string: pathname to convert. |
| 393 | -- @param relative_to string or nil: path to prepend when making | 18 | -- @param relative_to string or nil: path to prepend when making |
| @@ -398,7 +23,7 @@ function absolute_name(pathname, relative_to) | |||
| 398 | assert(type(pathname) == "string") | 23 | assert(type(pathname) == "string") |
| 399 | assert(type(relative_to) == "string" or not relative_to) | 24 | assert(type(relative_to) == "string" or not relative_to) |
| 400 | 25 | ||
| 401 | relative_to = relative_to or fs_current_dir() | 26 | relative_to = relative_to or fs.current_dir() |
| 402 | if pathname:sub(1,1) == "/" then | 27 | if pathname:sub(1,1) == "/" then |
| 403 | return pathname | 28 | return pathname |
| 404 | else | 29 | else |
| @@ -420,7 +45,7 @@ function split_url(url) | |||
| 420 | pathname = url | 45 | pathname = url |
| 421 | end | 46 | end |
| 422 | if protocol == "file" then | 47 | if protocol == "file" then |
| 423 | pathname = fs_absolute_name(pathname) | 48 | pathname = fs.absolute_name(pathname) |
| 424 | end | 49 | end |
| 425 | return protocol, pathname | 50 | return protocol, pathname |
| 426 | end | 51 | end |
| @@ -446,7 +71,7 @@ function wrap_script(file, dest) | |||
| 446 | wrapper:write('export LUA_PATH LUA_CPATH\n') | 71 | wrapper:write('export LUA_PATH LUA_CPATH\n') |
| 447 | wrapper:write('exec "'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.require "'..file..'" "$@"\n') | 72 | wrapper:write('exec "'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.require "'..file..'" "$@"\n') |
| 448 | wrapper:close() | 73 | wrapper:close() |
| 449 | if fs_execute("chmod +x",wrapname) then | 74 | if fs.execute("chmod +x",wrapname) then |
| 450 | return true | 75 | return true |
| 451 | else | 76 | else |
| 452 | return nil, "Could not make "..wrapname.." executable." | 77 | return nil, "Could not make "..wrapname.." executable." |
| @@ -487,7 +112,33 @@ function is_actual_binary(filename) | |||
| 487 | return false | 112 | return false |
| 488 | end | 113 | end |
| 489 | 114 | ||
| 115 | function is_actual_binary(filename) | ||
| 116 | if filename:match("%.lua$") then | ||
| 117 | return false | ||
| 118 | end | ||
| 119 | local file = io.open(filename) | ||
| 120 | if file then | ||
| 121 | local found = false | ||
| 122 | local first = file:read() | ||
| 123 | if first:match("#!.*lua") then | ||
| 124 | file:close() | ||
| 125 | return true | ||
| 126 | elseif first:match("#!/bin/sh") then | ||
| 127 | local line = file:read() | ||
| 128 | line = file:read() | ||
| 129 | if not(line and line:match("LUA_PATH")) then | ||
| 130 | file:close() | ||
| 131 | return true | ||
| 132 | end | ||
| 133 | end | ||
| 134 | file:close() | ||
| 135 | else | ||
| 136 | return true | ||
| 137 | end | ||
| 138 | return false | ||
| 139 | end | ||
| 140 | |||
| 490 | function copy_binary(filename, dest) | 141 | function copy_binary(filename, dest) |
| 491 | return fs_copy(filename, dest) | 142 | return fs.copy(filename, dest) |
| 492 | end | 143 | end |
| 493 | 144 | ||
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 @@ | |||
| 3 | -- used by this module. | 3 | -- used by this module. |
| 4 | module("luarocks.fs.win32", package.seeall) | 4 | module("luarocks.fs.win32", package.seeall) |
| 5 | 5 | ||
| 6 | local fs = require("luarocks.fs") | ||
| 7 | |||
| 6 | local cfg = require("luarocks.cfg") | 8 | local cfg = require("luarocks.cfg") |
| 7 | local dir = require("luarocks.dir") | 9 | local dir = require("luarocks.dir") |
| 8 | 10 | ||
| 9 | local fs_copy, | ||
| 10 | fs_current_dir, | ||
| 11 | fs_execute, | ||
| 12 | fs_execute_string, | ||
| 13 | fs_is_dir, | ||
| 14 | fs_Q | ||
| 15 | |||
| 16 | function init_fs_functions(impl) | ||
| 17 | fs_copy = impl.copy | ||
| 18 | fs_current_dir = impl.current_dir | ||
| 19 | fs_execute = impl.execute | ||
| 20 | fs_execute_string = impl.execute_string | ||
| 21 | fs_is_dir = impl.is_dir | ||
| 22 | fs_Q = impl.Q | ||
| 23 | end | ||
| 24 | |||
| 25 | --- Quote argument for shell processing. Fixes paths on Windows. | 11 | --- Quote argument for shell processing. Fixes paths on Windows. |
| 26 | -- Adds single quotes and escapes. | 12 | -- Adds single quotes and escapes. |
| 27 | -- @param arg string: Unquoted argument. | 13 | -- @param arg string: Unquoted argument. |
| @@ -36,202 +22,6 @@ function Q(arg) | |||
| 36 | return '"' .. arg:gsub('"', '\\"') .. '"' | 22 | return '"' .. arg:gsub('"', '\\"') .. '"' |
| 37 | end | 23 | end |
| 38 | 24 | ||
| 39 | local function command_at(directory, cmd) | ||
| 40 | local drive = directory:match("^([A-Za-z]:)") | ||
| 41 | cmd = "cd " .. fs_Q(directory) .. " & " .. cmd | ||
| 42 | if drive then | ||
| 43 | cmd = drive .. " & " .. cmd | ||
| 44 | end | ||
| 45 | return cmd | ||
| 46 | end | ||
| 47 | |||
| 48 | --- Run the given command. | ||
| 49 | -- The command is executed in the current directory in the dir stack. | ||
| 50 | -- @param cmd string: No quoting/escaping is applied to the command. | ||
| 51 | -- @return boolean: true if command succeeds (status code 0), false | ||
| 52 | -- otherwise. | ||
| 53 | function execute_string(cmd) | ||
| 54 | if os.execute(command_at(fs_current_dir(), cmd)) == 0 then | ||
| 55 | return true | ||
| 56 | else | ||
| 57 | return false | ||
| 58 | end | ||
| 59 | end | ||
| 60 | |||
| 61 | --- Test for existance of a file. | ||
| 62 | -- @param file string: filename to test | ||
| 63 | -- @return boolean: true if file exists, false otherwise. | ||
| 64 | function exists(file) | ||
| 65 | assert(file) | ||
| 66 | return fs_execute("if not exist " .. fs_Q(file) .. | ||
| 67 | " invalidcommandname 2>NUL 1>NUL") | ||
| 68 | end | ||
| 69 | |||
| 70 | --- Test is pathname is a directory. | ||
| 71 | -- @param file string: pathname to test | ||
| 72 | -- @return boolean: true if it is a directory, false otherwise. | ||
| 73 | function is_dir(file) | ||
| 74 | assert(file) | ||
| 75 | return fs_execute("chdir /D " .. fs_Q(file) .. " 2>NUL 1>NUL") | ||
| 76 | end | ||
| 77 | |||
| 78 | --- Test is pathname is a regular file. | ||
| 79 | -- @param file string: pathname to test | ||
| 80 | -- @return boolean: true if it is a regular file, false otherwise. | ||
| 81 | function is_dir(file) | ||
| 82 | assert(file) | ||
| 83 | return fs_execute("test -d" .. fs_Q(file) .. " 2>NUL 1>NUL") | ||
| 84 | end | ||
| 85 | |||
| 86 | --- Test is file/dir is writable. | ||
| 87 | -- @param file string: filename to test | ||
| 88 | -- @return boolean: true if file exists, false otherwise. | ||
| 89 | function is_writable(file) | ||
| 90 | assert(file) | ||
| 91 | local result | ||
| 92 | if is_dir(file) then | ||
| 93 | local file2 = file .. '/.tmpluarockstestwritable' | ||
| 94 | local fh = io.open(file2, 'w') | ||
| 95 | result = fh ~= nil | ||
| 96 | if fh then fh:close() end | ||
| 97 | os.remove(file2) | ||
| 98 | else | ||
| 99 | local fh = io.open(file, 'r+') | ||
| 100 | result = fh ~= nil | ||
| 101 | if fh then fh:close() end | ||
| 102 | end | ||
| 103 | return result | ||
| 104 | end | ||
| 105 | |||
| 106 | |||
| 107 | --- Create a directory if it does not already exist. | ||
| 108 | -- If any of the higher levels in the path name does not exist | ||
| 109 | -- too, they are created as well. | ||
| 110 | -- @param d string: pathname of directory to create. | ||
| 111 | -- @return boolean: true on success, false on failure. | ||
| 112 | function make_dir(d) | ||
| 113 | assert(d) | ||
| 114 | fs_execute("mkdir "..fs_Q(d).." 1> NUL 2> NUL") | ||
| 115 | return 1 | ||
| 116 | end | ||
| 117 | |||
| 118 | --- Remove a directory if it is empty. | ||
| 119 | -- Does not return errors (for example, if directory is not empty or | ||
| 120 | -- if already does not exist) | ||
| 121 | -- @param d string: pathname of directory to remove. | ||
| 122 | function remove_dir_if_empty(d) | ||
| 123 | assert(d) | ||
| 124 | fs_execute_string("rmdir "..fs_Q(d).." 1> NUL 2> NUL") | ||
| 125 | end | ||
| 126 | |||
| 127 | --- Copy a file. | ||
| 128 | -- @param src string: Pathname of source | ||
| 129 | -- @param dest string: Pathname of destination | ||
| 130 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 131 | -- plus an error message. | ||
| 132 | function copy(src, dest) | ||
| 133 | assert(src and dest) | ||
| 134 | if dest:match("[/\\]$") then dest = dest:sub(1, -2) end | ||
| 135 | if fs_execute("cp", src, dest) then | ||
| 136 | return true | ||
| 137 | else | ||
| 138 | return false, "Failed copying "..src.." to "..dest | ||
| 139 | end | ||
| 140 | end | ||
| 141 | |||
| 142 | --- Recursively copy the contents of a directory. | ||
| 143 | -- @param src string: Pathname of source | ||
| 144 | -- @param dest string: Pathname of destination | ||
| 145 | -- @return boolean or (boolean, string): true on success, false on failure, | ||
| 146 | -- plus an error message. | ||
| 147 | function copy_contents(src, dest) | ||
| 148 | assert(src and dest) | ||
| 149 | if fs_execute_string("cp -a "..src.."\\*.* "..fs_Q(dest).." 1> NUL 2> NUL") then | ||
| 150 | return true | ||
| 151 | else | ||
| 152 | return false, "Failed copying "..src.." to "..dest | ||
| 153 | end | ||
| 154 | end | ||
| 155 | |||
| 156 | --- Delete a file or a directory and all its contents. | ||
| 157 | -- For safety, this only accepts absolute paths. | ||
| 158 | -- @param arg string: Pathname of source | ||
| 159 | -- @return boolean: true on success, false on failure. | ||
| 160 | function delete(arg) | ||
| 161 | assert(arg) | ||
| 162 | assert(arg:match("^[\a-zA-Z]?:?[\\/]")) | ||
| 163 | fs_execute("chmod a+rw -R ", arg) | ||
| 164 | return fs_execute_string("rm -rf " .. fs_Q(arg) .. " 1> NUL 2> NUL") | ||
| 165 | end | ||
| 166 | |||
| 167 | --- List the contents of a directory. | ||
| 168 | -- @param at string or nil: directory to list (will be the current | ||
| 169 | -- directory if none is given). | ||
| 170 | -- @return table: an array of strings with the filenames representing | ||
| 171 | -- the contents of a directory. | ||
| 172 | function list_dir(at) | ||
| 173 | assert(type(at) == "string" or not at) | ||
| 174 | if not at then | ||
| 175 | at = fs_current_dir() | ||
| 176 | end | ||
| 177 | if not fs_is_dir(at) then | ||
| 178 | return {} | ||
| 179 | end | ||
| 180 | local result = {} | ||
| 181 | local pipe = io.popen(command_at(at, "ls")) | ||
| 182 | for file in pipe:lines() do | ||
| 183 | table.insert(result, file) | ||
| 184 | end | ||
| 185 | pipe:close() | ||
| 186 | |||
| 187 | return result | ||
| 188 | end | ||
| 189 | |||
| 190 | --- Recursively scan the contents of a directory. | ||
| 191 | -- @param at string or nil: directory to scan (will be the current | ||
| 192 | -- directory if none is given). | ||
| 193 | -- @return table: an array of strings with the filenames representing | ||
| 194 | -- the contents of a directory. Paths are returned with forward slashes. | ||
| 195 | function find(at) | ||
| 196 | assert(type(at) == "string" or not at) | ||
| 197 | if not at then | ||
| 198 | at = fs_current_dir() | ||
| 199 | end | ||
| 200 | if not fs_is_dir(at) then | ||
| 201 | return {} | ||
| 202 | end | ||
| 203 | local result = {} | ||
| 204 | local pipe = io.popen(command_at(at, "find 2> NUL")) | ||
| 205 | for file in pipe:lines() do | ||
| 206 | -- Windows find is a bit different | ||
| 207 | if file:sub(1,2)==".\\" then file=file:sub(3) end | ||
| 208 | if file ~= "." then | ||
| 209 | table.insert(result, (file:gsub("\\", "/"))) | ||
| 210 | end | ||
| 211 | end | ||
| 212 | return result | ||
| 213 | end | ||
| 214 | |||
| 215 | |||
| 216 | --- Download a remote file. | ||
| 217 | -- @param url string: URL to be fetched. | ||
| 218 | -- @param filename string or nil: this function attempts to detect the | ||
| 219 | -- resulting local filename of the remote file as the basename of the URL; | ||
| 220 | -- if that is not correct (due to a redirection, for example), the local | ||
| 221 | -- filename can be given explicitly as this second argument. | ||
| 222 | -- @return boolean: true on success, false on failure. | ||
| 223 | function download(url, filename) | ||
| 224 | assert(type(url) == "string") | ||
| 225 | assert(type(filename) == "string" or not filename) | ||
| 226 | local wget_cmd = "wget --user-agent="..cfg.user_agent.." --quiet --continue " | ||
| 227 | |||
| 228 | if filename then | ||
| 229 | return fs_execute(wget_cmd.." --output-document ", filename, url) | ||
| 230 | else | ||
| 231 | return fs_execute(wget_cmd, url) | ||
| 232 | end | ||
| 233 | end | ||
| 234 | |||
| 235 | --- Strip the last extension of a filename. | 25 | --- Strip the last extension of a filename. |
| 236 | -- Example: "foo.tar.gz" becomes "foo.tar". | 26 | -- Example: "foo.tar.gz" becomes "foo.tar". |
| 237 | -- If filename has no dots, returns it unchanged. | 27 | -- If filename has no dots, returns it unchanged. |
| @@ -243,55 +33,6 @@ local function strip_extension(filename) | |||
| 243 | return (filename:gsub("%.[^.]+$", "")) or filename | 33 | return (filename:gsub("%.[^.]+$", "")) or filename |
| 244 | end | 34 | end |
| 245 | 35 | ||
| 246 | --- Uncompress gzip file. | ||
| 247 | -- @param archive string: Filename of archive. | ||
| 248 | -- @return boolean : success status | ||
| 249 | local function gunzip(archive) | ||
| 250 | local cmd = fs_execute("gunzip -h 1>NUL 2>NUL") and 'gunzip' or | ||
| 251 | fs_execute("gzip -h 1>NUL 2>NUL") and 'gzip -d' | ||
| 252 | local ok = fs_execute(cmd, archive) | ||
| 253 | return ok | ||
| 254 | end | ||
| 255 | |||
| 256 | --- Unpack an archive. | ||
| 257 | -- Extract the contents of an archive, detecting its format by | ||
| 258 | -- filename extension. | ||
| 259 | -- @param archive string: Filename of archive. | ||
| 260 | -- @return boolean or (boolean, string): true on success, false and an error message on failure. | ||
| 261 | function unpack_archive(archive) | ||
| 262 | assert(type(archive) == "string") | ||
| 263 | |||
| 264 | local ok | ||
| 265 | if archive:match("%.tar%.gz$") then | ||
| 266 | ok = gunzip(archive) | ||
| 267 | if ok then | ||
| 268 | ok = fs_execute("tar -xf ", strip_extension(archive)) | ||
| 269 | end | ||
| 270 | elseif archive:match("%.tgz$") then | ||
| 271 | ok = gunzip(archive) | ||
| 272 | if ok then | ||
| 273 | ok = fs_execute("tar -xf ", strip_extension(archive)..".tar") | ||
| 274 | end | ||
| 275 | elseif archive:match("%.tar%.bz2$") then | ||
| 276 | ok = fs_execute("bunzip2 ", archive) | ||
| 277 | if ok then | ||
| 278 | ok = fs_execute("tar -xf ", strip_extension(archive)) | ||
| 279 | end | ||
| 280 | elseif archive:match("%.zip$") then | ||
| 281 | ok = fs_execute("unzip ", archive) | ||
| 282 | elseif archive:match("%.lua$") or archive:match("%.c$") then | ||
| 283 | -- Ignore .lua and .c files; they don't need to be extracted. | ||
| 284 | return true | ||
| 285 | else | ||
| 286 | local ext = archive:match(".*(%..*)") | ||
| 287 | return false, "Unrecognized filename extension "..(ext or "") | ||
| 288 | end | ||
| 289 | if not ok then | ||
| 290 | return false, "Failed extracting "..archive | ||
| 291 | end | ||
| 292 | return true | ||
| 293 | end | ||
| 294 | |||
| 295 | --- Return an absolute pathname from a potentially relative one. | 36 | --- Return an absolute pathname from a potentially relative one. |
| 296 | -- @param pathname string: pathname to convert. | 37 | -- @param pathname string: pathname to convert. |
| 297 | -- @param relative_to string or nil: path to prepend when making | 38 | -- @param relative_to string or nil: path to prepend when making |
| @@ -302,7 +43,7 @@ function absolute_name(pathname, relative_to) | |||
| 302 | assert(type(pathname) == "string") | 43 | assert(type(pathname) == "string") |
| 303 | assert(type(relative_to) == "string" or not relative_to) | 44 | assert(type(relative_to) == "string" or not relative_to) |
| 304 | 45 | ||
| 305 | relative_to = relative_to or fs_current_dir() | 46 | relative_to = relative_to or fs.current_dir() |
| 306 | if pathname:match("^[\.a-zA-Z]?:?[\\/]") then | 47 | if pathname:match("^[\.a-zA-Z]?:?[\\/]") then |
| 307 | return pathname | 48 | return pathname |
| 308 | else | 49 | else |
| @@ -344,7 +85,7 @@ function is_actual_binary(name) | |||
| 344 | end | 85 | end |
| 345 | 86 | ||
| 346 | function copy_binary(filename, dest) | 87 | function copy_binary(filename, dest) |
| 347 | local ok, err = fs_copy(filename, dest) | 88 | local ok, err = fs.copy(filename, dest) |
| 348 | if not ok then | 89 | if not ok then |
| 349 | return nil, err | 90 | return nil, err |
| 350 | end | 91 | 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 @@ | |||
| 1 | 1 | ||
| 2 | --- Core functions for querying manifest files. | 2 | --- Core functions for querying manifest files. |
| 3 | -- This module requires no specific 'fs' functionality. | ||
| 3 | module("luarocks.manif_core", package.seeall) | 4 | module("luarocks.manif_core", package.seeall) |
| 4 | 5 | ||
| 5 | local persist = require("luarocks.persist") | 6 | 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, ...) | |||
| 209 | 209 | ||
| 210 | local ok, err | 210 | local ok, err |
| 211 | for _, file in pairs({...}) do | 211 | for _, file in pairs({...}) do |
| 212 | if fs_is_dir(file) then | 212 | if fs.is_dir(file) then |
| 213 | for _, file in pairs(fs_find(file)) do | 213 | for _, file in pairs(fs.find(file)) do |
| 214 | if fs_is_file(file) then | 214 | if fs.is_file(file) then |
| 215 | ok, err = add_to_zip(file) | 215 | ok, err = add_to_zip(file) |
| 216 | if not ok then break end | 216 | if not ok then break end |
| 217 | end | 217 | end |
