From 2c4ff5240bf298fec07749f5984de2f08b8736ec Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 20 Feb 2024 13:43:44 -0300 Subject: fix: better normalization for paths and slashes Fixes #1195. --- spec/build_spec.lua | 3 +- spec/dir_spec.lua | 27 +-- spec/fs_spec.lua | 31 ++-- spec/path_spec.lua | 15 -- spec/quick/config.q | 4 +- spec/quick/list.q | 4 +- spec/remove_spec.lua | 3 +- spec/util/quick.lua | 106 ++++++++---- spec/util/test_env.lua | 398 ++++++++++++++++++++++++------------------- spec/util_spec.lua | 59 +++---- spec/which_spec.lua | 9 +- src/luarocks/admin/cache.lua | 2 +- src/luarocks/cmd/doc.lua | 2 +- src/luarocks/cmd/init.lua | 4 +- src/luarocks/core/cfg.lua | 82 +++++---- src/luarocks/core/dir.lua | 15 +- src/luarocks/core/path.lua | 8 +- src/luarocks/core/util.lua | 8 +- src/luarocks/dir.lua | 21 ++- src/luarocks/fetch.lua | 4 +- src/luarocks/fs/lua.lua | 39 +++-- src/luarocks/fs/unix.lua | 6 +- src/luarocks/fs/win32.lua | 23 +-- 23 files changed, 489 insertions(+), 384 deletions(-) diff --git a/spec/build_spec.lua b/spec/build_spec.lua index 5e78aa4f..0a270ec4 100644 --- a/spec/build_spec.lua +++ b/spec/build_spec.lua @@ -5,6 +5,7 @@ local run = test_env.run local testing_paths = test_env.testing_paths local write_file = test_env.write_file local git_repo = require("spec.util.git_repo") +local P = test_env.P test_env.unload_luarocks() local cfg = require("luarocks.core.cfg") @@ -661,7 +662,7 @@ describe("LuaRocks build #unit", function() write_file("bin/binfile", "", finally) local _, install, copy_directories = build_builtin.autodetect_modules({}, {}, {}) - assert.same(install, { bin = { "bin/binfile" } }) + assert.same(install, { bin = { P"bin/binfile" } }) assert.same(copy_directories, { "doc", "docs", "samples", "tests" }) lfs.rmdir("doc") diff --git a/spec/dir_spec.lua b/spec/dir_spec.lua index f6ef172e..b5dadda8 100644 --- a/spec/dir_spec.lua +++ b/spec/dir_spec.lua @@ -1,5 +1,6 @@ local test_env = require("spec.util.test_env") local testing_paths = test_env.testing_paths +local P = test_env.P test_env.unload_luarocks() test_env.setup_specs() @@ -45,26 +46,26 @@ describe("luarocks.dir #unit", function() describe("dir.normalize", function() it("converts backslashes and removes trailing slashes", function() - assert.are.same("/foo/ovo", dir.normalize("\\foo\\ovo\\")) - assert.are.same("c:/some/dir", dir.normalize("c:\\..\\some\\foo\\..\\dir")) + assert.are.same(P"/foo/ovo", dir.normalize("\\foo\\ovo\\")) + assert.are.same(P"c:/some/dir", dir.normalize("c:\\..\\some\\foo\\..\\dir")) assert.are.same("http://example.com/foo/ovo", dir.normalize("http://example.com/foo\\ovo\\")) end) it("strips unneeded /../ and /./", function() - assert.are.same("/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) - assert.are.same("/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) - assert.are.same("/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./some/subdir/../..")) - assert.are.same("/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./.")) + assert.are.same(P"/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) + assert.are.same(P"/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) + assert.are.same(P"/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./some/subdir/../..")) + assert.are.same(P"/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./.")) end) it("respects relative paths", function() - assert.are.same(".", dir.normalize(".")) - assert.are.same("boo", dir.normalize("./boo")) - assert.are.same("/boo", dir.normalize("/./boo")) - assert.are.same("../../../../boo", dir.normalize("../../../hello/world/../../../boo")) + assert.are.same(P".", dir.normalize(".")) + assert.are.same(P"boo", dir.normalize("./boo")) + assert.are.same(P"/boo", dir.normalize("/./boo")) + assert.are.same(P"../../../../boo", dir.normalize("../../../hello/world/../../../boo")) end) it("respects root directory", function() - assert.are.same("/", dir.normalize("/")) - assert.are.same("/", dir.normalize("/////")) - assert.are.same("/", dir.normalize("/a/b/.././../c/./../../")) + assert.are.same(P"/", dir.normalize("/")) + assert.are.same(P"/", dir.normalize("/////")) + assert.are.same(P"/", dir.normalize("/a/b/.././../c/./../../")) end) end) diff --git a/spec/fs_spec.lua b/spec/fs_spec.lua index cd6e5c13..aea86af3 100644 --- a/spec/fs_spec.lua +++ b/spec/fs_spec.lua @@ -11,6 +11,7 @@ local posix_ok = pcall(require, "posix") local testing_paths = test_env.testing_paths local get_tmp_path = test_env.get_tmp_path local write_file = test_env.write_file +local P = test_env.P -- A chdir that works in both full and minimal mode, setting -- both the real process current dir and the LuaRocks internal stack in minimal mode @@ -92,33 +93,33 @@ describe("luarocks.fs #unit", function() describe("fs.absolute_name", function() it("unchanged if already absolute", function() if is_win then - assert.are.same("c:\\foo\\bar", fs.absolute_name("\"c:\\foo\\bar\"")) - assert.are.same("c:\\foo\\bar", fs.absolute_name("c:\\foo\\bar")) - assert.are.same("d:\\foo\\bar", fs.absolute_name("d:\\foo\\bar")) - assert.are.same("\\foo\\bar", fs.absolute_name("\\foo\\bar")) + assert.are.same(P"c:\\foo\\bar", fs.absolute_name("\"c:\\foo\\bar\"")) + assert.are.same(P"c:\\foo\\bar", fs.absolute_name("c:\\foo\\bar")) + assert.are.same(P"d:\\foo\\bar", fs.absolute_name("d:\\foo\\bar")) + assert.are.same(P"\\foo\\bar", fs.absolute_name("\\foo\\bar")) else - assert.are.same("/foo/bar", fs.absolute_name("/foo/bar")) + assert.are.same(P"/foo/bar", fs.absolute_name("/foo/bar")) end end) it("converts to absolute if relative", function() local cur = fs.current_dir() if is_win then - assert.are.same(cur .. "/foo\\bar", fs.absolute_name("\"foo\\bar\"")) - assert.are.same(cur .. "/foo\\bar", fs.absolute_name("foo\\bar")) + assert.are.same(P(cur .. "/foo\\bar"), fs.absolute_name("\"foo\\bar\"")) + assert.are.same(P(cur .. "/foo\\bar"), fs.absolute_name("foo\\bar")) else - assert.are.same(cur .. "/foo/bar", fs.absolute_name("foo/bar")) + assert.are.same(P(cur .. "/foo/bar"), fs.absolute_name("foo/bar")) end end) it("converts a relative to specified base if given", function() if is_win then - assert.are.same("c:\\bla/foo\\bar", fs.absolute_name("\"foo\\bar\"", "c:\\bla")) - assert.are.same("c:\\bla/foo\\bar", fs.absolute_name("foo\\bar", "c:\\bla")) - assert.are.same("c:\\bla/foo\\bar", fs.absolute_name("foo\\bar", "c:\\bla\\")) + assert.are.same(P"c:\\bla/foo\\bar", fs.absolute_name("\"foo\\bar\"", "c:\\bla")) + assert.are.same(P"c:\\bla/foo\\bar", fs.absolute_name("foo/bar", "c:\\bla")) + assert.are.same(P"c:\\bla/foo\\bar", fs.absolute_name("foo\\bar", "c:\\bla\\")) else - assert.are.same("/bla/foo/bar", fs.absolute_name("foo/bar", "/bla")) - assert.are.same("/bla/foo/bar", fs.absolute_name("foo/bar", "/bla/")) + assert.are.same(P"/bla/foo/bar", fs.absolute_name("foo/bar", "/bla")) + assert.are.same(P"/bla/foo/bar", fs.absolute_name("foo/bar", "/bla/")) end end) end) @@ -619,9 +620,9 @@ describe("luarocks.fs #unit", function() assert.truthy(fs.change_dir_to_root()) if is_win then local curr_dir = fs.current_dir() - assert.truthy(curr_dir == "C:\\" or curr_dir == "/") + assert.truthy(curr_dir == "C:\\" or curr_dir == P"/") else - assert.same("/", fs.current_dir()) + assert.same(P"/", fs.current_dir()) end end) diff --git a/spec/path_spec.lua b/spec/path_spec.lua index 9b2a2854..ba2ecdde 100644 --- a/spec/path_spec.lua +++ b/spec/path_spec.lua @@ -57,19 +57,4 @@ describe("luarocks path #integration", function() it("--tree", function() assert.is_true(run.luarocks_bool("path --tree=lua_modules")) end) - - it("--project-tree", function() - local path1 = "/share/lua/5%." .. test_env.lua_version:sub(3, 3) .. "/%?%.lua" - local path2 = "/share/lua/5%." .. test_env.lua_version:sub(3, 3) .. "/%?/init%.lua" - - local path = run.luarocks("path --project-tree=foo") - assert.truthy(path:find("foo" .. path1)) - assert.truthy(path:find("foo" .. path2)) - - path = run.luarocks("path --project-tree=foo --tree=bar") - assert.falsy(path:find("foo" .. path1)) - assert.falsy(path:find("foo" .. path2)) - assert.truthy(path:find("bar" .. path1)) - assert.truthy(path:find("bar" .. path2)) - end) end) diff --git a/spec/quick/config.q b/spec/quick/config.q index ec338f98..3150a9ce 100644 --- a/spec/quick/config.q +++ b/spec/quick/config.q @@ -12,6 +12,6 @@ RUN: luarocks config --system-config STDOUT: -------------------------------------------------------------------------------- -%{testing_lrprefix}/etc/luarocks/config-%{LUA_VERSION}.lua +%{path(%{testing_lrprefix}/etc/luarocks/config-%{LUA_VERSION}.lua)} -------------------------------------------------------------------------------- -#TODO: ^^^ %{path()} + diff --git a/spec/quick/list.q b/spec/quick/list.q index 7cbdee43..fbb3f557 100644 --- a/spec/quick/list.q +++ b/spec/quick/list.q @@ -5,6 +5,6 @@ RUN: luarocks --tree=%{path(/some/invalid/tree)} list STDOUT: -------------------------------------------------------------------------------- -Rocks installed for Lua %{lua_version} in /some/invalid/tree +Rocks installed for Lua %{lua_version} in %{path(/some/invalid/tree)} -------------------------------------------------------------------------------- -#TODO: ^^^ %{path()} + diff --git a/spec/remove_spec.lua b/spec/remove_spec.lua index a67db591..ddeb0644 100644 --- a/spec/remove_spec.lua +++ b/spec/remove_spec.lua @@ -4,6 +4,7 @@ local run = test_env.run local testing_paths = test_env.testing_paths local env_variables = test_env.env_variables local V = test_env.V +local P = test_env.P test_env.unload_luarocks() @@ -86,7 +87,7 @@ describe("luarocks remove #integration", function() end) it("restores old versions", function() - local libdir = testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION + local libdir = P(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION) assert.is_true(run.luarocks_bool("install luafilesystem ${LUAFILESYSTEM_OLD_V}")) assert.is.truthy(lfs.attributes(libdir.."/lfs."..test_env.lib_extension)) diff --git a/spec/util/quick.lua b/spec/util/quick.lua index c8bfb61a..1fcf2b36 100644 --- a/spec/util/quick.lua +++ b/spec/util/quick.lua @@ -37,7 +37,7 @@ local function is_hr(line) end local function parse(filename) - local fd = assert(io.open(filename, "r")) + local fd = assert(io.open(filename, "rb")) local input = assert(fd:read("*a")) fd:close() @@ -67,11 +67,27 @@ local function parse(filename) os.exit(1) end - local function bool_arg(cmd, cur_block, field, arg) + local function bool_arg(cmd, cur, field, arg) if arg ~= "true" and arg ~= "false" then fail(cmd .. " argument must be 'true' or 'false'") end - cur_block[field] = (arg == "true") + cur[field] = (arg == "true") + end + + local function block_start_arg(cmd, cur, field) + if not cur or cur.op ~= "RUN" then + fail(cmd .. " must be given in the context of a RUN") + end + if cur[field] then + fail(cmd .. " was already declared") + end + + cur[field] = { + data = {} + } + cur_block = cur[field] + cur_block_name = cmd + table.insert(stack, "block start") end local test_env = require("spec.util.test_env") @@ -109,7 +125,11 @@ local function parse(filename) end)) end - for line in input:gmatch("[^\n]*") do + if input:sub(#input, #input) ~= "\n" then + input = input .. "\n" + end + + for line in input:gmatch("([^\r\n]*)\r?\n?") do cur_line = cur_line + 1 local state = stack[#stack] @@ -182,34 +202,20 @@ local function parse(filename) cur_op.exit = code cur_op.exit_line = cur_line - elseif cmd == "STDERR" then + elseif cmd == "VERBOSE" then if not cur_op or cur_op.op ~= "RUN" then - fail("STDERR must be given in the context of a RUN") - end - if cur_op.stderr then - fail("STDERR was already declared") + fail("VERBOSE must be given in the context of a RUN") end - cur_op.stderr = { - data = {} - } - cur_block = cur_op.stderr - cur_block_name = "STDERR" - table.insert(stack, "block start") + bool_arg("VERBOSE", cur_op, "verbose", arg) + elseif cmd == "STDERR" then + block_start_arg("STDERR", cur_op, "stderr") + elseif cmd == "NOT_STDERR" then + block_start_arg("NOT_STDERR", cur_op, "not_stderr") elseif cmd == "STDOUT" then - if not cur_op or cur_op.op ~= "RUN" then - fail("STDOUT must be given in the context of a RUN") - end - if cur_op.stdout then - fail("STDOUT was already declared") - end - - cur_op.stdout = { - data = {} - } - cur_block = cur_op.stdout - cur_block_name = "STDOUT" - table.insert(stack, "block start") + block_start_arg("STDOUT", cur_op, "stdout") + elseif cmd == "NOT_STDOUT" then + block_start_arg("NOT_STDOUT", cur_op, "not_stdout") elseif cmd == "TEST" then table.remove(stack) start_test(arg) @@ -298,7 +304,7 @@ function quick.compile(filename, env) write([=[ end ]=]) for _, op in ipairs(t.ops) do if op.op == "FILE" then - write([=[ test_env.write_file(handle_tmpdir("]=], op.name, [=["), handle_tmpdir([=====[ ]=]) + write(([=[ test_env.write_file(handle_tmpdir(%q), handle_tmpdir([=====[ ]=]):format(op.name)) for _, line in ipairs(op.data) do write(line) end @@ -324,7 +330,7 @@ function quick.compile(filename, env) write(([=[ local ok, _, code = os.execute(%s .. " " .. %q .. %q) ]=]):format(cmd_helper, op.args, redirs)) write([=[ if type(ok) == "number" then code = (ok >= 256 and ok / 256 or ok) end ]=]) - write([=[ local fd_stderr = assert(io.open("stderr.txt", "r")) ]=]) + write([=[ local fd_stderr = assert(io.open("stderr.txt", "rb")) ]=]) write([=[ local stderr_data = fd_stderr:read("*a") ]=]) write([=[ fd_stderr:close() ]=]) @@ -332,23 +338,46 @@ function quick.compile(filename, env) write(([=[ assert(false, error_message(%d, "RUN crashed: ", stderr_data)) ]=]):format(op.line)) write([=[ end ]=]) - if op.stdout then - write([=[ local fd_stdout = assert(io.open("stdout.txt", "r")) ]=]) + if op.stdout or op.not_stdout or op.verbose then + write([=[ local fd_stdout = assert(io.open("stdout.txt", "rb")) ]=]) write([=[ local stdout_data = fd_stdout:read("*a") ]=]) write([=[ fd_stdout:close() ]=]) + end + + if op.verbose then + write([=[ print() ]=]) + write([=[ print("STDOUT: --" .. ("-"):rep(70)) ]=]) + write([=[ print(stdout_data) ]=]) + write([=[ print("STDERR: --" .. ("-"):rep(70)) ]=]) + write([=[ print(stderr_data) ]=]) + write([=[ print(("-"):rep(80)) ]=]) + write([=[ print() ]=]) + end + if op.stdout then write([=[ do ]=]) write([=[ local block_at = 1 ]=]) write([=[ local s, e, line ]=]) for i, line in ipairs(op.stdout.data) do write(([=[ line = %q ]=]):format(line)) - write(([=[ s, e = string.find(stdout_data, line, block_at, true) ]=])) + write(([=[ s, e = string.find(stdout_data, line, 1, true) ]=])) write(([=[ assert(s, error_message(%d, "STDOUT did not match: " .. line, stdout_data)) ]=]):format(op.stdout.start + i)) write(([=[ block_at = e + 1 ]=]):format(i)) end write([=[ end ]=]) end + if op.not_stdout then + write([=[ do ]=]) + write([=[ local line ]=]) + for i, line in ipairs(op.not_stdout.data) do + write(([=[ line = %q ]=]):format(line)) + write(([=[ s = string.find(stdout_data, line, 1, true) ]=])) + write(([=[ assert(not s, error_message(%d, "NOT_STDOUT did match unwanted output: " .. line, stdout_data)) ]=]):format(op.stdout.start + i)) + end + write([=[ end ]=]) + end + if op.stderr then write([=[ do ]=]) write([=[ local block_at = 1 ]=]) @@ -362,6 +391,17 @@ function quick.compile(filename, env) write([=[ end ]=]) end + if op.not_stderr then + write([=[ do ]=]) + write([=[ local line ]=]) + for i, line in ipairs(op.not_stderr.data) do + write(([=[ line = %q ]=]):format(line)) + write(([=[ s = string.find(stderr_data, line, block_at, true) ]=])) + write(([=[ assert(not s, error_message(%d, "NOT_STDERR did match unwanted output: " .. line, stderr_data)) ]=]):format(op.stderr.start + i)) + end + write([=[ end ]=]) + end + if op.exit then write(([=[ assert.same(%d, code, error_message(%d, "EXIT did not match: " .. %d, stderr_data)) ]=]):format(op.exit, op.exit_line, op.exit)) end diff --git a/spec/util/test_env.lua b/spec/util/test_env.lua index dcda6311..41787cb7 100644 --- a/spec/util/test_env.lua +++ b/spec/util/test_env.lua @@ -37,6 +37,19 @@ local function title(str) print(("-"):rep(#str)) end +local dir_sep = package.config:sub(1, 1) +local function P(p) + return (p:gsub("/", dir_sep)) +end + +local function dir_path(...) + return P((table.concat({ ... }, "/"):gsub("\\", "/"):gsub("/+", "/"))) +end + +local function C(...) + return table.concat({...}, " ") +end + --- Quote argument for shell processing. Fixes paths on Windows. -- Adds double quotes and escapes. Based on function in fs/win32.lua. -- @param arg string: Unquoted argument. @@ -46,7 +59,7 @@ local function Q(arg) local drive_letter = "[%.a-zA-Z]?:?[\\/]" -- Quote DIR for Windows if arg:match("^"..drive_letter) then - arg = arg:gsub("/", "\\") + arg = P(arg) end if arg == "\\" then @@ -72,7 +85,7 @@ local function V(str) elseif suffix == "v" then return v elseif suffix == "r" then - return v + return r else print("Test error: invalid suffix " .. suffix .. " in variable " .. name) os.exit(1) @@ -87,6 +100,14 @@ local function V(str) end)) end +local function tool(name) + if test_env.TEST_TARGET_OS == "windows" then + return Q(dir_path(test_env.testing_paths.win_tools, name .. ".exe")) + else + return name + end +end + local os_remove = os.remove os.remove = function(f) -- luacheck: ignore return os_remove(V(f)) @@ -131,8 +152,18 @@ function test_env.copy(source, destination) source = V(source) destination = V(destination) - local r_source, err = io.open(source, "r") - local r_destination, err = io.open(destination, "w") + local r_source, r_destination, err + r_source, err = io.open(source, "r") + if err then + print(debug.traceback()) + os.exit(1) + end + + r_destination, err = io.open(destination, "w") + if err then + print(debug.traceback()) + os.exit(1) + end while true do local block = r_source:read(8192) @@ -147,7 +178,7 @@ end function test_env.get_tmp_path() local path = os.tmpname() if test_env.TEST_TARGET_OS == "windows" and not path:find(":") then - path = os.getenv("TEMP") .. path + path = dir_path(os.getenv("TEMP"), path) end os.remove(path) return path @@ -234,8 +265,8 @@ local function execute_bool(command, print_command, env_variables) local redirect_filename local redirect = "" if print_command ~= nil then - redirect_filename = test_env.testing_paths.luarocks_tmp.."/output.txt" - redirect = " > "..redirect_filename + redirect_filename = dir_path(test_env.testing_paths.luarocks_tmp, "output.txt") + redirect = " > " .. redirect_filename os.remove(redirect_filename) end local ok = test_env.execute(command .. redirect) @@ -312,7 +343,7 @@ function test_env.set_args() if not test_env.TEST_TARGET_OS then title("OS CHECK") - if package.config:sub(1,1) == "\\" then + if dir_sep == "\\" then test_env.TEST_TARGET_OS = "windows" if test_env.APPVEYOR then test_env.OPENSSL_INCDIR = "C:\\OpenSSL-v111-Win32\\include" @@ -348,7 +379,8 @@ function test_env.set_args() test_env.openssl_dirs = "" if test_env.OPENSSL_INCDIR then - test_env.openssl_dirs = "OPENSSL_INCDIR=" .. test_env.OPENSSL_INCDIR .. " OPENSSL_LIBDIR=" .. test_env.OPENSSL_LIBDIR + test_env.openssl_dirs = C("OPENSSL_INCDIR=" .. test_env.OPENSSL_INCDIR, + "OPENSSL_LIBDIR=" .. test_env.OPENSSL_LIBDIR) end return true @@ -358,12 +390,8 @@ function test_env.copy_dir(source_path, target_path) source_path = V(source_path) target_path = V(target_path) - local testing_paths = test_env.testing_paths - if test_env.TEST_TARGET_OS == "windows" then - execute_bool(testing_paths.win_tools .. "/cp -R ".. source_path .. "/. " .. target_path) - else - execute_bool("cp -a ".. source_path .. "/. " .. target_path) - end + local flag = test_env.TEST_TARGET_OS == "windows" and "-R" or "-a" + os.execute(C(tool("cp"), flag, dir_path(source_path, "."), target_path)) end --- Remove directory recursively @@ -374,7 +402,7 @@ function test_env.remove_dir(path) if exists(path) then for file in lfs.dir(path) do if file ~= "." and file ~= ".." then - local full_path = path..'/'..file + local full_path = dir_path(path, file) if lfs.attributes(full_path, "mode") == "directory" then test_env.remove_dir(full_path) @@ -396,7 +424,7 @@ function test_env.remove_subdirs(path, pattern) if exists(path) then for file in lfs.dir(path) do if file ~= "." and file ~= ".." then - local full_path = path..'/'..file + local full_path = dir_path(path, file) if lfs.attributes(full_path, "mode") == "directory" and file:find(pattern) then test_env.remove_dir(full_path) @@ -418,7 +446,7 @@ function test_env.remove_files(path, pattern) for file in lfs.dir(path) do if file ~= "." and file ~= ".." then if file:find(pattern) then - if os.remove(path .. "/" .. file) then + if os.remove(dir_path(path, file)) then result_check = true end end @@ -442,27 +470,21 @@ local function download_rocks(urls, save_path) url = V(url) if url:match("^spec/fixtures") then - table.insert(fixtures, (url:gsub("^spec/fixtures", test_env.testing_paths.fixtures_dir))) + table.insert(fixtures, P(url:gsub("^spec/fixtures", test_env.testing_paths.fixtures_dir))) else -- check if already downloaded - if not exists(save_path .. "/" .. url) then + if not exists(dir_path(save_path, url)) then table.insert(to_download, ((luarocks_repo .. url):gsub("org//", "org/"))) end end end if #fixtures > 0 then - os.execute("cp " .. table.concat(fixtures, " ") .. " " .. save_path) + os.execute(C(tool("cp"), table.concat(fixtures, " "), save_path)) end if #to_download > 0 then - local cmd - if test_env.TEST_TARGET_OS == "windows" then - cmd = test_env.testing_paths.win_tools .. "/wget --no-check-certificate -cP " .. save_path - else - cmd = "wget -cP " .. save_path - end - local ok = execute_bool(cmd.." "..table.concat(to_download, " ")) + local ok = execute_bool(C(tool("wget"), "--no-check-certificate -cP", save_path, table.concat(to_download, " "))) if not ok then os.exit(1) end @@ -492,12 +514,13 @@ end -- @return md5sum string: md5sum of directory local function hash_environment(path) if test_env.TEST_TARGET_OS == "linux" then - return execute_output("cd " .. path .. " && find . -printf \"%s %p\n\"") + return execute_output(C("cd", path, "&& find . -printf \"%s %p\n\" | md5sum")) elseif test_env.TEST_TARGET_OS == "osx" then - return execute_output("find " .. path .. " -type f -exec stat -f \"%z %N\" {} \\; | md5") + return execute_output(C("find", path, "-type f -exec stat -f \"%z %N\" {} \\; | md5")) elseif test_env.TEST_TARGET_OS == "windows" then - return execute_output("\"" .. Q(test_env.testing_paths.win_tools .. "/find") .. " " .. Q(path) - .. " -printf \"%s %p\"\" > temp_sum.txt && certUtil -hashfile temp_sum.txt && del temp_sum.txt") + return execute_output( + "\"" .. C(tool("find"), Q(path), "-printf", "\"%s %p\"") .. "\"" .. + " > temp_sum.txt && certUtil -hashfile temp_sum.txt && del temp_sum.txt") end end @@ -505,29 +528,44 @@ end -- @param testing_paths table: table with paths to testing directory -- @return env_variables table: table with created environment variables local function create_env(testing_paths) - local luaversion_short = _VERSION:gsub("Lua ", "") + local lua_v = _VERSION:gsub("Lua ", "") + local testrun_dir = test_env.testing_paths.testrun_dir + local lrprefix = testing_paths.testing_lrprefix + local tree = testing_paths.testing_tree + local sys_tree = testing_paths.testing_sys_tree if test_env.LUAJIT_V then - luaversion_short="5.1" + lua_v="5.1" end local env_variables = {} env_variables.GNUPGHOME = testing_paths.gpg_dir - env_variables.LUA_VERSION = luaversion_short - env_variables.LUAROCKS_CONFIG = testing_paths.testrun_dir .. "/testing_config.lua" + env_variables.LUA_VERSION = lua_v + env_variables.LUAROCKS_CONFIG = dir_path(testrun_dir, "testing_config.lua") + + local lua_path = {} if test_env.TEST_TARGET_OS == "windows" then - env_variables.LUA_PATH = testing_paths.testing_lrprefix .. "\\lua\\?.lua;" + table.insert(lua_path, dir_path(lrprefix, "lua", "?.lua")) else - env_variables.LUA_PATH = testing_paths.testing_lrprefix .. "/share/lua/" .. luaversion_short .. "/?.lua;" + table.insert(lua_path, dir_path(lrprefix, "share", "lua", lua_v, "?.lua")) end - env_variables.LUA_PATH = env_variables.LUA_PATH .. testing_paths.testing_tree .. "/share/lua/" .. luaversion_short .. "/?.lua;" - env_variables.LUA_PATH = env_variables.LUA_PATH .. testing_paths.testing_tree .. "/share/lua/".. luaversion_short .. "/?/init.lua;" - env_variables.LUA_PATH = env_variables.LUA_PATH .. testing_paths.testing_sys_tree .. "/share/lua/" .. luaversion_short .. "/?.lua;" - env_variables.LUA_PATH = env_variables.LUA_PATH .. testing_paths.testing_sys_tree .. "/share/lua/".. luaversion_short .. "/?/init.lua;" - env_variables.LUA_PATH = env_variables.LUA_PATH .. testing_paths.src_dir .. "/?.lua;" - env_variables.LUA_CPATH = testing_paths.testing_tree .. "/lib/lua/" .. luaversion_short .. "/?." .. test_env.lib_extension .. ";" - .. testing_paths.testing_sys_tree .. "/lib/lua/" .. luaversion_short .. "/?." .. test_env.lib_extension .. ";" - env_variables.PATH = os.getenv("PATH") .. ";" .. testing_paths.testing_tree .. "/bin;" .. testing_paths.testing_sys_tree .. "/bin;" + table.insert(lua_path, dir_path(tree, "share", "lua", lua_v, "?.lua")) + table.insert(lua_path, dir_path(tree, "share", "lua", lua_v, "?", "init.lua")) + table.insert(lua_path, dir_path(sys_tree, "share", "lua", lua_v, "?.lua")) + table.insert(lua_path, dir_path(sys_tree, "share", "lua", lua_v, "?", "init.lua")) + table.insert(lua_path, dir_path(testing_paths.src_dir, "?.lua")) + env_variables.LUA_PATH = table.concat(lua_path, ";") .. ";" + + local lua_cpath = {} + local lib_pattern = "?." .. test_env.lib_extension + table.insert(lua_cpath, dir_path(tree, "lib", "lua", lua_v, lib_pattern)) + table.insert(lua_cpath, dir_path(sys_tree, "lib", "lua", lua_v, lib_pattern)) + env_variables.LUA_CPATH = table.concat(lua_cpath, ";") .. ";" + + local path = { os.getenv("PATH") } + table.insert(path, dir_path(tree, "bin")) + table.insert(path, dir_path(sys_tree, "bin")) + env_variables.PATH = table.concat(path, test_env.TARGET_OS == "windows" and ";" or ":") return env_variables end @@ -544,16 +582,19 @@ local function create_md5sums(testing_paths) end local function make_run_function(cmd_name, exec_function, with_coverage, do_print) - local cmd_prefix = Q(test_env.testing_paths.lua) .. " " + local cmd_prefix = Q(test_env.testing_paths.lua) + local testrun_dir = test_env.testing_paths.testrun_dir if with_coverage then - cmd_prefix = cmd_prefix .. "-e \"require('luacov.runner')('" .. test_env.testing_paths.testrun_dir .. "/luacov.config')\" " + cmd_prefix = C(cmd_prefix, "-e", "\"require('luacov.runner')([[" .. testrun_dir .. "/luacov.config]])\"") end if cmd_name then - cmd_prefix = cmd_prefix .. test_env.testing_paths.src_dir .. "/bin/" .. cmd_name .. " " + cmd_prefix = C(cmd_prefix, dir_path(test_env.testing_paths.src_dir, "bin", cmd_name)) end + cmd_prefix = P(cmd_prefix) + return function(cmd, new_vars) cmd = V(cmd) local temp_vars = {} @@ -565,34 +606,34 @@ local function make_run_function(cmd_name, exec_function, with_coverage, do_prin temp_vars[k] = v end end - return exec_function(cmd_prefix .. cmd, do_print, temp_vars) + return exec_function(C(cmd_prefix, cmd), do_print, temp_vars) end end local function make_run_functions() - return { - lua = make_run_function(nil, execute_output, true, true), - lua_bool = make_run_function(nil, execute_bool, true, true), - luarocks = make_run_function("luarocks", execute_output, true, true), - luarocks_bool = make_run_function("luarocks", execute_bool, true, true), - luarocks_noprint = make_run_function("luarocks", execute_bool, true, false), - luarocks_nocov = make_run_function("luarocks", execute_bool, false, true), - luarocks_noprint_nocov = make_run_function("luarocks", execute_bool, false, false), - luarocks_admin = make_run_function("luarocks-admin", execute_output, true, true), - luarocks_admin_bool = make_run_function("luarocks-admin", execute_bool, true, true), - luarocks_admin_nocov = make_run_function("luarocks-admin", execute_bool, false, false) + local fns = {} + + local cmds = { + ["lua"] = nil, + ["luarocks"] = "luarocks", + ["luarocks_admin"] = "luarocks-admin", } + + for _, name in ipairs({"lua", "luarocks", "luarocks_admin"}) do + fns[name] = make_run_function(cmds[name], execute_output, true, true) + fns[name .. "_bool"] = make_run_function(cmds[name], execute_bool, true, true) + fns[name .. "_nocov"] = make_run_function(cmds[name], execute_bool, false, true) + fns[name .. "_noprint_nocov"] = make_run_function(cmds[name], execute_bool, false, false) + end + + return fns end local function move_file(src, dst) - if test_env.TEST_TARGET_OS == "windows" then - execute_bool(test_env.testing_paths.win_tools .. "/mv " .. src .. " " .. dst) - else - local ok = execute_bool("mv " .. src .. " " .. dst) - if not ok then - print(debug.traceback()) - os.exit(1) - end + local ok = execute_bool(C(tool("mv"), P(src), P(dst))) + if not ok then + print(debug.traceback()) + os.exit(1) end end @@ -610,13 +651,15 @@ local function build_environment(rocks, env_variables) lfs.mkdir(testing_paths.testing_tree) lfs.mkdir(testing_paths.testing_sys_tree) - test_env.run.luarocks_admin_nocov("make_manifest " .. Q(testing_paths.testing_server)) - test_env.run.luarocks_admin_nocov("make_manifest " .. Q(testing_paths.testing_cache)) + test_env.run.luarocks_admin_nocov(C("make_manifest", Q(testing_paths.testing_server))) + test_env.run.luarocks_admin_nocov(C("make_manifest", Q(testing_paths.testing_cache))) for _, rock in ipairs(rocks) do - if not test_env.run.luarocks_nocov(test_env.quiet("install --only-server=" .. testing_paths.testing_cache .. " --tree=" .. testing_paths.testing_sys_tree .. " " .. Q(rock), env_variables)) then - assert(test_env.run.luarocks_nocov("build --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables)) - assert(test_env.run.luarocks_nocov("pack --tree=" .. Q(testing_paths.testing_sys_tree) .. " " .. Q(rock), env_variables)) + local only_server = "--only-server=" .. testing_paths.testing_cache + local tree = "--tree=" .. testing_paths.testing_sys_tree + if not test_env.run.luarocks_nocov(test_env.quiet(C("install", only_server, tree, Q(rock)), env_variables)) then + assert(test_env.run.luarocks_nocov(C("build", tree, Q(rock)), env_variables)) + assert(test_env.run.luarocks_nocov(C("pack", tree, Q(rock)), env_variables)) move_file(rock .. "-*.rock", testing_paths.testing_cache) end end @@ -641,16 +684,6 @@ local function reset_environment(testing_paths, md5sums) end end -local function found_interpreter(testing_paths, luadir, lua_bindir) - local location = lua_bindir .. "/" .. testing_paths.lua_exe - if exists(location) then - testing_paths.lua_bindir = lua_bindir - testing_paths.luadir = luadir - testing_paths.lua = location - return true - end -end - local function find_lua() -- (1) LUA is a full path if test_env.LUA and test_env.LUA:match("[/\\]") then @@ -671,22 +704,22 @@ local function find_lua() if test_env.LUA_DIR then local luadir = test_env.LUA_DIR - local lua_bindir = exists(luadir .. "/bin") - and luadir .. "/bin" + local lua_bindir = exists(dir_path(luadir, "bin")) + and dir_path(luadir, "bin") or luadir - local lua = lua_bindir .. "/" .. lua_exe + local lua = dir_path(lua_bindir, lua_exe) return lua_bindir, luadir, lua end -- (2.2) LUA_DIR was not given, try some default paths local try_dirs = (test_env.TEST_TARGET_OS == "windows") - and { os.getenv("ProgramFiles(x86)").."/LuaRocks" } + and { os.getenv("ProgramFiles(x86)").."\\LuaRocks" } or { "/usr/local", "/usr" } for _, luadir in ipairs(try_dirs) do - for _, lua_bindir in ipairs({ luadir, luadir .. "/bin" }) do - local lua = lua_bindir .. "/" .. lua_exe + for _, lua_bindir in ipairs({ luadir, dir_path(luadir, "bin") }) do + local lua = dir_path(lua_bindir, lua_exe) if exists(lua) then return lua_bindir, luadir, lua end @@ -694,50 +727,47 @@ local function find_lua() end end -local function create_paths(luaversion_full) - - local testing_paths = {} +local function create_testing_paths(suffix) + local paths = {} - testing_paths.lua_bindir, testing_paths.luadir, testing_paths.lua = find_lua() - if (not testing_paths.lua) or (not exists(testing_paths.lua)) then + paths.lua_bindir, paths.luadir, paths.lua = find_lua() + if (not paths.lua) or (not exists(paths.lua)) then error("Lua interpreter not found! Run `busted -Xhelper help` for options") end local base_dir = lfs.currentdir() + paths.src_dir = dir_path(base_dir, "src") + paths.spec_dir = dir_path(base_dir, "spec") + paths.util_dir = dir_path(base_dir, "spec", "util") + paths.fixtures_dir = dir_path(base_dir, "spec", "fixtures") + paths.fixtures_repo_dir = dir_path(base_dir, "spec", "fixtures", "a_repo") + paths.gpg_dir = dir_path(base_dir, "spec", "fixtures", "gpg") + + local testrun_dir = dir_path(base_dir, "testrun") + paths.testrun_dir = testrun_dir + paths.testing_lrprefix = dir_path(testrun_dir, "testing_lrprefix-" .. suffix) + paths.testing_tree = dir_path(testrun_dir, "testing-" .. suffix) + paths.testing_tree_copy = dir_path(testrun_dir, "testing_copy-" .. suffix) + paths.testing_sys_tree = dir_path(testrun_dir, "testing_sys-" .. suffix) + paths.testing_sys_tree_copy = dir_path(testrun_dir, "testing_sys_copy-" .. suffix) + paths.testing_cache = dir_path(testrun_dir, "testing_cache-" .. suffix) + paths.testing_server = dir_path(testrun_dir, "testing_server-" .. suffix) + + local rocks_v = "rocks-" .. test_env.lua_version + paths.testing_rocks = dir_path(paths.testing_tree, "lib", "luarocks", rocks_v) + paths.testing_sys_rocks = dir_path(paths.testing_sys_tree, "lib", "luarocks", rocks_v) if test_env.TEST_TARGET_OS == "windows" then - base_dir = base_dir:gsub("\\","/") - end - - testing_paths.fixtures_dir = base_dir .. "/spec/fixtures" - testing_paths.gpg_dir = testing_paths.fixtures_dir .. "/gpg" - testing_paths.fixtures_repo_dir = base_dir .. "/spec/fixtures/a_repo" - testing_paths.util_dir = base_dir .. "/spec/util" - testing_paths.testrun_dir = base_dir .. "/testrun" - testing_paths.src_dir = base_dir .. "/src" - testing_paths.spec_dir = base_dir .. "/spec" - testing_paths.testing_lrprefix = testing_paths.testrun_dir .. "/testing_lrprefix-" .. luaversion_full - testing_paths.testing_tree = testing_paths.testrun_dir .. "/testing-" .. luaversion_full - testing_paths.testing_tree_copy = testing_paths.testrun_dir .. "/testing_copy-" .. luaversion_full - testing_paths.testing_sys_tree = testing_paths.testrun_dir .. "/testing_sys-" .. luaversion_full - testing_paths.testing_sys_tree_copy = testing_paths.testrun_dir .. "/testing_sys_copy-" .. luaversion_full - testing_paths.testing_cache = testing_paths.testrun_dir .. "/testing_cache-" .. luaversion_full - testing_paths.testing_server = testing_paths.testrun_dir .. "/testing_server-" .. luaversion_full - - testing_paths.testing_rocks = testing_paths.testing_tree .. "/lib/luarocks/rocks-" .. test_env.lua_version - testing_paths.testing_sys_rocks = testing_paths.testing_sys_tree .. "/lib/luarocks/rocks-" .. test_env.lua_version - - if test_env.TEST_TARGET_OS == "windows" then - testing_paths.luarocks_tmp = os.getenv("TEMP") + paths.luarocks_tmp = os.getenv("TEMP") else - testing_paths.luarocks_tmp = "/tmp/luarocks_testing" + paths.luarocks_tmp = "/tmp/luarocks_testing" end if test_env.TEST_TARGET_OS == "windows" then - testing_paths.win_tools = base_dir .. "/win32/tools" + paths.win_tools = dir_path(base_dir, "win32", "tools") end - return testing_paths + return paths end --- Helper function to unload luarocks modules from global table package.loaded @@ -748,7 +778,7 @@ function test_env.unload_luarocks() package.loaded[modname] = nil end end - local src_pattern = test_env.testing_paths.src_dir .. "/?.lua" + local src_pattern = dir_path(test_env.testing_paths.src_dir, "?.lua") if not package.path:find(src_pattern, 1, true) then package.path = src_pattern .. ";" .. package.path end @@ -760,16 +790,19 @@ local function get_luarocks_platform(variables) "cfg.init();" .. "print(cfg.arch)" .. "\"" - local cmd = test_env.testing_paths.lua .. " -e " .. print_arch_script + local cmd = C(test_env.testing_paths.lua, "-e", print_arch_script) return execute_output(cmd, false, variables) end --- Function for initial setup of environment, variables, md5sums for spec files function test_env.setup_specs(extra_rocks) + local testrun_dir = test_env.testing_paths.testrun_dir + local variables = test_env.env_variables + -- if global variable about successful creation of testing environment doesn't exist, build environment if not test_env.setup_done then if test_env.CI then - if not exists(os.getenv("HOME") .. "/.ssh/id_rsa.pub") then + if not exists(os.getenv("HOME"), ".ssh/id_rsa.pub") then execute_bool("ssh-keygen -t rsa -P \"\" -f ~/.ssh/id_rsa") execute_bool("cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys") execute_bool("chmod og-wx ~/.ssh/authorized_keys") @@ -783,8 +816,8 @@ function test_env.setup_specs(extra_rocks) require("spec.util.git_repo") require("spec.util.quick") - package.path = test_env.env_variables.LUA_PATH - package.cpath = test_env.env_variables.LUA_CPATH + package.path = variables.LUA_PATH + package.cpath = variables.LUA_CPATH test_env.platform = get_luarocks_platform(test_env.env_variables) test_env.wrapper_extension = test_env.TEST_TARGET_OS == "windows" and ".bat" or "" @@ -801,10 +834,10 @@ function test_env.setup_specs(extra_rocks) end if test_env.RESET_ENV then - reset_environment(test_env.testing_paths, test_env.md5sums, test_env.env_variables) + reset_environment(test_env.testing_paths, test_env.md5sums, variables) end - lfs.chdir(test_env.testing_paths.testrun_dir) + lfs.chdir(testrun_dir) end --- Test if required rock is installed and if not, install it. @@ -829,7 +862,11 @@ end -- replace %{key} in given string with value. local function substitute(str, replacements) return (str:gsub("%%%b{}", function(marker) - return replacements[marker:sub(3, -2)] + local r = replacements[marker:sub(3, -2)] + if r then + r = r:gsub("\\", "\\\\") + end + return r end)) end @@ -837,6 +874,8 @@ end --- Create configs for luacov and several versions of Luarocks -- configs needed for some tests. local function create_configs() + local testrun_dir = test_env.testing_paths.testrun_dir + -- testing_config.lua -- testing_config_show_downloads.lua -- testing_config_no_downloader.lua @@ -857,17 +896,17 @@ local function create_configs() }, } ]], { - user = os.getenv("USER"), + user = "testuser", testing_sys_tree = test_env.testing_paths.testing_sys_tree, testing_tree = test_env.testing_paths.testing_tree, testing_server = test_env.testing_paths.testing_server, testing_cache = test_env.testing_paths.testing_cache }) - test_env.write_file(test_env.testing_paths.testrun_dir .. "/testing_config.lua", config_content .. " \nweb_browser = \"true\"") - test_env.write_file(test_env.testing_paths.testrun_dir .. "/testing_config_show_downloads.lua", config_content + test_env.write_file(dir_path(testrun_dir, "testing_config.lua"), config_content .. " \nweb_browser = \"true\"") + test_env.write_file(dir_path(testrun_dir, "testing_config_show_downloads.lua"), config_content .. "show_downloads = true \n rocks_servers={\"http://luarocks.org/repositories/rocks\"}") - test_env.write_file(test_env.testing_paths.testrun_dir .. "/testing_config_no_downloader.lua", config_content + test_env.write_file(dir_path(testrun_dir, "testing_config_no_downloader.lua"), config_content .. "variables = { WGET = 'invalid', CURL = 'invalid' }") -- testing_config_sftp.lua @@ -885,32 +924,35 @@ local function create_configs() }, } ]], { - user = os.getenv("USER"), + user = "testuser", testing_sys_tree = test_env.testing_paths.testing_sys_tree, testing_tree = test_env.testing_paths.testing_tree, testing_cache = test_env.testing_paths.testing_cache }) - test_env.write_file(test_env.testing_paths.testrun_dir .. "/testing_config_sftp.lua", config_content) + test_env.write_file(dir_path(testrun_dir, "testing_config_sftp.lua"), config_content) -- luacov.config config_content = substitute([[ return { - statsfile = "%{testrun_dir}/luacov.stats.out", - reportfile = "%{testrun_dir}/luacov.report.out", + statsfile = "%{statsfile}", + reportfile = "%{reportfile}", modules = { - ["luarocks"] = "src/bin/luarocks", - ["luarocks-admin"] = "src/bin/luarocks-admin", + ["luarocks"] = "%{luarocks_path}", + ["luarocks-admin"] = "%{luarocks_admin_path}", ["luarocks.*"] = "src", ["luarocks.*.*"] = "src", ["luarocks.*.*.*"] = "src" } } ]], { - testrun_dir = test_env.testing_paths.testrun_dir + statsfile = dir_path(testrun_dir, "luacov.stats.out"), + reportfile = dir_path(testrun_dir, "luacov.report.out"), + luarocks_path = dir_path("src", "bin", "luarocks"), + luarocks_admin_path = dir_path("src", "bin", "luarocks-admin"), }) - test_env.write_file(test_env.testing_paths.testrun_dir .. "/luacov.config", config_content) + test_env.write_file(dir_path(testrun_dir, "luacov.config"), config_content) config_content = [[ -- Config file of mock LuaRocks.org site for tests @@ -920,18 +962,20 @@ local function create_configs() api_version = "1", } ]] - test_env.write_file(test_env.testing_paths.testrun_dir .. "/luarocks_site.lua", config_content) + test_env.write_file(dir_path(testrun_dir, "luarocks_site.lua"), config_content) end --- Remove testing directories. local function clean() + local testrun_dir = test_env.testing_paths.testrun_dir + print("Cleaning testing directory...") test_env.remove_dir(test_env.testing_paths.luarocks_tmp) - test_env.remove_subdirs(test_env.testing_paths.testrun_dir, "testing[_%-]") - test_env.remove_files(test_env.testing_paths.testrun_dir, "testing_") - test_env.remove_files(test_env.testing_paths.testrun_dir, "luacov") - test_env.remove_files(test_env.testing_paths.testrun_dir, "upload_config") - test_env.remove_files(test_env.testing_paths.testrun_dir, "luarocks_site") + test_env.remove_subdirs(testrun_dir, "testing[_%-]") + test_env.remove_files(testrun_dir, "testing_") + test_env.remove_files(testrun_dir, "luacov") + test_env.remove_files(testrun_dir, "upload_config") + test_env.remove_files(testrun_dir, "luarocks_site") print("Cleaning done!") end @@ -942,7 +986,7 @@ local function setup_luarocks() local lines = { "return {", - ("SYSCONFDIR = %q,"):format(testing_paths.testing_lrprefix .. "/etc/luarocks"), + ("SYSCONFDIR = %q,"):format(dir_path(testing_paths.testing_lrprefix, "etc/luarocks")), ("LUA_DIR = %q,"):format(testing_paths.luadir), ("LUA_BINDIR = %q,"):format(testing_paths.lua_bindir), ("LUA = %q,"):format(testing_paths.lua), @@ -965,33 +1009,33 @@ local function setup_luarocks() end local function mock_api_call(path) - if test_env.TEST_TARGET_OS == "windows" then - return test_env.execute(Q(test_env.testing_paths.win_tools .. "/wget") .. " --quiet --timeout=5 --tries=1 localhost:8080" .. path) - else - return test_env.execute("curl -s localhost:8080" .. path) - end + test_env.execute(C(tool("wget"), "--quiet --timeout=5 --tries=1 localhost:8080" .. path)) end function test_env.mock_server_init() local testing_paths = test_env.testing_paths assert(test_env.need_rock("restserver-xavante")) - if test_env.TEST_TARGET_OS == "windows" then - os.execute(test_env.execute_helper("start /b \"\" " .. Q(testing_paths.lua) .. " " .. Q(testing_paths.util_dir .. "/mock-server.lua") .. " " .. Q(testing_paths.fixtures_dir), true, test_env.env_variables)) - else - os.execute(test_env.execute_helper(testing_paths.lua .. " " .. testing_paths.util_dir .. "/mock-server.lua " .. testing_paths.fixtures_dir .. " &", true, test_env.env_variables)) - end + local lua = Q(testing_paths.lua) + local mock_server = Q(dir_path(testing_paths.util_dir, "mock-server.lua")) + local fixtures_dir = Q(testing_paths.fixtures_dir) + + local cmd = C(lua, mock_server, fixtures_dir) + + local bg_cmd = test_env.TEST_TARGET_OS == "windows" + and C("start", "/b", "\"\"", cmd) + or C(cmd, "&") + + os.execute(test_env.execute_helper(bg_cmd, true, test_env.env_variables)) for _ = 1, 10 do if mock_api_call("/api/tool_version") then break end - if test_env.TEST_TARGET_OS == "windows" then - os.execute("timeout 1 > NUL") - else - os.execute("sleep 1") - end + os.execute(test_env.TEST_TARGET_OS == "windows" + and "timeout 1 > NUL" + or "sleep 1") end end @@ -1000,9 +1044,9 @@ function test_env.mock_server_done() mock_api_call("/shutdown") end -local function find_binary_rock(src_rock, dir) +local function find_binary_rock(src_rock, dirname) local patt = src_rock:gsub("([.-])", "%%%1"):gsub("src", ".*[^s][^r][^c]") - for name in lfs.dir(dir) do + for name in lfs.dir(dirname) do if name:match(patt) then return true end @@ -1034,14 +1078,18 @@ local function prepare_mock_server_binary_rocks() rock = V(rock) local rockname = rock:gsub("%-[^-]+%-%d+%.[%a.]+$", "") if not find_binary_rock(rock, testing_paths.testing_server) then - test_env.run.luarocks_nocov("build " .. Q(testing_paths.testing_server .. "/" .. rock) .. " --tree=" .. testing_paths.testing_cache) - test_env.run.luarocks_nocov("pack " .. rockname .. " --tree=" .. testing_paths.testing_cache) + local rockpath = dir_path(testing_paths.testing_server, rock) + local tree = "--tree=" .. testing_paths.testing_cache + + test_env.run.luarocks_nocov(C("build", Q(rockpath), tree)) + test_env.run.luarocks_nocov(C("pack", rockname, tree)) + move_file(rockname .. "-*.rock", testing_paths.testing_server) make_manifest = true end end if make_manifest then - test_env.run.luarocks_admin_nocov("make_manifest " .. Q(testing_paths.testing_server)) + test_env.run.luarocks_admin_nocov(C("make_manifest", Q(testing_paths.testing_server))) end end @@ -1049,13 +1097,14 @@ end -- Main function to create config files and testing environment function test_env.main() local testing_paths = test_env.testing_paths + local testrun_dir = test_env.testing_paths.testrun_dir if test_env.TEST_ENV_CLEAN then clean() end - lfs.mkdir(testing_paths.testrun_dir) - test_env.write_file(testing_paths.testrun_dir .. "/.luarocks-no-project", "") + lfs.mkdir(testrun_dir) + test_env.write_file(dir_path(testrun_dir, ".luarocks-no-project"), "") lfs.mkdir(testing_paths.testing_cache) lfs.mkdir(testing_paths.luarocks_tmp) @@ -1068,7 +1117,7 @@ function test_env.main() local urls = {} -- names of rock and rockspec files to be downloaded local env_vars = { - LUAROCKS_CONFIG = test_env.testing_paths.testrun_dir .. "/testing_config.lua" + LUAROCKS_CONFIG = dir_path(testrun_dir, "testing_config.lua") } if test_env.TYPE_TEST_ENV == "full" then @@ -1088,8 +1137,8 @@ function test_env.main() table.insert(urls, "/luaposix-${LUAPOSIX}.src.rock") table.insert(rocks, "luaposix") end - assert(test_env.run.luarocks_nocov("config variables.OPENSSL_INCDIR " .. Q(test_env.OPENSSL_INCDIR), env_vars)) - assert(test_env.run.luarocks_nocov("config variables.OPENSSL_LIBDIR " .. Q(test_env.OPENSSL_LIBDIR), env_vars)) + assert(test_env.run.luarocks_nocov(C("config", "variables.OPENSSL_INCDIR", Q(test_env.OPENSSL_INCDIR)), env_vars)) + assert(test_env.run.luarocks_nocov(C("config", "variables.OPENSSL_LIBDIR", Q(test_env.OPENSSL_LIBDIR)), env_vars)) end -- luacov is needed for both minimal or full environment @@ -1111,12 +1160,13 @@ end test_env.set_lua_version() test_env.set_args() -test_env.testing_paths = create_paths(test_env.LUA_V or test_env.LUAJIT_V) +test_env.testing_paths = create_testing_paths(test_env.LUA_V or test_env.LUAJIT_V) test_env.env_variables = create_env(test_env.testing_paths) test_env.run = make_run_functions() test_env.exists = exists test_env.V = V test_env.Q = Q +test_env.P = P test_env.platform = get_luarocks_platform(test_env.env_variables) return test_env diff --git a/spec/util_spec.lua b/spec/util_spec.lua index 0c2d620e..abc0da57 100644 --- a/spec/util_spec.lua +++ b/spec/util_spec.lua @@ -2,6 +2,7 @@ local test_env = require("spec.util.test_env") local lfs = require("lfs") local run = test_env.run local testing_paths = test_env.testing_paths +local P = test_env.P describe("Basic tests #integration", function() @@ -182,34 +183,34 @@ describe("luarocks.util #unit", function() end) describe("core.util.cleanup_path", function() - it("does not change order of existing items of prepended path", function() - local sys_path = '/usr/local/bin;/usr/bin' - local lr_path = '/home/user/.luarocks/bin;/usr/bin' - local path = lr_path .. ';' .. sys_path - - local result = core_util.cleanup_path(path, ';', '5.3', false) - assert.are.equal('/home/user/.luarocks/bin;/usr/local/bin;/usr/bin', result) - end) - - it("does not change order of existing items of appended path", function() - local sys_path = '/usr/local/bin;/usr/bin' - local lr_path = '/home/user/.luarocks/bin;/usr/bin' - local path = sys_path .. ';' .. lr_path - - local result = core_util.cleanup_path(path, ';', '5.3', true) - assert.are.equal('/usr/local/bin;/usr/bin;/home/user/.luarocks/bin', result) - end) - - it("rewrites versions that do not match the provided version", function() - local expected = 'a/b/lua/5.3/?.lua;a/b/c/lua/5.3/?.lua' - local result = core_util.cleanup_path('a/b/lua/5.2/?.lua;a/b/c/lua/5.3/?.lua', ';', '5.3') - assert.are.equal(expected, result) - end) - - it("does not rewrite versions for which the provided version is a substring", function() - local expected = 'a/b/lua/5.3/?.lua;a/b/c/lua/5.3.4/?.lua' - local result = core_util.cleanup_path('a/b/lua/5.2/?.lua;a/b/c/lua/5.3.4/?.lua', ';', '5.3') - assert.are.equal(expected, result) - end) + it("does not change order of existing items of prepended path", function() + local sys_path = P'/usr/local/bin;/usr/bin' + local lr_path = P'/home/user/.luarocks/bin;/usr/bin' + local path = lr_path .. ';' .. sys_path + + local result = core_util.cleanup_path(path, ';', '5.3', false) + assert.are.equal(P'/home/user/.luarocks/bin;/usr/local/bin;/usr/bin', result) + end) + + it("does not change order of existing items of appended path", function() + local sys_path = P'/usr/local/bin;/usr/bin' + local lr_path = P'/home/user/.luarocks/bin;/usr/bin' + local path = sys_path .. ';' .. lr_path + + local result = core_util.cleanup_path(path, ';', '5.3', true) + assert.are.equal(P'/usr/local/bin;/usr/bin;/home/user/.luarocks/bin', result) + end) + + it("rewrites versions that do not match the provided version", function() + local expected = P'a/b/lua/5.3/?.lua;a/b/c/lua/5.3/?.lua' + local result = core_util.cleanup_path(P'a/b/lua/5.2/?.lua;a/b/c/lua/5.3/?.lua', ';', '5.3') + assert.are.equal(expected, result) + end) + + it("does not rewrite versions for which the provided version is a substring", function() + local expected = P'a/b/lua/5.3/?.lua;a/b/c/lua/5.3.4/?.lua' + local result = core_util.cleanup_path(P'a/b/lua/5.2/?.lua;a/b/c/lua/5.3.4/?.lua', ';', '5.3') + assert.are.equal(expected, result) + end) end) end) diff --git a/spec/which_spec.lua b/spec/which_spec.lua index d6e07eb7..9ccb1040 100644 --- a/spec/which_spec.lua +++ b/spec/which_spec.lua @@ -1,10 +1,6 @@ local test_env = require("spec.util.test_env") -local lfs = require("lfs") local run = test_env.run -local testing_paths = test_env.testing_paths -local env_variables = test_env.env_variables -local write_file = test_env.write_file -local hardcoded +local P = test_env.P test_env.unload_luarocks() @@ -17,7 +13,6 @@ describe("luarocks which #integration", function() setup(function() test_env.setup_specs(extra_rocks) test_env.unload_luarocks() -- need to be required here, because hardcoded is created after first loading of specs - hardcoded = require("luarocks.core.hardcoded") end) it("fails on missing arguments", function() @@ -28,7 +23,7 @@ describe("luarocks which #integration", function() it("finds modules found in package.path", function() assert.is_true(run.luarocks_bool("install say 1.2")) local output = run.luarocks("which say") - assert.match("say/init.lua", output, 1, true) + assert.match(P"say/init.lua", output, 1, true) assert.match("provided by say 1.2-1", output, 1, true) end) diff --git a/src/luarocks/admin/cache.lua b/src/luarocks/admin/cache.lua index 10b273ea..7a4e4af8 100644 --- a/src/luarocks/admin/cache.lua +++ b/src/luarocks/admin/cache.lua @@ -45,7 +45,7 @@ function cache.split_server_url(url, user, password) user = credentials end end - local local_cache = cfg.local_cache .. "/" .. server_path:gsub("[\\/]", "_") + local local_cache = dir.path(cfg.local_cache, (server_path:gsub("[\\/]", "_"))) return local_cache, protocol, server_path, user, password end diff --git a/src/luarocks/cmd/doc.lua b/src/luarocks/cmd/doc.lua index ae471230..a3117007 100644 --- a/src/luarocks/cmd/doc.lua +++ b/src/luarocks/cmd/doc.lua @@ -96,7 +96,7 @@ function doc.command(args) return nil, "Documentation directory not found for "..name.." "..version end - docdir = dir.normalize(docdir):gsub("/+", "/") + docdir = dir.normalize(docdir) local files = fs.find(docdir) local htmlpatt = "%.html?$" local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } diff --git a/src/luarocks/cmd/init.lua b/src/luarocks/cmd/init.lua index 1783750c..65513104 100644 --- a/src/luarocks/cmd/init.lua +++ b/src/luarocks/cmd/init.lua @@ -27,8 +27,8 @@ function init.add_to_parser(parser) end local function gitignore_path(pwd, wrapper_dir, filename) - local norm_cur = dir.normalize(fs.absolute_name(pwd)) - local norm_file = dir.normalize(fs.absolute_name(dir.path(wrapper_dir, filename))) + local norm_cur = fs.absolute_name(pwd) + local norm_file = fs.absolute_name(dir.path(wrapper_dir, filename)) if norm_file:sub(1, #norm_cur) == norm_cur then return norm_file:sub(#norm_cur + 2) else diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua index a3a7d6cb..b991f581 100644 --- a/src/luarocks/core/cfg.lua +++ b/src/luarocks/core/cfg.lua @@ -13,6 +13,7 @@ local table, pairs, require, os, pcall, ipairs, package, type, assert = table, pairs, require, os, pcall, ipairs, package, type, assert +local dir = require("luarocks.core.dir") local util = require("luarocks.core.util") local persist = require("luarocks.core.persist") local sysdetect = require("luarocks.core.sysdetect") @@ -53,21 +54,21 @@ local function detect_sysconfdir() if not debug then return end - local src = debug.getinfo(1, "S").source:gsub("\\", "/"):gsub("/+", "/") + local src = dir.normalize(debug.getinfo(1, "S")) if src:sub(1, 1) == "@" then src = src:sub(2) end - local basedir = src:match("^(.*)/luarocks/core/cfg.lua$") + local basedir = src:match("^(.*)[\\/]luarocks[\\/]core[\\/]cfg.lua$") if not basedir then return end -- If installed in a Unix-like tree, use a Unix-like sysconfdir - local installdir = basedir:match("^(.*)/share/lua/[^/]*$") + local installdir = basedir:match("^(.*)[\\/]share[\\/]lua[\\/][^/]*$") if installdir then if installdir == "/usr" then return "/etc/luarocks" end - return installdir .. "/etc/luarocks" + return dir.path(installdir, "etc", "luarocks") end -- Otherwise, use base directory of sources return basedir @@ -186,9 +187,9 @@ local function make_defaults(lua_version, target_cpu, platforms, home) cache_timeout = 60, cache_fail_timeout = 86400, - lua_modules_path = "/share/lua/"..lua_version, - lib_modules_path = "/lib/lua/"..lua_version, - rocks_subdir = "/lib/luarocks/rocks-"..lua_version, + lua_modules_path = dir.path("share", "lua", lua_version), + lib_modules_path = dir.path("lib", "lua", lua_version), + rocks_subdir = dir.path("lib", "luarocks", "rocks-"..lua_version), arch = "unknown", lib_extension = "unknown", @@ -283,10 +284,14 @@ local function make_defaults(lua_version, target_cpu, platforms, home) defaults.external_lib_extension = "dll" defaults.static_lib_extension = "lib" defaults.obj_extension = "obj" - defaults.external_deps_dirs = { "c:/external/", "c:/windows/system32" } + defaults.external_deps_dirs = { + dir.path("c:", "external"), + dir.path("c:", "windows", "system32"), + } defaults.makefile = "Makefile.win" defaults.variables.PWD = "echo %cd%" + defaults.variables.MKDIR = "md" defaults.variables.MAKE = os.getenv("MAKE") or "nmake" defaults.variables.CC = os.getenv("CC") or "cl" defaults.variables.RC = os.getenv("WINDRES") or "rc" @@ -313,9 +318,9 @@ local function make_defaults(lua_version, target_cpu, platforms, home) local localappdata = os.getenv("LOCALAPPDATA") if not localappdata then -- for Windows versions below Vista - localappdata = (os.getenv("USERPROFILE") or "c:/Users/All Users").."/Local Settings/Application Data" + localappdata = dir.path((os.getenv("USERPROFILE") or dir.path("c:", "Users", "All Users")), "Local Settings", "Application Data") end - defaults.local_cache = localappdata.."/LuaRocks/Cache" + defaults.local_cache = dir.path(localappdata, "LuaRocks", "Cache") defaults.web_browser = "start" defaults.external_deps_subdirs.lib = { "lib", "", "bin" } @@ -327,7 +332,11 @@ local function make_defaults(lua_version, target_cpu, platforms, home) if platforms.mingw32 then defaults.obj_extension = "o" defaults.static_lib_extension = "a" - defaults.external_deps_dirs = { "c:/external/", "c:/mingw", "c:/windows/system32" } + defaults.external_deps_dirs = { + dir.path("c:", "external"), + dir.path("c:", "mingw"), + dir.path("c:", "windows", "system32"), + } defaults.cmake_generator = "MinGW Makefiles" defaults.variables.MAKE = os.getenv("MAKE") or "mingw32-make" if target_cpu == "x86_64" then @@ -431,10 +440,13 @@ local function make_defaults(lua_version, target_cpu, platforms, home) local pipe = io.popen("cygpath --windows %MINGW_PREFIX%") local mingw_prefix = pipe:read("*l") pipe:close() - defaults.external_deps_dirs = { mingw_prefix, "c:/windows/system32" } + defaults.external_deps_dirs = { + mingw_prefix, + dir.path("c:", "windows", "system32"), + } defaults.makefile = "Makefile" defaults.cmake_generator = "MSYS Makefiles" - defaults.local_cache = home.."/.cache/luarocks" + defaults.local_cache = dir.path(home, ".cache", "luarocks") defaults.variables.MAKE = os.getenv("MAKE") or "make" defaults.variables.CC = os.getenv("CC") or "gcc" defaults.variables.RC = os.getenv("WINDRES") or "windres" @@ -668,17 +680,17 @@ function cfg.init(detected, warning) local sysconfdir = os.getenv("LUAROCKS_SYSCONFDIR") or hardcoded.SYSCONFDIR if platforms.windows and not platforms.msys2_mingw_w64 then cfg.home = os.getenv("APPDATA") or "c:" - cfg.home_tree = cfg.home.."/luarocks" - cfg.sysconfdir = sysconfdir or ((os.getenv("PROGRAMFILES") or "c:") .. "/luarocks") + cfg.home_tree = dir.path(cfg.home, "luarocks") + cfg.sysconfdir = sysconfdir or dir.path((os.getenv("PROGRAMFILES") or "c:"), "luarocks") else cfg.home = os.getenv("HOME") or "" - cfg.home_tree = cfg.home.."/.luarocks" + cfg.home_tree = dir.path(cfg.home, ".luarocks") cfg.sysconfdir = sysconfdir or detect_sysconfdir() or "/etc/luarocks" end end -- Load system configuration file - sys_config_file = (cfg.sysconfdir .. "/" .. config_file_name):gsub("\\", "/") + sys_config_file = dir.path(cfg.sysconfdir, config_file_name) local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file) if err then exit_ok, exit_err, exit_what = nil, err, "config" @@ -710,9 +722,9 @@ function cfg.init(detected, warning) -- try XDG config home if platforms.unix and not home_config_ok then - local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or cfg.home .. "/.config" - cfg.homeconfdir = xdg_config_home .. "/luarocks" - home_config_file = (cfg.homeconfdir .. "/" .. config_file_name):gsub("\\", "/") + local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or dir.path(cfg.home, ".config") + cfg.homeconfdir = dir.path(xdg_config_home, "luarocks") + home_config_file = dir.path(cfg.homeconfdir, config_file_name) home_config_ok, err = load_config_file(cfg, platforms, home_config_file) if err then exit_ok, exit_err, exit_what = nil, err, "config" @@ -722,7 +734,7 @@ function cfg.init(detected, warning) -- try the alternative defaults if there was no environment specified file or it didn't work if not home_config_ok then cfg.homeconfdir = cfg.home_tree - home_config_file = (cfg.homeconfdir .. "/" .. config_file_name):gsub("\\", "/") + home_config_file = dir.path(cfg.homeconfdir, config_file_name) home_config_ok, err = load_config_file(cfg, platforms, home_config_file) if err then exit_ok, exit_err, exit_what = nil, err, "config" @@ -731,7 +743,7 @@ function cfg.init(detected, warning) -- finally, use the project-specific config file if any if cfg.project_dir then - project_config_file = cfg.project_dir .. "/.luarocks/" .. config_file_name + project_config_file = dir.path(cfg.project_dir, ".luarocks", config_file_name) project_config_ok, err = load_config_file(cfg, platforms, project_config_file) if err then exit_ok, exit_err, exit_what = nil, err, "config" @@ -741,7 +753,7 @@ function cfg.init(detected, warning) -- backwards compatibility: if cfg.lua_interpreter and cfg.variables.LUA_BINDIR and not cfg.variables.LUA then - cfg.variables.LUA = (cfg.variables.LUA_BINDIR .. "/" .. cfg.lua_interpreter):gsub("\\", "/") + cfg.variables.LUA = dir.path(cfg.variables.LUA_BINDIR, cfg.lua_interpreter) end ---------------------------------------- @@ -776,7 +788,7 @@ function cfg.init(detected, warning) if platforms.windows and hardcoded.WIN_TOOLS then local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET", } for _, tool in ipairs(tools) do - defaults.variables[tool] = '"' .. hardcoded.WIN_TOOLS .. "/" .. defaults.variables[tool] .. '.exe"' + defaults.variables[tool] = '"' .. dir.path(hardcoded.WIN_TOOLS, defaults.variables[tool] .. '.exe') .. '"' end else defaults.fs_use_modules = true @@ -785,9 +797,9 @@ function cfg.init(detected, warning) -- if only cfg.variables.LUA is given in config files, -- derive LUA_BINDIR and LUA_DIR from them. if cfg.variables.LUA and not cfg.variables.LUA_BINDIR then - cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[/\\][^/\\]*$") + cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[\\/][^\\/]*$") if not cfg.variables.LUA_DIR then - cfg.variables.LUA_DIR = cfg.variables.LUA_BINDIR:gsub("[/\\]bin$", "") or cfg.variables.LUA_BINDIR + cfg.variables.LUA_DIR = cfg.variables.LUA_BINDIR:gsub("[\\/]bin$", "") or cfg.variables.LUA_BINDIR end end @@ -826,13 +838,13 @@ function cfg.init(detected, warning) local function make_paths_from_tree(tree) local lua_path, lib_path, bin_path if type(tree) == "string" then - lua_path = tree..cfg.lua_modules_path - lib_path = tree..cfg.lib_modules_path - bin_path = tree.."/bin" + lua_path = dir.path(tree, cfg.lua_modules_path) + lib_path = dir.path(tree, cfg.lib_modules_path) + bin_path = dir.path(tree, "bin") else - lua_path = tree.lua_dir or tree.root..cfg.lua_modules_path - lib_path = tree.lib_dir or tree.root..cfg.lib_modules_path - bin_path = tree.bin_dir or tree.root.."/bin" + lua_path = tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path) + lib_path = tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path) + bin_path = tree.bin_dir or dir.path(tree.root, "bin") end return lua_path, lib_path, bin_path end @@ -841,9 +853,9 @@ function cfg.init(detected, warning) local new_path, new_cpath, new_bin = {}, {}, {} local function add_tree_to_paths(tree) local lua_path, lib_path, bin_path = make_paths_from_tree(tree) - table.insert(new_path, lua_path.."/?.lua") - table.insert(new_path, lua_path.."/?/init.lua") - table.insert(new_cpath, lib_path.."/?."..cfg.lib_extension) + table.insert(new_path, dir.path(lua_path, "?.lua")) + table.insert(new_path, dir.path(lua_path, "?", "init.lua")) + table.insert(new_cpath, dir.path(lib_path, "?."..cfg.lib_extension)) table.insert(new_bin, bin_path) end if current then diff --git a/src/luarocks/core/dir.lua b/src/luarocks/core/dir.lua index 46dbeafd..5d6f2c9f 100644 --- a/src/luarocks/core/dir.lua +++ b/src/luarocks/core/dir.lua @@ -4,6 +4,8 @@ local dir = {} local require = nil -------------------------------------------------------------------------------- +local dir_sep = package.config:sub(1, 1) + local function unquote(c) local first, last = c:sub(1,1), c:sub(-1) if (first == '"' and last == '"') or @@ -30,7 +32,7 @@ function dir.path(...) for i, c in ipairs(t) do t[i] = unquote(c) end - return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", "")) + return dir.normalize(table.concat(t, "/")) end --- Split protocol and path from an URL or local pathname. @@ -51,8 +53,9 @@ function dir.split_url(url) end --- Normalize a url or local path. --- URLs should be in the "protocol://path" format. System independent --- forward slashes are used, removing trailing and double slashes +-- URLs should be in the "protocol://path" format. +-- Removes trailing and double slashes, and '.' and '..' components. +-- for 'file' URLs, the native system's slashes are used. -- @param url string: an URL or a local pathname. -- @return string: Normalized result. function dir.normalize(name) @@ -83,7 +86,11 @@ function dir.normalize(name) else pathname = drive .. table.concat(pieces, "/") end - if protocol ~= "file" then pathname = protocol .."://"..pathname end + if protocol ~= "file" then + pathname = protocol .. "://" .. pathname + else + pathname = pathname:gsub("/", dir_sep) + end return pathname end diff --git a/src/luarocks/core/path.lua b/src/luarocks/core/path.lua index b354a41a..2f037b41 100644 --- a/src/luarocks/core/path.lua +++ b/src/luarocks/core/path.lua @@ -5,6 +5,8 @@ local path = {} local cfg = require("luarocks.core.cfg") local dir = require("luarocks.core.dir") local require = nil + +local dir_sep = package.config:sub(1, 1) -------------------------------------------------------------------------------- function path.rocks_dir(tree) @@ -26,10 +28,10 @@ end -- @return string: a pathname with the same directory parts and a versioned basename. function path.versioned_name(file, prefix, name, version) assert(type(file) == "string") - assert(type(name) == "string" and not name:match("/")) + assert(type(name) == "string" and not name:match(dir_sep)) assert(type(version) == "string") - local rest = file:sub(#prefix+1):gsub("^/*", "") + local rest = file:sub(#prefix+1):gsub("^" .. dir_sep .. "*", "") local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_") return dir.path(prefix, name_version.."-"..rest) end @@ -57,7 +59,7 @@ function path.path_to_module(file) for ext, _ in pairs(exts) do name = file:match("(.*)%." .. ext .. "$") if name then - name = name:gsub("[/\\]", ".") + name = name:gsub("[\\/]", ".") break end end diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua index 26e78369..e9abdd34 100644 --- a/src/luarocks/core/util.lua +++ b/src/luarocks/core/util.lua @@ -4,6 +4,8 @@ local util = {} local require = nil -------------------------------------------------------------------------------- +local dir_sep = package.config:sub(1, 1) + --- Run a process and read a its output. -- Equivalent to io.popen(cmd):read("*l"), except that it -- closes the fd right away. @@ -12,7 +14,6 @@ local require = nil -- May be used to read more, passing, for instance, "*a". -- @return string: the output of the program. function util.popen_read(cmd, spec) - local dir_sep = package.config:sub(1, 1) local tmpfile = (dir_sep == "\\") and (os.getenv("TMP") .. "/luarocks-" .. tostring(math.floor(math.random() * 10000))) or os.tmpname() @@ -165,6 +166,9 @@ end function util.cleanup_path(list, sep, lua_version, keep_first) assert(type(list) == "string") assert(type(sep) == "string") + + list = list:gsub(dir_sep, "/") + local parts = util.split_string(list, sep) local final, entries = {}, {} local start, stop, step @@ -191,7 +195,7 @@ function util.cleanup_path(list, sep, lua_version, keep_first) end end - return table.concat(final, sep) + return (table.concat(final, sep):gsub("/", dir_sep)) end -- from http://lua-users.org/wiki/SplitJoin diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua index 74adbea2..be89e37b 100644 --- a/src/luarocks/dir.lua +++ b/src/luarocks/dir.lua @@ -8,6 +8,8 @@ dir.path = core.path dir.split_url = core.split_url dir.normalize = core.normalize +local dir_sep = package.config:sub(1, 1) + --- Strip the path off a path+filename. -- @param pathname string: A path+name, such as "/a/b/c" -- or "\a\b\c". @@ -15,8 +17,13 @@ dir.normalize = core.normalize function dir.base_name(pathname) assert(type(pathname) == "string") - local base = pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") - return base or pathname + local b + b = pathname:gsub("[/\\]", "/") -- canonicalize to forward slashes + b = b:gsub("/*$", "") -- drop trailing slashes + b = b:match(".*[/\\]([^/\\]*)") -- match last component + b = b or pathname -- fallback to original if no slashes + + return b end --- Strip the name off a path+filename. @@ -26,7 +33,15 @@ end -- no directory separators in input, "" is returned. function dir.dir_name(pathname) assert(type(pathname) == "string") - return (pathname:gsub("/*$", ""):match("(.*)[/]+[^/]*")) or "" + + local d + d = pathname:gsub("[/\\]", "/") -- canonicalize to forward slashes + d = d:gsub("/*$", "") -- drop trailing slashes + d = d:match("(.*)[/]+[^/]*") -- match all components but the last + d = d or "" -- switch to "" if there's no match + d = d:gsub("/", dir_sep) -- decanonicalize to native slashes + + return d end --- Returns true if protocol does not require additional tools. diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index f17a9279..373a998f 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua @@ -133,7 +133,7 @@ function fetch.fetch_url(url, filename, cache, mirroring) local protocol, pathname = dir.split_url(url) if protocol == "file" then - local fullname = dir.normalize(fs.absolute_name(pathname)) + local fullname = fs.absolute_name(pathname) if not fs.exists(fullname) then local hint = (not pathname:match("^/")) and (" - note that given path in rockspec is not absolute: " .. url) @@ -141,7 +141,7 @@ function fetch.fetch_url(url, filename, cache, mirroring) return nil, "Local file not found: " .. fullname .. hint end filename = filename or dir.base_name(pathname) - local dstname = dir.normalize(fs.absolute_name(dir.path(".", filename))) + local dstname = fs.absolute_name(dir.path(".", filename)) local ok, err if fullname == dstname then ok = true diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 934bba48..29ffb255 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -28,6 +28,8 @@ end local patch = require("luarocks.tools.patch") local tar = require("luarocks.tools.tar") +local dir_sep = package.config:sub(1, 1) + local dir_stack = {} --- Test is file/dir is writable. @@ -277,6 +279,11 @@ function fs_lua.system_temp_dir() return os.getenv("TMPDIR") or os.getenv("TEMP") or "/tmp" end +local function temp_dir_pattern(name_pattern) + return dir.path(fs.system_temp_dir(), + "luarocks_" .. dir.normalize(name_pattern):gsub("[/\\]", "_") .. "-") +end + --------------------------------------------------------------------- -- LuaFileSystem functions --------------------------------------------------------------------- @@ -361,12 +368,12 @@ function fs_lua.make_dir(directory) path = directory:sub(1, 2) directory = directory:sub(4) else - if directory:match("^/") then + if directory:match("^" .. dir_sep) then path = "" end end - for d in directory:gmatch("([^/]+)/*") do - path = path and path .. "/" .. d or d + for d in directory:gmatch("([^" .. dir_sep .. "]+)" .. dir_sep .. "*") do + path = path and path .. dir_sep .. d or d local mode = lfs.attributes(path, "mode") if not mode then local ok, err = lfs.mkdir(path) @@ -504,7 +511,8 @@ end -- @return boolean or (boolean, string): true on success, false on failure, -- plus an error message. function fs_lua.copy_contents(src, dest, perms) - assert(src and dest) + assert(src) + assert(dest) src = dir.normalize(src) dest = dir.normalize(dest) if not fs.is_dir(src) then @@ -589,7 +597,7 @@ local function recursive_find(cwd, prefix, result) table.insert(result, item) local pathname = dir.path(cwd, file) if lfs.attributes(pathname, "mode") == "directory" then - recursive_find(pathname, item.."/", result) + recursive_find(pathname, item .. dir_sep, result) end end end @@ -656,9 +664,8 @@ else -- if not lfs_ok function fs_lua.exists(file) assert(file) - file = dir.normalize(fs.absolute_name(file)) -- check if file exists by attempting to open it - return util.exists(file) + return util.exists(fs.absolute_name(file)) end end @@ -1072,9 +1079,8 @@ if posix.mkdtemp then -- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. function fs_lua.make_temp_dir(name_pattern) assert(type(name_pattern) == "string") - name_pattern = dir.normalize(name_pattern) - return posix.mkdtemp(fs.system_temp_dir() .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-XXXXXX") + return posix.mkdtemp(temp_dir_pattern(name_pattern) .. "-XXXXXX") end end -- if posix.mkdtemp @@ -1085,20 +1091,21 @@ end -- Other functions --------------------------------------------------------------------- -if lfs_ok and not fs_lua.make_temp_dir then +if not fs_lua.make_temp_dir then function fs_lua.make_temp_dir(name_pattern) assert(type(name_pattern) == "string") - name_pattern = dir.normalize(name_pattern) - - local pattern = fs.system_temp_dir() .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-" - while true do - local name = pattern .. tostring(math.random(10000000)) - if lfs.mkdir(name) then + local ok, err + for _ = 1, 3 do + local name = temp_dir_pattern(name_pattern) .. tostring(math.random(10000000)) + ok, err = fs.make_dir(name) + if ok then return name end end + + return nil, err end end diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua index 6bc183cb..f5f3b349 100644 --- a/src/luarocks/fs/unix.lua +++ b/src/luarocks/fs/unix.lua @@ -47,11 +47,11 @@ function unix.absolute_name(pathname, relative_to) pathname = unquoted end - relative_to = (relative_to or fs.current_dir()):gsub("/*$", "") + relative_to = relative_to or fs.current_dir() if pathname:sub(1,1) == "/" then - return pathname + return dir.normalize(pathname) else - return relative_to .. "/" .. pathname + return dir.path(relative_to, pathname) end end diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index 879f3e76..09ce7290 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -133,11 +133,11 @@ function win32.absolute_name(pathname, relative_to) local drive, root, rest = split_root(pathname) if root:match("[\\/]$") then -- It's an absolute path already. Ensure is not quoted. - return drive .. root .. rest + return dir.normalize(drive .. root .. rest) else -- It's a relative path, join it with base path. -- This drops drive letter from paths like "C:foo". - return relative_to .. "/" .. rest + return dir.path(relative_to, rest) end end @@ -237,7 +237,7 @@ function win32.copy_binary(filename, dest) dest = dir.dir_name(dest) if base:match(exe_pattern) then base = base:gsub(exe_pattern, ".lua") - local helpname = dest.."/"..base + local helpname = dest.."\\"..base local helper = io.open(helpname, "w") if not helper then return nil, "Could not open "..helpname.." for writing." @@ -331,23 +331,6 @@ function win32.is_writable(file) return result end ---- Create a temporary directory. --- @param name_pattern string: name pattern to use for avoiding conflicts --- when creating temporary directory. --- @return string or (nil, string): name of temporary directory or (nil, error message) on failure. -function win32.make_temp_dir(name_pattern) - assert(type(name_pattern) == "string") - name_pattern = dir.normalize(name_pattern) - - local temp_dir = os.getenv("TMP") .. "/luarocks_" .. name_pattern:gsub("/", "_") .. "-" .. tostring(math.floor(math.random() * 10000)) - local ok, err = fs.make_dir(temp_dir) - if ok then - return temp_dir - else - return nil, err - end -end - function win32.tmpname() local name = os.tmpname() local tmp = os.getenv("TMP") -- cgit v1.2.3-55-g6feb