# HG changeset patch # User HackBot # Date 1355523867 0 # Node ID d137f631bad536d9cfd5749894490ff5546951bb # Parent ff65dfb632633924692b7d4a515de05945309540 (cd luabuild/luarocks-2.0.12; make install) diff -r ff65dfb63263 -r d137f631bad5 bin/luarocks --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/luarocks Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,26 @@ +#!/hackenv/bin/lua +package.path = [[/hackenv/share/lua/5.2//?.lua;/hackenv/share/lua/5.2//?/init.lua;]]..package.path + +local command_line = require("luarocks.command_line") + +program_name = "luarocks" +program_description = "LuaRocks main command-line interface" + +commands = {} +commands.help = require("luarocks.help") +commands.pack = require("luarocks.pack") +commands.unpack = require("luarocks.unpack") +commands.build = require("luarocks.build") +commands.install = require("luarocks.install") +commands.search = require("luarocks.search") +commands.list = require("luarocks.list") +commands.remove = require("luarocks.remove") +commands.make = require("luarocks.make") +commands.download = require("luarocks.download") +commands.path = require("luarocks.path") +commands.show = require("luarocks.show") +commands.new_version = require("luarocks.new_version") +commands.lint = require("luarocks.lint") +commands.purge = require("luarocks.purge") + +command_line.run_command(...) diff -r ff65dfb63263 -r d137f631bad5 bin/luarocks-admin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/luarocks-admin Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,18 @@ +#!/hackenv/bin/lua +package.path = [[/hackenv/share/lua/5.2//?.lua;/hackenv/share/lua/5.2//?/init.lua;]]..package.path + +local command_line = require("luarocks.command_line") + +program_name = "luarocks-admin" +program_description = "LuaRocks repository administration interface" + +commands = { +} + +commands.help = require("luarocks.help") +commands.make_manifest = require("luarocks.make_manifest") +commands.add = require("luarocks.add") +commands.remove = require("luarocks.admin_remove") +commands.refresh_cache = require("luarocks.refresh_cache") + +command_line.run_command(...) diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/add.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/add.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,108 @@ + +--- Module implementing the luarocks-admin "add" command. +-- Adds a rock or rockspec to a rocks server. +module("luarocks.add", package.seeall) + +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local fetch = require("luarocks.fetch") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.cache") + +help_summary = "Add a rock or rockspec to a rocks server." +help_arguments = "[--server=] [--no-refresh] {|...}" +help = [[ +Arguments are local files, which may be rockspecs or rocks. +The flag --server indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +The flag --no-refresh indicates the local cache should not be refreshed +prior to generation of the updated manifest. +]] + +local function add_files_to_server(refresh, rockfiles, server, upload_server) + assert(type(refresh) == "boolean" or not refresh) + assert(type(rockfiles) == "table") + assert(type(server) == "string") + assert(type(upload_server) == "table" or not upload_server) + + local download_url, login_url = cache.get_server_urls(server, upload_server) + local at = fs.current_dir() + local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url + + local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password) + if not local_cache then + return nil, protocol + end + if protocol == "file" then + return nil, "Server "..server.." is not recognized, check your configuration." + end + + if not login_url then + login_url = protocol.."://"..server_path + end + + fs.change_dir(at) + + local files = {} + for i, rockfile in ipairs(rockfiles) do + if fs.exists(rockfile) then + util.printout("Copying file "..rockfile.." to "..local_cache.."...") + local absolute = fs.absolute_name(rockfile) + fs.copy(absolute, local_cache) + table.insert(files, dir.base_name(absolute)) + else + util.printerr("File "..rockfile.." not found") + end + end + if #files == 0 then + return nil, "No files found" + end + + fs.change_dir(local_cache) + + util.printout("Updating manifest...") + manif.make_manifest(local_cache, "one") + util.printout("Updating index.html...") + index.make_index(local_cache) + + local login_info = "" + if user then login_info = " -u "..user end + if password then login_info = login_info..":"..password end + if not login_url:match("/$") then + login_url = login_url .. "/" + end + + -- TODO abstract away explicit 'curl' call + + local cmd + if protocol == "rsync" then + local srv, path = server_path:match("([^/]+)(/.+)") + cmd = cfg.variables.RSYNC.." --exclude=.git -Oavz -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" + elseif upload_server and upload_server.sftp then + local part1, part2 = upload_server.sftp:match("^([^/]*)/(.*)$") + cmd = cfg.variables.SCP.." manifest index.html "..table.concat(files, " ").." "..user.."@"..part1..":/"..part2 + else + cmd = cfg.variables.CURL.." "..login_info.." -T '{manifest,index.html,"..table.concat(files, ",").."}' "..login_url + end + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function run(...) + local files = { util.parse_flags(...) } + local flags = table.remove(files, 1) + if #files < 1 then + return nil, "Argument missing, see help." + end + local server, server_table = cache.get_upload_server(flags["server"]) + if not server then return nil, server_table end + return add_files_to_server(not flags["no-refresh"], files, server, server_table) +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/admin_remove.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/admin_remove.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,87 @@ + +--- Module implementing the luarocks-admin "remove" command. +-- Removes a rock or rockspec from a rocks server. +module("luarocks.admin_remove", package.seeall) + +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local fetch = require("luarocks.fetch") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.cache") + +help_summary = "Remove a rock or rockspec from a rocks server." +help_arguments = "[--from=] [--no-refresh] {|...}" +help = [[ +Arguments are local files, which may be rockspecs or rocks. +The flag --from indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +The flag --no-refresh indicates the local cache should not be refreshed +prior to generation of the updated manifest. +]] + +local function remove_files_from_server(refresh, rockfiles, server, upload_server) + assert(type(refresh) == "boolean" or not refresh) + assert(type(rockfiles) == "table") + assert(type(server) == "string") + assert(type(upload_server) == "table" or not upload_server) + + local download_url, login_url = cache.get_server_urls(server, upload_server) + local at = fs.current_dir() + local refresh_fn = refresh and cache.refresh_local_cache or cache.split_server_url + + local local_cache, protocol, server_path, user, password = refresh_fn(server, download_url, cfg.upload_user, cfg.upload_password) + if not local_cache then + return nil, protocol + end + if protocol ~= "rsync" then + return nil, "This command requires 'rsync', check your configuration." + end + + fs.change_dir(at) + + local nr_files = 0 + for i, rockfile in ipairs(rockfiles) do + local basename = dir.base_name(rockfile) + local file = dir.path(local_cache, basename) + util.printout("Removing file "..file.."...") + if fs.delete(file) then + nr_files = nr_files + 1 + else + util.printerr("Failed removing "..file) + end + end + if nr_files == 0 then + return nil, "No files removed." + end + + fs.change_dir(local_cache) + + util.printout("Updating manifest...") + manif.make_manifest(local_cache, "one") + util.printout("Updating index.html...") + index.make_index(local_cache) + + local srv, path = server_path:match("([^/]+)(/.+)") + local cmd = "rsync -Oavz --delete -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function run(...) + local files = { util.parse_flags(...) } + local flags = table.remove(files, 1) + if #files < 1 then + return nil, "Argument missing, see help." + end + local server, server_table = cache.get_upload_server(flags["server"]) + if not server then return nil, server_table end + return remove_files_from_server(not flags["no-refresh"], files, server, server_table) +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/build.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/build.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,335 @@ + +--- Module implementing the LuaRocks "build" command. +-- Builds a rock, compiling its C parts if any. +module("luarocks.build", package.seeall) + +local pack = require("luarocks.pack") +local path = require("luarocks.path") +local util = require("luarocks.util") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local deps = require("luarocks.deps") +local manif = require("luarocks.manif") +local cfg = require("luarocks.cfg") + +help_summary = "Build/compile a rock." +help_arguments = "[--pack-binary-rock] {|| []}" +help = [[ +Build and install a rock, compiling its C parts if any. +Argument may be a rockspec file, a source rock file +or the name of a rock to be fetched from a repository. + +If --pack-binary-rock is passed, the rock is not installed; +instead, a .rock file with the contents of compilation is produced +in the current directory. +]] + +--- Install files to a given location. +-- Takes a table where the array part is a list of filenames to be copied. +-- In the hash part, other keys, if is_module_path is set, are identifiers +-- in Lua module format, to indicate which subdirectory the file should be +-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo") +-- will copy src/bar.lua to boo/foo. +-- @param files table or nil: A table containing a list of files to copy in +-- the format described above. If nil is passed, this function is a no-op. +-- Directories should be delimited by forward slashes as in internet URLs. +-- @param location string: The base directory files should be copied to. +-- @param is_module_path boolean: True if string keys in files should be +-- interpreted as dotted module paths. +-- @return boolean or (nil, string): True if succeeded or +-- nil and an error message. +local function install_files(files, location, is_module_path) + assert(type(files) == "table" or not files) + assert(type(location) == "string") + if files then + for k, file in pairs(files) do + local dest = location + if type(k) == "string" then + if is_module_path then + dest = dir.path(location, path.module_to_path(k)) + fs.make_dir(dest) + else + dest = dir.path(location, dir.dir_name(k)) + fs.make_dir(dest) + dest = dir.path(dest, dir.base_name(k)) + end + else + fs.make_dir(dest) + end + local ok = fs.copy(dir.path(file), dest) + if not ok then + return nil, "Failed copying "..file + end + end + end + return true +end + +--- Write to the current directory the contents of a table, +-- where each key is a file name and its value is the file content. +-- @param files table: The table of files to be written. +local function extract_from_rockspec(files) + for name, content in pairs(files) do + local fd = io.open(dir.path(fs.current_dir(), name), "w+") + fd:write(content) + fd:close() + end +end + +--- Applies patches inlined in the build.patches section +-- and extracts files inlined in the build.extra_files section +-- of a rockspec. +-- @param rockspec table: A rockspec table. +-- @return boolean or (nil, string): True if succeeded or +-- nil and an error message. +function apply_patches(rockspec) + assert(type(rockspec) == "table") + + local build = rockspec.build + if build.extra_files then + extract_from_rockspec(build.extra_files) + end + if build.patches then + extract_from_rockspec(build.patches) + for patch, patchdata in util.sortedpairs(build.patches) do + util.printout("Applying patch "..patch.."...") + local ok, err = fs.apply_patch(tostring(patch), patchdata) + if not ok then + return nil, "Failed applying patch "..patch + end + end + end + return true +end + +--- Build and install a rock given a rockspec. +-- @param rockspec_file string: local or remote filename of a rockspec. +-- @param need_to_fetch boolean: true if sources need to be fetched, +-- false if the rockspec was obtained from inside a source rock. +-- @param minimal_mode boolean: true if there's no need to fetch, +-- unpack or change dir (this is used by "luarocks make"). Implies +-- need_to_fetch = false. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "none", "one", "order" or "all". +-- @return boolean or (nil, string, [string]): True if succeeded or +-- nil and an error message followed by an error code. +function build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode) + assert(type(rockspec_file) == "string") + assert(type(need_to_fetch) == "boolean") + + local rockspec, err, errcode = fetch.load_rockspec(rockspec_file) + if err then + return nil, err, errcode + elseif not rockspec.build then + return nil, "Rockspec error: build table not specified" + elseif not rockspec.build.type then + return nil, "Rockspec error: build type not specified" + end + + if deps_mode == "none" then + util.printerr("Warning: skipping dependency checks.") + else + local ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) + if err then + return nil, err, errcode + end + end + + ok, err, errcode = deps.check_external_deps(rockspec, "build") + if err then + return nil, err, errcode + end + + local name, version = rockspec.name, rockspec.version + if repos.is_installed(name, version) then + repos.delete_version(name, version) + end + + if not minimal_mode then + local _, source_dir + if need_to_fetch then + ok, source_dir, errcode = fetch.fetch_sources(rockspec, true) + if not ok then + return nil, source_dir, errcode + end + fs.change_dir(source_dir) + elseif rockspec.source.file then + local ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then + return nil, err + end + end + fs.change_dir(rockspec.source.dir) + end + + local dirs = { + lua = { name = path.lua_dir(name, version), is_module_path = true }, + lib = { name = path.lib_dir(name, version), is_module_path = true }, + conf = { name = path.conf_dir(name, version), is_module_path = false }, + bin = { name = path.bin_dir(name, version), is_module_path = false }, + } + + for _, d in pairs(dirs) do + fs.make_dir(d.name) + end + local rollback = util.schedule_function(function() + fs.delete(path.install_dir(name, version)) + fs.remove_dir_if_empty(path.versions_dir(name)) + end) + + local build = rockspec.build + + if not minimal_mode then + ok, err = apply_patches(rockspec) + if err then + return nil, err + end + end + + if build.type ~= "none" then + + -- Temporary compatibility + if build.type == "module" then + util.printout("Do not use 'module' as a build type. Use 'builtin' instead.") + build.type = "builtin" + end + + local build_type + ok, build_type = pcall(require, "luarocks.build." .. build.type) + if not ok or not type(build_type) == "table" then + return nil, "Failed initializing build back-end for build type '"..build.type.."': "..build_type + end + + ok, err = build_type.run(rockspec) + if not ok then + return nil, "Build error: " .. err + end + end + + if build.install then + for id, install_dir in pairs(dirs) do + ok, err = install_files(build.install[id], install_dir.name, install_dir.is_module_path) + if not ok then + return nil, err + end + end + end + + local copy_directories = build.copy_directories or {"doc"} + + for _, copy_dir in pairs(copy_directories) do + if fs.is_dir(copy_dir) then + local dest = dir.path(path.install_dir(name, version), copy_dir) + fs.make_dir(dest) + fs.copy_contents(copy_dir, dest) + else + util.warning("Directory '"..copy_dir.."' not found") + end + end + + for _, d in pairs(dirs) do + fs.remove_dir_if_empty(d.name) + end + + fs.pop_dir() + + fs.copy(rockspec.local_filename, path.rockspec_file(name, version)) + if need_to_fetch then + fs.pop_dir() + end + + ok, err = manif.make_rock_manifest(name, version) + if err then return nil, err end + + ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec)) + if err then return nil, err end + + util.remove_scheduled_function(rollback) + rollback = util.schedule_function(function() + repos.delete_version(name, version) + end) + + ok, err = repos.run_hook(rockspec, "post_install") + if err then return nil, err end + + ok, err = manif.update_manifest(name, version, nil, deps_mode) + if err then return nil, err end + + local license = "" + if rockspec.description and rockspec.description.license then + license = ("(license: "..rockspec.description.license..")") + end + + local root_dir = path.root_dir(cfg.rocks_dir) + util.printout() + util.printout(name.." "..version.." is now built and installed in "..root_dir.." "..license) + + util.remove_scheduled_function(rollback) + return true +end + +--- Build and install a rock. +-- @param rock_file string: local or remote filename of a rock. +-- @param need_to_fetch boolean: true if sources need to be fetched, +-- false if the rockspec was obtained from inside a source rock. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "none", "one", "order" or "all". +-- @return boolean or (nil, string, [string]): True if build was successful, +-- or false and an error message and an optional error code. +function build_rock(rock_file, need_to_fetch, deps_mode) + assert(type(rock_file) == "string") + assert(type(need_to_fetch) == "boolean") + + local unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file) + if not unpack_dir then + return nil, err, errcode + end + local rockspec_file = path.rockspec_name_from_rock(rock_file) + fs.change_dir(unpack_dir) + local ok, err, errcode = build_rockspec(rockspec_file, need_to_fetch, false, deps_mode) + fs.pop_dir() + return ok, err, errcode +end + +local function do_build(name, version, deps_mode) + if name:match("%.rockspec$") then + return build_rockspec(name, true, false, deps_mode) + elseif name:match("%.src%.rock$") then + return build_rock(name, false, deps_mode) + elseif name:match("%.all%.rock$") then + local install = require("luarocks.install") + return install.install_binary_rock(name, deps_mode) + elseif name:match("%.rock$") then + return build_rock(name, true, deps_mode) + elseif not name:match(dir.separator) then + local search = require("luarocks.search") + return search.act_on_src_or_rockspec(run, name:lower(), version, deps.deps_mode_to_flag(deps_mode)) + end + return nil, "Don't know what to do with "..name +end + +--- Driver function for "build" command. +-- @param name string: A local or remote rockspec or rock file. +-- If a package name is given, forwards the request to "search" and, +-- if returned a result, installs the matching rock. +-- @param version string: When passing a package name, a version number may +-- also be given. +-- @return boolean or (nil, string): True if build was successful; nil and an +-- error message otherwise. +function run(...) + local flags, name, version = util.parse_flags(...) + if type(name) ~= "string" then + return nil, "Argument missing, see help." + end + assert(type(version) == "string" or not version) + + if flags["pack-binary-rock"] then + return pack.pack_binary_rock(name, version, do_build, name, version, deps.get_deps_mode(flags)) + else + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err end + return do_build(name, version, deps.get_deps_mode(flags)) + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/build/builtin.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/build/builtin.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,252 @@ + +--- A builtin build system: back-end to provide a portable way of building C-based Lua modules. +module("luarocks.build.builtin", package.seeall) + +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") + +--- Run a command displaying its execution on standard output. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +local function execute(...) + io.stdout:write(table.concat({...}, " ").."\n") + return fs.execute(...) +end + +--- Makes an RC file with an embedded Lua script, for building .exes on Windows +-- @return nil if could open files, error otherwise +local function make_rc(luafilename, rcfilename) + local rcfile = io.open(rcfilename, "w") + if not rcfile then + error("Could not open "..rcfilename.." for writing.") + end + rcfile:write("STRINGTABLE\r\nBEGIN\r\n") + + local i = 1 + for line in io.lines(luafilename) do + if not line:match("^#!") then + rcfile:write(i .. " \"") + line = line:gsub("\\", "\\\\"):gsub('"', '""'):gsub("[\r\n]+", "") + rcfile:write(line .. "\\r\\n\"\r\n") + i = i + 1 + end + end + + rcfile:write("END\r\n") + + rcfile:close() +end + +--- Driver function for the builtin build back-end. +-- @param rockspec table: the loaded rockspec. +-- @return boolean or (nil, string): true if no errors ocurred, +-- nil and an error message otherwise. +function run(rockspec) + assert(type(rockspec) == "table") + local compile_object, compile_library, compile_wrapper_binary + + local build = rockspec.build + local variables = rockspec.variables + + local function add_flags(extras, flag, flags) + if flags then + if type(flags) ~= "table" then + flags = { tostring(flags) } + end + util.variable_substitutions(flags, variables) + for _, v in ipairs(flags) do + table.insert(extras, flag:format(v)) + end + end + end + + if cfg.is_platform("mingw32") then + compile_object = function(object, source, defines, incdirs) + local extras = {} + add_flags(extras, "-D%s", defines) + add_flags(extras, "-I%s", incdirs) + return execute(variables.CC.." "..variables.CFLAGS, "-c", "-o", object, "-I"..variables.LUA_INCDIR, source, unpack(extras)) + end + compile_library = function(library, objects, libraries, libdirs, name) + local extras = { unpack(objects) } + add_flags(extras, "-L%s", libdirs) + add_flags(extras, "%s.lib", libraries) + extras[#extras+1] = dir.path(variables.LUA_LIBDIR, variables.LUALIB) + extras[#extras+1] = "-l" .. (variables.MSVCRT or "msvcr80") + local ok = execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras)) + return ok + end + compile_wrapper_binary = function(fullname, name) + local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\") + local basename = name:gsub("%.lua$", ""):gsub("/", "\\") + local rcname = basename..".rc" + local resname = basename..".o" + local wrapname = basename..".exe" + make_rc(fullname, fullbasename..".rc") + local ok = execute(variables.RC, "-o", resname, rcname) + if not ok then return ok end + ok = execute(variables.LD, "-o", wrapname, resname, variables.WRAPPER, + dir.path(variables.LUA_LIBDIR, variables.LUALIB), "-l" .. (variables.MSVCRT or "msvcr80"), "-luser32") + return ok, wrapname + end + elseif cfg.is_platform("win32") then + compile_object = function(object, source, defines, incdirs) + local extras = {} + add_flags(extras, "-D%s", defines) + add_flags(extras, "-I%s", incdirs) + return execute(variables.CC.." "..variables.CFLAGS, "-c", "-Fo"..object, "-I"..variables.LUA_INCDIR, source, unpack(extras)) + end + compile_library = function(library, objects, libraries, libdirs, name) + local extras = { unpack(objects) } + add_flags(extras, "-libpath:%s", libdirs) + add_flags(extras, "%s.lib", libraries) + local basename = dir.base_name(library):gsub(".[^.]*$", "") + local deffile = basename .. ".def" + local def = io.open(dir.path(fs.current_dir(), deffile), "w+") + def:write("EXPORTS\n") + def:write("luaopen_"..name:gsub("%.", "_").."\n") + def:close() + local ok = execute(variables.LD, "-dll", "-def:"..deffile, "-out:"..library, dir.path(variables.LUA_LIBDIR, variables.LUALIB), unpack(extras)) + local manifestfile = basename..".dll.manifest" + if ok and fs.exists(manifestfile) then + ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..basename..".dll;2") + end + return ok + end + compile_wrapper_binary = function(fullname, name) + local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\") + local basename = name:gsub("%.lua$", ""):gsub("/", "\\") + local rcname = basename..".rc" + local resname = basename..".res" + local wrapname = basename..".exe" + make_rc(fullname, fullbasename..".rc") + local ok = execute(variables.RC, "-r", "-fo"..resname, rcname) + if not ok then return ok end + ok = execute(variables.LD, "-out:"..wrapname, resname, variables.WRAPPER, + dir.path(variables.LUA_LIBDIR, variables.LUALIB), "user32.lib") + local manifestfile = wrapname..".manifest" + if ok and fs.exists(manifestfile) then + ok = execute(variables.MT, "-manifest", manifestfile, "-outputresource:"..wrapname..";1") + end + return ok, wrapname + end + else + compile_object = function(object, source, defines, incdirs) + local extras = {} + add_flags(extras, "-D%s", defines) + add_flags(extras, "-I%s", incdirs) + return execute(variables.CC.." "..variables.CFLAGS, "-I"..variables.LUA_INCDIR, "-c", source, "-o", object, unpack(extras)) + end + compile_library = function (library, objects, libraries, libdirs) + local extras = { unpack(objects) } + add_flags(extras, "-L%s", libdirs) + if cfg.gcc_rpath then + add_flags(extras, "-Wl,-rpath,%s:", libdirs) + end + add_flags(extras, "-l%s", libraries) + if cfg.is_platform("cygwin") then + add_flags(extras, "-l%s", {"lua"}) + end + return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, "-L"..variables.LUA_LIBDIR, unpack(extras)) + end + compile_wrapper_binary = function(fullname, name) return true, name end + end + + local ok = true + local err = "Build error" + local built_modules = {} + local luadir = path.lua_dir(rockspec.name, rockspec.version) + local libdir = path.lib_dir(rockspec.name, rockspec.version) + local docdir = path.doc_dir(rockspec.name, rockspec.version) + -- On Windows, compiles an .exe for each Lua file in build.install.bin, and + -- replaces the filename with the .exe name. Strips the .lua extension if it exists, + -- otherwise just appends .exe to the name + if build.install and build.install.bin then + for i, name in ipairs(build.install.bin) do + local fullname = dir.path(fs.current_dir(), name) + local match = name:match("%.lua$") + local basename = name:gsub("%.lua$", "") + local file + if not match then + file = io.open(fullname) + end + if match or (file and file:read():match("#!.*lua.*")) then + ok, name = compile_wrapper_binary(fullname, name) + if ok then + build.install.bin[i] = name + else + if file then file:close() end + return nil, "Build error in wrapper binaries" + end + end + if file then file:close() end + end + end + for name, info in pairs(build.modules) do + local moddir = path.module_to_path(name) + if type(info) == "string" then + local ext = info:match(".([^.]+)$") + if ext == "lua" then + if info:match("init%.lua$") and not name:match("%.init$") then + moddir = path.module_to_path(name..".init") + end + local dest = dir.path(luadir, moddir) + built_modules[info] = dest + else + info = {info} + end + end + if type(info) == "table" then + local objects = {} + local sources = info.sources + if info[1] then sources = info end + if type(sources) == "string" then sources = {sources} end + for _, source in ipairs(sources) do + local object = source:gsub(".[^.]*$", "."..cfg.obj_extension) + if not object then + object = source.."."..cfg.obj_extension + end + ok = compile_object(object, source, info.defines, info.incdirs) + if not ok then + err = "Failed compiling object "..object + break + end + table.insert(objects, object) + end + if not ok then break end + local module_name = dir.path(moddir, name:match("([^.]*)$").."."..cfg.lib_extension):gsub("//", "/") + if moddir ~= "" then + fs.make_dir(moddir) + end + local dest = dir.path(libdir, moddir) + built_modules[module_name] = dest + ok = compile_library(module_name, objects, info.libraries, info.libdirs, name) + if not ok then + err = "Failed compiling module "..module_name + break + end + end + end + for name, dest in pairs(built_modules) do + fs.make_dir(dest) + ok = fs.copy(name, dest) + if not ok then + err = "Failed installing "..name.." in "..dest + break + end + end + if ok then + if fs.is_dir("lua") then + ok = fs.copy_contents("lua", luadir) + if not ok then err = "Failed copying contents of 'lua' directory." end + end + end + if ok then + return true + else + return nil, err + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/build/cmake.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/build/cmake.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,58 @@ + +--- Build back-end for CMake-based modules. +module("luarocks.build.cmake", package.seeall) + +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +--- Driver function for the "cmake" build back-end. +-- @param rockspec table: the loaded rockspec. +-- @return boolean or (nil, string): true if no errors ocurred, +-- nil and an error message otherwise. +function run(rockspec) + assert(type(rockspec) == "table") + local build = rockspec.build + local variables = build.variables or {} + + -- Pass Env variables + variables.CMAKE_MODULE_PATH=os.getenv("CMAKE_MODULE_PATH") + variables.CMAKE_LIBRARY_PATH=os.getenv("CMAKE_LIBRARY_PATH") + variables.CMAKE_INCLUDE_PATH=os.getenv("CMAKE_INCLUDE_PATH") + + util.variable_substitutions(variables, rockspec.variables) + + if not fs.execute_string(fs.quiet(rockspec.variables.CMAKE.." --help")) then + return nil, "'"..rockspec.variables.CMAKE.."' program not found. Is cmake installed? You may want to edit variables.CMAKE" + end + + -- If inline cmake is present create CMakeLists.txt from it. + if type(build.cmake) == "string" then + local cmake = assert(io.open(fs.current_dir().."/CMakeLists.txt", "w")) + cmake:write(build.cmake) + cmake:close() + end + + + -- Execute cmake with variables. + local args = "" + if cfg.cmake_generator then + args = args .. ' -G"'..cfg.cmake_generator.. '"' + end + for k,v in pairs(variables) do + args = args .. ' -D' ..k.. '="' ..v.. '"' + end + + if not fs.execute_string(rockspec.variables.CMAKE.." . " ..args) then + return nil, "Failed cmake." + end + + if not fs.execute_string(rockspec.variables.MAKE.." -fMakefile") then + return nil, "Failed building." + end + + if not fs.execute_string(rockspec.variables.MAKE.." -fMakefile install") then + return nil, "Failed installing." + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/build/command.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/build/command.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,32 @@ + +--- Build back-end for raw listing of commands in rockspec files. +module("luarocks.build.command", package.seeall) + +local fs = require("luarocks.fs") +local util = require("luarocks.util") + +--- Driver function for the "command" build back-end. +-- @param rockspec table: the loaded rockspec. +-- @return boolean or (nil, string): true if no errors ocurred, +-- nil and an error message otherwise. +function run(rockspec) + assert(type(rockspec) == "table") + + local build = rockspec.build + + util.variable_substitutions(build, rockspec.variables) + + if build.build_command then + util.printout(build.build_command) + if not fs.execute(build.build_command) then + return nil, "Failed building." + end + end + if build.install_command then + util.printout(build.install_command) + if not fs.execute(build.install_command) then + return nil, "Failed installing." + end + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/build/make.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/build/make.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,92 @@ + +--- Build back-end for using Makefile-based packages. +module("luarocks.build.make", package.seeall) + +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +--- Call "make" with given target and variables +-- @param make_cmd string: the make command to be used (typically +-- configured through variables.MAKE in the config files, or +-- the appropriate platform-specific default). +-- @param pass boolean: If true, run make; if false, do nothing. +-- @param target string: The make target; an empty string indicates +-- the default target. +-- @param variables table: A table containing string-string key-value +-- pairs representing variable assignments to be passed to make. +-- @return boolean: false if any errors occurred, true otherwise. +local function make_pass(make_cmd, pass, target, variables) + assert(type(pass) == "boolean") + assert(type(target) == "string") + assert(type(variables) == "table") + + local assignments = {} + for k,v in pairs(variables) do + table.insert(assignments, k.."="..v) + end + if pass then + return fs.execute(make_cmd.." "..target, unpack(assignments)) + else + return true + end +end + +--- Driver function for the "make" build back-end. +-- @param rockspec table: the loaded rockspec. +-- @return boolean or (nil, string): true if no errors ocurred, +-- nil and an error message otherwise. +function run(rockspec) + assert(type(rockspec) == "table") + + local build = rockspec.build + + if build.build_pass == nil then build.build_pass = true end + if build.install_pass == nil then build.install_pass = true end + build.build_variables = build.build_variables or {} + build.install_variables = build.install_variables or {} + build.build_target = build.build_target or "" + build.install_target = build.install_target or "install" + local makefile = build.makefile or cfg.makefile + if makefile then + -- Assumes all make's accept -f. True for POSIX make, GNU make and Microsoft nmake. + build.build_target = "-f "..makefile.." "..build.build_target + build.install_target = "-f "..makefile.." "..build.install_target + end + + if build.variables then + for var, val in pairs(build.variables) do + build.build_variables[var] = val + build.install_variables[var] = val + end + end + + util.warn_if_not_used(build.build_variables, { CFLAGS=true }, "variable %s was not passed in build_variables") + + util.variable_substitutions(build.build_variables, rockspec.variables) + util.variable_substitutions(build.install_variables, rockspec.variables) + + local auto_variables = { "CC" } + + for _, variable in pairs(auto_variables) do + if not build.build_variables[variable] then + build.build_variables[variable] = rockspec.variables[variable] + end + if not build.install_variables[variable] then + build.install_variables[variable] = rockspec.variables[variable] + end + end + + -- backwards compatibility + local make_cmd = cfg.make or rockspec.variables.MAKE + + local ok = make_pass(make_cmd, build.build_pass, build.build_target, build.build_variables) + if not ok then + return nil, "Failed building." + end + ok = make_pass(make_cmd, build.install_pass, build.install_target, build.install_variables) + if not ok then + return nil, "Failed installing." + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/cache.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/cache.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,85 @@ + +--- Module handling the LuaRocks local cache. +-- Adds a rock or rockspec to a rocks server. +module("luarocks.cache", package.seeall) + +local fs = require("luarocks.fs") +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +function get_upload_server(server) + if not server then server = cfg.upload_server end + if not server then + return nil, "No server specified and no default configured with upload_server." + end + return server, cfg.upload_servers and cfg.upload_servers[server] +end + +function get_server_urls(server, upload_server) + local download_url = server + local login_url = nil + if upload_server then + if upload_server.rsync then download_url = "rsync://"..upload_server.rsync + elseif upload_server.http then download_url = "http://"..upload_server.http + elseif upload_server.ftp then download_url = "ftp://"..upload_server.ftp + end + + if upload_server.ftp then login_url = "ftp://"..upload_server.ftp + elseif upload_server.sftp then login_url = "sftp://"..upload_server.sftp + end + end + return download_url, login_url +end + +function split_server_url(server, url, user, password) + local protocol, server_path = dir.split_url(url) + if server_path:match("@") then + local credentials + credentials, server_path = server_path:match("([^@]*)@(.*)") + if credentials:match(":") then + user, password = credentials:match("([^:]*):(.*)") + else + user = credentials + end + end + local local_cache + if cfg.local_cache then + local_cache = cfg.local_cache .. "/" .. server + end + return local_cache, protocol, server_path, user, password +end + +function refresh_local_cache(server, url, user, password) + local local_cache, protocol, server_path, user, password = split_server_url(server, url, user, password) + + fs.make_dir(cfg.local_cache) + + local tmp_cache = false + if not local_cache then + local_cache = fs.make_temp_dir("local_cache") + tmp_cache = true + end + local ok = fs.make_dir(local_cache) + if not ok then + return nil, "Failed creating local cache dir." + end + fs.change_dir(local_cache) + util.printout("Refreshing cache "..local_cache.."...") + + -- TODO abstract away explicit 'wget' call + local ok = false + if protocol == "rsync" then + local srv, path = server_path:match("([^/]+)(/.+)") + ok = fs.execute(cfg.variables.RSYNC.." -avz -e ssh "..user.."@"..srv..":"..path.."/ "..local_cache.."/") + else + local login_info = "" + if user then login_info = " --user="..user end + if password then login_info = login_info .. " --password="..password end + ok = fs.execute(cfg.variables.WGET.." --no-cache -q -m -np -nd "..protocol.."://"..server_path..login_info) + end + if not ok then + return nil, "Failed downloading cache." + end + return local_cache, protocol, server_path, user, password +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/cfg.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/cfg.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,454 @@ +--- Configuration for LuaRocks. +-- Tries to load the user's configuration file and +-- defines defaults for unset values. See the +-- config +-- file format documentation for details. +-- +-- End-users shouldn't edit this file. They can override any defaults +-- set in this file using their system-wide $LUAROCKS_SYSCONFIG file +-- (see luarocks.site_config) or their user-specific configuration file +-- (~/.luarocks/config.lua on Unix or %APPDATA%/luarocks/config.lua on +-- Windows). + +local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION = + rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION + +module("luarocks.cfg") + +-- Load site-local global configurations +local ok, site_config = pcall(require, "luarocks.site_config") +if not ok then + io.stderr:write("Site-local luarocks/site_config.lua file not found. Incomplete installation?\n") + site_config = {} +end + +_M.site_config = site_config + +lua_version = _VERSION:sub(5) +program_version = "2.0.12" + +local persist = require("luarocks.persist") + +local popen_ok, popen_result = pcall(io.popen, "") +if popen_ok then + if popen_result then + popen_result:close() + end +else + io.stderr:write("Your version of Lua does not support io.popen,\n") + io.stderr:write("which is required by LuaRocks. Please check your Lua installation.\n") + os.exit(1) +end + +-- System detection: + +local detected = {} +local system,proc + +-- A proper installation of LuaRocks will hardcode the system +-- and proc values with site_config.LUAROCKS_UNAME_S and site_config.LUAROCKS_UNAME_M, +-- so that this detection does not run every time. When it is +-- performed, we use the Unix way to identify the system, +-- even on Windows (assuming UnxUtils or Cygwin). +system = site_config.LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l") +proc = site_config.LUAROCKS_UNAME_M or io.popen("uname -m"):read("*l") +if proc:match("i[%d]86") then + proc = "x86" +elseif proc:match("amd64") or proc:match("x86_64") then + proc = "x86_64" +elseif proc:match("Power Macintosh") then + proc = "powerpc" +end + +if system == "FreeBSD" then + detected.unix = true + detected.freebsd = true + detected.bsd = true +elseif system == "OpenBSD" then + detected.unix = true + detected.openbsd = true + detected.bsd = true +elseif system == "NetBSD" then + detected.unix = true + detected.netbsd = true + detected.bsd = true +elseif system == "Darwin" then + detected.unix = true + detected.macosx = true + detected.bsd = true +elseif system == "Linux" then + detected.unix = true + detected.linux = true +elseif system == "SunOS" then + detected.unix = true + detected.solaris = true +elseif system and system:match("^CYGWIN") then + detected.unix = true + detected.cygwin = true +elseif system and system:match("^Windows") then + detected.windows = true +elseif system and system:match("^MINGW") then + detected.windows = true + detected.mingw32 = true +else + detected.unix = true + -- Fall back to Unix in unknown systems. +end + +-- Path configuration: + +local version_suffix = lua_version:gsub ("%.", "_") +local sys_config_file, home_config_file +local sys_config_ok, home_config_ok = false, false +sys_config_file = site_config["LUAROCKS_SYSCONFIG_" .. version_suffix] or site_config.LUAROCKS_SYSCONFIG +if detected.windows then + home = os.getenv("APPDATA") or "c:" + sys_config_file = sys_config_file or "c:/luarocks/config.lua" + home_config_file = home.."/luarocks/config.lua" + home_tree = home.."/luarocks/" +else + home = os.getenv("HOME") or "" + sys_config_file = sys_config_file or "/etc/luarocks/config.lua" + home_config_file = home.."/.luarocks/config.lua" + home_tree = home.."/.luarocks/" +end + +variables = {} +rocks_trees = {} + +local ok, err = persist.load_into_table(sys_config_file, _M) +if ok then + sys_config_ok = true +else -- nil or false + sys_config_ok = ok + if err and ok == nil then + io.stderr:write(err.."\n") + end +end + +if not site_config.LUAROCKS_FORCE_CONFIG then + home_config_file = os.getenv("LUAROCKS_CONFIG_" .. version_suffix) or os.getenv("LUAROCKS_CONFIG") or home_config_file + local home_overrides, err = persist.load_into_table(home_config_file, { home = home }) + if home_overrides then + home_config_ok = true + local util = require("luarocks.util") + if home_overrides.rocks_trees then + _M.rocks_trees = nil + end + if home_overrides.rocks_servers then + _M.rocks_servers = nil + end + util.deep_merge(_M, home_overrides) + else -- nil or false + home_config_ok = home_overrides + if err and home_config_ok == nil then + io.stderr:write(err.."\n") + end + end +end + +if not next(rocks_trees) then + if home_tree then + table.insert(rocks_trees, home_tree) + end + if site_config.LUAROCKS_ROCKS_TREE then + table.insert(rocks_trees, site_config.LUAROCKS_ROCKS_TREE) + end +end + +-- Configure defaults: + +local root = rocks_trees[#rocks_trees] +local defaults = { + + local_by_default = false, + use_extensions = false, + accept_unknown_fields = false, + fs_use_modules = true, + deps_mode = "one", + + lua_modules_path = "/share/lua/"..lua_version, + lib_modules_path = "/lib/lua/"..lua_version, + + arch = "unknown", + lib_extension = "unknown", + obj_extension = "unknown", + + rocks_servers = { + { + "http://www.luarocks.org/repositories/rocks", + "http://luarocks.giga.puc-rio.br/", + "http://luafr.org/luarocks/rocks", + "http://liblua.so/luarocks/repositories/rocks", + "http://luarocks.logiceditor.com/rocks", + } + }, + + lua_extension = "lua", + lua_interpreter = site_config.LUA_INTERPRETER or "lua", + downloader = site_config.LUAROCKS_DOWNLOADER or "wget", + md5checker = site_config.LUAROCKS_MD5CHECKER or "md5sum", + + variables = { + MAKE = "make", + CC = "cc", + LD = "ld", + + CVS = "cvs", + GIT = "git", + SSCM = "sscm", + SVN = "svn", + HG = "hg", + + RSYNC = "rsync", + WGET = "wget", + SCP = "scp", + CURL = "curl", + + PWD = "pwd", + MKDIR = "mkdir", + RMDIR = "rmdir", + CP = "cp", + LS = "ls", + RM = "rm", + FIND = "find", + TEST = "test", + CHMOD = "chmod", + PATCH = "patch", + + ZIP = "zip", + UNZIP = "unzip", + GUNZIP = "gunzip", + BUNZIP2 = "bunzip2", + TAR = "tar", + + MD5SUM = "md5sum", + OPENSSL = "openssl", + MD5 = "md5", + STAT = "stat", + + CMAKE = "cmake", + SEVENZ = "7z", + + STATFLAG = "-c '%a'", + }, + + external_deps_subdirs = { + bin = "bin", + lib = "lib", + include = "include" + }, + runtime_external_deps_subdirs = { + bin = "bin", + lib = "lib", + include = "include" + }, +} + +if detected.windows then + home_config_file = home_config_file:gsub("\\","/") + defaults.fs_use_modules = false + defaults.arch = "win32-"..proc + defaults.platforms = {"win32", "windows" } + defaults.lib_extension = "dll" + defaults.external_lib_extension = "dll" + defaults.obj_extension = "obj" + defaults.external_deps_dirs = { "c:/external/" } + defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR and site_config.LUA_BINDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/bin" + defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR and site_config.LUA_INCDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/include" + defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR and site_config.LUA_LIBDIR:gsub("\\", "/") or "c:/lua"..lua_version.."/lib" + defaults.cmake_generator = "MinGW Makefiles" + defaults.makefile = "Makefile.win" + defaults.variables.MAKE = "nmake" + defaults.variables.CC = "cl" + defaults.variables.RC = "rc" + defaults.variables.WRAPPER = site_config.LUAROCKS_PREFIX .. "\\2.0\\rclauncher.obj" + defaults.variables.LD = "link" + defaults.variables.MT = "mt" + defaults.variables.LUALIB = "lua"..lua_version..".lib" + defaults.variables.CFLAGS = "/MD /O2" + defaults.variables.LIBFLAG = "/dll" + defaults.variables.LUALIB = "lua"..lua_version..".lib" + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "?.lib", "?.dll", "lib?.dll" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "?.dll", "lib?.dll" }, + include = { "?.h" } + } + defaults.export_path = "SET PATH=%s" + defaults.export_path_separator = ";" + defaults.export_lua_path = "SET LUA_PATH=%s" + defaults.export_lua_cpath = "SET LUA_CPATH=%s" + defaults.local_cache = home.."/cache/luarocks" +end + +if detected.mingw32 then + defaults.platforms = { "win32", "mingw32" } + defaults.obj_extension = "o" + defaults.cmake_generator = "MinGW Makefiles" + defaults.variables.MAKE = "mingw32-make" + defaults.variables.CC = "mingw32-gcc" + defaults.variables.RC = "windres" + defaults.variables.WRAPPER = site_config.LUAROCKS_PREFIX .. "\\2.0\\rclauncher.o" + defaults.variables.LD = "mingw32-gcc" + defaults.variables.CFLAGS = "-O2" + defaults.variables.LIBFLAG = "-shared" +end + +if detected.unix then + defaults.lib_extension = "so" + defaults.external_lib_extension = "so" + defaults.obj_extension = "o" + defaults.external_deps_dirs = { "/usr/local", "/usr" } + defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR or "/usr/local/bin" + defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR or "/usr/local/include" + defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR or "/usr/local/lib" + defaults.variables.CFLAGS = "-O2" + defaults.cmake_generator = "Unix Makefiles" + defaults.platforms = { "unix" } + defaults.variables.CC = "gcc" + defaults.variables.LD = "gcc" + defaults.gcc_rpath = true + defaults.variables.LIBFLAG = "-shared" + defaults.external_deps_patterns = { + bin = { "?" }, + lib = { "lib?.a", "lib?.so", "lib?.so.*" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?" }, + lib = { "lib?.so", "lib?.so.*" }, + include = { "?.h" } + } + defaults.export_path = "export PATH='%s'" + defaults.export_path_separator = ":" + defaults.export_lua_path = "export LUA_PATH='%s'" + defaults.export_lua_cpath = "export LUA_CPATH='%s'" + defaults.local_cache = home.."/.cache/luarocks" + if not defaults.variables.CFLAGS:match("-fPIC") then + defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" + end +end + +if detected.cygwin then + defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds + defaults.arch = "cygwin-"..proc + defaults.platforms = {"unix", "cygwin"} + defaults.cmake_generator = "Unix Makefiles" + defaults.variables.CC = "echo -llua | xargs gcc" + defaults.variables.LD = "echo -llua | xargs gcc" + defaults.variables.LIBFLAG = "-shared" +end + +if detected.bsd then + defaults.variables.MAKE = "gmake" + defaults.variables.STATFLAG = "-f '%OLp'" +end + +if detected.macosx then + defaults.external_lib_extension = "dylib" + defaults.arch = "macosx-"..proc + defaults.platforms = {"unix", "bsd", "macosx"} + defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" + defaults.variables.STATFLAG = "-f '%A'" + local version = io.popen("sw_vers -productVersion"):read("*l") + version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3 + if version >= 5 then + version = 5 + else + defaults.gcc_rpath = false + end + defaults.variables.CC = "export MACOSX_DEPLOYMENT_TARGET=10."..version.."; gcc" + defaults.variables.LD = "export MACOSX_DEPLOYMENT_TARGET=10."..version.."; gcc" +end + +if detected.linux then + defaults.arch = "linux-"..proc + defaults.platforms = {"unix", "linux"} +end + +if detected.freebsd then + defaults.arch = "freebsd-"..proc + defaults.platforms = {"unix", "bsd", "freebsd"} +end + +if detected.openbsd then + defaults.arch = "openbsd-"..proc + defaults.platforms = {"unix", "bsd", "openbsd"} +end + +if detected.netbsd then + defaults.arch = "netbsd-"..proc + defaults.platforms = {"unix", "bsd", "netbsd"} +end + +if detected.solaris then + defaults.arch = "solaris-"..proc + defaults.platforms = {"unix", "solaris"} + defaults.variables.MAKE = "gmake" +end + +-- Expose some more values detected by LuaRocks for use by rockspec authors. +defaults.variables.LIB_EXTENSION = defaults.lib_extension +defaults.variables.OBJ_EXTENSION = defaults.obj_extension +defaults.variables.LUAROCKS_PREFIX = site_config.LUAROCKS_PREFIX +defaults.variables.LUA = site_config.LUA_DIR_SET and (defaults.variables.LUA_BINDIR.."/"..defaults.lua_interpreter) or defaults.lua_interpreter + +-- Use defaults: + +-- Populate values from 'defaults.variables' in 'variables' if they were not +-- already set by user. +if not _M.variables then + _M.variables = {} +end +for k,v in pairs(defaults.variables) do + if not _M.variables[k] then + _M.variables[k] = v + end +end + +-- For values not set in the config file, use values from the 'defaults' table. +local cfg_mt = { + __index = function(t, k) + local default = defaults[k] + if default then + rawset(t, k, default) + end + return default + end +} +setmetatable(_M, cfg_mt) + +for _,tree in ipairs(rocks_trees) do + if type(tree) == "string" then + package.path = tree..lua_modules_path.."/?.lua;"..tree..lua_modules_path.."/?/init.lua;"..package.path + package.cpath = tree..lib_modules_path.."/?."..lib_extension..";"..package.cpath + else + package.path = (tree.lua_dir or tree.root..lua_modules_path).."/?.lua;".. + (tree.lua_dir or tree.root..lua_modules_path).."/?/init.lua;"..package.path + package.cpath = (tree.lib_dir or tree.root..lib_modules_path).."/?."..lib_extension..";"..package.cpath + end +end + +function which_config() + return sys_config_file, sys_config_ok, home_config_file, home_config_ok +end + +user_agent = "LuaRocks/"..program_version.." "..arch + +--- Check if platform was detected +-- @param query string: The platform name to check. +-- @return boolean: true if LuaRocks is currently running on queried platform. +function is_platform(query) + assert(type(query) == "string") + + for _, platform in ipairs(platforms) do + if platform == query then + return true + end + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/command_line.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/command_line.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,166 @@ + +--- Functions for command-line scripts. +module("luarocks.command_line", package.seeall) + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local deps = require("luarocks.deps") + +--- Display an error message and exit. +-- @param message string: The error message. +local function die(message) + assert(type(message) == "string") + + local ok, err = pcall(util.run_scheduled_functions) + if not ok then + util.printerr("\nLuaRocks "..cfg.program_version.." internal bug (please report at luarocks-developers@lists.sourceforge.net):\n"..err) + end + util.printerr("\nError: "..message) + os.exit(1) +end + +--- Main command-line processor. +-- Parses input arguments and calls the appropriate driver function +-- to execute the action requested on the command-line, forwarding +-- to it any additional arguments passed by the user. +-- Uses the global table "commands", which contains +-- the loaded modules representing commands. +-- @param ... string: Arguments given on the command-line. +function run_command(...) + local args = {...} + local cmdline_vars = {} + for i = #args, 1, -1 do + local arg = args[i] + if arg:match("^[^-][^=]*=") then + local var, val = arg:match("^([A-Z_][A-Z0-9_]*)=(.*)") + if val then + cmdline_vars[var] = val + table.remove(args, i) + else + die("Invalid assignment: "..arg) + end + end + end + local nonflags = { util.parse_flags(unpack(args)) } + local flags = table.remove(nonflags, 1) + + if flags["from"] then flags["server"] = flags["from"] end + if flags["only-from"] then flags["only-server"] = flags["only-from"] end + if flags["only-sources-from"] then flags["only-sources"] = flags["only-sources-from"] end + if flags["to"] then flags["tree"] = flags["to"] end + if flags["nodeps"] then + flags["deps-mode"] = "none" + table.insert(args, "--deps-mode=none") + end + + cfg.flags = flags + + local command + + if flags["version"] then + util.printout(program_name.." "..cfg.program_version) + util.printout(program_description) + util.printout() + os.exit(0) + elseif flags["help"] or #nonflags == 0 then + command = "help" + args = nonflags + else + command = nonflags[1] + for i, arg in ipairs(args) do + if arg == command then + table.remove(args, i) + break + end + end + end + command = command:gsub("-", "_") + + if flags["extensions"] then + cfg.use_extensions = true + local type_check = require("luarocks.type_check") + type_check.load_extensions() + end + + if cfg.local_by_default then + flags["local"] = true + end + + if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then + die("Invalid entry for --deps-mode.") + end + + if flags["tree"] then + if flags["tree"] == true or flags["tree"] == "" then + die("Argument error: use --tree=") + end + local fs = require("luarocks.fs") + local root_dir = fs.absolute_name(flags["tree"]) + path.use_tree(root_dir) + elseif flags["local"] then + path.use_tree(cfg.home_tree) + else + local trees = cfg.rocks_trees + path.use_tree(trees[#trees]) + end + + if type(cfg.root_dir) == "string" then + cfg.root_dir = cfg.root_dir:gsub("/+$", "") + else + cfg.root_dir.root = cfg.root_dir.root:gsub("/+$", "") + end + cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "") + cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "") + cfg.deploy_lua_dir = cfg.deploy_lua_dir:gsub("/+$", "") + cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "") + + cfg.variables.ROCKS_TREE = cfg.rocks_dir + cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir + + if flags["server"] then + if flags["server"] == true then + die("Argument error: use --server=") + end + local protocol, path = dir.split_url(flags["server"]) + table.insert(cfg.rocks_servers, 1, protocol.."://"..path) + end + + if flags["only-server"] then + if flags["only-server"] == true then + die("Argument error: use --only-server=") + end + cfg.rocks_servers = { flags["only-server"] } + end + + if flags["only-sources"] then + cfg.only_sources_from = flags["only-sources"] + end + + if command ~= "help" then + for k, v in pairs(cmdline_vars) do + cfg.variables[k] = v + end + end + + if commands[command] then + -- TODO the interface of run should be modified, to receive the + -- flags table and the (possibly unpacked) nonflags arguments. + -- This would remove redundant parsing of arguments. + -- I'm not changing this now to avoid messing with the run() + -- interface, which I know some people use (even though + -- I never published it as a public API...) + local xp, ok, err = xpcall(function() return commands[command].run(unpack(args)) end, function(err) + die(debug.traceback("LuaRocks "..cfg.program_version + .." bug (please report at luarocks-developers@lists.sourceforge.net).\n" + ..err, 2)) + end) + if xp and (not ok) then + die(err) + end + else + die("Unknown command: "..command) + end + util.run_scheduled_functions() +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/deps.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/deps.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,706 @@ + +--- Dependency handling functions. +-- Dependencies are represented in LuaRocks through strings with +-- a package name followed by a comma-separated list of constraints. +-- Each constraint consists of an operator and a version number. +-- In this string format, version numbers are represented as +-- naturally as possible, like they are used by upstream projects +-- (e.g. "2.0beta3"). Internally, LuaRocks converts them to a purely +-- numeric representation, allowing comparison following some +-- "common sense" heuristics. The precise specification of the +-- comparison criteria is the source code of this module, but the +-- test/test_deps.lua file included with LuaRocks provides some +-- insights on what these criteria are. +module("luarocks.deps", package.seeall) + +local cfg = require("luarocks.cfg") +local manif_core = require("luarocks.manif_core") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +local operators = { + ["=="] = "==", + ["~="] = "~=", + [">"] = ">", + ["<"] = "<", + [">="] = ">=", + ["<="] = "<=", + ["~>"] = "~>", + -- plus some convenience translations + [""] = "==", + ["="] = "==", + ["!="] = "~=" +} + +local deltas = { + scm = 1000, + cvs = 1000, + rc = -1000, + pre = -10000, + beta = -100000, + alpha = -1000000 +} + +local version_mt = { + --- Equality comparison for versions. + -- All version numbers must be equal. + -- If both versions have revision numbers, they must be equal; + -- otherwise the revision number is ignored. + -- @param v1 table: version table to compare. + -- @param v2 table: version table to compare. + -- @return boolean: true if they are considered equivalent. + __eq = function(v1, v2) + if #v1 ~= #v2 then + return false + end + for i = 1, #v1 do + if v1[i] ~= v2[i] then + return false + end + end + if v1.revision and v2.revision then + return (v1.revision == v2.revision) + end + return true + end, + --- Size comparison for versions. + -- All version numbers are compared. + -- If both versions have revision numbers, they are compared; + -- otherwise the revision number is ignored. + -- @param v1 table: version table to compare. + -- @param v2 table: version table to compare. + -- @return boolean: true if v1 is considered lower than v2. + __lt = function(v1, v2) + for i = 1, math.max(#v1, #v2) do + local v1i, v2i = v1[i] or 0, v2[i] or 0 + if v1i ~= v2i then + return (v1i < v2i) + end + end + if v1.revision and v2.revision then + return (v1.revision < v2.revision) + end + return false + end +} + +local version_cache = {} +setmetatable(version_cache, { + __mode = "kv" +}) + +--- Parse a version string, converting to table format. +-- A version table contains all components of the version string +-- converted to numeric format, stored in the array part of the table. +-- If the version contains a revision, it is stored numerically +-- in the 'revision' field. The original string representation of +-- the string is preserved in the 'string' field. +-- Returned version tables use a metatable +-- allowing later comparison through relational operators. +-- @param vstring string: A version number in string format. +-- @return table or nil: A version table or nil +-- if the input string contains invalid characters. +function parse_version(vstring) + if not vstring then return nil end + assert(type(vstring) == "string") + + local cached = version_cache[vstring] + if cached then + return cached + end + + local version = {} + local i = 1 + + local function add_token(number) + version[i] = version[i] and version[i] + number/100000 or number + i = i + 1 + end + + -- trim leading and trailing spaces + vstring = vstring:match("^%s*(.*)%s*$") + version.string = vstring + -- store revision separately if any + local main, revision = vstring:match("(.*)%-(%d+)$") + if revision then + vstring = main + version.revision = tonumber(revision) + end + while #vstring > 0 do + -- extract a number + local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)") + if token then + add_token(tonumber(token)) + else + -- extract a word + token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)") + if not token then + util.printerr("Warning: version number '"..vstring.."' could not be parsed.") + version[i] = 0 + break + end + local last = #version + version[i] = deltas[token] or (token:byte() / 1000) + end + vstring = rest + end + setmetatable(version, version_mt) + version_cache[vstring] = version + return version +end + +--- Utility function to compare version numbers given as strings. +-- @param a string: one version. +-- @param b string: another version. +-- @return boolean: True if a > b. +function compare_versions(a, b) + return parse_version(a) > parse_version(b) +end + +--- Consumes a constraint from a string, converting it to table format. +-- For example, a string ">= 1.0, > 2.0" is converted to a table in the +-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned +-- back to the caller. +-- @param input string: A list of constraints in string format. +-- @return (table, string) or nil: A table representing the same +-- constraints and the string with the unused input, or nil if the +-- input string is invalid. +local function parse_constraint(input) + assert(type(input) == "string") + + local no_upgrade, op, version, rest = input:match("^(@?)([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)") + op = operators[op] + version = parse_version(version) + if not op or not version then return nil end + return { op = op, version = version, no_upgrade = no_upgrade=="@" and true or nil }, rest +end + +--- Convert a list of constraints from string to table format. +-- For example, a string ">= 1.0, < 2.0" is converted to a table in the format +-- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}. +-- Version tables use a metatable allowing later comparison through +-- relational operators. +-- @param input string: A list of constraints in string format. +-- @return table or nil: A table representing the same constraints, +-- or nil if the input string is invalid. +function parse_constraints(input) + assert(type(input) == "string") + + local constraints, constraint = {}, nil + while #input > 0 do + constraint, input = parse_constraint(input) + if constraint then + table.insert(constraints, constraint) + else + return nil + end + end + return constraints +end + +--- Convert a dependency from string to table format. +-- For example, a string "foo >= 1.0, < 2.0" +-- is converted to a table in the format +-- {name = "foo", constraints = {{op = ">=", version={1,0}}, +-- {op = "<", version={2,0}}}}. Version tables use a metatable +-- allowing later comparison through relational operators. +-- @param dep string: A dependency in string format +-- as entered in rockspec files. +-- @return table or nil: A table representing the same dependency relation, +-- or nil if the input string is invalid. +function parse_dep(dep) + assert(type(dep) == "string") + + local name, rest = dep:match("^%s*([a-zA-Z][a-zA-Z0-9%.%-%_]*)%s*(.*)") + if not name then return nil end + local constraints = parse_constraints(rest) + if not constraints then return nil end + return { name = name, constraints = constraints } +end + +--- Convert a version table to a string. +-- @param v table: The version table +-- @param internal boolean or nil: Whether to display versions in their +-- internal representation format or how they were specified. +-- @return string: The dependency information pretty-printed as a string. +function show_version(v, internal) + assert(type(v) == "table") + assert(type(internal) == "boolean" or not internal) + + return (internal + and table.concat(v, ":")..(v.revision and tostring(v.revision) or "") + or v.string) +end + +--- Convert a dependency in table format to a string. +-- @param dep table: The dependency in table format +-- @param internal boolean or nil: Whether to display versions in their +-- internal representation format or how they were specified. +-- @return string: The dependency information pretty-printed as a string. +function show_dep(dep, internal) + assert(type(dep) == "table") + assert(type(internal) == "boolean" or not internal) + + local pretty = {} + for _, c in ipairs(dep.constraints) do + table.insert(pretty, c.op .. " " .. show_version(c.version, internal)) + end + return dep.name.." "..table.concat(pretty, ", ") +end + +--- A more lenient check for equivalence between versions. +-- This returns true if the requested components of a version +-- match and ignore the ones that were not given. For example, +-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match. +-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2" +-- doesn't. +-- @param version string or table: Version to be tested; may be +-- in string format or already parsed into a table. +-- @param requested string or table: Version requested; may be +-- in string format or already parsed into a table. +-- @return boolean: True if the tested version matches the requested +-- version, false otherwise. +local function partial_match(version, requested) + assert(type(version) == "string" or type(version) == "table") + assert(type(requested) == "string" or type(version) == "table") + + if type(version) ~= "table" then version = parse_version(version) end + if type(requested) ~= "table" then requested = parse_version(requested) end + if not version or not requested then return false end + + for i, ri in ipairs(requested) do + local vi = version[i] or 0 + if ri ~= vi then return false end + end + if requested.revision then + return requested.revision == version.revision + end + return true +end + +--- Check if a version satisfies a set of constraints. +-- @param version table: A version in table format +-- @param constraints table: An array of constraints in table format. +-- @return boolean: True if version satisfies all constraints, +-- false otherwise. +function match_constraints(version, constraints) + assert(type(version) == "table") + assert(type(constraints) == "table") + local ok = true + setmetatable(version, version_mt) + for _, constr in pairs(constraints) do + local constr_version = constr.version + setmetatable(constr.version, version_mt) + if constr.op == "==" then ok = version == constr_version + elseif constr.op == "~=" then ok = version ~= constr_version + elseif constr.op == ">" then ok = version > constr_version + elseif constr.op == "<" then ok = version < constr_version + elseif constr.op == ">=" then ok = version >= constr_version + elseif constr.op == "<=" then ok = version <= constr_version + elseif constr.op == "~>" then ok = partial_match(version, constr_version) + end + if not ok then break end + end + return ok +end + +--- Attempt to match a dependency to an installed rock. +-- @param dep table: A dependency parsed in table format. +-- @param blacklist table: Versions that can't be accepted. Table where keys +-- are program versions and values are 'true'. +-- @return table or nil: A table containing fields 'name' and 'version' +-- representing an installed rock which matches the given dependency, +-- or nil if it could not be matched. +local function match_dep(dep, blacklist, deps_mode) + assert(type(dep) == "table") + + local versions + if dep.name == "lua" then + versions = { cfg.lua_version } + else + versions = manif_core.get_versions(dep.name, deps_mode) + end + if not versions then + return nil + end + if blacklist then + local i = 1 + while versions[i] do + if blacklist[versions[i]] then + table.remove(versions, i) + else + i = i + 1 + end + end + end + local candidates = {} + for _, vstring in ipairs(versions) do + local version = parse_version(vstring) + if match_constraints(version, dep.constraints) then + table.insert(candidates, version) + end + end + if #candidates == 0 then + return nil + else + table.sort(candidates) + return { + name = dep.name, + version = candidates[#candidates].string + } + end +end + +--- Attempt to match dependencies of a rockspec to installed rocks. +-- @param rockspec table: The rockspec loaded as a table. +-- @param blacklist table or nil: Program versions to not use as valid matches. +-- Table where keys are program names and values are tables where keys +-- are program versions and values are 'true'. +-- @return table, table: A table where keys are dependencies parsed +-- in table format and values are tables containing fields 'name' and +-- version' representing matches, and a table of missing dependencies +-- parsed as tables. +function match_deps(rockspec, blacklist, deps_mode) + assert(type(rockspec) == "table") + assert(type(blacklist) == "table" or not blacklist) + local matched, missing, no_upgrade = {}, {}, {} + + for _, dep in ipairs(rockspec.dependencies) do + local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode) + if found then + if dep.name ~= "lua" then + matched[dep] = found + end + else + if dep.constraints[1] and dep.constraints[1].no_upgrade then + no_upgrade[dep.name] = dep + else + missing[dep.name] = dep + end + end + end + return matched, missing, no_upgrade +end + +--- Return a set of values of a table. +-- @param tbl table: The input table. +-- @return table: The array of keys. +local function values_set(tbl) + local set = {} + for _, v in pairs(tbl) do + set[v] = true + end + return set +end + +--- Check dependencies of a rock and attempt to install any missing ones. +-- Packages are installed using the LuaRocks "install" command. +-- Aborts the program if a dependency could not be fulfilled. +-- @param rockspec table: A rockspec in table format. +-- @return boolean or (nil, string, [string]): True if no errors occurred, or +-- nil and an error message if any test failed, followed by an optional +-- error code. +function fulfill_dependencies(rockspec, deps_mode) + + local search = require("luarocks.search") + local install = require("luarocks.install") + + if rockspec.supported_platforms then + if not platforms_set then + platforms_set = values_set(cfg.platforms) + end + local supported = nil + for _, plat in pairs(rockspec.supported_platforms) do + local neg, plat = plat:match("^(!?)(.*)") + if neg == "!" then + if platforms_set[plat] then + return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." + end + else + if platforms_set[plat] then + supported = true + else + if supported == nil then + supported = false + end + end + end + end + if supported == false then + local plats = table.concat(cfg.platforms, ", ") + return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms." + end + end + + local matched, missing, no_upgrade = match_deps(rockspec, nil, deps_mode) + + if next(no_upgrade) then + util.printerr("Missing dependencies for "..rockspec.name.." "..rockspec.version..":") + for _, dep in pairs(no_upgrade) do + util.printerr(show_dep(dep)) + end + if next(missing) then + for _, dep in pairs(missing) do + util.printerr(show_dep(dep)) + end + end + util.printerr() + for _, dep in pairs(no_upgrade) do + util.printerr("This version of "..rockspec.name.." is designed for use with") + util.printerr(show_dep(dep)..", but is configured to avoid upgrading it") + util.printerr("automatically. Please upgrade "..dep.name.." with") + util.printerr(" luarocks install "..dep.name) + util.printerr("or choose an older version of "..rockspec.name.." with") + util.printerr(" luarocks search "..rockspec.name) + end + return nil, "Failed matching dependencies." + end + + if next(missing) then + util.printerr() + util.printerr("Missing dependencies for "..rockspec.name..":") + for _, dep in pairs(missing) do + util.printerr(show_dep(dep)) + end + util.printerr() + + for _, dep in pairs(missing) do + -- Double-check in case dependency was filled during recursion. + if not match_dep(dep, nil, deps_mode) then + local rock = search.find_suitable_rock(dep) + if not rock then + return nil, "Could not satisfy dependency: "..show_dep(dep) + end + local ok, err, errcode = install.run(rock) + if not ok then + return nil, "Failed installing dependency: "..rock.." - "..err, errcode + end + end + end + end + return true +end + +--- If filename matches a pattern, return the capture. +-- For example, given "libfoo.so" and "lib?.so" is a pattern, +-- returns "foo" (which can then be used to build names +-- based on other patterns. +-- @param file string: a filename +-- @param pattern string: a pattern, where ? is to be matched by the filename. +-- @return string The pattern, if found, or nil. +local function deconstruct_pattern(file, pattern) + local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$" + return (file:match(depattern)) +end + +--- Construct all possible patterns for a name and add to the files array. +-- Run through the patterns array replacing all occurrences of "?" +-- with the given file name and store them in the files array. +-- @param file string A raw name (e.g. "foo") +-- @param array of string An array of patterns with "?" as the wildcard +-- (e.g. {"?.so", "lib?.so"}) +-- @param files The array of constructed names +local function add_all_patterns(file, patterns, files) + for _, pattern in ipairs(patterns) do + table.insert(files, (pattern:gsub("?", file))) + end +end + +--- Set up path-related variables for external dependencies. +-- For each key in the external_dependencies table in the +-- rockspec file, four variables are created: _DIR, _BINDIR, +-- _INCDIR and _LIBDIR. These are not overwritten +-- if already set (e.g. by the LuaRocks config file or through the +-- command-line). Values in the external_dependencies table +-- are tables that may contain a "header" or a "library" field, +-- with filenames to be tested for existence. +-- @param rockspec table: The rockspec table. +-- @param mode string: if "build" is given, checks all files; +-- if "install" is given, do not scan for headers. +-- @return boolean or (nil, string): True if no errors occurred, or +-- nil and an error message if any test failed. +function check_external_deps(rockspec, mode) + assert(type(rockspec) == "table") + + local fs = require("luarocks.fs") + + local vars = rockspec.variables + local patterns = cfg.external_deps_patterns + local subdirs = cfg.external_deps_subdirs + if mode == "install" then + patterns = cfg.runtime_external_deps_patterns + subdirs = cfg.runtime_external_deps_subdirs + end + if rockspec.external_dependencies then + for name, files in pairs(rockspec.external_dependencies) do + local ok = true + local failed_file = nil + local failed_dirname = nil + for _, extdir in ipairs(cfg.external_deps_dirs) do + ok = true + local prefix = vars[name.."_DIR"] + local dirs = { + BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin }, + INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include }, + LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib } + } + if mode == "install" then + dirs.INCDIR = nil + end + if not prefix then + prefix = extdir + end + if type(prefix) == "table" then + if prefix.bin then + dirs.BINDIR.subdir = prefix.bin + end + if prefix.include then + if dirs.INCDIR then + dirs.INCDIR.subdir = prefix.include + end + end + if prefix.lib then + dirs.LIBDIR.subdir = prefix.lib + end + prefix = prefix.prefix + end + for dirname, dirdata in pairs(dirs) do + dirdata.dir = vars[name.."_"..dirname] or dir.path(prefix, dirdata.subdir) + local file = files[dirdata.testfile] + if file then + local files = {} + if not file:match("%.") then + add_all_patterns(file, dirdata.pattern, files) + else + for _, pattern in ipairs(dirdata.pattern) do + local matched = deconstruct_pattern(file, pattern) + if matched then + add_all_patterns(matched, dirdata.pattern, files) + end + end + table.insert(files, file) + end + local found = false + failed_file = nil + for _, f in pairs(files) do + -- small convenience hack + if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then + f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension) + end + if f:match("%*") then + local replaced = f:gsub("%.", "%%."):gsub("%*", ".*") + for _, entry in ipairs(fs.list_dir(dirdata.dir)) do + if entry:match(replaced) then + found = true + break + end + end + else + found = fs.is_file(dir.path(dirdata.dir, f)) + end + if found then + break + else + if failed_file then + failed_file = failed_file .. ", or " .. f + else + failed_file = f + end + end + end + if not found then + ok = false + failed_dirname = dirname + break + end + end + end + if ok then + for dirname, dirdata in pairs(dirs) do + vars[name.."_"..dirname] = dirdata.dir + end + vars[name.."_DIR"] = prefix + break + end + end + if not ok then + return nil, "Could not find expected file "..failed_file.." for "..name.." -- you may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..failed_dirname.." to the luarocks command. Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local", "dependency" + end + end + end + return true +end + +--- Recursively scan dependencies, to build a transitive closure of all +-- dependent packages. +-- @param results table: The results table being built. +-- @param missing table: The table of missing dependencies being recursively built. +-- @param manifest table: The manifest table containing dependencies. +-- @param name string: Package name. +-- @param version string: Package version. +-- @return (table, table): The results and a table of missing dependencies. +function scan_deps(results, missing, manifest, name, version, deps_mode) + assert(type(results) == "table") + assert(type(missing) == "table") + assert(type(manifest) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + + local fetch = require("luarocks.fetch") + + local err + if results[name] then + return results, missing + end + if not manifest.dependencies then manifest.dependencies = {} end + local dependencies = manifest.dependencies + if not dependencies[name] then dependencies[name] = {} end + local dependencies_name = dependencies[name] + local deplist = dependencies_name[version] + local rockspec, err + if not deplist then + rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version)) + if err then + missing[name.." "..version] = err + return results, missing + end + dependencies_name[version] = rockspec.dependencies + else + rockspec = { dependencies = deplist } + end + local matched, failures = match_deps(rockspec, nil, deps_mode) + for _, match in pairs(matched) do + results, missing = scan_deps(results, missing, manifest, match.name, match.version, deps_mode) + end + if next(failures) then + for _, failure in pairs(failures) do + missing[show_dep(failure)] = "failed" + end + end + results[name] = version + return results, missing +end + +local valid_deps_modes = { + one = true, + order = true, + all = true, + none = true, +} + +function check_deps_mode_flag(flag) + return valid_deps_modes[flag] +end + +function get_deps_mode(flags) + if flags["deps-mode"] then + return flags["deps-mode"] + else + return cfg.deps_mode + end +end + +function deps_mode_to_flag(deps_mode) + return "--deps-mode="..deps_mode +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/dir.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/dir.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,70 @@ + +--- Generic utilities for handling pathnames. +module("luarocks.dir", package.seeall) + +separator = "/" + +--- Strip the path off a path+filename. +-- @param pathname string: A path+name, such as "/a/b/c" +-- or "\a\b\c". +-- @return string: The filename without its path, such as "c". +function base_name(pathname) + assert(type(pathname) == "string") + + local base = pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") + return base or pathname +end + +--- Strip the name off a path+filename. +-- @param pathname string: A path+name, such as "/a/b/c". +-- @return string: The filename without its path, such as "/a/b/". +-- For entries such as "/a/b/", "/a/" is returned. If there are +-- no directory separators in input, "" is returned. +function dir_name(pathname) + assert(type(pathname) == "string") + + return (pathname:gsub("/*$", ""):match("(.*/)[^/]*")) or "" +end + +--- Describe a path in a cross-platform way. +-- Use this function to avoid platform-specific directory +-- separators in other modules. Removes trailing slashes from +-- each component given, to avoid repeated separators. +-- Separators inside strings are kept, to handle URLs containing +-- protocols. +-- @param ... strings representing directories +-- @return string: a string with a platform-specific representation +-- of the path. +function path(...) + local items = {...} + local i = 1 + while items[i] do + items[i] = items[i]:gsub("(.+)/+$", "%1") + if items[i] == "" then + table.remove(items, i) + else + i = i + 1 + end + end + return (table.concat(items, "/"):gsub("(.+)/+$", "%1")) +end + +--- Split protocol and path from an URL or local pathname. +-- URLs should be in the "protocol://path" format. +-- For local pathnames, "file" is returned as the protocol. +-- @param url string: an URL or a local pathname. +-- @return string, string: the protocol, and the pathname without the protocol. +function split_url(url) + assert(type(url) == "string") + + local protocol, pathname = url:match("^([^:]*)://(.*)") + if not protocol then + protocol = "file" + pathname = url + end + return protocol, pathname +end + +function normalize(name) + return name:gsub("\\", "/"):gsub("(.)/*$", "%1") +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/download.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/download.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,88 @@ + +--- Module implementing the luarocks "download" command. +-- Download a rock from the repository. +module("luarocks.download", package.seeall) + +local util = require("luarocks.util") +local path = require("luarocks.path") +local fetch = require("luarocks.fetch") +local search = require("luarocks.search") + +help_summary = "Download a specific rock file from a rocks server." +help_arguments = "[--all] [--arch= | --source | --rockspec] [ []]" + +help = [[ +--all Download all files if there are multiple matches. +--source Download .src.rock if available. +--rockspec Download .rockspec if available. +--arch= Download rock for a specific architecture. +]] + +function download(arch, name, version, all) + local results, err + local query = search.make_query(name, version) + if arch then query.arch = arch end + if all then + if name == "" then query.exact_name = false end + results = search.search_repos(query) + else + results, err = search.find_suitable_rock(query) + end + if type(results) == "string" then + local file = fetch.fetch_url(results) + return file + elseif type(results) == "table" and next(results) then + if all then + local all_ok = true + local any_err = "" + for name, result in pairs(results) do + for version, versions in pairs(result) do + for _,items in pairs(versions) do + local filename = path.make_url(items.repo, name, version, items.arch) + local ok, err = fetch.fetch_url(filename) + if not ok then + all_ok = false + any_err = any_err .. "\n" .. err + end + end + end + end + return all_ok, any_err + else + util.printerr("Multiple search results were returned.") + util.title("Search results:") + search.print_results(results) + return nil, "Please narrow your query or use --all." + end + end + return nil, "Could not find a result named "..name..(version and " "..version or "").."." +end + +--- Driver function for the "download" command. +-- @param name string: a rock name. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function run(...) + local flags, name, version = util.parse_flags(...) + + assert(type(version) == "string" or not version) + if type(name) ~= "string" and not flags["all"] then + return nil, "Argument missing, see help." + end + if not name then name, version = "", "" end + + local arch + + if flags["source"] then + arch = "src" + elseif flags["rockspec"] then + arch = "rockspec" + elseif flags["arch"] then + arch = flags["arch"] + end + + local dl, err = download(arch, name, version, flags["all"]) + return dl and true, err +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,321 @@ + +--- Functions related to fetching and loading local and remote files. +module("luarocks.fetch", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local type_check = require("luarocks.type_check") +local path = require("luarocks.path") +local deps = require("luarocks.deps") +local persist = require("luarocks.persist") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +--- Fetch a local or remote file. +-- Make a remote or local URL/pathname local, fetching the file if necessary. +-- Other "fetch" and "load" functions use this function to obtain files. +-- If a local pathname is given, it is returned as a result. +-- @param url string: a local pathname or a remote URL. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return string or (nil, string, [string]): the absolute local pathname for the +-- fetched file, or nil and a message in case of errors, followed by +-- an optional error code. +function fetch_url(url, filename) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + local protocol, pathname = dir.split_url(url) + if protocol == "file" then + return fs.absolute_name(pathname) + elseif protocol == "http" or protocol == "ftp" or protocol == "https" then + local ok, err = fs.download(url, filename) + if not ok then + return nil, "Failed downloading "..url..(err and " - "..err or ""), "network" + end + return dir.path(fs.current_dir(), filename or dir.base_name(url)) + else + return nil, "Unsupported protocol "..protocol + end +end + +--- For remote URLs, create a temporary directory and download URL inside it. +-- This temporary directory will be deleted on program termination. +-- For local URLs, just return the local pathname and its directory. +-- @param url string: URL to be downloaded +-- @param tmpname string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @param filename string or nil: local filename of URL to be downloaded, +-- in case it can't be inferred from the URL. +-- @return (string, string) or (nil, string, [string]): absolute local pathname of +-- the fetched file and temporary directory name; or nil and an error message +-- followed by an optional error code +function fetch_url_at_temp_dir(url, tmpname, filename) + assert(type(url) == "string") + assert(type(tmpname) == "string") + assert(type(filename) == "string" or not filename) + filename = filename or dir.base_name(url) + + local protocol, pathname = dir.split_url(url) + if protocol == "file" then + if fs.exists(pathname) then + return pathname, dir.dir_name(fs.absolute_name(pathname)) + else + return nil, "File not found: "..pathname + end + else + local temp_dir = fs.make_temp_dir(tmpname) + if not temp_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, temp_dir) + fs.change_dir(temp_dir) + local file, err, errcode = fetch_url(url, filename) + fs.pop_dir() + if not file then + return nil, "Error fetching file: "..err, errcode + end + return file, temp_dir + end +end + +--- Obtain a rock and unpack it. +-- If a directory is not given, a temporary directory will be created, +-- which will be deleted on program termination. +-- @param rock_file string: URL or filename of the rock. +-- @param dest string or nil: if given, directory will be used as +-- a permanent destination. +-- @return string or (nil, string, [string]): the directory containing the contents +-- of the unpacked rock. +function fetch_and_unpack_rock(rock_file, dest) + assert(type(rock_file) == "string") + assert(type(dest) == "string" or not dest) + + local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock") + + local rock_file, err, errcode = fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name) + if not rock_file then + return nil, "Could not fetch rock file: " .. err, errcode + end + + rock_file = fs.absolute_name(rock_file) + local unpack_dir + if dest then + unpack_dir = dest + fs.make_dir(unpack_dir) + else + unpack_dir = fs.make_temp_dir(name) + end + if not dest then + util.schedule_function(fs.delete, unpack_dir) + end + fs.change_dir(unpack_dir) + local ok = fs.unzip(rock_file) + if not ok then + return nil, "Failed unpacking rock file: " .. rock_file + end + fs.pop_dir() + return unpack_dir +end + +--- Back-end function that actually loads the local rockspec. +-- Performs some validation and postprocessing of the rockspec contents. +-- @param filename string: The local filename of the rockspec file. +-- @return table or (nil, string): A table representing the rockspec +-- or nil followed by an error message. +function load_local_rockspec(filename) + assert(type(filename) == "string") + filename = fs.absolute_name(filename) + local rockspec, err = persist.load_into_table(filename) + if not rockspec then + return nil, "Could not load rockspec file "..filename.." ("..err..")" + end + + local ok, err = type_check.type_check_rockspec(rockspec) + if not ok then + return nil, filename..": "..err + end + + if rockspec.rockspec_format then + if deps.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then + return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." + end + end + + util.platform_overrides(rockspec.build) + util.platform_overrides(rockspec.dependencies) + util.platform_overrides(rockspec.external_dependencies) + util.platform_overrides(rockspec.source) + util.platform_overrides(rockspec.hooks) + + local basename = dir.base_name(filename) + if basename == "rockspec" then + rockspec.name = rockspec.package:lower() + else + rockspec.name = basename:match("(.*)-[^-]*-[0-9]*") + if not rockspec.name then + return nil, "Expected filename in format 'name-version-revision.rockspec'." + end + end + + local protocol, pathname = dir.split_url(rockspec.source.url) + if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then + rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) + end + rockspec.source.protocol, rockspec.source.pathname = protocol, pathname + + -- Temporary compatibility + if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end + if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end + + local name_version = rockspec.package:lower() .. "-" .. rockspec.version + if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then + return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." + end + + rockspec.local_filename = filename + local filebase = rockspec.source.file or rockspec.source.url + local base = dir.base_name(filebase) + base = base:gsub("%.[^.]*$", ""):gsub("%.tar$", "") + rockspec.source.dir = rockspec.source.dir + or rockspec.source.module + or ((filebase:match(".lua$") or filebase:match(".c$")) and ".") + or base + if rockspec.dependencies then + for i = 1, #rockspec.dependencies do + local parsed = deps.parse_dep(rockspec.dependencies[i]) + if not parsed then + return nil, "Parse error processing dependency '"..rockspec.dependencies[i].."'" + end + rockspec.dependencies[i] = parsed + end + else + rockspec.dependencies = {} + end + local ok, err = path.configure_paths(rockspec) + if err then + return nil, "Error verifying paths: "..err + end + + return rockspec +end + +--- Load a local or remote rockspec into a table. +-- This is the entry point for the LuaRocks tools. +-- Only the LuaRocks runtime loader should use +-- load_local_rockspec directly. +-- @param filename string: Local or remote filename of a rockspec. +-- @param location string or nil: Where to download. If not given, +-- a temporary dir is created. +-- @return table or (nil, string, [string]): A table representing the rockspec +-- or nil followed by an error message and optional error code. +function load_rockspec(filename, location) + assert(type(filename) == "string") + + local name + local basename = dir.base_name(filename) + if basename == "rockspec" then + name = "rockspec" + else + name = basename:match("(.*)%.rockspec") + if not name and not basename == "rockspec" then + return nil, "Filename '"..filename.."' does not look like a rockspec." + end + end + + local err, errcode + if location then + fs.change_dir(location) + filename, err = fetch_url(filename) + fs.pop_dir() + else + filename, err, errcode = fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name) + end + if not filename then + return nil, err, errcode + end + + return load_local_rockspec(filename) +end + +--- Download sources for building a rock using the basic URL downloader. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Whether to extract the sources from +-- the fetched source tarball or not. +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string, [string]): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message and optional error code. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(extract) == "boolean") + assert(type(dest_dir) == "string" or not dest_dir) + + local url = rockspec.source.url + local name = rockspec.name.."-"..rockspec.version + local filename = rockspec.source.file + local source_file, store_dir, err, errcode + if dest_dir then + fs.change_dir(dest_dir) + source_file, err, errcode = fetch_url(url, filename) + fs.pop_dir() + store_dir = dest_dir + else + source_file, store_dir, errcode = fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename) + end + if not source_file then + return nil, err or store_dir, errcode + end + if rockspec.source.md5 then + if not fs.check_md5(source_file, rockspec.source.md5) then + return nil, "MD5 check for "..filename.." has failed." + end + end + if extract then + fs.change_dir(store_dir) + fs.unpack_archive(rockspec.source.file) + if not fs.exists(rockspec.source.dir) then + return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file + end + fs.pop_dir() + end + return source_file, store_dir +end + +--- Download sources for building a rock, calling the appropriate protocol method. +-- @param rockspec table: The rockspec table +-- @param extract boolean: When downloading compressed formats, whether to extract +-- the sources from the fetched archive or not. +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function fetch_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(extract) == "boolean") + assert(type(dest_dir) == "string" or not dest_dir) + + local protocol = rockspec.source.protocol + local ok, proto + if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then + proto = require("luarocks.fetch") + else + ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) + if not ok then + return nil, "Unknown protocol "..protocol + end + end + + if cfg.only_sources_from + and rockspec.source.pathname + and #rockspec.source.pathname > 0 then + if #cfg.only_sources_from == 0 then + return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled" + elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then + return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from + end + end + return proto.get_sources(rockspec, extract, dest_dir) +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/cvs.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/cvs.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,44 @@ + +--- Fetch back-end for retrieving sources from CVS. +module("luarocks.fetch.cvs", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using CVS. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local name_version = rockspec.name .. "-" .. rockspec.version + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local command = {rockspec.variables.CVS, "-d"..rockspec.source.pathname, "export", module} + if rockspec.source.tag then + table.insert(command, 4, "-r") + table.insert(command, 5, rockspec.source.tag) + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + fs.change_dir(store_dir) + if not fs.execute(unpack(command)) then + return nil, "Failed fetching files from CVS." + end + fs.pop_dir() + return module, store_dir +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/git.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/git.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,81 @@ + +--- Fetch back-end for retrieving sources from GIT. +module("luarocks.fetch.git", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We +-- need to know this in order to build the appropriate command; if we can't +-- clone by tag then we'll have to issue a subsequent command to check out the +-- given tag. +-- @return boolean: Whether Git can clone by tag. +local function git_can_clone_by_tag() + local version_string = io.popen('git --version'):read() + local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)') + major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0 + local value = major > 1 or (major == 1 and (minor > 7 or (minor == 7 and tiny >= 10))) + git_can_clone_by_tag = function() return value end + return git_can_clone_by_tag() +end + +--- Download sources for building a rock, using git. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local git_cmd = rockspec.variables.GIT + local name_version = rockspec.name .. "-" .. rockspec.version + local module = dir.base_name(rockspec.source.url) + -- Strip off .git from base name if present + module = module:gsub("%.git$", "") + + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + store_dir = fs.absolute_name(store_dir) + fs.change_dir(store_dir) + + local command = {git_cmd, "clone", "--depth=1", rockspec.source.url, module} + local tag_or_branch = rockspec.source.tag or rockspec.source.branch + -- If the tag or branch is explicitly set to "master" in the rockspec, then + -- we can avoid passing it to Git since it's the default. + if tag_or_branch == "master" then tag_or_branch = nil end + if tag_or_branch then + if git_can_clone_by_tag() then + -- The argument to `--branch` can actually be a branch or a tag as of + -- Git 1.7.10. + table.insert(command, 4, "--branch=" .. tag_or_branch) + end + end + if not fs.execute(unpack(command)) then + return nil, "Failed cloning git repository." + end + fs.change_dir(module) + if tag_or_branch and not git_can_clone_by_tag() then + local checkout_command = {git_cmd, "checkout", tag_or_branch} + if not fs.execute(unpack(checkout_command)) then + return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.' + end + end + + fs.delete(dir.path(store_dir, module, ".git")) + fs.delete(dir.path(store_dir, module, ".gitignore")) + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/git_file.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/git_file.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,17 @@ + +--- Fetch back-end for retrieving sources from local Git repositories. +module("luarocks.fetch.git_file", package.seeall) + +local git = require("luarocks.fetch.git") + +--- Fetch sources for building a rock from a local Git repository. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + rockspec.source.url = rockspec.source.url:gsub("^git.file://", "") + return git.get_sources(rockspec, extract, dest_dir) +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/hg.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/hg.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,54 @@ + +--- Fetch back-end for retrieving sources from HG. +module("luarocks.fetch.hg", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using hg. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local hg_cmd = rockspec.variables.HG + local name_version = rockspec.name .. "-" .. rockspec.version + -- Strip off special hg:// protocol type + local url = rockspec.source.url:gsub("^hg://", "") + + local module = dir.base_name(url) + + local command = {hg_cmd, "clone", url, module} + local tag_or_branch = rockspec.source.tag or rockspec.source.branch + if tag_or_branch then + command = {hg_cmd, "clone", "--rev", url, module} + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + fs.change_dir(store_dir) + if not fs.execute(unpack(command)) then + return nil, "Failed cloning hg repository." + end + fs.change_dir(module) + + fs.delete(dir.path(store_dir, module, ".hg")) + fs.delete(dir.path(store_dir, module, ".hgignore")) + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/sscm.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/sscm.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,42 @@ + +--- Fetch back-end for retrieving sources from Surround SCM Server +module("luarocks.fetch.sscm", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +--- Download sources via Surround SCM Server for building a rock. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local sscm_cmd = rockspec.variables.SSCM + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local branch, repository = string.match(rockspec.source.pathname, "^([^/]*)/(.*)") + if not branch or not repository then + return nil, "Error retrieving branch and repository from rockspec." + end + -- Search for working directory. + local working_dir + local tmp = io.popen(string.format(sscm_cmd..[[ property "/" -d -b%s -p%s]], branch, repository)) + for line in tmp:lines() do + --%c because a chr(13) comes in the end. + working_dir = string.match(line, "Working directory:[%s]*(.*)%c$") + if working_dir then break end + end + tmp:close() + if not working_dir then + return nil, "Error retrieving working directory from SSCM." + end + if not fs.execute(sscm_cmd, "get", "*", "-e" , "-r", "-b"..branch, "-p"..repository, "-tmodify", "-wreplace") then + return nil, "Failed fetching files from SSCM." + end + -- FIXME: This function does not honor the dest_dir parameter. + return module, working_dir +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fetch/svn.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fetch/svn.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,53 @@ + +--- Fetch back-end for retrieving sources from Subversion. +module("luarocks.fetch.svn", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +--- Download sources for building a rock, using Subversion. +-- @param rockspec table: The rockspec table +-- @param extract boolean: Unused in this module (required for API purposes.) +-- @param dest_dir string or nil: If set, will extract to the given directory. +-- @return (string, string) or (nil, string): The absolute pathname of +-- the fetched source tarball and the temporary directory created to +-- store it; or nil and an error message. +function get_sources(rockspec, extract, dest_dir) + assert(type(rockspec) == "table") + assert(type(dest_dir) == "string" or not dest_dir) + + local svn_cmd = rockspec.variables.SVN + local name_version = rockspec.name .. "-" .. rockspec.version + local module = rockspec.source.module or dir.base_name(rockspec.source.url) + local url = rockspec.source.url:gsub("^svn://", "") + local command = {svn_cmd, "checkout", url, module} + if rockspec.source.tag then + table.insert(command, 5, "-r") + table.insert(command, 6, rockspec.source.tag) + end + local store_dir + if not dest_dir then + store_dir = fs.make_temp_dir(name_version) + if not store_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, store_dir) + else + store_dir = dest_dir + end + fs.change_dir(store_dir) + if not fs.execute(unpack(command)) then + return nil, "Failed fetching files from Subversion." + end + fs.change_dir(module) + for _, d in ipairs(fs.find(".")) do + if dir.base_name(d) == ".svn" then + fs.delete(dir.path(store_dir, module, d)) + end + end + fs.pop_dir() + fs.pop_dir() + return module, store_dir +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,40 @@ + +--- Proxy module for filesystem and platform abstractions. +-- All code using "fs" code should require "luarocks.fs", +-- and not the various platform-specific implementations. +-- However, see the documentation of the implementation +-- for the API reference. + +local pairs = pairs + +module("luarocks.fs", package.seeall) + +local cfg = require("luarocks.cfg") + +local function load_fns(fs_table) + for name, fn in pairs(fs_table) do + if not _M[name] then + _M[name] = fn + end + end +end + +-- Load platform-specific functions +local loaded_platform = nil +for _, platform in ipairs(cfg.platforms) do + local ok, fs_plat = pcall(require, "luarocks.fs."..platform) + if ok and fs_plat then + loaded_platform = platform + load_fns(fs_plat) + break + end +end + +-- Load platform-independent pure-Lua functionality +local fs_lua = require("luarocks.fs.lua") +load_fns(fs_lua) + +-- Load platform-specific fallbacks for missing Lua modules +local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") +if ok and fs_plat_tools then load_fns(fs_plat_tools) end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs/lua.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs/lua.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,697 @@ + +--- Native Lua implementation of filesystem and platform abstractions, +-- using LuaFileSystem, LZLib, MD5 and LuaCurl. +module("luarocks.fs.lua", package.seeall) + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") +local path = require("luarocks.path") + +local socket_ok, zip_ok, unzip_ok, lfs_ok, md5_ok, posix_ok, _ +local http, ftp, lrzip, luazip, lfs, md5, posix + +if cfg.fs_use_modules then + socket_ok, http = pcall(require, "socket.http") + _, ftp = pcall(require, "socket.ftp") + zip_ok, lrzip = pcall(require, "luarocks.tools.zip") + unzip_ok, luazip = pcall(require, "zip"); _G.zip = nil + lfs_ok, lfs = pcall(require, "lfs") + md5_ok, md5 = pcall(require, "md5") + posix_ok, posix = pcall(require, "posix") +end + +local patch = require("luarocks.tools.patch") + +local dir_stack = {} + +math.randomseed(os.time()) + +dir_separator = "/" + +--- Quote argument for shell processing. +-- Adds single quotes and escapes. +-- @param arg string: Unquoted argument. +-- @return string: Quoted argument. +function Q(arg) + assert(type(arg) == "string") + + -- FIXME Unix-specific + return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'" +end + +--- Test is file/dir is writable. +-- Warning: testing if a file/dir is writable does not guarantee +-- that it will remain writable and therefore it is no replacement +-- for checking the result of subsequent operations. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function is_writable(file) + assert(file) + file = dir.normalize(file) + local result + if fs.is_dir(file) then + local file2 = dir.path(file, '.tmpluarockstestwritable') + local fh = io.open(file2, 'wb') + result = fh ~= nil + if fh then fh:close() end + os.remove(file2) + else + local fh = io.open(file, 'r+b') + result = fh ~= nil + if fh then fh:close() end + end + return result +end + +--- Create a temporary directory. +-- @param name string: name pattern to use for avoiding conflicts +-- when creating temporary directory. +-- @return string or nil: name of temporary directory or nil on failure. +function make_temp_dir(name) + assert(type(name) == "string") + name = dir.normalize(name) + + local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) + if fs.make_dir(temp_dir) then + return temp_dir + else + return nil + end +end + +--- Run the given command, quoting its arguments. +-- The command is executed in the current directory in the dir stack. +-- @param command string: The command to be executed. No quoting/escaping +-- is applied. +-- @param ... Strings containing additional arguments, which are quoted. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function execute(command, ...) + assert(type(command) == "string") + + for _, arg in ipairs({...}) do + assert(type(arg) == "string") + command = command .. " " .. fs.Q(arg) + end + return fs.execute_string(command) +end + +--- Check the MD5 checksum for a file. +-- @param file string: The file to be checked. +-- @param md5sum string: The string with the expected MD5 checksum. +-- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not +-- or if it could not perform the check for any reason. +function check_md5(file, md5sum) + file = dir.normalize(file) + local computed = fs.get_md5(file) + if not computed then + return false + end + if computed:match("^"..md5sum) then + return true + else + return false + end +end + +--------------------------------------------------------------------- +-- LuaFileSystem functions +--------------------------------------------------------------------- + +if lfs_ok then + +--- Run the given command. +-- The command is executed in the current directory in the dir stack. +-- @param cmd string: No quoting/escaping is applied to the command. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function execute_string(cmd) + local code = os.execute(cmd) + if code == 0 or code == true then + return true + else + return false + end +end + +--- Obtain current directory. +-- Uses the module's internal dir stack. +-- @return string: the absolute pathname of the current directory. +function current_dir() + return lfs.currentdir() +end + +--- Change the current directory. +-- Uses the module's internal dir stack. This does not have exact +-- semantics of chdir, as it does not handle errors the same way, +-- but works well for our purposes for now. +-- @param d string: The directory to switch to. +function change_dir(d) + table.insert(dir_stack, lfs.currentdir()) + d = dir.normalize(d) + lfs.chdir(d) +end + +--- Change directory to root. +-- Allows leaving a directory (e.g. for deleting it) in +-- a crossplatform way. +function change_dir_to_root() + table.insert(dir_stack, lfs.currentdir()) + lfs.chdir("/") -- works on Windows too +end + +--- Change working directory to the previous in the dir stack. +-- @return true if a pop ocurred, false if the stack was empty. +function pop_dir() + local d = table.remove(dir_stack) + if d then + lfs.chdir(d) + return true + else + return false + end +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name does not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean: true on success, false on failure. +function make_dir(directory) + assert(type(directory) == "string") + directory = dir.normalize(directory) + local path = nil + if directory:sub(2, 2) == ":" then + path = directory:sub(1, 2) + directory = directory:sub(4) + else + if directory:match("^/") then + path = "" + end + end + for d in directory:gmatch("([^"..dir.separator.."]+)"..dir.separator.."*") do + path = path and path .. dir.separator .. d or d + local mode = lfs.attributes(path, "mode") + if not mode then + if not lfs.mkdir(path) then + return false + end + elseif mode ~= "directory" then + return false + end + end + return true +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param d string: pathname of directory to remove. +function remove_dir_if_empty(d) + assert(d) + d = dir.normalize(d) + lfs.rmdir(d) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param d string: pathname of directory to remove. +function remove_dir_tree_if_empty(d) + assert(d) + d = dir.normalize(d) + for i=1,10 do + lfs.rmdir(d) + d = dir.dir_name(d) + end +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perms string or nil: Permissions for destination file, +-- or nil to use the source filename permissions +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy(src, dest, perms) + assert(src and dest) + src = dir.normalize(src) + dest = dir.normalize(dest) + local destmode = lfs.attributes(dest, "mode") + if destmode == "directory" then + dest = dir.path(dest, dir.base_name(src)) + end + if not perms then perms = fs.get_permissions(src) end + local src_h, err = io.open(src, "rb") + if not src_h then return nil, err end + local dest_h, err = io.open(dest, "w+b") + if not dest_h then src_h:close() return nil, err end + while true do + local block = src_h:read(8192) + if not block then break end + dest_h:write(block) + end + src_h:close() + dest_h:close() + fs.chmod(dest, perms) + return true +end + +--- Implementation function for recursive copy of directory contents. +-- Assumes paths are normalized. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure +local function recursive_copy(src, dest) + local srcmode = lfs.attributes(src, "mode") + + if srcmode == "file" then + local ok = fs.copy(src, dest) + if not ok then return false end + elseif srcmode == "directory" then + local subdir = dir.path(dest, dir.base_name(src)) + fs.make_dir(subdir) + for file in lfs.dir(src) do + if file ~= "." and file ~= ".." then + local ok = recursive_copy(dir.path(src, file), subdir) + if not ok then return false end + end + end + end + return true +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy_contents(src, dest) + assert(src and dest) + src = dir.normalize(src) + dest = dir.normalize(dest) + assert(lfs.attributes(src, "mode") == "directory") + + for file in lfs.dir(src) do + if file ~= "." and file ~= ".." then + local ok = recursive_copy(dir.path(src, file), dest) + if not ok then + return false, "Failed copying "..src.." to "..dest + end + end + end + return true +end + +--- Implementation function for recursive removal of directories. +-- Assumes paths are normalized. +-- @param name string: Pathname of file +-- @return boolean or (boolean, string): true on success, +-- or nil and an error message on failure. +local function recursive_delete(name) + local mode = lfs.attributes(name, "mode") + + if mode == "file" then + return os.remove(name) + elseif mode == "directory" then + for file in lfs.dir(name) do + if file ~= "." and file ~= ".." then + local ok, err = recursive_delete(dir.path(name, file)) + if not ok then return nil, err end + end + end + local ok, err = lfs.rmdir(name) + if not ok then return nil, err end + end + return true +end + +--- Delete a file or a directory and all its contents. +-- @param name string: Pathname of source +-- @return boolean: true on success, false on failure. +function delete(name) + name = dir.normalize(name) + return recursive_delete(name) or false +end + +--- List the contents of a directory. +-- @param at string or nil: directory to list (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function list_dir(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + at = dir.normalize(at) + if not fs.is_dir(at) then + return {} + end + local result = {} + for file in lfs.dir(at) do + if file ~= "." and file ~= ".." then + table.insert(result, file) + end + end + return result +end + +--- Implementation function for recursive find. +-- Assumes paths are normalized. +-- @param cwd string: Current working directory in recursion. +-- @param prefix string: Auxiliary prefix string to form pathname. +-- @param result table: Array of strings where results are collected. +local function recursive_find(cwd, prefix, result) + for file in lfs.dir(cwd) do + if file ~= "." and file ~= ".." then + local item = prefix .. file + table.insert(result, item) + local pathname = dir.path(cwd, file) + if lfs.attributes(pathname, "mode") == "directory" then + recursive_find(pathname, item..dir_separator, result) + end + end + end +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + at = dir.normalize(at) + if not fs.is_dir(at) then + return {} + end + local result = {} + recursive_find(at, "", result) + return result +end + +--- Test for existance of a file. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function exists(file) + assert(file) + file = dir.normalize(file) + return type(lfs.attributes(file)) == "table" +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function is_dir(file) + assert(file) + file = dir.normalize(file) + return lfs.attributes(file, "mode") == "directory" +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a file, false otherwise. +function is_file(file) + assert(file) + file = dir.normalize(file) + return lfs.attributes(file, "mode") == "file" +end + +function set_time(file, time) + file = dir.normalize(file) + return lfs.touch(file, time) +end + +end + +--------------------------------------------------------------------- +-- LuaZip functions +--------------------------------------------------------------------- + +if zip_ok then + +function zip(zipfile, ...) + return lrzip.zip(zipfile, ...) +end + +end + +if unzip_ok then +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function unzip(zipfile) + local zipfile, err = luazip.open(zipfile) + if not zipfile then return nil, err end + local files = zipfile:files() + local file = files() + repeat + if file.filename:sub(#file.filename) == "/" then + fs.make_dir(dir.path(fs.current_dir(), file.filename)) + else + local rf, err = zipfile:open(file.filename) + if not rf then zipfile:close(); return nil, err end + local contents = rf:read("*a") + rf:close() + local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb") + if not wf then zipfile:close(); return nil, err end + wf:write(contents) + wf:close() + end + file = files() + until not file + zipfile:close() + return true +end + +end + +--------------------------------------------------------------------- +-- LuaSocket functions +--------------------------------------------------------------------- + +if socket_ok then + +local ltn12 = require("ltn12") +local luasec_ok, https = pcall(require, "ssl.https") +local redirect_protocols = { + http = http, + https = luasec_ok and https, +} + +local function http_request(url, http, loop_control) + local result = {} + + local proxy = cfg.proxy + if type(proxy) ~= "string" then proxy = nil end + -- LuaSocket's http.request crashes when given URLs missing the scheme part. + if proxy and not proxy:find("://") then + proxy = "http://" .. proxy + end + + local res, status, headers, err = http.request { + url = url, + proxy = proxy, + redirect = false, + sink = ltn12.sink.table(result), + headers = { + ["user-agent"] = cfg.user_agent.." via LuaSocket" + }, + } + if not res then + return nil, status + elseif status == 301 or status == 302 then + local location = headers.location + if location then + local protocol, rest = dir.split_url(location) + if redirect_protocols[protocol] then + if not loop_control then + loop_control = {} + elseif loop_control[location] then + return nil, "Redirection loop -- broken URL?" + end + loop_control[url] = true + return http_request(location, redirect_protocols[protocol], loop_control) + else + return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support." + end + end + return nil, err + elseif status ~= 200 then + return nil, err + else + return table.concat(result) + end +end + +--- Download a remote file. +-- @param url string: URL to be fetched. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return boolean: true on success, false on failure. +function download(url, filename) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + filename = dir.path(fs.current_dir(), filename or dir.base_name(url)) + + local content, err + if util.starts_with(url, "http:") then + content, err = http_request(url, http) + elseif util.starts_with(url, "ftp:") then + content, err = ftp.get(url) + elseif util.starts_with(url, "https:") then + if luasec_ok then + content, err = http_request(url, https) + else + err = "Unsupported protocol - install luasec to get HTTPS support." + end + else + err = "Unsupported protocol" + end + if not content then + return false, tostring(err) + end + local file = io.open(filename, "wb") + if not file then return false end + file:write(content) + file:close() + return true +end + +end +--------------------------------------------------------------------- +-- MD5 functions +--------------------------------------------------------------------- + +if md5_ok then + +--- Get the MD5 checksum for a file. +-- @param file string: The file to be computed. +-- @return string: The MD5 checksum +function get_md5(file) + file = fs.absolute_name(file) + local file = io.open(file, "rb") + if not file then return false end + local computed = md5.sumhexa(file:read("*a")) + file:close() + return computed +end + +end + +--------------------------------------------------------------------- +-- POSIX functions +--------------------------------------------------------------------- + +if posix_ok then + +local octal_to_rwx = { + ["0"] = "---", + ["1"] = "--x", + ["2"] = "-w-", + ["3"] = "-wx", + ["4"] = "r--", + ["5"] = "r-x", + ["6"] = "rw-", + ["7"] = "rwx", +} + +function chmod(file, mode) + -- LuaPosix (as of 5.1.15) does not support octal notation... + if mode:sub(1,1) == "0" then + local new_mode = {} + for c in mode:sub(2):gmatch(".") do + table.insert(new_mode, octal_to_rwx[c]) + end + mode = table.concat(new_mode) + end + local err = posix.chmod(file, mode) + return err == 0 +end + +function get_permissions(file) + return posix.stat(file, "mode") +end + +end + +--------------------------------------------------------------------- +-- Other functions +--------------------------------------------------------------------- + +--- Apply a patch. +-- @param patchname string: The filename of the patch. +-- @param patchdata string or nil: The actual patch as a string. +function apply_patch(patchname, patchdata) + local p, all_ok = patch.read_patch(patchname, patchdata) + if not all_ok then + return nil, "Failed reading patch "..patchname + end + if p then + return patch.apply_patch(p, 1) + end +end + +--- Move a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function move(src, dest) + assert(src and dest) + if fs.exists(dest) and not fs.is_dir(dest) then + return false, "File already exists: "..dest + end + local ok, err = fs.copy(src, dest) + if not ok then + return false, err + end + ok = fs.delete(src) + if not ok then + return false, "Failed move: could not delete "..src.." after copy." + end + return true +end + +--- Check if user has write permissions for the command. +-- Assumes the configuration variables under cfg have been previously set up. +-- @param flags table: the flags table passed to run() drivers. +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function check_command_permissions(flags) + local root_dir = path.root_dir(cfg.rocks_dir) + local ok = true + local err = "" + for _, dir in ipairs { cfg.rocks_dir, root_dir } do + if fs.exists(dir) and not fs.is_writable(dir) then + ok = false + err = "Your user does not have write permissions in " .. dir + break + end + end + local root_parent = dir.dir_name(root_dir) + if ok and not fs.exists(root_dir) and not fs.is_writable(root_parent) then + ok = false + err = root_dir.." does not exist and your user does not have write permissions in " .. root_parent + end + if ok then + return true + else + if flags["local"] then + err = err .. " \n-- please check your permissions." + else + err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local." + end + return nil, err + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs/unix.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs/unix.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,109 @@ + +--- Unix implementation of filesystem and platform abstractions. + +local assert, type, table, io, package, math, os, ipairs = + assert, type, table, io, package, math, os, ipairs + +module("luarocks.fs.unix", package.seeall) + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") +local fs = require("luarocks.fs") +local util = require("luarocks.util") + +math.randomseed(os.time()) + +--- Annotate command string for quiet execution. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with silencing annotation. +function quiet(cmd) + return cmd.." 1> /dev/null 2> /dev/null" +end + +--- Return an absolute pathname from a potentially relative one. +-- @param pathname string: pathname to convert. +-- @param relative_to string or nil: path to prepend when making +-- pathname absolute, or the current dir in the dir stack if +-- not given. +-- @return string: The pathname converted to absolute. +function absolute_name(pathname, relative_to) + assert(type(pathname) == "string") + assert(type(relative_to) == "string" or not relative_to) + + relative_to = relative_to or fs.current_dir() + if pathname:sub(1,1) == "/" then + return pathname + else + return relative_to .. "/" .. pathname + end +end + +--- Create a wrapper to make a script executable from the command-line. +-- @param file string: Pathname of script to be made executable. +-- @param dest string: Directory where to put the wrapper. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function wrap_script(file, dest) + assert(type(file) == "string") + assert(type(dest) == "string") + + local base = dir.base_name(file) + local wrapname = fs.is_dir(dest) and dest.."/"..base or dest + local wrapper = io.open(wrapname, "w") + if not wrapper then + return nil, "Could not open "..wrapname.." for writing." + end + wrapper:write("#!/bin/sh\n\n") + wrapper:write('LUA_PATH="'..package.path..';$LUA_PATH"\n') + wrapper:write('LUA_CPATH="'..package.cpath..';$LUA_CPATH"\n') + wrapper:write('export LUA_PATH LUA_CPATH\n') + wrapper:write('exec "'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.loader "'..file..'" "$@"\n') + wrapper:close() + if fs.chmod(wrapname, "0755") then + return true + else + return nil, "Could not make "..wrapname.." executable." + end +end + +--- Check if a file (typically inside path.bin_dir) is an actual binary +-- or a Lua wrapper. +-- @param filename string: the file name with full path. +-- @return boolean: returns true if file is an actual binary +-- (or if it couldn't check) or false if it is a Lua wrapper. +function is_actual_binary(filename) + if filename:match("%.lua$") then + return false + end + local file = io.open(filename) + if not file then + return true + end + local first = file:read(2) + file:close() + if not first then + util.printerr("Warning: could not read "..filename) + return true + end + return first ~= "#!" +end + +function copy_binary(filename, dest) + return fs.copy(filename, dest, "0755") +end + +--- Move a file on top of the other. +-- The new file ceases to exist under its original name, +-- and takes over the name of the old file. +-- On Unix this is done through a single rename operation. +-- @param old_file The name of the original file, +-- which will be the new name of new_file. +-- @param new_file The name of the new file, +-- which will replace old_file. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function replace_file(old_file, new_file) + return os.rename(new_file, old_file) +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs/unix/tools.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs/unix/tools.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,318 @@ + +--- fs operations implemented with third-party tools for Unix platform abstractions. +module("luarocks.fs.unix.tools", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +local dir_stack = {} + +local vars = cfg.variables + +local function command_at(directory, cmd) + return "cd " .. fs.Q(directory) .. " && " .. cmd +end + +--- Obtain current directory. +-- Uses the module's internal directory stack. +-- @return string: the absolute pathname of the current directory. +function current_dir() + local pipe = io.popen(vars.PWD) + local current = pipe:read("*l") + pipe:close() + for _, directory in ipairs(dir_stack) do + current = fs.absolute_name(directory, current) + end + return current +end + +--- Run the given command. +-- The command is executed in the current directory in the directory stack. +-- @param cmd string: No quoting/escaping is applied to the command. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function execute_string(cmd) + local code = os.execute(command_at(fs.current_dir(), cmd)) + if code == 0 or code == true then + return true + else + return false + end +end + +--- Change the current directory. +-- Uses the module's internal directory stack. This does not have exact +-- semantics of chdir, as it does not handle errors the same way, +-- but works well for our purposes for now. +-- @param directory string: The directory to switch to. +function change_dir(directory) + assert(type(directory) == "string") + table.insert(dir_stack, directory) +end + +--- Change directory to root. +-- Allows leaving a directory (e.g. for deleting it) in +-- a crossplatform way. +function change_dir_to_root() + table.insert(dir_stack, "/") +end + +--- Change working directory to the previous in the directory stack. +function pop_dir() + local directory = table.remove(dir_stack) + return directory ~= nil +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name does not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean: true on success, false on failure. +function make_dir(directory) + assert(directory) + return fs.execute(vars.MKDIR.." -p", directory) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function remove_dir_if_empty(directory) + assert(directory) + fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory))) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function remove_dir_tree_if_empty(directory) + assert(directory) + fs.execute_string(fs.quiet(vars.RMDIR.." -p "..fs.Q(directory))) +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @param perm string or nil: Permissions for destination file, +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy(src, dest, perm) + assert(src and dest) + if fs.execute(vars.CP, src, dest) then + if perm then + if fs.is_dir(dest) then + dest = dir.path(dest, dir.base_name(src)) + end + if fs.chmod(dest, perm) then + return true + else + return false, "Failed setting permissions of "..dest + end + end + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy_contents(src, dest) + assert(src and dest) + if fs.execute_string(fs.quiet(vars.CP.." -pPR "..fs.Q(src).."/* "..fs.Q(dest))) then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end +--- Delete a file or a directory and all its contents. +-- For safety, this only accepts absolute paths. +-- @param arg string: Pathname of source +-- @return boolean: true on success, false on failure. +function delete(arg) + assert(arg) + assert(arg:sub(1,1) == "/") + return fs.execute_string(fs.quiet(vars.RM.." -rf " .. fs.Q(arg))) +end + +--- List the contents of a directory. +-- @param at string or nil: directory to list (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function list_dir(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(command_at(at, vars.LS)) + for file in pipe:lines() do + table.insert(result, file) + end + pipe:close() + return result +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(command_at(at, vars.FIND.." * 2>/dev/null")) + for file in pipe:lines() do + table.insert(result, file) + end + pipe:close() + return result +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean: true on success, false on failure. +function zip(zipfile, ...) + return fs.execute(vars.ZIP.." -r", zipfile, ...) +end + +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function unzip(zipfile) + assert(zipfile) + return fs.execute(vars.UNZIP, zipfile) +end + +--- Test is file/directory exists +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function exists(file) + assert(file) + return fs.execute(vars.TEST, "-e", file) +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function is_dir(file) + assert(file) + return fs.execute(vars.TEST, "-d", file) +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a regular file, false otherwise. +function is_file(file) + assert(file) + return fs.execute(vars.TEST, "-f", file) +end + +--- Download a remote file. +-- @param url string: URL to be fetched. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return boolean: true on success, false on failure. +function download(url, filename) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + if cfg.downloader == "wget" then + local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet --continue " + if filename then + return fs.execute(wget_cmd.." --output-document ", filename, url) + else + return fs.execute(wget_cmd, url) + end + elseif cfg.downloader == "curl" then + filename = filename or dir.base_name(url) + return fs.execute_string(vars.CURL.." -L --user-agent '"..cfg.user_agent.." via curl' "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename)) + end +end + +function chmod(pathname, mode) + if mode then + return fs.execute(vars.CHMOD, mode, pathname) + else + return false + end +end + +--- Apply a patch. +-- @param patchname string: The filename of the patch. +function apply_patch(patchname) + return fs.execute(vars.PATCH.." -p1 -f -i ", patchname) +end + +--- Unpack an archive. +-- Extract the contents of an archive, detecting its format by +-- filename extension. +-- @param archive string: Filename of archive. +-- @return boolean or (boolean, string): true on success, false and an error message on failure. +function unpack_archive(archive) + assert(type(archive) == "string") + + local ok + if archive:match("%.tar%.gz$") or archive:match("%.tgz$") then + ok = fs.execute_string(vars.GUNZIP.." -c "..archive.."|"..vars.TAR.." -xf -") + elseif archive:match("%.tar%.bz2$") then + ok = fs.execute_string(vars.BUNZIP2.." -c "..archive.."|tar -xf -") + elseif archive:match("%.zip$") then + ok = fs.execute(vars.UNZIP, archive) + elseif archive:match("%.lua$") or archive:match("%.c$") then + -- Ignore .lua and .c files; they don't need to be extracted. + return true + else + local ext = archive:match(".*(%..*)") + return false, "Unrecognized filename extension "..(ext or "") + end + if not ok then + return false, "Failed extracting "..archive + end + return true +end + +local md5_cmd = { + md5sum = vars.MD5SUM, + openssl = vars.OPENSSL.." md5", + md5 = vars.MD5, +} + +--- Get the MD5 checksum for a file. +-- @param file string: The file to be computed. +-- @return string: The MD5 checksum +function get_md5(file) + local cmd = md5_cmd[cfg.md5checker] + if not cmd then return nil end + local pipe = io.popen(cmd.." "..fs.absolute_name(file)) + local computed = pipe:read("*a") + pipe:close() + if not computed then return nil end + return computed:match("("..("%x"):rep(32)..")") +end + +function get_permissions(filename) + local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename)) + local ret = pipe:read("*l") + pipe:close() + return ret +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs/win32.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs/win32.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,131 @@ +--- Windows implementation of filesystem and platform abstractions. +-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities +-- used by this module. +module("luarocks.fs.win32", package.seeall) + +local fs = require("luarocks.fs") + +local cfg = require("luarocks.cfg") +local dir = require("luarocks.dir") + +--- Annotate command string for quiet execution. +-- @param cmd string: A command-line string. +-- @return string: The command-line, with silencing annotation. +function quiet(cmd) + return cmd.." 2> NUL 1> NUL" +end + +--- Quote argument for shell processing. Fixes paths on Windows. +-- Adds single quotes and escapes. +-- @param arg string: Unquoted argument. +-- @return string: Quoted argument. +function Q(arg) + assert(type(arg) == "string") + -- Quote DIR for Windows + if arg:match("^[%.a-zA-Z]?:?[\\/]") then + return '"' .. arg:gsub("/", "\\"):gsub('"', '\\"') .. '"' + end + -- URLs and anything else + return '"' .. arg:gsub('"', '\\"') .. '"' +end + +--- Return an absolute pathname from a potentially relative one. +-- @param pathname string: pathname to convert. +-- @param relative_to string or nil: path to prepend when making +-- pathname absolute, or the current dir in the dir stack if +-- not given. +-- @return string: The pathname converted to absolute. +function absolute_name(pathname, relative_to) + assert(type(pathname) == "string") + assert(type(relative_to) == "string" or not relative_to) + + relative_to = relative_to or fs.current_dir() + -- FIXME I'm not sure this first \\ should be there at all. + -- What are the Windows rules for drive letters? + if pathname:match("^[\\.a-zA-Z]?:?[\\/]") then + return pathname + else + return relative_to .. "/" .. pathname + end +end + +--- Create a wrapper to make a script executable from the command-line. +-- @param file string: Pathname of script to be made executable. +-- @param dest string: Directory where to put the wrapper. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function wrap_script(file, dest) + assert(type(file) == "string") + assert(type(dest) == "string") + + local base = dir.base_name(file) + local wrapname = fs.is_dir(dest) and dest.."/"..base or dest + wrapname = wrapname..".bat" + local wrapper = io.open(wrapname, "w") + if not wrapper then + return nil, "Could not open "..wrapname.." for writing." + end + wrapper:write("@echo off\n") + wrapper:write("setlocal\n") + wrapper:write('set LUA_PATH='..package.path..";%LUA_PATH%\n") + wrapper:write('set LUA_CPATH='..package.cpath..";%LUA_CPATH%\n") + wrapper:write('"'..dir.path(cfg.variables["LUA_BINDIR"], cfg.lua_interpreter)..'" -lluarocks.loader "'..file..'" %*\n') + wrapper:write("endlocal\n") + wrapper:close() + return true +end + +function is_actual_binary(name) + name = name:lower() + if name:match("%.bat$") or name:match("%.exe$") then + return true + end + return false +end + +function copy_binary(filename, dest) + local ok, err = fs.copy(filename, dest) + if not ok then + return nil, err + end + local exe_pattern = "%.[Ee][Xx][Ee]$" + local base = dir.base_name(filename) + local dest = dir.dir_name(dest) + if base:match(exe_pattern) then + base = base:gsub(exe_pattern, ".lua") + local helpname = dest.."/"..base + local helper = io.open(helpname, "w") + if not helper then + return nil, "Could not open "..helpname.." for writing." + end + helper:write('package.path=\"'..package.path:gsub("\\","\\\\")..';\"..package.path\n') + helper:write('package.cpath=\"'..package.path:gsub("\\","\\\\")..';\"..package.cpath\n') + helper:close() + end + return true +end + +function chmod(filename, mode) + return true +end + +function get_permissions(filename) + return "" +end + +--- Move a file on top of the other. +-- The new file ceases to exist under its original name, +-- and takes over the name of the old file. +-- On Windows this is done by removing the original file and +-- renaming the new file to its original name. +-- @param old_file The name of the original file, +-- which will be the new name of new_file. +-- @param new_file The name of the new file, +-- which will replace old_file. +-- @return boolean or (nil, string): True if succeeded, or nil and +-- an error message. +function replace_file(old_file, new_file) + os.remove(old_file) + return os.rename(new_file, old_file) +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/fs/win32/tools.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/fs/win32/tools.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,333 @@ + +--- fs operations implemented with third-party tools for Windows platform abstractions. +-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities +-- used by this module. +module("luarocks.fs.win32.tools", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") + +local dir_stack = {} + +local vars = cfg.variables + +--- Strip the last extension of a filename. +-- Example: "foo.tar.gz" becomes "foo.tar". +-- If filename has no dots, returns it unchanged. +-- @param filename string: The file name to strip. +-- @return string: The stripped name. +local function strip_extension(filename) + assert(type(filename) == "string") + + return (filename:gsub("%.[^.]+$", "")) or filename +end + +local function command_at(directory, cmd) + local drive = directory:match("^([A-Za-z]:)") + cmd = "cd " .. fs.Q(directory) .. " & " .. cmd + if drive then + cmd = drive .. " & " .. cmd + end + return cmd +end + +--- Obtain current directory. +-- Uses the module's internal directory stack. +-- @return string: the absolute pathname of the current directory. +function current_dir() + local pipe = io.popen(vars.PWD) + local current = pipe:read("*l") + pipe:close() + for _, directory in ipairs(dir_stack) do + current = fs.absolute_name(directory, current) + end + return current +end + +--- Run the given command. +-- The command is executed in the current directory in the directory stack. +-- @param cmd string: No quoting/escaping is applied to the command. +-- @return boolean: true if command succeeds (status code 0), false +-- otherwise. +function execute_string(cmd) + local code = os.execute(command_at(fs.current_dir(), cmd)) + if code == 0 or code == true then + return true + else + return false + end +end + +--- Change the current directory. +-- Uses the module's internal directory stack. This does not have exact +-- semantics of chdir, as it does not handle errors the same way, +-- but works well for our purposes for now. +-- @param directory string: The directory to switch to. +function change_dir(directory) + assert(type(directory) == "string") + table.insert(dir_stack, directory) +end + +--- Change directory to root. +-- Allows leaving a directory (e.g. for deleting it) in +-- a crossplatform way. +function change_dir_to_root() + table.insert(dir_stack, "/") +end + +--- Change working directory to the previous in the directory stack. +function pop_dir() + local directory = table.remove(dir_stack) + return directory ~= nil +end + +--- Create a directory if it does not already exist. +-- If any of the higher levels in the path name does not exist +-- too, they are created as well. +-- @param directory string: pathname of directory to create. +-- @return boolean: true on success, false on failure. +function make_dir(directory) + assert(directory) + fs.execute(fs.quiet(vars.MKDIR.." "..fs.Q(directory))) + return 1 +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function remove_dir_if_empty(directory) + assert(directory) + fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory))) +end + +--- Remove a directory if it is empty. +-- Does not return errors (for example, if directory is not empty or +-- if already does not exist) +-- @param directory string: pathname of directory to remove. +function remove_dir_tree_if_empty(directory) + assert(directory) + fs.execute_string(fs.quiet(vars.RMDIR.." "..fs.Q(directory))) +end + +--- Copy a file. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy(src, dest) + assert(src and dest) + if dest:match("[/\\]$") then dest = dest:sub(1, -2) end + if fs.execute(vars.CP, src, dest) then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Recursively copy the contents of a directory. +-- @param src string: Pathname of source +-- @param dest string: Pathname of destination +-- @return boolean or (boolean, string): true on success, false on failure, +-- plus an error message. +function copy_contents(src, dest) + assert(src and dest) + if fs.execute_string(fs.quiet(vars.CP.." -a "..src.."\\*.* "..fs.Q(dest))) then + return true + else + return false, "Failed copying "..src.." to "..dest + end +end + +--- Delete a file or a directory and all its contents. +-- For safety, this only accepts absolute paths. +-- @param arg string: Pathname of source +-- @return boolean: true on success, false on failure. +function delete(arg) + assert(arg) + assert(arg:match("^[\a-zA-Z]?:?[\\/]")) + fs.execute(vars.CHMOD.." a+rw -R ", arg) + return fs.execute_string(fs.quiet(vars.RM.." -rf " .. fs.Q(arg))) +end + +--- List the contents of a directory. +-- @param at string or nil: directory to list (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. +function list_dir(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(command_at(at, vars.LS)) + for file in pipe:lines() do + table.insert(result, file) + end + pipe:close() + + return result +end + +--- Recursively scan the contents of a directory. +-- @param at string or nil: directory to scan (will be the current +-- directory if none is given). +-- @return table: an array of strings with the filenames representing +-- the contents of a directory. Paths are returned with forward slashes. +function find(at) + assert(type(at) == "string" or not at) + if not at then + at = fs.current_dir() + end + if not fs.is_dir(at) then + return {} + end + local result = {} + local pipe = io.popen(command_at(at, vars.FIND.." 2> NUL")) + for file in pipe:lines() do + -- Windows find is a bit different + local first_two = file:sub(1,2) + if first_two == ".\\" or first_two == "./" then file=file:sub(3) end + if file ~= "." then + table.insert(result, (file:gsub("\\", "/"))) + end + end + pipe:close() + return result +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean: true on success, false on failure. +function zip(zipfile, ...) + return fs.execute(vars.SEVENZ.." a -tzip", zipfile, ...) +end + +--- Uncompress files from a .zip archive. +-- @param zipfile string: pathname of .zip archive to be extracted. +-- @return boolean: true on success, false on failure. +function unzip(zipfile) + assert(zipfile) + return fs.execute(vars.SEVENZ.." x", zipfile) +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function is_dir(file) + assert(file) + return fs.execute(fs.quiet(vars.TEST.." -d " .. fs.Q(file))) +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a regular file, false otherwise. +function is_file(file) + assert(file) + return fs.execute(vars.TEST.." -f", file) +end + +--- Download a remote file. +-- @param url string: URL to be fetched. +-- @param filename string or nil: this function attempts to detect the +-- resulting local filename of the remote file as the basename of the URL; +-- if that is not correct (due to a redirection, for example), the local +-- filename can be given explicitly as this second argument. +-- @return boolean: true on success, false on failure. +function download(url, filename) + assert(type(url) == "string") + assert(type(filename) == "string" or not filename) + + if cfg.downloader == "wget" then + local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet --continue " + if filename then + return fs.execute(wget_cmd.." --output-document ", filename, url) + else + return fs.execute(wget_cmd, url) + end + elseif cfg.downloader == "curl" then + filename = filename or dir.base_name(url) + return fs.execute_string(vars.CURL.." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename)) + end +end + +--- Uncompress gzip file. +-- @param archive string: Filename of archive. +-- @return boolean : success status +local function gunzip(archive) + return fs.execute(vars.SEVENZ.." x", archive) +end + +--- Unpack an archive. +-- Extract the contents of an archive, detecting its format by +-- filename extension. +-- @param archive string: Filename of archive. +-- @return boolean or (boolean, string): true on success, false and an error message on failure. +function unpack_archive(archive) + assert(type(archive) == "string") + + local ok + local sevenzx = vars.SEVENZ.." x" + if archive:match("%.tar%.gz$") then + ok = gunzip(archive) + if ok then + ok = fs.execute(sevenzx, strip_extension(archive)) + end + elseif archive:match("%.tgz$") then + ok = gunzip(archive) + if ok then + ok = fs.execute(sevenzx, strip_extension(archive)..".tar") + end + elseif archive:match("%.tar%.bz2$") then + ok = fs.execute(sevenzx, archive) + if ok then + ok = fs.execute(sevenzx, strip_extension(archive)) + end + elseif archive:match("%.zip$") then + ok = fs.execute(sevenzx, archive) + elseif archive:match("%.lua$") or archive:match("%.c$") then + -- Ignore .lua and .c files; they don't need to be extracted. + return true + else + local ext = archive:match(".*(%..*)") + return false, "Unrecognized filename extension "..(ext or "") + end + if not ok then + return false, "Failed extracting "..archive + end + return true +end + +local md5_cmd = { + md5sum = vars.MD5SUM, + openssl = vars.OPENSSL.." md5", + md5 = vars.MD5, +} + +--- Get the MD5 checksum for a file. +-- @param file string: The file to be computed. +-- @return string: The MD5 checksum +function get_md5(file) + local cmd = md5_cmd[cfg.md5checker] + if not cmd then return nil end + local pipe = io.popen(cmd.." "..fs.absolute_name(file)) + local computed = pipe:read("*a") + pipe:close() + if not computed then return nil end + return computed:match("("..("%x"):rep(32)..")") +end + +--- Test for existance of a file. +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function exists(file) + assert(file) + return fs.execute(fs.quiet("if not exist " .. fs.Q(file) .. " invalidcommandname")) +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/help.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/help.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,101 @@ + +--- Module implementing the LuaRocks "help" command. +-- This is a generic help display module, which +-- uses a global table called "commands" to find commands +-- to show help for; each command should be represented by a +-- table containing "help" and "help_summary" fields. +module("luarocks.help", package.seeall) + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") + +help_summary = "Help on commands. Type '"..program_name.." help ' for more." + +help_arguments = "[]" +help = [[ + is the command to show help for. +]] + +local function print_banner() + util.printout("\nLuaRocks "..cfg.program_version..", a module deployment system for Lua") +end + +local function print_section(section) + util.printout("\n"..section) +end + +local function get_status(status) + if status then + return "ok" + elseif status == false then + return "not found" + else + return "failed" + end +end + +--- Driver function for the "help" command. +-- @param command string or nil: command to show help for; if not +-- given, help summaries for all commands are shown. +-- @return boolean or (nil, string): true if there were no errors +-- or nil and an error message if an invalid command was requested. +function run(...) + local flags, command = util.parse_flags(...) + + if not command then + local sys_file, sys_ok, home_file, home_ok = cfg.which_config() + print_banner() + print_section("NAME") + util.printout("\t"..program_name..[[ - ]]..program_description) + print_section("SYNOPSIS") + util.printout("\t"..program_name..[[ [--from= | --only-from=] [--to=] [VAR=VALUE]... [] ]]) + print_section("GENERAL OPTIONS") + util.printout([[ + These apply to all commands, as appropriate: + + --server= Fetch rocks/rockspecs from this server + (takes priority over config file) + --only-server= Fetch rocks/rockspecs from this server only + (overrides any entries in the config file) + --only-sources= Restrict downloads to paths matching the + given URL. + --tree= Which tree to operate on. + --local Use the tree in the user's home directory.]]) + print_section("VARIABLES") + util.printout([[ + Variables from the "variables" table of the configuration file + can be overriden with VAR=VALUE assignments.]]) + print_section("COMMANDS") + local names = {} + for name, command in pairs(commands) do + table.insert(names, name) + end + table.sort(names) + for _, name in ipairs(names) do + local command = commands[name] + util.printout("", name) + util.printout("\t", command.help_summary) + end + print_section("CONFIGURATION") + util.printout([[ + System configuration file: ]]..sys_file .. " (" .. get_status(sys_ok) ..[[) + User configuration file: ]]..home_file .. " (" .. get_status(home_ok) ..")\n") + else + command = command:gsub("-", "_") + if commands[command] then + local arguments = commands[command].help_arguments or "" + print_banner() + print_section("NAME") + util.printout("\t"..program_name.." "..command.." - "..commands[command].help_summary) + print_section("SYNOPSIS") + util.printout("\t"..program_name.." "..command.." "..arguments) + print_section("DESCRIPTION") + util.printout("",(commands[command].help:gsub("\n","\n\t"):gsub("\n\t$",""))) + print_section("SEE ALSO") + util.printout("","'luarocks help' for general options and configuration.\n") + else + return nil, "Unknown command '"..command.."'" + end + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/index.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/index.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,172 @@ + +--- Module which builds the index.html page to be used in rocks servers. +module("luarocks.index", package.seeall) + +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local deps = require("luarocks.deps") +local persist = require("luarocks.persist") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") + +local ext_url_target = ' target="_blank"' + +local index_header = [[ + + + +Available rocks + + + + +

Available rocks

+

+Lua modules available from this location for use with LuaRocks: +

+ +]] + +local index_package_start = [[ + + + +]] + +local index_footer = [[ +
+

$package - $summary
+

$detailed
+$externaldependencies +latest sources $homepage | License: $license

+
+]] + +local index_package_end = [[ +
+

+manifest file +

+ + +]] + +function format_external_dependencies(rockspec) + if rockspec.external_dependencies then + local deplist = {} + local listed_set = {} + local plats = nil + for name, desc in util.sortedpairs(rockspec.external_dependencies) do + if name ~= "platforms" then + table.insert(deplist, name:lower()) + listed_set[name] = true + else + plats = desc + end + end + if plats then + for plat, entries in util.sortedpairs(plats) do + for name, desc in util.sortedpairs(entries) do + if not listed_set[name] then + table.insert(deplist, name:lower() .. " (on "..plat..")") + end + end + end + end + return '

External dependencies: ' .. table.concat(deplist, ', ').. '

' + else + return "" + end +end + +function make_index(repo) + if not fs.is_dir(repo) then + return nil, "Cannot access repository at "..repo + end + local manifest = manif.load_manifest(repo) + local out = io.open(dir.path(repo, "index.html"), "w") + + out:write(index_header) + for package, version_list in util.sortedpairs(manifest.repository) do + local latest_rockspec = nil + local output = index_package_start + for version, data in util.sortedpairs(version_list, deps.compare_versions) do + local versions = {} + output = output..version..': ' + table.sort(data, function(a,b) return a.arch < b.arch end) + for _, item in ipairs(data) do + local link = ''..item.arch..'' + if item.arch == 'rockspec' then + local rs = ("%s-%s.rockspec"):format(package, version) + if not latest_rockspec then latest_rockspec = rs end + link = link:gsub("$url", rs) + else + link = link:gsub("$url", ("%s-%s.%s.rock"):format(package, version, item.arch)) + end + table.insert(versions, link) + end + output = output .. table.concat(versions, ', ') .. '
' + end + output = output .. index_package_end + if latest_rockspec then + local rockspec = persist.load_into_table(dir.path(repo, latest_rockspec)) + local descript = rockspec.description or {} + local vars = { + anchor = package, + package = rockspec.package, + original = rockspec.source.url, + summary = descript.summary or "", + detailed = descript.detailed or "", + license = descript.license or "N/A", + homepage = descript.homepage and ('| project homepage') or "", + externaldependencies = format_external_dependencies(rockspec) + } + vars.detailed = vars.detailed:gsub("\n\n", "

"):gsub("%s+", " ") + vars.detailed = vars.detailed:gsub("(https?://[a-zA-Z0-9%.%%-_%+%[%]=%?&/$@;:]+)", '%1') + output = output:gsub("$(%w+)", vars) + else + output = output:gsub("$anchor", package) + output = output:gsub("$package", package) + output = output:gsub("$(%w+)", "") + end + out:write(output) + end + out:write(index_footer) + out:close() +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/install.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/install.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,150 @@ + +--- Module implementing the LuaRocks "install" command. +-- Installs binary rocks. +module("luarocks.install", package.seeall) + +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local deps = require("luarocks.deps") +local manif = require("luarocks.manif") +local cfg = require("luarocks.cfg") + +help_summary = "Install a rock." + +help_arguments = "{| []}" + +help = [[ +Argument may be the name of a rock to be fetched from a repository +or a filename of a locally available rock. +]] + +--- Install a binary rock. +-- @param rock_file string: local or remote filename of a rock. +-- @param deps_mode: string: Which trees to check dependencies for: +-- "none", "one", "order" or "all". +-- @return boolean or (nil, string, [string]): True if succeeded or +-- nil and an error message and an optional error code. +function install_binary_rock(rock_file, deps_mode) + assert(type(rock_file) == "string") + + local name, version, arch = path.parse_name(rock_file) + if not name then + return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." + end + + if arch ~= "all" and arch ~= cfg.arch then + return nil, "Incompatible architecture "..arch, "arch" + end + if repos.is_installed(name, version) then + repos.delete_version(name, version) + end + + local rollback = util.schedule_function(function() + fs.delete(path.install_dir(name, version)) + fs.remove_dir_if_empty(path.versions_dir(name)) + end) + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) + if not ok then return nil, err, errcode end + + local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) + if err then + return nil, "Failed loading rockspec for installed package: "..err, errcode + end + + if deps_mode == "none" then + util.printerr("Warning: skipping dependency checks.") + else + ok, err, errcode = deps.check_external_deps(rockspec, "install") + if err then return nil, err, errcode end + end + + -- For compatibility with .rock files built with LuaRocks 1 + if not fs.exists(path.rock_manifest_file(name, version)) then + ok, err = manif.make_rock_manifest(name, version) + if err then return nil, err end + end + + if deps_mode ~= "none" then + ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) + if err then return nil, err, errcode end + end + + local wrap_bin_scripts = true + if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then + wrap_bin_scripts = false + end + + ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec)) + if err then return nil, err end + + util.remove_scheduled_function(rollback) + rollback = util.schedule_function(function() + repos.delete_version(name, version) + end) + + ok, err = repos.run_hook(rockspec, "post_install") + if err then return nil, err end + + ok, err = manif.update_manifest(name, version, nil, deps_mode) + if err then return nil, err end + + local license = "" + if rockspec.description.license then + license = ("(license: "..rockspec.description.license..")") + end + + local root_dir = path.root_dir(cfg.rocks_dir) + util.printout() + util.printout(name.." "..version.." is now installed in "..root_dir.." "..license) + + util.remove_scheduled_function(rollback) + return true +end + +--- Driver function for the "install" command. +-- @param name string: name of a binary rock. If an URL or pathname +-- to a binary rock is given, fetches and installs it. If a rockspec or a +-- source rock is given, forwards the request to the "build" command. +-- If a package name is given, forwards the request to "search" and, +-- if returned a result, installs the matching rock. +-- @param version string: When passing a package name, a version number +-- may also be given. +-- @return boolean or (nil, string): True if installation was +-- successful, nil and an error message otherwise. +function run(...) + local flags, name, version = util.parse_flags(...) + if type(name) ~= "string" then + return nil, "Argument missing, see help." + end + + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err end + + if name:match("%.rockspec$") or name:match("%.src%.rock$") then + util.printout("Using "..name.."... switching to 'build' mode") + local build = require("luarocks.build") + return build.run(name, deps.get_deps_mode(flags), flags["local"] and "--local") + elseif name:match("%.rock$") then + return install_binary_rock(name, deps.get_deps_mode(flags)) + else + local search = require("luarocks.search") + local results, err = search.find_suitable_rock(search.make_query(name:lower(), version)) + if err then + return nil, err + elseif type(results) == "string" then + local url = results + util.printout("Installing "..url.."...") + return run(url) + else + util.printout() + util.printerr("Could not determine which rock to install.") + util.title("Search results:") + search.print_results(results) + return nil, (next(results) and "Please narrow your query." or "No results found.") + end + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/lint.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/lint.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,41 @@ + +--- Module implementing the LuaRocks "lint" command. +-- Utility function that checks syntax of the rockspec. +module("luarocks.lint", package.seeall) + +local util = require("luarocks.util") +local download = require("luarocks.download") +local fetch = require("luarocks.fetch") + +help_summary = "Check syntax of a rockspec." +help_arguments = "" +help = [[ +This is a utility function that checks the syntax of a rockspec. + +It returns success or failure if the text of a rockspec is +syntactically correct. +]] + +function run(...) + local flags, input = util.parse_flags(...) + + if not input then + return nil, "Argument missing, see help." + end + + local filename = input + if not input:match(".rockspec$") then + local err + filename, err = download.download("rockspec", input) + if not filename then + return nil, err + end + end + + local rs, err = fetch.load_local_rockspec(filename) + if not rs then + return nil, "Failed loading rockspec: "..err + end + + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/list.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/list.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,38 @@ + +--- Module implementing the LuaRocks "list" command. +-- Lists currently installed rocks. +module("luarocks.list", package.seeall) + +local search = require("luarocks.search") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local path = require("luarocks.path") + +help_summary = "Lists currently installed rocks." +help_arguments = "[--porcelain] " +help = [[ + is a substring of a rock name to filter by. + +--porcelain Produce machine-friendly output. +]] + +--- Driver function for "list" command. +-- @param filter string or nil: A substring of a rock name to filter by. +-- @param version string or nil: a version may also be passed. +-- @return boolean: True if succeeded, nil on errors. +function run(...) + local flags, filter, version = util.parse_flags(...) + local results = {} + local query = search.make_query(filter and filter:lower() or "", version) + query.exact_name = false + local trees = cfg.rocks_trees + if flags["tree"] then + trees = { flags["tree"] } + end + for _, tree in ipairs(trees) do + search.manifest_search(results, path.rocks_dir(tree), query) + end + util.title("Installed rocks:", flags["porcelain"]) + search.print_results(results, flags["porcelain"]) + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/loader.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/loader.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,212 @@ + +--- A module which installs a Lua package loader that is LuaRocks-aware. +-- This loader uses dependency information from the LuaRocks tree to load +-- correct versions of modules. It does this by constructing a "context" +-- table in the environment, which records which versions of packages were +-- used to load previous modules, so that the loader chooses versions +-- that are declared to be compatible with the ones loaded earlier. +local global_env = _G +local package, require, ipairs, pairs, table, type, next, unpack = + package, require, ipairs, pairs, table, type, next, unpack + +module("luarocks.loader") + +local path = require("luarocks.path") +local manif_core = require("luarocks.manif_core") +local deps = require("luarocks.deps") +local cfg = require("luarocks.cfg") + +context = {} + +-- Contains a table when rocks trees are loaded, +-- or 'false' to indicate rocks trees failed to load. +-- 'nil' indicates rocks trees were not attempted to be loaded yet. +rocks_trees = nil + +local function load_rocks_trees() + local any_ok = false + local trees = {} + for _, tree in ipairs(cfg.rocks_trees) do + local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree)) + if manifest then + any_ok = true + table.insert(trees, {tree=tree, manifest=manifest}) + end + end + if not any_ok then + rocks_trees = false + return false + end + rocks_trees = trees + return true +end + +--- Process the dependencies of a package to determine its dependency +-- chain for loading modules. +-- @param name string: The name of an installed rock. +-- @param version string: The version of the rock, in string format +function add_context(name, version) + -- assert(type(name) == "string") + -- assert(type(version) == "string") + + if context[name] then + return + end + context[name] = version + + if not rocks_trees and not load_rocks_trees() then + return nil + end + + local providers = {} + for _, tree in ipairs(rocks_trees) do + local manifest = tree.manifest + + local pkgdeps + if manifest.dependencies and manifest.dependencies[name] then + pkgdeps = manifest.dependencies[name][version] + end + if not pkgdeps then + return nil + end + for _, dep in ipairs(pkgdeps) do + local pkg, constraints = dep.name, dep.constraints + + for _, tree in ipairs(rocks_trees) do + local entries = tree.manifest.repository[pkg] + if entries then + for version, pkgs in pairs(entries) do + if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then + add_context(pkg, version) + end + end + end + end + end + end +end + +--- Internal sorting function. +-- @param a table: A provider table. +-- @param b table: Another provider table. +-- @return boolean: True if the version of a is greater than that of b. +local function sort_versions(a,b) + return a.version > b.version +end + +--- Request module to be loaded through other loaders, +-- once the proper name of the module has been determined. +-- For example, in case the module "socket.core" has been requested +-- to the LuaRocks loader and it determined based on context that +-- the version 2.0.2 needs to be loaded and it is not the current +-- version, the module requested for the other loaders will be +-- "socket.core_2_0_2". +-- @param module The module name requested by the user, such as "socket.core" +-- @param name The rock name, such as "luasocket" +-- @param version The rock version, such as "2.0.2-1" +-- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". +-- @return table or (nil, string): The module table as returned by some other loader, +-- or nil followed by an error message if no other loader managed to load the module. +local function call_other_loaders(module, name, version, module_name) + for i, loader in pairs(package.loaders) do + if loader ~= luarocks_loader then + local results = { loader(module_name) } + if type(results[1]) == "function" then + return unpack(results) + end + end + end + return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version +end + +--- Search for a module in the rocks trees +-- @param module string: module name (eg. "socket.core") +-- @param filter_module_name function(string, string, string, string, number): +-- a function that takes the module name (eg "socket.core"), the rock name +-- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree +-- (eg "/usr/local"), and the numeric index of the matching entry, so the +-- filter function can know if the matching module was the first entry or not. +-- @return string, string, string: name of the rock containing the module +-- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"), +-- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is +-- stored versioned). +local function select_module(module, filter_module_name) + --assert(type(module) == "string") + --assert(type(filter_module_name) == "function") + + if not rocks_trees and not load_rocks_trees() then + return nil + end + + local providers = {} + for _, tree in ipairs(rocks_trees) do + local entries = tree.manifest.modules[module] + if entries then + for i, entry in ipairs(entries) do + local name, version = entry:match("^([^/]*)/(.*)$") + local module_name = tree.manifest.repository[name][version][1].modules[module] + if type(module_name) ~= "string" then + error("Invalid format in manifest file (invalid data for "..tostring(name).." "..tostring(version)..")") + end + module_name = filter_module_name(module_name, name, version, tree.tree, i) + if context[name] == version then + return name, version, module_name + end + version = deps.parse_version(version) + table.insert(providers, {name = name, version = version, module_name = module_name}) + end + end + end + + if next(providers) then + table.sort(providers, sort_versions) + local first = providers[1] + return first.name, first.version.string, first.module_name + end +end + +--- Search for a module +-- @param module string: module name (eg. "socket.core") +-- @return string, string, string: name of the rock containing the module +-- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"), +-- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is +-- stored versioned). +local function pick_module(module) + return + select_module(module, function(module_name, name, version, tree, i) + if i > 1 then + module_name = path.versioned_name(module_name, "", name, version) + end + module_name = path.path_to_module(module_name) + return module_name + end) +end + +--- Return the pathname of the file that would be loaded for a module. +-- @param module string: module name (eg. "socket.core") +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function which(module) + local name, version, module_name = select_module(module, path.which_i) + return module_name +end + +--- Package loader for LuaRocks support. +-- A module is searched in installed rocks that match the +-- current LuaRocks context. If module is not part of the +-- context, or if a context has not yet been set, the module +-- in the package with the highest version is used. +-- @param module string: The module name, like in plain require(). +-- @return table: The module table (typically), like in plain +-- require(). See require() +-- in the Lua reference manual for details. +function luarocks_loader(module) + local name, version, module_name = pick_module(module) + if not name then + return "No LuaRocks module found for "..module + else + add_context(name, version) + return call_other_loaders(module, name, version, module_name) + end +end + +table.insert(global_env.package.loaders, 1, luarocks_loader) diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/make.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/make.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,72 @@ + +--- Module implementing the LuaRocks "make" command. +-- Builds sources in the current directory, but unlike "build", +-- it does not fetch sources, etc., assuming everything is +-- available in the current directory. +module("luarocks.make", package.seeall) + +local build = require("luarocks.build") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local fetch = require("luarocks.fetch") +local pack = require("luarocks.pack") +local deps = require("luarocks.deps") + +help_summary = "Compile package in current directory using a rockspec." +help_arguments = "[--pack-binary-rock] []" +help = [[ +Builds sources in the current directory, but unlike "build", +it does not fetch sources, etc., assuming everything is +available in the current directory. If no argument is given, +look for a rockspec in the current directory. If more than one +is found, you must specify which to use, through the command-line. + +This command is useful as a tool for debugging rockspecs. +To install rocks, you'll normally want to use the "install" and +"build" commands. See the help on those for details. + +If --pack-binary-rock is passed, the rock is not installed; +instead, a .rock file with the contents of compilation is produced +in the current directory. +]] + +--- Driver function for "make" command. +-- @param name string: A local rockspec. +-- @return boolean or (nil, string): True if build was successful; nil and an +-- error message otherwise. +function run(...) + local flags, rockspec = util.parse_flags(...) + assert(type(rockspec) == "string" or not rockspec) + + if not rockspec then + local files = fs.list_dir(fs.current_dir()) + for _, file in pairs(files) do + if file:match("rockspec$") then + if rockspec then + return nil, "Please specify which rockspec file to use." + else + rockspec = file + end + end + end + if not rockspec then + return nil, "Argument missing: please specify a rockspec to use on current directory." + end + end + if not rockspec:match("rockspec$") then + return nil, "Invalid argument: 'make' takes a rockspec as a parameter. See help." + end + + if flags["pack-binary-rock"] then + local rspec, err, errcode = fetch.load_rockspec(rockspec) + if not rspec then + return nil, err + end + return pack.pack_binary_rock(rspec.name, rspec.version, build.build_rockspec, rockspec, false, true, deps.get_deps_mode(flags)) + else + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err end + return build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/make_manifest.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/make_manifest.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,37 @@ + +--- Module implementing the luarocks-admin "make_manifest" command. +-- Compile a manifest file for a repository. +module("luarocks.make_manifest", package.seeall) + +local manif = require("luarocks.manif") +local index = require("luarocks.index") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local deps = require("luarocks.deps") + +help_summary = "Compile a manifest file for a repository." + +help = [[ +, if given, is a local repository pathname. +]] + +--- Driver function for "make_manifest" command. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository configured as cfg.rocks_dir is used. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function run(...) + local flags, repo = util.parse_flags(...) + + assert(type(repo) == "string" or not repo) + repo = repo or cfg.rocks_dir + + util.printout("Making manifest for "..repo) + + local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags)) + if ok then + util.printout("Generating index.html for "..repo) + index.make_index(repo) + end + return ok, err +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/manif.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/manif.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,374 @@ + +--- Module for handling manifest files and tables. +-- Manifest files describe the contents of a LuaRocks tree or server. +-- They are loaded into manifest tables, which are then used for +-- performing searches, matching dependencies, etc. +module("luarocks.manif", package.seeall) + +local manif_core = require("luarocks.manif_core") +local persist = require("luarocks.persist") +local fetch = require("luarocks.fetch") +local dir = require("luarocks.dir") +local fs = require("luarocks.fs") +local search = require("luarocks.search") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local deps = require("luarocks.deps") + +rock_manifest_cache = {} + +--- Commit a table to disk in given local path. +-- @param where string: The directory where the table should be saved. +-- @param name string: The filename. +-- @param tbl table: The table to be saved. +-- @return boolean or (nil, string): true if successful, or nil and a +-- message in case of errors. +local function save_table(where, name, tbl) + assert(type(where) == "string") + assert(type(name) == "string") + assert(type(tbl) == "table") + + local filename = dir.path(where, name) + local ok, err = persist.save_from_table(filename..".tmp", tbl) + if ok then + ok, err = fs.replace_file(filename, filename..".tmp") + end + return ok, err +end + +function load_rock_manifest(name, version, root) + assert(type(name) == "string") + assert(type(version) == "string") + + local name_version = name.."/"..version + if rock_manifest_cache[name_version] then + return rock_manifest_cache[name_version].rock_manifest + end + local pathname = path.rock_manifest_file(name, version, root) + local rock_manifest = persist.load_into_table(pathname) + if not rock_manifest then return nil end + rock_manifest_cache[name_version] = rock_manifest + return rock_manifest.rock_manifest +end + +function make_rock_manifest(name, version) + local install_dir = path.install_dir(name, version) + local rock_manifest = path.rock_manifest_file(name, version) + local tree = {} + for _, file in ipairs(fs.find(install_dir)) do + local full_path = dir.path(install_dir, file) + local walk = tree + local last + local last_name + for name in file:gmatch("[^/]+") do + local next = walk[name] + if not next then + next = {} + walk[name] = next + end + last = walk + last_name = name + walk = next + end + if fs.is_file(full_path) then + last[last_name] = fs.get_md5(full_path) + end + end + local rock_manifest = { rock_manifest=tree } + rock_manifest_cache[name.."/"..version] = rock_manifest + save_table(install_dir, "rock_manifest", rock_manifest ) +end + +--- Load a local or remote manifest describing a repository. +-- All functions that use manifest tables assume they were obtained +-- through either this function or load_local_manifest. +-- @param repo_url string: URL or pathname for the repository. +-- @return table or (nil, string, [string]): A table representing the manifest, +-- or nil followed by an error message and an optional error code. +function load_manifest(repo_url) + assert(type(repo_url) == "string") + + if manif_core.manifest_cache[repo_url] then + return manif_core.manifest_cache[repo_url] + end + + local protocol, pathname = dir.split_url(repo_url) + if protocol == "file" then + pathname = dir.path(pathname, "manifest") + else + local url = dir.path(repo_url, "manifest") + local name = repo_url:gsub("[/:]","_") + local file, err, errcode = fetch.fetch_url_at_temp_dir(url, "luarocks-manifest-"..name) + if not file then + return nil, "Failed fetching manifest for "..repo_url..(err and " - "..err or ""), errcode + end + pathname = file + end + return manif_core.manifest_loader(pathname, repo_url) +end + +--- Output a table listing items of a package. +-- @param itemsfn function: a function for obtaining items of a package. +-- pkg and version will be passed to it; it should return a table with +-- items as keys. +-- @param pkg string: package name +-- @param version string: package version +-- @param tbl table: the package matching table: keys should be item names +-- and values arrays of strings with packages names in "name/version" format. +local function store_package_items(itemsfn, pkg, version, tbl) + assert(type(itemsfn) == "function") + assert(type(pkg) == "string") + assert(type(version) == "string") + assert(type(tbl) == "table") + + local pkg_version = pkg.."/"..version + local result = {} + + for item, path in pairs(itemsfn(pkg, version)) do + result[item] = path + if not tbl[item] then + tbl[item] = {} + end + table.insert(tbl[item], pkg_version) + end + return result +end + +--- Sort function for ordering rock identifiers in a manifest's +-- modules table. Rocks are ordered alphabetically by name, and then +-- by version which greater first. +-- @param a string: Version to compare. +-- @param b string: Version to compare. +-- @return boolean: The comparison result, according to the +-- rule outlined above. +local function sort_pkgs(a, b) + assert(type(a) == "string") + assert(type(b) == "string") + + local na, va = a:match("(.*)/(.*)$") + local nb, vb = b:match("(.*)/(.*)$") + + return (na == nb) and deps.compare_versions(va, vb) or na < nb +end + +--- Sort items of a package matching table by version number (higher versions first). +-- @param tbl table: the package matching table: keys should be strings +-- and values arrays of strings with packages names in "name/version" format. +local function sort_package_matching_table(tbl) + assert(type(tbl) == "table") + + if next(tbl) then + for item, pkgs in pairs(tbl) do + if #pkgs > 1 then + table.sort(pkgs, sort_pkgs) + -- Remove duplicates from the sorted array. + local prev = nil + local i = 1 + while pkgs[i] do + local curr = pkgs[i] + if curr == prev then + table.remove(pkgs, i) + else + prev = curr + i = i + 1 + end + end + end + end + end +end + +--- Process the dependencies of a manifest table to determine its dependency +-- chains for loading modules. The manifest dependencies information is filled +-- and any dependency inconsistencies or missing dependencies are reported to +-- standard error. +-- @param manifest table: a manifest table. +local function update_dependencies(manifest, deps_mode) + assert(type(manifest) == "table") + assert(type(deps_mode) == "string") + + for pkg, versions in pairs(manifest.repository) do + for version, repositories in pairs(versions) do + local current = pkg.." "..version + for _, repo in ipairs(repositories) do + if repo.arch == "installed" then + local missing + repo.dependencies, missing = deps.scan_deps({}, {}, manifest, pkg, version, deps_mode) + repo.dependencies[pkg] = nil + if missing then + for miss, err in pairs(missing) do + if miss == current then + util.printerr("Tree inconsistency detected: "..current.." has no rockspec. "..err) + else + util.printerr("Missing dependency for "..pkg.." "..version..": "..miss) + end + end + end + end + end + end + end +end + +--- Store search results in a manifest table. +-- @param results table: The search results as returned by search.disk_search. +-- @param manifest table: A manifest table (must contain repository, modules, commands tables). +-- It will be altered to include the search results. +-- @return boolean or (nil, string): true in case of success, or nil followed by an error message. +local function store_results(results, manifest, deps_mode) + assert(type(results) == "table") + assert(type(manifest) == "table") + assert(type(deps_mode) == "string") + + for name, versions in pairs(results) do + local pkgtable = manifest.repository[name] or {} + for version, entries in pairs(versions) do + local versiontable = {} + for _, entry in ipairs(entries) do + local entrytable = {} + entrytable.arch = entry.arch + if entry.arch == "installed" then + local rock_manifest = load_rock_manifest(name, version) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + entrytable.modules = store_package_items(repos.package_modules, name, version, manifest.modules) + entrytable.commands = store_package_items(repos.package_commands, name, version, manifest.commands) + end + table.insert(versiontable, entrytable) + end + pkgtable[version] = versiontable + end + manifest.repository[name] = pkgtable + end + update_dependencies(manifest, deps_mode) + sort_package_matching_table(manifest.modules) + sort_package_matching_table(manifest.commands) + return true +end + +--- Scan a LuaRocks repository and output a manifest file. +-- A file called 'manifest' will be written in the root of the given +-- repository directory. +-- @param repo A local repository directory. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function make_manifest(repo, deps_mode) + assert(type(repo) == "string") + assert(type(deps_mode) == "string") + + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + if not fs.is_dir(repo) then + return nil, "Cannot access repository at "..repo + end + + local query = search.make_query("") + query.exact_name = false + query.arch = "any" + local results = search.disk_search(repo, query) + local manifest = { repository = {}, modules = {}, commands = {} } + manif_core.manifest_cache[repo] = manifest + + local ok, err = store_results(results, manifest, deps_mode) + if not ok then return nil, err end + + return save_table(repo, "manifest", manifest) +end + +--- Load a manifest file from a local repository and add to the repository +-- information with regard to the given name and version. +-- A file called 'manifest' will be written in the root of the given +-- repository directory. +-- @param name string: Name of a package from the repository. +-- @param version string: Version of a package from the repository. +-- @param repo string or nil: Pathname of a local repository. If not given, +-- the default local repository configured as cfg.rocks_dir is used. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function update_manifest(name, version, repo, deps_mode) + assert(type(name) == "string") + assert(type(version) == "string") + repo = path.rocks_dir(repo or cfg.root_dir) + assert(type(deps_mode) == "string") + + if deps_mode == "none" then deps_mode = cfg.deps_mode end + + util.printout("Updating manifest for "..repo) + + local manifest, err = load_manifest(repo) + if not manifest then + util.printerr("No existing manifest. Attempting to rebuild...") + local ok, err = make_manifest(repo, deps_mode) + if not ok then + return nil, err + end + manifest, err = load_manifest(repo) + if not manifest then + return nil, err + end + end + + local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}} + + local ok, err = store_results(results, manifest, deps_mode) + if not ok then return nil, err end + + return save_table(repo, "manifest", manifest) +end + +local function find_providers(file, root) + assert(type(file) == "string") + root = root or cfg.root_dir + + local manifest, err = manif_core.load_local_manifest(path.rocks_dir(root)) + if not manifest then + return nil, err .. " -- corrupted local rocks tree?" + end + local deploy_bin = path.deploy_bin_dir(root) + local deploy_lua = path.deploy_lua_dir(root) + local deploy_lib = path.deploy_lib_dir(root) + local key, manifest_tbl + + if util.starts_with(file, deploy_lua) then + manifest_tbl = manifest.modules + key = path.path_to_module(file:sub(#deploy_lua+1):gsub("\\", "/")) + elseif util.starts_with(file, deploy_lib) then + manifest_tbl = manifest.modules + key = path.path_to_module(file:sub(#deploy_lib+1):gsub("\\", "/")) + elseif util.starts_with(file, deploy_bin) then + manifest_tbl = manifest.commands + key = file:sub(#deploy_bin+1):gsub("^[\\/]*", "") + else + assert(false, "Assertion failed: '"..file.."' is not a deployed file.") + end + + local providers = manifest_tbl[key] + if not providers then + return nil, "untracked" + end + return providers +end + +--- Given a path of a deployed file, figure out which rock name and version +-- correspond to it in the tree manifest. +-- @param file string: The full path of a deployed file. +-- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. +-- @return string, string: name and version of the provider rock. +function find_current_provider(file, root) + local providers, err = find_providers(file, root) + if not providers then return nil, err end + return providers[1]:match("([^/]*)/([^/]*)") +end + +function find_next_provider(file, root) + local providers, err = find_providers(file, root) + if not providers then return nil, err end + if providers[2] then + return providers[2]:match("([^/]*)/([^/]*)") + else + return nil + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/manif_core.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/manif_core.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,79 @@ + +--- Core functions for querying manifest files. +-- This module requires no specific 'fs' functionality. +module("luarocks.manif_core", package.seeall) + +local persist = require("luarocks.persist") +local type_check = require("luarocks.type_check") +local dir = require("luarocks.dir") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local path = require("luarocks.path") + +manifest_cache = {} + +--- Back-end function that actually loads the manifest +-- and stores it in the manifest cache. +-- @param file string: The local filename of the manifest file. +-- @param repo_url string: The repository identifier. +-- @param quick boolean: If given, skips type checking. +function manifest_loader(file, repo_url, quick) + local manifest, err = persist.load_into_table(file) + if not manifest then + return nil, "Failed loading manifest for "..repo_url..": "..err + end + if not quick then + local ok, err = type_check.type_check_manifest(manifest) + if not ok then + return nil, "Error checking manifest: "..err + end + end + + manifest_cache[repo_url] = manifest + return manifest +end + +--- Load a local manifest describing a repository. +-- All functions that use manifest tables assume they were obtained +-- through either this function or load_manifest. +-- @param repo_url string: URL or pathname for the repository. +-- @return table or (nil, string): A table representing the manifest, +-- or nil followed by an error message. +function load_local_manifest(repo_url) + assert(type(repo_url) == "string") + + if manifest_cache[repo_url] then + return manifest_cache[repo_url] + end + + local pathname = dir.path(repo_url, "manifest") + + return manifest_loader(pathname, repo_url, true) +end + +--- Get all versions of a package listed in a manifest file. +-- @param name string: a package name. +-- @param deps_mode string: "one", to use only the currently +-- configured tree; "order" to select trees based on order +-- (use the current tree and all trees below it on the list) +-- or "all", to use all trees. +-- @return table: An array of strings listing installed +-- versions of a package. +function get_versions(name, deps_mode) + assert(type(name) == "string") + assert(type(deps_mode) == "string") + + local manifest = {} + path.map_trees(deps_mode, function(tree) + local loaded = load_local_manifest(path.rocks_dir(tree)) + if loaded then + util.deep_merge(manifest, loaded) + end + end) + + local item = next(manifest) and manifest.repository[name] + if item then + return util.keys(item) + end + return {} +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/new_version.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/new_version.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,141 @@ + +--- Module implementing the LuaRocks "new_version" command. +-- Utility function that writes a new rockspec, updating data from a previous one. +module("luarocks.new_version", package.seeall) + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local download = require("luarocks.download") +local fetch = require("luarocks.fetch") +local persist = require("luarocks.persist") +local dir = require("luarocks.dir") +local fs = require("luarocks.fs") + +help_summary = "Auto-write a rockspec for a new version of a rock." +help_arguments = "{|} [] []" +help = [[ +This is a utility function that writes a new rockspec, updating data +from a previous one. + +If a package name is given, it downloads the latest rockspec from the +default server. If a rockspec is given, it uses it instead. + +If the version number is not given, it only increments the revision +number of the given (or downloaded) rockspec. + +If a URL is given, it replaces the one from the old rockspec with the +given URL. If a URL is not given and a new version is given, it tries +to guess the new URL by replacing occurrences of the version number +in the URL or tag. It also tries to download the new URL to determine +the new MD5 checksum. + +WARNING: it writes the new rockspec to the current directory, +overwriting the file if it already exists. +]] + +local order = {"rockspec_format", "package", "version", + { "source", { "url", "tag", "branch", "md5" } }, + { "description", {"summary", "detailed", "homepage", "license" } }, + "supported_platforms", "dependencies", "external_dependencies", + { "build", {"type", "modules", "copy_directories", "platforms"} }, + "hooks"} + +local function try_replace(tbl, field, old, new) + if not tbl[field] then + return false + end + local old_field = tbl[field] + local new_field = tbl[field]:gsub(old, new) + if new_field ~= old_field then + util.printout("Guessing new '"..field.."' field as "..new_field) + tbl[field] = new_field + return true + end + return false +end + +local function check_url_and_update_md5(out_rs, out_name) + out_rs.source.md5 = nil + local file, temp_dir = fetch.fetch_url_at_temp_dir(out_rs.source.url, "luarocks-new-version-"..out_name) + if file then + util.printout("File successfully downloaded. Updating MD5 checksum...") + out_rs.source.md5 = fs.get_md5(file) + else + util.printerr("Warning: invalid URL - "..temp_dir) + end +end + +function run(...) + local flags, input, version, url = util.parse_flags(...) + if not input then + return nil, "Missing arguments: expected program or rockspec. See help." + end + assert(type(input) == "string") + + local filename = input + if not input:match(".rockspec$") then + local err + filename, err = download.download("rockspec", input) + if not filename then + return nil, err + end + end + + local valid_rs, err = fetch.load_rockspec(filename) + if not valid_rs then + return nil, err + end + + local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") + local new_ver, new_rev + + if version then + new_ver, new_rev = version:match("(.*)%-(%d+)$") + new_rev = tonumber(new_rev) + if not new_rev then + new_ver = version + new_rev = 1 + end + else + new_ver = old_ver + new_rev = tonumber(old_rev) + 1 + end + + + local out_rs = persist.load_into_table(filename) + local out_name = out_rs.package:lower() + out_rs.version = new_ver.."-"..new_rev + if url then + out_rs.source.url = url + check_url_and_update_md5(out_rs, out_name) + else + if new_ver ~= old_ver then + local ok = try_replace(out_rs.source, "url", old_ver, new_ver) + if ok then + check_url_and_update_md5(out_rs, out_name) + else + ok = try_replace(out_rs.source, "tag", old_ver, new_ver) + if not ok then + return nil, "Failed to determine the location of the new version." + end + end + end + end + + if out_rs.build and out_rs.build.type == "module" then + out_rs.build.type = "builtin" + end + + local out_filename = out_name.."-"..new_ver.."-"..new_rev..".rockspec" + + persist.save_from_table(out_filename, out_rs, order) + + util.printout("Wrote "..out_filename) + + local valid_out_rs, err = fetch.load_local_rockspec(out_filename) + if not valid_out_rs then + return nil, "Failed loading generated rockspec: "..err + end + + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/pack.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/pack.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,205 @@ + +--- Module implementing the LuaRocks "pack" command. +-- Creates a rock, packing sources or binaries. +module("luarocks.pack", package.seeall) + +local path = require("luarocks.path") +local repos = require("luarocks.repos") +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local search = require("luarocks.search") + +help_summary = "Create a rock, packing sources or binaries." +help_arguments = "{| []}" +help = [[ +Argument may be a rockspec file, for creating a source rock, +or the name of an installed package, for creating a binary rock. +In the latter case, the app version may be given as a second +argument. +]] + +--- Create a source rock. +-- Packages a rockspec and its required source files in a rock +-- file with the .src.rock extension, which can later be built and +-- installed with the "build" command. +-- @param rockspec_file string: An URL or pathname for a rockspec file. +-- @return string or (nil, string): The filename of the resulting +-- .src.rock file; or nil and an error message. +local function pack_source_rock(rockspec_file) + assert(type(rockspec_file) == "string") + + local rockspec, err = fetch.load_rockspec(rockspec_file) + if err then + return nil, "Error loading rockspec: "..err + end + rockspec_file = rockspec.local_filename + + local name_version = rockspec.name .. "-" .. rockspec.version + local rock_file = fs.absolute_name(name_version .. ".src.rock") + + local source_file, source_dir = fetch.fetch_sources(rockspec, false) + if not source_file then + return nil, source_dir + end + fs.change_dir(source_dir) + + fs.delete(rock_file) + fs.copy(rockspec_file, source_dir) + if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then + return nil, "Failed packing "..rock_file + end + fs.pop_dir() + + return rock_file +end + +local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir) + fs.make_dir(pack_dir) + for file, sub in pairs(file_tree) do + local source = dir.path(deploy_dir, file) + local target = dir.path(pack_dir, file) + if type(sub) == "table" then + local ok, err = copy_back_files(name, version, sub, source, target) + else + local versioned = path.versioned_name(source, deploy_dir, name, version) + if fs.exists(versioned) then + fs.copy(versioned, target) + else + fs.copy(source, target) + end + end + end + return true +end + +-- @param name string: Name of package to pack. +-- @param version string or nil: A version number may also be passed. +-- @return string or (nil, string): The filename of the resulting +-- .src.rock file; or nil and an error message. +local function do_pack_binary_rock(name, version) + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local query = search.make_query(name, version) + query.exact_name = true + local results = {} + + search.manifest_search(results, cfg.rocks_dir, query) + + if not next(results) then + return nil, "'"..name.."' does not seem to be an installed rock." + end + + local versions = results[name] + + if not version then + local first = next(versions) + if next(versions, first) then + return nil, "Please specify which version of '"..name.."' to pack." + end + version = first + end + if not version:match("[^-]+%-%d+") then + return nil, "Expected version "..version.." in version-revision format." + end + + local info = versions[version][1] + + local root = path.root_dir(info.repo) + local prefix = path.install_dir(name, version, root) + + if not fs.exists(prefix) then + return nil, "'"..name.." "..version.."' does not seem to be an installed rock." + end + + local rock_manifest = manif.load_rock_manifest(name, version, root) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + + local name_version = name .. "-" .. version + local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock") + + local temp_dir = fs.make_temp_dir("pack") + fs.copy_contents(prefix, temp_dir) + + local is_binary = false + if rock_manifest.lib then + copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib")) + is_binary = true + end + if rock_manifest.lua then + copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua")) + end + + fs.change_dir(temp_dir) + if not is_binary and not repos.has_binaries(name, version) then + rock_file = rock_file:gsub("%."..cfg.arch:gsub("%-","%%-").."%.", ".all.") + end + fs.delete(rock_file) + if not fs.zip(rock_file, unpack(fs.list_dir())) then + return nil, "Failed packing "..rock_file + end + fs.pop_dir() + fs.delete(temp_dir) + return rock_file +end + +function pack_binary_rock(name, version, cmd, ...) + + -- The --pack-binary-rock option for "luarocks build" basically performs + -- "luarocks build" on a temporary tree and then "luarocks pack". The + -- alternative would require refactoring parts of luarocks.build and + -- luarocks.pack, which would save a few file operations: the idea would be + -- to shave off the final deploy steps from the build phase and the initial + -- collect steps from the pack phase. + + local temp_dir = fs.make_temp_dir("luarocks-build-pack-"..dir.base_name(name)) + if not temp_dir then + return nil, "Failed creating temporary directory." + end + util.schedule_function(fs.delete, temp_dir) + + path.use_tree(temp_dir) + local ok, err = cmd(...) + if not ok then + return nil, err + end + local rname, rversion = path.parse_name(name) + if not rname then + rname, rversion = name, version + end + return do_pack_binary_rock(rname, rversion) +end + +--- Driver function for the "pack" command. +-- @param arg string: may be a rockspec file, for creating a source rock, +-- or the name of an installed package, for creating a binary rock. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function run(...) + local flags, arg, version = util.parse_flags(...) + assert(type(version) == "string" or not version) + if type(arg) ~= "string" then + return nil, "Argument missing, see help." + end + + local file, err + if arg:match(".*%.rockspec") then + file, err = pack_source_rock(arg) + else + file, err = do_pack_binary_rock(arg, version) + end + if err then + return nil, err + else + util.printout("Packed: "..file) + return true + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/path.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/path.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,388 @@ + +--- LuaRocks-specific path handling functions. +-- All paths are configured in this module, making it a single +-- point where the layout of the local installation is defined in LuaRocks. +module("luarocks.path", package.seeall) + +local dir = require("luarocks.dir") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local deps = require("luarocks.deps") + +help_summary = "Return the currently configured package path." +help_arguments = "" +help = [[ +Returns the package path currently configured for this installation +of LuaRocks, formatted as shell commands to update LUA_PATH and +LUA_CPATH. (On Unix systems, you may run: eval `luarocks path`) +]] + +--- Infer rockspec filename from a rock filename. +-- @param rock_name string: Pathname of a rock file. +-- @return string: Filename of the rockspec, without path. +function rockspec_name_from_rock(rock_name) + assert(type(rock_name) == "string") + local base_name = dir.base_name(rock_name) + return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec" +end + +function rocks_dir(tree) + if type(tree) == "string" then + return dir.path(tree, "lib", "luarocks", "rocks") + else + assert(type(tree) == "table") + return tree.rocks_dir or dir.path(tree.root, "lib", "luarocks", "rocks") + end +end + +function root_dir(rocks_dir) + assert(type(rocks_dir) == "string") + + local suffix = dir.path("lib", "luarocks") + return rocks_dir:match("(.*)" .. suffix .. ".*$") +end + +function deploy_bin_dir(tree) + if type(tree) == "string" then + return dir.path(tree, "bin") + else + assert(type(tree) == "table") + return tree.bin_dir or dir.path(tree.root, "bin") + end +end + +function deploy_lua_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.lua_modules_path) + else + assert(type(tree) == "table") + return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path) + end +end + +function deploy_lib_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.lib_modules_path) + else + assert(type(tree) == "table") + return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path) + end +end + +function manifest_file(tree) + if type(tree) == "string" then + return dir.path(tree, "lib", "luarocks", "rocks", "manifest") + else + assert(type(tree) == "table") + return (tree.rocks_dir and dir.path(tree.rocks_dir, "manifest")) or dir.path(tree.root, "lib", "luarocks", "rocks", "manifest") + end +end + +--- Get the directory for all versions of a package in a tree. +-- @param name string: The package name. +-- @return string: The resulting path -- does not guarantee that +-- @param tree string or nil: If given, specifies the local tree to use. +-- the package (and by extension, the path) exists. +function versions_dir(name, tree) + assert(type(name) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name) +end + +--- Get the local installation directory (prefix) for a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function install_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version) +end + +--- Get the local filename of the rockspec of an installed rock. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the file) exists. +function rockspec_file(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, name.."-"..version..".rockspec") +end + +--- Get the local filename of the rock_manifest file of an installed rock. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the file) exists. +function rock_manifest_file(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "rock_manifest") +end + +--- Get the local installation directory for C libraries of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function lib_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "lib") +end + +--- Get the local installation directory for Lua modules of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function lua_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "lua") +end + +--- Get the local installation directory for documentation of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function doc_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "doc") +end + +--- Get the local installation directory for configuration files of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function conf_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "conf") +end + +--- Get the local installation directory for command-line scripts +-- of a package. +-- @param name string: The package name. +-- @param version string: The package version. +-- @param tree string or nil: If given, specifies the local tree to use. +-- @return string: The resulting path -- does not guarantee that +-- the package (and by extension, the path) exists. +function bin_dir(name, version, tree) + assert(type(name) == "string") + assert(type(version) == "string") + tree = tree or cfg.root_dir + return dir.path(rocks_dir(tree), name, version, "bin") +end + +--- Extract name, version and arch of a rock filename, +-- or name, version and "rockspec" from a rockspec name. +-- @param file_name string: pathname of a rock or rockspec +-- @return (string, string, string) or nil: name, version and arch +-- or nil if name could not be parsed +function parse_name(file_name) + assert(type(file_name) == "string") + if file_name:match("%.rock$") then + return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.([^.]+)%.rock$") + else + return dir.base_name(file_name):match("(.*)-([^-]+-%d+)%.(rockspec)") + end +end + +--- Make a rockspec or rock URL. +-- @param pathname string: Base URL or pathname. +-- @param name string: Package name. +-- @param version string: Package version. +-- @param arch string: Architecture identifier, or "rockspec" or "installed". +-- @return string: A URL or pathname following LuaRocks naming conventions. +function make_url(pathname, name, version, arch) + assert(type(pathname) == "string") + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(arch) == "string") + + local filename = name.."-"..version + if arch == "installed" then + filename = dir.path(name, version, filename..".rockspec") + elseif arch == "rockspec" then + filename = filename..".rockspec" + else + filename = filename.."."..arch..".rock" + end + return dir.path(pathname, filename) +end + +--- Convert a pathname to a module identifier. +-- In Unix, for example, a path "foo/bar/baz.lua" is converted to +-- "foo.bar.baz"; "bla/init.lua" returns "bla"; "foo.so" returns "foo". +-- @param file string: Pathname of module +-- @return string: The module identifier, or nil if given path is +-- not a conformant module path (the function does not check if the +-- path actually exists). +function path_to_module(file) + assert(type(file) == "string") + + local name = file:match("(.*)%."..cfg.lua_extension.."$") + if name then + name = name:gsub(dir.separator, ".") + local init = name:match("(.*)%.init$") + if init then + name = init + end + else + name = file:match("(.*)%."..cfg.lib_extension.."$") + if name then + name = name:gsub(dir.separator, ".") + end + end + if not name then name = file end + name = name:gsub("^%.+", ""):gsub("%.+$", "") + return name +end + +--- Obtain the directory name where a module should be stored. +-- For example, on Unix, "foo.bar.baz" will return "foo/bar". +-- @param mod string: A module name in Lua dot-separated format. +-- @return string: A directory name using the platform's separator. +function module_to_path(mod) + assert(type(mod) == "string") + return (mod:gsub("[^.]*$", ""):gsub("%.", dir.separator)) +end + +--- Set up path-related variables for a given rock. +-- Create a "variables" table in the rockspec table, containing +-- adjusted variables according to the configuration file. +-- @param rockspec table: The rockspec table. +function configure_paths(rockspec) + assert(type(rockspec) == "table") + local vars = {} + for k,v in pairs(cfg.variables) do + vars[k] = v + end + local name, version = rockspec.name, rockspec.version + vars.PREFIX = install_dir(name, version) + vars.LUADIR = lua_dir(name, version) + vars.LIBDIR = lib_dir(name, version) + vars.CONFDIR = conf_dir(name, version) + vars.BINDIR = bin_dir(name, version) + vars.DOCDIR = doc_dir(name, version) + rockspec.variables = vars +end + +function versioned_name(file, prefix, name, version) + assert(type(file) == "string") + assert(type(name) == "string") + assert(type(version) == "string") + + local rest = file:sub(#prefix+1):gsub("^/*", "") + local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_") + return dir.path(prefix, name_version.."-"..rest) +end + +function use_tree(tree) + cfg.root_dir = tree + cfg.rocks_dir = rocks_dir(tree) + cfg.deploy_bin_dir = deploy_bin_dir(tree) + cfg.deploy_lua_dir = deploy_lua_dir(tree) + cfg.deploy_lib_dir = deploy_lib_dir(tree) +end + +function map_trees(deps_mode, fn, ...) + local result = {} + if deps_mode == "one" then + table.insert(result, (fn(cfg.root_dir, ...)) or 0) + elseif deps_mode == "all" or deps_mode == "order" then + local use = false + if deps_mode == "all" then + use = true + end + for _, tree in ipairs(cfg.rocks_trees) do + if dir.normalize(tree) == dir.normalize(cfg.root_dir) then + use = true + end + if use then + table.insert(result, (fn(tree, ...)) or 0) + end + end + end + return result +end + +--- Return the pathname of the file that would be loaded for a module, indexed. +-- @param module_name string: module name (eg. "socket.core") +-- @param name string: name of the package (eg. "luasocket") +-- @param version string: version number (eg. "2.0.2-1") +-- @param tree string: repository path (eg. "/usr/local") +-- @param i number: the index, 1 if version is the current default, > 1 otherwise. +-- This is done this way for use by select_module in luarocks.loader. +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function which_i(module_name, name, version, tree, i) + local deploy_dir + if module_name:match("%.lua$") then + deploy_dir = deploy_lua_dir(tree) + module_name = dir.path(deploy_dir, module_name) + else + deploy_dir = deploy_lib_dir(tree) + module_name = dir.path(deploy_dir, module_name) + end + if i > 1 then + module_name = versioned_name(module_name, deploy_dir, name, version) + end + return module_name +end + +--- Return the pathname of the file that would be loaded for a module, +-- returning the versioned pathname if given version is not the default version +-- in the given manifest. +-- @param module_name string: module name (eg. "socket.core") +-- @param name string: name of the package (eg. "luasocket") +-- @param version string: version number (eg. "2.0.2-1") +-- @param tree string: repository path (eg. "/usr/local") +-- @param manifest table: the manifest table for the tree. +-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") +function which(module_name, filename, name, version, tree, manifest) + local versions = manifest.modules[module_name] + assert(versions) + for i, name_version in ipairs(versions) do + if name_version == name.."/"..version then + return which_i(filename, name, version, tree, i):gsub("//", "/") + end + end + assert(false) +end + +--- Driver function for "path" command. +-- @return boolean This function always succeeds. +function run(...) + local flags = util.parse_flags(...) + local deps_mode = deps.get_deps_mode(flags) + + util.printout(cfg.export_lua_path:format(util.remove_path_dupes(package.path, ';'))) + util.printout(cfg.export_lua_cpath:format(util.remove_path_dupes(package.cpath, ';'))) + if flags["bin"] then + local bin_dirs = map_trees(deps_mode, deploy_bin_dir) + table.insert(bin_dirs, 1, os.getenv("PATH")) + util.printout(cfg.export_path:format(util.remove_path_dupes(table.concat(bin_dirs, cfg.export_path_separator), cfg.export_path_separator))) + end + return true +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/persist.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/persist.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,173 @@ + +--- Utility module for loading files into tables and +-- saving tables into files. +-- Implemented separately to avoid interdependencies, +-- as it is used in the bootstrapping stage of the cfg module. +module("luarocks.persist", package.seeall) + +local util = require("luarocks.util") + +--- Load a Lua file containing assignments, storing them in a table. +-- The global environment is not propagated to the loaded file. +-- @param filename string: the name of the file. +-- @param tbl table or nil: if given, this table is used to store +-- loaded values. +-- @return table or (nil, string): a table with the file's assignments +-- as fields, or nil and a message in case of errors. +function load_into_table(filename, tbl) + assert(type(filename) == "string") + assert(type(tbl) == "table" or not tbl) + + local result, chunk, ran, err + local result = tbl or {} + if setfenv then -- Lua 5.1 + chunk, err = loadfile(filename) + if chunk then + setfenv(chunk, result) + ran, err = pcall(chunk) + end + else -- Lua 5.2 + chunk, err = loadfile(filename, "t", result) + if chunk then + ran, err = pcall(chunk) + end + end + + if not chunk then + if err:sub(1,5) ~= filename:sub(1,5) then + return false, err + end + return nil, "Error loading file: "..err + end + if not ran then + return nil, "Error running file: "..err + end + return result +end + +local write_table + +--- Write a value as Lua code, invoking write_table. +-- This function handles only numbers, strings and tables +-- are keys (tables are handled recursively). +-- @param out userdata: a file object, open for writing. +-- @param v: the value to be written. +-- @param level number: the indentation level +-- @param sub_order table: optional prioritization table +-- @see write_table +local function write_value(out, v, level, sub_order) + if type(v) == "table" then + write_table(out, v, level + 1, sub_order) + elseif type(v) == "string" then + if v:match("\n") then + local open, close = "[[", "]]" + local equals = 0 + while v:find(open,1,true) or v:find(close,1,true) do + equals = equals + 1 + local eqs = ("="):rep(equals) + open, close = "["..eqs.."[", "]"..eqs.."]" + end + out:write(open.."\n"..v..close) + else + out:write("\""..v:gsub("\"", "\\\"").."\"") + end + else + out:write(tostring(v)) + end +end + +--- Write a table as Lua code representing a table to disk +-- (that is, in curly brackets notation). +-- This function handles only numbers, strings and tables +-- are keys (tables are handled recursively). +-- @param out userdata: a file object, open for writing. +-- @param tbl table: the table to be written. +-- @param level number: the indentation level +-- @param field_order table: optional prioritization table +write_table = function(out, tbl, level, field_order) + out:write("{") + local sep = "\n" + local indentation = " " + local indent = true + local i = 1 + for k, v, sub_order in util.sortedpairs(tbl, field_order) do + out:write(sep) + if indent then + for n = 1,level do out:write(indentation) end + end + sep = ",\n" + indent = true + if type(k) == "number" then + if k ~= i then + out:write("["..tostring(k).."]=") + else + i = i + 1 + end + indent = false + sep = ", " + elseif type(k) == "table" then + out:write("[") + write_table(out, k, level + 1) + out:write("] = ") + else + if k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then + out:write(k.." = ") + else + out:write("['"..k:gsub("'", "\\'").."'] = ") + end + end + write_value(out, v, level, sub_order) + end + if sep ~= "\n" then + out:write("\n") + for n = 1,level-1 do out:write(indentation) end + end + out:write("}") +end + +--- Writes a table to an io-like object. +-- @param out userdata: a file object, open for writing. +-- @param tbl table: the table to be written. +-- @param field_order table: optional prioritization table +-- @return userdata The file object originally passed in as the `out` parameter. +local function write_table(out, tbl, field_order) + for k, v, sub_order in util.sortedpairs(tbl, field_order) do + out:write(k.." = ") + write_value(out, v, 0, sub_order) + out:write("\n") + end + return out +end + +--- Save the contents of a table to a string. +-- Each element of the table is saved as a global assignment. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param tbl table: the table containing the data to be written +-- @param field_order table: an optional array indicating the order of top-level fields. +-- @return string +function save_from_table_to_string(tbl, field_order) + local out = {buffer = {}} + function out:write(data) table.insert(self.buffer, data) end + write_table(out, tbl, field_order) + return table.concat(out.buffer) +end + +--- Save the contents of a table in a file. +-- Each element of the table is saved as a global assignment. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param filename string: the output filename +-- @param tbl table: the table containing the data to be written +-- @param field_order table: an optional array indicating the order of top-level fields. +-- @return boolean or (nil, string): true if successful, or nil and a +-- message in case of errors. +function save_from_table(filename, tbl, field_order) + local out = io.open(filename, "w") + if not out then + return nil, "Cannot create file at "..filename + end + write_table(out, tbl, field_order) + out:close() + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/purge.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/purge.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,48 @@ + +--- Module implementing the LuaRocks "purge" command. +-- Remove all rocks from a given tree. +module("luarocks.purge", package.seeall) + +local util = require("luarocks.util") +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local search = require("luarocks.search") +local deps = require("luarocks.deps") +local repos = require("luarocks.repos") +local manif = require("luarocks.manif") +local cfg = require("luarocks.cfg") + +help_summary = "Remove all installed rocks from a tree." +help_arguments = "--tree=" +help = [[ +This command removes all rocks from a given tree. + +The --tree argument is mandatory: luarocks purge does not +assume a default tree. +]] + +function run(...) + local flags = util.parse_flags(...) + + local tree = flags["tree"] + + if type(tree) ~= "string" then + return nil, "The --tree argument is mandatory, see help." + end + + local results = {} + local query = search.make_query("") + query.exact_name = false + search.manifest_search(results, path.rocks_dir(tree), query) + + for package, versions in util.sortedpairs(results) do + for version, repositories in util.sortedpairs(versions, function(a,b) return deps.compare_versions(b,a) end) do + util.printout("Removing "..package.." "..version.."...") + local ok, err = repos.delete_version(package, version, true) + if not ok then + util.printerr(err) + end + end + end + return manif.make_manifest(cfg.rocks_dir, "one") +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/refresh_cache.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/refresh_cache.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,30 @@ + +--- Module implementing the luarocks-admin "refresh_cache" command. +module("luarocks.refresh_cache", package.seeall) + +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local cache = require("luarocks.cache") + +help_summary = "Refresh local cache of a remote rocks server." +help_arguments = "[--from=]" +help = [[ +The flag --from indicates which server to use. +If not given, the default server set in the upload_server variable +from the configuration file is used instead. +]] + +function run(...) + local flags = util.parse_flags(...) + local server, upload_server = cache.get_upload_server(flags["server"]) + if not server then return nil, upload_server end + local download_url = cache.get_server_urls(server, upload_server) + + local ok, err = cache.refresh_local_cache(server, download_url, cfg.upload_user, cfg.upload_password) + if not ok then + return nil, err + else + return true + end +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/remove.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/remove.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,137 @@ + +--- Module implementing the LuaRocks "remove" command. +-- Uninstalls rocks. +module("luarocks.remove", package.seeall) + +local search = require("luarocks.search") +local deps = require("luarocks.deps") +local fetch = require("luarocks.fetch") +local repos = require("luarocks.repos") +local path = require("luarocks.path") +local util = require("luarocks.util") +local cfg = require("luarocks.cfg") +local manif = require("luarocks.manif") +local fs = require("luarocks.fs") + +help_summary = "Uninstall a rock." +help_arguments = "[--force] []" +help = [[ +Argument is the name of a rock to be uninstalled. +If a version is not given, try to remove all versions at once. +Will only perform the removal if it does not break dependencies. +To override this check and force the removal, use --force. +]] + +--- Obtain a list of packages that depend on the given set of packages +-- (where all packages of the set are versions of one program). +-- @param name string: the name of a program +-- @param versions array of string: the versions to be deleted. +-- @return array of string: an empty table if no packages depend on any +-- of the given list, or an array of strings in "name/version" format. +local function check_dependents(name, versions, deps_mode) + local dependents = {} + local blacklist = {} + blacklist[name] = {} + for version, _ in pairs(versions) do + blacklist[name][version] = true + end + local local_rocks = {} + local query_all = search.make_query("") + query_all.exact_name = false + search.manifest_search(local_rocks, cfg.rocks_dir, query_all) + local_rocks[name] = nil + for rock_name, rock_versions in pairs(local_rocks) do + for rock_version, _ in pairs(rock_versions) do + local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version)) + if rockspec then + local _, missing = deps.match_deps(rockspec, blacklist, deps_mode) + if missing[name] then + table.insert(dependents, { name = rock_name, version = rock_version }) + end + end + end + end + return dependents +end + +--- Delete given versions of a program. +-- @param name string: the name of a program +-- @param versions array of string: the versions to be deleted. +-- @return boolean or (nil, string): true on success or nil and an error message. +local function delete_versions(name, versions) + + for version, _ in pairs(versions) do + util.printout("Removing "..name.." "..version.."...") + local ok, err = repos.delete_version(name, version) + if not ok then return nil, err end + end + + return true +end + +--- Driver function for the "remove" command. +-- @param name string: name of a rock. If a version is given, refer to +-- a specific version; otherwise, try to remove all versions. +-- @param version string: When passing a package name, a version number +-- may also be given. +-- @return boolean or (nil, string): True if removal was +-- successful, nil and an error message otherwise. +function run(...) + local flags, name, version = util.parse_flags(...) + + if type(name) ~= "string" then + return nil, "Argument missing, see help." + end + + local deps_mode = flags["deps-mode"] or cfg.deps_mode + + local ok, err = fs.check_command_permissions(flags) + if not ok then return nil, err end + + local results = {} + search.manifest_search(results, cfg.rocks_dir, search.make_query(name, version)) + + local versions = results[name] + if not versions then + return nil, "Could not find rock '"..name..(version and " "..version or "").."' in local tree." + else + local version = next(versions) + local second = next(versions, version) + + util.printout("Checking stability of dependencies on the absence of") + util.printout(name.." "..table.concat(util.keys(versions), ", ").."...") + util.printout() + + local dependents = check_dependents(name, versions, deps_mode) + + if #dependents == 0 or flags["force"] then + if #dependents > 0 then + util.printerr("The following packages may be broken by this forced removal:") + for _, dependent in ipairs(dependents) do + util.printerr(dependent.name.." "..dependent.version) + end + util.printerr() + end + local ok, err = delete_versions(name, versions) + if not ok then return nil, err end + ok, err = manif.make_manifest(cfg.rocks_dir, deps_mode) + if not ok then return nil, err end + else + if not second then + util.printerr("Will not remove "..name.." "..version..".") + util.printerr("Removing it would break dependencies for: ") + else + util.printerr("Will not remove all versions of "..name..".") + util.printerr("Removing them would break dependencies for: ") + end + for _, dependent in ipairs(dependents) do + util.printerr(dependent.name.." "..dependent.version) + end + util.printerr() + util.printerr("Use --force to force removal (warning: this may break modules).") + return nil, "Failed removing." + end + end + util.printout("Removal successful.") + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/repos.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/repos.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,303 @@ + +--- Functions for managing the repository on disk. +module("luarocks.repos", package.seeall) + +local fs = require("luarocks.fs") +local path = require("luarocks.path") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local manif = require("luarocks.manif") +local deps = require("luarocks.deps") + +--- Get all installed versions of a package. +-- @param name string: a package name. +-- @return table or nil: An array of strings listing installed +-- versions of a package, or nil if none is available. +local function get_installed_versions(name) + assert(type(name) == "string") + + local dirs = fs.list_dir(path.versions_dir(name)) + return (dirs and #dirs > 0) and dirs or nil +end + +--- Check if a package exists in a local repository. +-- Version numbers are compared as exact string comparison. +-- @param name string: name of package +-- @param version string: package version in string format +-- @return boolean: true if a package is installed, +-- false otherwise. +function is_installed(name, version) + assert(type(name) == "string") + assert(type(version) == "string") + + return fs.is_dir(path.install_dir(name, version)) +end + +local function recurse_rock_manifest_tree(file_tree, action) + assert(type(file_tree) == "table") + assert(type(action) == "function") + local function do_recurse_rock_manifest_tree(tree, parent_path, parent_module) + + for file, sub in pairs(tree) do + if type(sub) == "table" then + local ok, err = do_recurse_rock_manifest_tree(sub, parent_path..file.."/", parent_module..file..".") + if not ok then return nil, err end + else + local ok, err = action(parent_path, parent_module, file) + if not ok then return nil, err end + end + end + return true + end + return do_recurse_rock_manifest_tree(file_tree, "", "") +end + +local function store_package_data(result, name, file_tree) + if not file_tree then return end + return recurse_rock_manifest_tree(file_tree, + function(parent_path, parent_module, file) + local pathname = parent_path..file + result[path.path_to_module(pathname)] = pathname + return true + end + ) +end + +--- Obtain a list of modules within an installed package. +-- @param package string: The package name; for example "luasocket" +-- @param version string: The exact version number including revision; +-- for example "2.0.1-1". +-- @return table: A table of modules where keys are module identifiers +-- in "foo.bar" format and values are pathnames in architecture-dependent +-- "foo/bar.so" format. If no modules are found or if package or version +-- are invalid, an empty table is returned. +function package_modules(package, version) + assert(type(package) == "string") + assert(type(version) == "string") + + local result = {} + local rock_manifest = manif.load_rock_manifest(package, version) + store_package_data(result, package, rock_manifest.lib) + store_package_data(result, package, rock_manifest.lua) + return result +end + +--- Obtain a list of command-line scripts within an installed package. +-- @param package string: The package name; for example "luasocket" +-- @param version string: The exact version number including revision; +-- for example "2.0.1-1". +-- @return table: A table of items where keys are command names +-- as strings and values are pathnames in architecture-dependent +-- ".../bin/foo" format. If no modules are found or if package or version +-- are invalid, an empty table is returned. +function package_commands(package, version) + assert(type(package) == "string") + assert(type(version) == "string") + + local result = {} + local rock_manifest = manif.load_rock_manifest(package, version) + store_package_data(result, package, rock_manifest.bin) + return result +end + + +--- Check if a rock contains binary executables. +-- @param name string: name of an installed rock +-- @param version string: version of an installed rock +-- @return boolean: returns true if rock contains platform-specific +-- binary executables, or false if it is a pure-Lua rock. +function has_binaries(name, version) + assert(type(name) == "string") + assert(type(version) == "string") + + local rock_manifest = manif.load_rock_manifest(name, version) + if rock_manifest.bin then + for name, md5 in pairs(rock_manifest.bin) do + -- TODO verify that it is the same file. If it isn't, find the actual command. + if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, name)) then + return true + end + end + end + return false +end + +function run_hook(rockspec, hook_name) + assert(type(rockspec) == "table") + assert(type(hook_name) == "string") + + local hooks = rockspec.hooks + if not hooks then + return true + end + if not hooks.substituted_variables then + util.variable_substitutions(hooks, rockspec.variables) + hooks.substituted_variables = true + end + local hook = hooks[hook_name] + if hook then + util.printout(hook) + if not fs.execute(hook) then + return nil, "Failed running "..hook_name.." hook." + end + end + return true +end + +local function install_binary(source, target) + assert(type(source) == "string") + assert(type(target) == "string") + + local match = source:match("%.lua$") + local file, ok, err + if not match then + file = io.open(source) + end + if match or (file and file:read():match("^#!.*lua.*")) then + ok, err = fs.wrap_script(source, target) + else + ok, err = fs.copy_binary(source, target) + end + if file then file:close() end + return ok, err +end + +local function resolve_conflict(target, deploy_dir, name, version) + local cname, cversion = manif.find_current_provider(target) + if not cname then + return nil, cversion + end + if name ~= cname or deps.compare_versions(version, cversion) then + local versioned = path.versioned_name(target, deploy_dir, cname, cversion) + fs.make_dir(dir.dir_name(versioned)) + fs.move(target, versioned) + return target + else + return path.versioned_name(target, deploy_dir, name, version) + end +end + +function should_wrap_bin_scripts(rockspec) + assert(type(rockspec) == "table") + + if cfg.wrap_bin_scripts ~= nil then + return cfg.wrap_bin_scripts + end + if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then + return false + end + return true +end + +function deploy_files(name, version, wrap_bin_scripts) + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(wrap_bin_scripts) == "boolean") + + local function deploy_file_tree(file_tree, source_dir, deploy_dir, move_fn) + if not move_fn then + move_fn = fs.move + end + return recurse_rock_manifest_tree(file_tree, + function(parent_path, parent_module, file) + local source = dir.path(source_dir, parent_path, file) + local target = dir.path(deploy_dir, parent_path, file) + local ok, err + if fs.exists(target) then + local new_target, err = resolve_conflict(target, deploy_dir, name, version) + if err == "untracked" then + fs.delete(target) + elseif err then + return nil, err.." Cannot install new version." + else + target = new_target + end + end + fs.make_dir(dir.dir_name(target)) + ok, err = move_fn(source, target) + fs.remove_dir_tree_if_empty(dir.dir_name(source)) + if not ok then return nil, err end + return true + end + ) + end + + local rock_manifest = manif.load_rock_manifest(name, version) + + local ok, err = true + if rock_manifest.bin then + local move_bin_fn = wrap_bin_scripts and install_binary or fs.copy_binary + ok, err = deploy_file_tree(rock_manifest.bin, path.bin_dir(name, version), cfg.deploy_bin_dir, move_bin_fn) + end + if ok and rock_manifest.lua then + ok, err = deploy_file_tree(rock_manifest.lua, path.lua_dir(name, version), cfg.deploy_lua_dir) + end + if ok and rock_manifest.lib then + ok, err = deploy_file_tree(rock_manifest.lib, path.lib_dir(name, version), cfg.deploy_lib_dir) + end + return ok, err +end + +--- Delete a package from the local repository. +-- Version numbers are compared as exact string comparison. +-- @param name string: name of package +-- @param version string: package version in string format +-- @param quick boolean: do not try to fix the versioned name +-- of another version that provides the same module that +-- was deleted. This is used during 'purge', as every module +-- will be eventually deleted. +function delete_version(name, version, quick) + assert(type(name) == "string") + assert(type(version) == "string") + + local function delete_deployed_file_tree(file_tree, deploy_dir) + return recurse_rock_manifest_tree(file_tree, + function(parent_path, parent_module, file) + local target = dir.path(deploy_dir, parent_path, file) + local versioned = path.versioned_name(target, deploy_dir, name, version) + if fs.exists(versioned) then + local ok = fs.delete(versioned) + fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) + if not ok then return nil, "Failed deleting "..versioned end + else + local ok = fs.delete(target) + if not quick then + local next_name, next_version = manif.find_next_provider(target) + if next_name then + local versioned = path.versioned_name(target, deploy_dir, next_name, next_version) + fs.move(versioned, target) + fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) + end + end + fs.remove_dir_tree_if_empty(dir.dir_name(target)) + if not ok then return nil, "Failed deleting "..target end + end + return true + end + ) + end + + local rock_manifest = manif.load_rock_manifest(name, version) + if not rock_manifest then + return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?" + end + + local ok, err = true + if rock_manifest.bin then + ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir) + end + if ok and rock_manifest.lua then + ok, err = delete_deployed_file_tree(rock_manifest.lua, cfg.deploy_lua_dir) + end + if ok and rock_manifest.lib then + ok, err = delete_deployed_file_tree(rock_manifest.lib, cfg.deploy_lib_dir) + end + if err then return nil, err end + + fs.delete(path.install_dir(name, version)) + if not get_installed_versions(name) then + fs.delete(dir.path(cfg.rocks_dir, name)) + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/require.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/require.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,6 @@ +--- Retained for compatibility reasons only. Use luarocks.loader instead. +local require, pairs = require, pairs +module("luarocks.require") +for k,v in pairs(require("luarocks.loader")) do + _M[k] = v +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/search.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/search.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,386 @@ + +--- Module implementing the LuaRocks "search" command. +-- Queries LuaRocks servers. +module("luarocks.search", package.seeall) + +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local manif = require("luarocks.manif") +local deps = require("luarocks.deps") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") + +help_summary = "Query the LuaRocks servers." +help_arguments = "[--source] [--binary] { [] | --all }" +help = [[ +--source Return only rockspecs and source rocks, + to be used with the "build" command. +--binary Return only pure Lua and binary rocks (rocks that can be used + with the "install" command without requiring a C toolchain). +--all List all contents of the server that are suitable to + this platform, do not filter by name. +]] + +--- Convert the arch field of a query table to table format. +-- @param query table: A query table. +local function query_arch_as_table(query) + local format = type(query.arch) + if format == "table" then + return + elseif format == "nil" then + local accept = {} + accept["src"] = true + accept["all"] = true + accept["rockspec"] = true + accept["installed"] = true + accept[cfg.arch] = true + query.arch = accept + elseif format == "string" then + local accept = {} + for a in query.arch:gmatch("[%w_-]+") do + accept[a] = true + end + query.arch = accept + end +end + +--- Store a search result (a rock or rockspec) in the results table. +-- @param results table: The results table, where keys are package names and +-- versions are tables matching version strings to an array of servers. +-- @param name string: Package name. +-- @param version string: Package version. +-- @param arch string: Architecture of rock ("all", "src" or platform +-- identifier), "rockspec" or "installed" +-- @param repo string: Pathname of a local repository of URL of +-- rocks server. +local function store_result(results, name, version, arch, repo) + assert(type(results) == "table") + assert(type(name) == "string") + assert(type(version) == "string") + assert(type(arch) == "string") + assert(type(repo) == "string") + + if not results[name] then results[name] = {} end + if not results[name][version] then results[name][version] = {} end + table.insert(results[name][version], { + arch = arch, + repo = repo + }) +end + +--- Test the name field of a query. +-- If query has a boolean field exact_name set to false, +-- then substring match is performed; otherwise, exact string +-- comparison is done. +-- @param query table: A query in dependency table format. +-- @param name string: A package name. +-- @return boolean: True if names match, false otherwise. +local function match_name(query, name) + assert(type(query) == "table") + assert(type(name) == "string") + if query.exact_name == false then + return name:find(query.name, 0, true) and true or false + else + return name == query.name + end +end + +--- Store a match in a results table if version matches query. +-- Name, version, arch and repository path are stored in a given +-- table, optionally checking if version and arch (if given) match +-- a query. +-- @param results table: The results table, where keys are package names and +-- versions are tables matching version strings to an array of servers. +-- @param repo string: URL or pathname of the repository. +-- @param name string: The name of the package being tested. +-- @param version string: The version of the package being tested. +-- @param arch string: The arch of the package being tested. +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +local function store_if_match(results, repo, name, version, arch, query) + if match_name(query, name) then + if query.arch[arch] or query.arch["any"] then + if deps.match_constraints(deps.parse_version(version), query.constraints) then + store_result(results, name, version, arch, repo) + end + end + end +end + +--- Perform search on a local repository. +-- @param repo string: The pathname of the local repository. +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +-- @param results table or nil: If given, this table will store the +-- results; if not given, a new table will be created. +-- @param table: The results table, where keys are package names and +-- versions are tables matching version strings to an array of servers. +-- If a table was given in the "results" parameter, that is the result value. +function disk_search(repo, query, results) + assert(type(repo) == "string") + assert(type(query) == "table") + assert(type(results) == "table" or not results) + + local fs = require("luarocks.fs") + + if not results then + results = {} + end + query_arch_as_table(query) + + for _, name in pairs(fs.list_dir(repo)) do + local pathname = dir.path(repo, name) + local rname, rversion, rarch = path.parse_name(name) + if fs.is_dir(pathname) then + for _, version in pairs(fs.list_dir(pathname)) do + if version:match("-%d+$") then + store_if_match(results, repo, name, version, "installed", query) + end + end + elseif rname then + store_if_match(results, repo, rname, rversion, rarch, query) + end + end + return results +end + +--- Perform search on a rocks server. +-- @param results table: The results table, where keys are package names and +-- versions are tables matching version strings to an array of servers. +-- @param repo string: The URL of the rocks server. +-- @param query table: A table describing the query in dependency +-- format (for example, {name = "filesystem", exact_name = false, +-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). +-- If the arch field is omitted, the local architecture (cfg.arch) +-- is used. The special value "any" is also recognized, returning all +-- matches regardless of architecture. +-- @return true or, in case of errors, nil and an error message. +function manifest_search(results, repo, query) + assert(type(results) == "table") + assert(type(repo) == "string") + assert(type(query) == "table") + + query_arch_as_table(query) + local manifest, err = manif.load_manifest(repo) + if not manifest then + return nil, "Failed loading manifest: "..err + end + for name, versions in pairs(manifest.repository) do + for version, items in pairs(versions) do + for _, item in ipairs(items) do + store_if_match(results, repo, name, version, item.arch, query) + end + end + end + return true +end + +--- Search on all configured rocks servers. +-- @param query table: A dependency query. +-- @return table: A table where keys are package names +-- and values are tables matching version strings to an array of +-- rocks servers; if no results are found, an empty table is returned. +function search_repos(query) + assert(type(query) == "table") + + local results = {} + for _, repo in ipairs(cfg.rocks_servers) do + if type(repo) == "string" then + repo = { repo } + end + for _, mirror in ipairs(repo) do + local protocol, pathname = dir.split_url(mirror) + if protocol == "file" then + mirror = pathname + end + local ok, err = manifest_search(results, mirror, query) + if ok then + break + else + util.warning("Failed searching manifest: "..err) + end + end + end + return results +end + +--- Prepare a query in dependency table format. +-- @param name string: The query name. +-- @param version string or nil: +-- @return table: A query in table format +function make_query(name, version) + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local query = { + name = name, + constraints = {} + } + if version then + table.insert(query.constraints, { op = "==", version = deps.parse_version(version)}) + end + return query +end + +--- Get the URL for the latest in a set of versions. +-- @param name string: The package name to be used in the URL. +-- @param versions table: An array of version informations, as stored +-- in search results tables. +-- @return string or nil: the URL for the latest version if one could +-- be picked, or nil. +local function pick_latest_version(name, versions) + assert(type(name) == "string") + assert(type(versions) == "table") + + local vtables = {} + for v, _ in pairs(versions) do + table.insert(vtables, deps.parse_version(v)) + end + table.sort(vtables) + local version = vtables[#vtables].string + local items = versions[version] + if items then + local pick = 1 + for i, item in ipairs(items) do + if (item.arch == 'src' and items[pick].arch == 'rockspec') + or (item.arch ~= 'src' and item.arch ~= 'rockspec') then + pick = i + end + end + return path.make_url(items[pick].repo, name, version, items[pick].arch) + end + return nil +end + +--- Attempt to get a single URL for a given search. +-- @param query table: A dependency query. +-- @return string or table or (nil, string): URL for matching rock if +-- a single one was found, a table of candidates if it could not narrow to +-- a single result, or nil followed by an error message. +function find_suitable_rock(query) + assert(type(query) == "table") + + local results = search_repos(query) + local first = next(results) + if not first then + return nil, "No results matching query were found." + elseif not next(results, first) then + return pick_latest_version(query.name, results[first]) + else + return results + end +end + +--- Print a list of rocks/rockspecs on standard output. +-- @param results table: A table where keys are package names and versions +-- are tables matching version strings to an array of rocks servers. +-- @param porcelain boolean or nil: A flag to force machine-friendly output. +function print_results(results, porcelain) + assert(type(results) == "table") + assert(type(porcelain) == "boolean" or not porcelain) + + for package, versions in util.sortedpairs(results) do + if not porcelain then + util.printout(package) + end + for version, repos in util.sortedpairs(versions, deps.compare_versions) do + for _, repo in ipairs(repos) do + if porcelain then + util.printout(package, version, repo.arch, repo.repo) + else + util.printout(" "..version.." ("..repo.arch..") - "..repo.repo) + end + end + end + if not porcelain then + util.printout() + end + end +end + +--- Splits a list of search results into two lists, one for "source" results +-- to be used with the "build" command, and one for "binary" results to be +-- used with the "install" command. +-- @param results table: A search results table. +-- @return (table, table): Two tables, one for source and one for binary +-- results. +local function split_source_and_binary_results(results) + local sources, binaries = {}, {} + for name, versions in pairs(results) do + for version, repositories in pairs(versions) do + for _, repo in ipairs(repositories) do + local where = sources + if repo.arch == "all" or repo.arch == cfg.arch then + where = binaries + end + store_result(where, name, version, repo.arch, repo.repo) + end + end + end + return sources, binaries +end + +--- Given a name and optionally a version, try to find in the rocks +-- servers a single .src.rock or .rockspec file that satisfies +-- the request, and run the given function on it; or display to the +-- user possibilities if it couldn't narrow down a single match. +-- @param action function: A function that takes a .src.rock or +-- .rockspec URL as a parameter. +-- @param name string: A rock name +-- @param version string or nil: A version number may also be given. +-- @return The result of the action function, or nil and an error message. +function act_on_src_or_rockspec(action, name, version, ...) + assert(type(action) == "function") + assert(type(name) == "string") + assert(type(version) == "string" or not version) + + local query = make_query(name, version) + query.arch = "src|rockspec" + local results, err = find_suitable_rock(query) + if type(results) == "string" then + return action(results, ...) + else + return nil, "Could not find a result named "..name..(version and " "..version or "").."." + end +end + +--- Driver function for "search" command. +-- @param name string: A substring of a rock name to search. +-- @param version string or nil: a version may also be passed. +-- @return boolean or (nil, string): True if build was successful; nil and an +-- error message otherwise. +function run(...) + local flags, name, version = util.parse_flags(...) + + if flags["all"] then + name, version = "", nil + end + + if type(name) ~= "string" and not flags["all"] then + return nil, "Enter name and version or use --all; see help." + end + + local query = make_query(name:lower(), version) + query.exact_name = false + local results, err = search_repos(query) + local porcelain = flags["porcelain"] + util.title("Search results:", porcelain, "=") + local sources, binaries = split_source_and_binary_results(results) + if next(sources) and not flags["binary"] then + util.title("Rockspecs and source rocks:", porcelain) + print_results(sources, porcelain) + end + if next(binaries) and not flags["source"] then + util.title("Binary and pure-Lua rocks:", porcelain) + print_results(binaries, porcelain) + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/show.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/show.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,156 @@ + +--- Module implementing the LuaRocks "show" command. +-- Shows information about an installed rock. +module("luarocks.show", package.seeall) + +local search = require("luarocks.search") +local cfg = require("luarocks.cfg") +local util = require("luarocks.util") +local path = require("luarocks.path") +local dir = require("luarocks.dir") +local deps = require("luarocks.deps") +local fetch = require("luarocks.fetch") +local manif = require("luarocks.manif") +help_summary = "Shows information about an installed rock." + +help = [[ + is an existing package name. +Without any flags, show all module information. +With these flags, return only the desired information: + +--home home page of project +--modules all modules provided by this package as used by require() +--deps packages this package depends on +--rockspec the full path of the rockspec file +--mversion the package version +--rock-tree local tree where rock is installed +--rock-dir data directory of the installed rock +]] + +local function keys_as_string(t, sep) + return table.concat(util.keys(t), sep or " ") +end + +local function word_wrap(line) + local width = tonumber(os.getenv("COLUMNS")) or 80 + if width > 80 then width = 80 end + if #line > width then + local brk = width + while brk > 0 and line:sub(brk, brk) ~= " " do + brk = brk - 1 + end + if brk > 0 then + return line:sub(1, brk-1) .. "\n" .. word_wrap(line:sub(brk+1)) + end + end + return line +end + +local function format_text(text) + text = text:gsub("^%s*",""):gsub("%s$", ""):gsub("\n[ \t]+","\n"):gsub("([^\n])\n([^\n])","%1 %2") + local paragraphs = util.split_string(text, "\n\n") + for n, line in ipairs(paragraphs) do + paragraphs[n] = word_wrap(line) + end + return (table.concat(paragraphs, "\n\n"):gsub("%s$", "")) +end + +local function module_name(mod, filename, name, version, repo, manifest) + local base_dir + if filename:match("%.lua$") then + base_dir = path.deploy_lua_dir(repo) + else + base_dir = path.deploy_lib_dir(repo) + end + + return dir.path(base_dir, filename) +end + +--- Driver function for "show" command. +-- @param name or nil: an existing package name. +-- @param version string or nil: a version may also be passed. +-- @return boolean: True if succeeded, nil on errors. +function run(...) + local flags, name, version = util.parse_flags(...) + if not name then + return nil, "Argument missing, see help." + end + local results = {} + local query = search.make_query(name, version) + query.exact_name = true + local tree_map = {} + local trees = cfg.rocks_trees + if flags["tree"] then + trees = { flags["tree"] } + end + for _, tree in ipairs(trees) do + local rocks_dir = path.rocks_dir(tree) + tree_map[rocks_dir] = tree + search.manifest_search(results, rocks_dir, query) + end + + if not next(results) then -- + return nil,"cannot find package "..name.." "..(version or "").."\nUse 'list' to find installed rocks." + end + + version = nil + local repo_url + local package, versions = util.sortedpairs(results)() + --question: what do we do about multiple versions? This should + --give us the latest version on the last repo (which is usually the global one) + for vs, repositories in util.sortedpairs(versions, deps.compare_versions) do + if not version then version = vs end + for _, rp in ipairs(repositories) do repo_url = rp.repo end + end + + + local repo = tree_map[repo_url] + local directory = path.install_dir(name,version,repo) + local rockspec_file = path.rockspec_file(name, version, repo) + local rockspec, err = fetch.load_local_rockspec(rockspec_file) + if not rockspec then return nil,err end + + local descript = rockspec.description or {} + local manifest, err = manif.load_manifest(repo_url) + if not manifest then return nil,err end + local minfo = manifest.repository[name][version][1] + + if flags["rock-tree"] then util.printout(repo) + elseif flags["rock-dir"] then util.printout(directory) + elseif flags["home"] then util.printout(descript.homepage) + elseif flags["modules"] then util.printout(keys_as_string(minfo.modules)) + elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies)) + elseif flags["rockspec"] then util.printout(rockspec_file) + elseif flags["mversion"] then util.printout(version) + else + util.printout() + util.printout(rockspec.package.." "..rockspec.version.." - "..(descript.summary or "")) + util.printout() + if descript.detailed then + util.printout(format_text(descript.detailed)) + util.printout() + end + if descript.license then + util.printout("License: ", descript.license) + end + if descript.homepage then + util.printout("Homepage: ", descript.homepage) + end + util.printout("Installed in: ", repo) + if next(minfo.modules) then + util.printout() + util.printout("Modules:") + for mod, filename in util.sortedpairs(minfo.modules) do + util.printout("\t"..mod.." ("..path.which(mod, filename, name, version, repo, manifest)..")") + end + end + if next(minfo.dependencies) then + util.printout() + util.printout("Depends on:") + util.printout("\t"..keys_as_string(minfo.dependencies, "\n\t")) + end + util.printout() + end + return true +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/tools/patch.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/tools/patch.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,712 @@ +--- Patch utility to apply unified diffs. +-- +-- http://lua-users.org/wiki/LuaPatch +-- +-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license). +-- Code is heavilly based on the Python-based patch.py version 8.06-1 +-- Copyright (c) 2008 rainforce.org, MIT License +-- Project home: http://code.google.com/p/python-patch/ . + +module("luarocks.tools.patch", package.seeall) + +local fs = require("luarocks.fs") + +local version = '0.1' + +local io = io +local os = os +local string = string +local table = table +local format = string.format + +-- logging +local debugmode = false +local function debug(s) end +local function info(s) end +local function warning(s) io.stderr:write(s .. '\n') end + +-- Returns boolean whether string s2 starts with string s. +local function startswith(s, s2) + return s:sub(1, #s2) == s2 +end + +-- Returns boolean whether string s2 ends with string s. +local function endswith(s, s2) + return #s >= #s2 and s:sub(#s-#s2+1) == s2 +end + +-- Returns string s after filtering out any new-line characters from end. +local function endlstrip(s) + return s:gsub('[\r\n]+$', '') +end + +-- Returns shallow copy of table t. +local function table_copy(t) + local t2 = {} + for k,v in pairs(t) do t2[k] = v end + return t2 +end + +-- Returns boolean whether array t contains value v. +local function array_contains(t, v) + for _,v2 in ipairs(t) do if v == v2 then return true end end + return false +end + +local function exists(filename) + local fh = io.open(filename) + local result = fh ~= nil + if fh then fh:close() end + return result +end +local function isfile() return true end --FIX? + +local function read_file(filename) + local fh, err, oserr = io.open(filename, 'rb') + if not fh then return fh, err, oserr end + local data, err, oserr = fh:read'*a' + fh:close() + if not data then return nil, err, oserr end + return data +end + +local function write_file(filename, data) + local fh, err, oserr = io.open(filename 'wb') + if not fh then return fh, err, oserr end + local status, err, oserr = fh:write(data) + fh:close() + if not status then return nil, err, oserr end + return true +end + +local function file_copy(src, dest) + local data, err, oserr = read_file(src) + if not data then return data, err, oserr end + local status, err, oserr = write_file(dest) + if not status then return status, err, oserr end + return true +end + +local function string_as_file(s) + return { + at = 0, + str = s, + len = #s, + eof = false, + read = function(self, n) + if self.eof then return nil end + local chunk = self.str:sub(self.at, self.at+n) + self.at = self.at + n + if self.at > self.len then + self.eof = true + end + return chunk + end, + close = function(self) + self.eof = true + end, + } +end + +-- +-- file_lines(f) is similar to f:lines() for file f. +-- The main difference is that read_lines includes +-- new-line character sequences ("\n", "\r\n", "\r"), +-- if any, at the end of each line. Embedded "\0" are also handled. +-- Caution: The newline behavior can depend on whether f is opened +-- in binary or ASCII mode. +-- (file_lines - version 20080913) +-- +local function file_lines(f) + local CHUNK_SIZE = 1024 + local buffer = "" + local pos_beg = 1 + return function() + local pos, chars + while 1 do + pos, chars = buffer:match('()([\r\n].)', pos_beg) + if pos or not f then + break + elseif f then + local chunk = f:read(CHUNK_SIZE) + if chunk then + buffer = buffer:sub(pos_beg) .. chunk + pos_beg = 1 + else + f = nil + end + end + end + if not pos then + pos = #buffer + elseif chars == '\r\n' then + pos = pos + 1 + end + local line = buffer:sub(pos_beg, pos) + pos_beg = pos + 1 + if #line > 0 then + return line + end + end +end + +local function match_linerange(line) + local m1, m2, m3, m4 = line:match("^@@ %-(%d+),(%d+) %+(%d+),(%d+)") + if not m1 then m1, m3, m4 = line:match("^@@ %-(%d+) %+(%d+),(%d+)") end + if not m1 then m1, m2, m3 = line:match("^@@ %-(%d+),(%d+) %+(%d+)") end + if not m1 then m1, m3 = line:match("^@@ %-(%d+) %+(%d+)") end + return m1, m2, m3, m4 +end + +function read_patch(filename, data) + -- define possible file regions that will direct the parser flow + local state = 'header' + -- 'header' - comments before the patch body + -- 'filenames' - lines starting with --- and +++ + -- 'hunkhead' - @@ -R +R @@ sequence + -- 'hunkbody' + -- 'hunkskip' - skipping invalid hunk mode + + local all_ok = true + local lineends = {lf=0, crlf=0, cr=0} + local files = {source={}, target={}, hunks={}, fileends={}, hunkends={}} + local nextfileno = 0 + local nexthunkno = 0 --: even if index starts with 0 user messages + -- number hunks from 1 + + -- hunkinfo holds parsed values, hunkactual - calculated + local hunkinfo = { + startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil, + invalid=false, text={} + } + local hunkactual = {linessrc=nil, linestgt=nil} + + info(format("reading patch %s", filename)) + + local fp + if data then + fp = string_as_file(data) + else + fp = filename == '-' and io.stdin or assert(io.open(filename, "rb")) + end + local lineno = 0 + + for line in file_lines(fp) do + lineno = lineno + 1 + if state == 'header' then + if startswith(line, "--- ") then + state = 'filenames' + end + -- state is 'header' or 'filenames' + end + if state == 'hunkbody' then + -- skip hunkskip and hunkbody code until definition of hunkhead read + + -- process line first + if line:match"^[- +\\]" or line:match"^[\r\n]*$" then + -- gather stats about line endings + local he = files.hunkends[nextfileno] + if endswith(line, "\r\n") then + he.crlf = he.crlf + 1 + elseif endswith(line, "\n") then + he.lf = he.lf + 1 + elseif endswith(line, "\r") then + he.cr = he.cr + 1 + end + if startswith(line, "-") then + hunkactual.linessrc = hunkactual.linessrc + 1 + elseif startswith(line, "+") then + hunkactual.linestgt = hunkactual.linestgt + 1 + elseif startswith(line, "\\") then + -- nothing + else + hunkactual.linessrc = hunkactual.linessrc + 1 + hunkactual.linestgt = hunkactual.linestgt + 1 + end + table.insert(hunkinfo.text, line) + -- todo: handle \ No newline cases + else + warning(format("invalid hunk no.%d at %d for target file %s", + nexthunkno, lineno, files.target[nextfileno])) + -- add hunk status node + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + files.hunks[nextfileno][nexthunkno].invalid = true + all_ok = false + state = 'hunkskip' + end + + -- check exit conditions + if hunkactual.linessrc > hunkinfo.linessrc or + hunkactual.linestgt > hunkinfo.linestgt + then + warning(format("extra hunk no.%d lines at %d for target %s", + nexthunkno, lineno, files.target[nextfileno])) + -- add hunk status node + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + files.hunks[nextfileno][nexthunkno].invalid = true + state = 'hunkskip' + elseif hunkinfo.linessrc == hunkactual.linessrc and + hunkinfo.linestgt == hunkactual.linestgt + then + table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) + state = 'hunkskip' + + -- detect mixed window/unix line ends + local ends = files.hunkends[nextfileno] + if (ends.cr~=0 and 1 or 0) + (ends.crlf~=0 and 1 or 0) + + (ends.lf~=0 and 1 or 0) > 1 + then + warning(format("inconsistent line ends in patch hunks for %s", + files.source[nextfileno])) + end + if debugmode then + local debuglines = {crlf=ends.crlf, lf=ends.lf, cr=ends.cr, + file=files.target[nextfileno], hunk=nexthunkno} + debug(format("crlf: %(crlf)d lf: %(lf)d cr: %(cr)d\t " .. + "- file: %(file)s hunk: %(hunk)d", debuglines)) + end + end + -- state is 'hunkbody' or 'hunkskip' + end + + if state == 'hunkskip' then + if match_linerange(line) then + state = 'hunkhead' + elseif startswith(line, "--- ") then + state = 'filenames' + if debugmode and #files.source > 0 then + debug(format("- %2d hunks for %s", #files.hunks[nextfileno], + files.source[nextfileno])) + end + end + -- state is 'hunkskip', 'hunkhead', or 'filenames' + end + local advance + if state == 'filenames' then + if startswith(line, "--- ") then + if array_contains(files.source, nextfileno) then + all_ok = false + warning(format("skipping invalid patch for %s", + files.source[nextfileno+1])) + table.remove(files.source, nextfileno+1) + -- double source filename line is encountered + -- attempt to restart from this second line + end + -- Accept a space as a terminator, like GNU patch does. + -- Breaks patches containing filenames with spaces... + -- FIXME Figure out what does GNU patch do in those cases. + local match = line:match("^--- ([^\t ]+)") + if not match then + all_ok = false + warning(format("skipping invalid filename at line %d", lineno+1)) + state = 'header' + else + table.insert(files.source, match) + end + elseif not startswith(line, "+++ ") then + if array_contains(files.source, nextfileno) then + all_ok = false + warning(format("skipping invalid patch with no target for %s", + files.source[nextfileno+1])) + table.remove(files.source, nextfileno+1) + else + -- this should be unreachable + warning("skipping invalid target patch") + end + state = 'header' + else + if array_contains(files.target, nextfileno) then + all_ok = false + warning(format("skipping invalid patch - double target at line %d", + lineno+1)) + table.remove(files.source, nextfileno+1) + table.remove(files.target, nextfileno+1) + nextfileno = nextfileno - 1 + -- double target filename line is encountered + -- switch back to header state + state = 'header' + else + -- Accept a space as a terminator, like GNU patch does. + -- Breaks patches containing filenames with spaces... + -- FIXME Figure out what does GNU patch do in those cases. + local re_filename = "^%+%+%+ ([^ \t]+)" + local match = line:match(re_filename) + if not match then + all_ok = false + warning(format( + "skipping invalid patch - no target filename at line %d", + lineno+1)) + state = 'header' + else + table.insert(files.target, match) + nextfileno = nextfileno + 1 + nexthunkno = 0 + table.insert(files.hunks, {}) + table.insert(files.hunkends, table_copy(lineends)) + table.insert(files.fileends, table_copy(lineends)) + state = 'hunkhead' + advance = true + end + end + end + -- state is 'filenames', 'header', or ('hunkhead' with advance) + end + if not advance and state == 'hunkhead' then + local m1, m2, m3, m4 = match_linerange(line) + if not m1 then + if not array_contains(files.hunks, nextfileno-1) then + all_ok = false + warning(format("skipping invalid patch with no hunks for file %s", + files.target[nextfileno])) + end + state = 'header' + else + hunkinfo.startsrc = tonumber(m1) + hunkinfo.linessrc = tonumber(m2 or 1) + hunkinfo.starttgt = tonumber(m3) + hunkinfo.linestgt = tonumber(m4 or 1) + hunkinfo.invalid = false + hunkinfo.text = {} + + hunkactual.linessrc = 0 + hunkactual.linestgt = 0 + + state = 'hunkbody' + nexthunkno = nexthunkno + 1 + end + -- state is 'header' or 'hunkbody' + end + end + if state ~= 'hunkskip' then + warning(format("patch file incomplete - %s", filename)) + all_ok = false + -- os.exit(?) + else + -- duplicated message when an eof is reached + if debugmode and #files.source > 0 then + debug(format("- %2d hunks for %s", #files.hunks[nextfileno], + files.source[nextfileno])) + end + end + + local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end + info(format("total files: %d total hunks: %d", #files.source, sum)) + fp:close() + return files, all_ok +end + +local function find_hunk(file, h, hno) + for fuzz=0,2 do + local lineno = h.startsrc + for i=0,#file do + local found = true + local location = lineno + local total = #h.text - fuzz + for l, hline in ipairs(h.text) do + if l > fuzz then + -- todo: \ No newline at the end of file + if startswith(hline, " ") or startswith(hline, "-") then + local line = file[lineno] + lineno = lineno + 1 + if not line or #line == 0 then + found = false + break + end + if endlstrip(line) ~= endlstrip(hline:sub(2)) then + found = false + break + end + end + end + end + if found then + local offset = location - h.startsrc - fuzz + if offset ~= 0 then + warning(format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or format(" (fuzz %d)", fuzz))) + end + h.startsrc = location + h.starttgt = h.starttgt + offset + for i=1,fuzz do + table.remove(h.text, 1) + table.remove(h.text, #h.text) + end + return true + end + lineno = i + end + end + return false +end + +local function load_file(filename) + local fp = assert(io.open(filename)) + local file = {} + local readline = file_lines(fp) + while true do + local line = readline() + if not line then break end + table.insert(file, line) + end + fp:close() + return file +end + +local function find_hunks(file, hunks) + local matched = true + local lineno = 1 + local hno = nil + for hno, h in ipairs(hunks) do + find_hunk(file, h, hno) + end +end + +local function check_patched(file, hunks) + local matched = true + local lineno = 1 + local hno = nil + local ok, err = pcall(function() + if #file == 0 then + error 'nomatch' + end + for hno, h in ipairs(hunks) do + -- skip to line just before hunk starts + if #file < h.starttgt then + error 'nomatch' + end + lineno = h.starttgt + for _, hline in ipairs(h.text) do + -- todo: \ No newline at the end of file + if not startswith(hline, "-") and not startswith(hline, "\\") then + local line = file[lineno] + lineno = lineno + 1 + if #line == 0 then + error 'nomatch' + end + if endlstrip(line) ~= endlstrip(hline:sub(2)) then + warning(format("file is not patched - failed hunk: %d", hno)) + error 'nomatch' + end + end + end + end + end) + if err == 'nomatch' then + matched = false + end + -- todo: display failed hunk, i.e. expected/found + + return matched +end + +local function patch_hunks(srcname, tgtname, hunks) + local src = assert(io.open(srcname, "rb")) + local tgt = assert(io.open(tgtname, "wb")) + + local src_readline = file_lines(src) + + -- todo: detect linefeeds early - in apply_files routine + -- to handle cases when patch starts right from the first + -- line and no lines are processed. At the moment substituted + -- lineends may not be the same at the start and at the end + -- of patching. Also issue a warning about mixed lineends + + local srclineno = 1 + local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0} + for hno, h in ipairs(hunks) do + debug(format("processing hunk %d for file %s", hno, tgtname)) + -- skip to line just before hunk starts + while srclineno < h.startsrc do + local line = src_readline() + -- Python 'U' mode works only with text files + if endswith(line, "\r\n") then + lineends["\r\n"] = lineends["\r\n"] + 1 + elseif endswith(line, "\n") then + lineends["\n"] = lineends["\n"] + 1 + elseif endswith(line, "\r") then + lineends["\r"] = lineends["\r"] + 1 + end + tgt:write(line) + srclineno = srclineno + 1 + end + + for _,hline in ipairs(h.text) do + -- todo: check \ No newline at the end of file + if startswith(hline, "-") or startswith(hline, "\\") then + src_readline() + srclineno = srclineno + 1 + else + if not startswith(hline, "+") then + src_readline() + srclineno = srclineno + 1 + end + local line2write = hline:sub(2) + -- detect if line ends are consistent in source file + local sum = 0 + for k,v in pairs(lineends) do if v > 0 then sum=sum+1 end end + if sum == 1 then + local newline + for k,v in pairs(lineends) do if v ~= 0 then newline = k end end + tgt:write(endlstrip(line2write) .. newline) + else -- newlines are mixed or unknown + tgt:write(line2write) + end + end + end + end + for line in src_readline do + tgt:write(line) + end + tgt:close() + src:close() + return true +end + +local function strip_dirs(filename, strip) + if strip == nil then return filename end + for i=1,strip do + filename=filename:gsub("^[^/]*/", "") + end + return filename +end + +function apply_patch(patch, strip) + local all_ok = true + local total = #patch.source + for fileno, filename in ipairs(patch.source) do + filename = strip_dirs(filename, strip) + local continue + local f2patch = filename + if not exists(f2patch) then + f2patch = strip_dirs(patch.target[fileno], strip) + f2patch = fs.absolute_name(f2patch) + if not exists(f2patch) then --FIX:if f2patch nil + warning(format("source/target file does not exist\n--- %s\n+++ %s", + filename, f2patch)) + all_ok = false + continue = true + end + end + if not continue and not isfile(f2patch) then + warning(format("not a file - %s", f2patch)) + all_ok = false + continue = true + end + if not continue then + + filename = f2patch + + info(format("processing %d/%d:\t %s", fileno, total, filename)) + + -- validate before patching + local hunks = patch.hunks[fileno] + local file = load_file(filename) + local hunkno = 1 + local hunk = hunks[hunkno] + local hunkfind = {} + local hunkreplace = {} + local validhunks = 0 + local canpatch = false + local hunklineno + local isbreak + local lineno = 0 + + find_hunks(file, hunks) + + for _, line in ipairs(file) do + lineno = lineno + 1 + local continue + if not hunk or lineno < hunk.startsrc then + continue = true + elseif lineno == hunk.startsrc then + hunkfind = {} + for _,x in ipairs(hunk.text) do + if x:sub(1,1) == ' ' or x:sub(1,1) == '-' then + hunkfind[#hunkfind+1] = endlstrip(x:sub(2)) + end end + hunkreplace = {} + for _,x in ipairs(hunk.text) do + if x:sub(1,1) == ' ' or x:sub(1,1) == '+' then + hunkreplace[#hunkreplace+1] = endlstrip(x:sub(2)) + end end + --pprint(hunkreplace) + hunklineno = 1 + + -- todo \ No newline at end of file + end + -- check hunks in source file + if not continue and lineno < hunk.startsrc + #hunkfind - 1 then + if endlstrip(line) == hunkfind[hunklineno] then + hunklineno = hunklineno + 1 + else + debug(format("hunk no.%d doesn't match source file %s", + hunkno, filename)) + -- file may be already patched, but check other hunks anyway + hunkno = hunkno + 1 + if hunkno <= #hunks then + hunk = hunks[hunkno] + continue = true + else + isbreak = true; break + end + end + end + -- check if processed line is the last line + if not continue and lineno == hunk.startsrc + #hunkfind - 1 then + debug(format("file %s hunk no.%d -- is ready to be patched", + filename, hunkno)) + hunkno = hunkno + 1 + validhunks = validhunks + 1 + if hunkno <= #hunks then + hunk = hunks[hunkno] + else + if validhunks == #hunks then + -- patch file + canpatch = true + isbreak = true; break + end + end + end + end + if not isbreak then + if hunkno <= #hunks then + warning(format("premature end of source file %s at hunk %d", + filename, hunkno)) + all_ok = false + end + end + if validhunks < #hunks then + if check_patched(file, hunks) then + warning(format("already patched %s", filename)) + else + warning(format("source file is different - %s", filename)) + all_ok = false + end + end + if canpatch then + local backupname = filename .. ".orig" + if exists(backupname) then + warning(format("can't backup original file to %s - aborting", + backupname)) + all_ok = false + else + assert(os.rename(filename, backupname)) + if patch_hunks(backupname, filename, hunks) then + warning(format("successfully patched %s", filename)) + assert(os.remove(backupname)) + else + warning(format("error patching file %s", filename)) + assert(file_copy(filename, filename .. ".invalid")) + warning(format("invalid version is saved to %s", + filename .. ".invalid")) + -- todo: proper rejects + assert(os.rename(backupname, filename)) + all_ok = false + end + end + end + + end -- if not continue + end -- for + -- todo: check for premature eof + return all_ok +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/tools/tar.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/tools/tar.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,144 @@ + +--- A pure-Lua implementation of untar (unpacking .tar archives) +module("luarocks.tools.tar", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +local blocksize = 512 + +local function get_typeflag(flag) + if flag == "0" or flag == "\0" then return "file" + elseif flag == "1" then return "link" + elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU + elseif flag == "3" then return "character" + elseif flag == "4" then return "block" + elseif flag == "5" then return "directory" + elseif flag == "6" then return "fifo" + elseif flag == "7" then return "contiguous" -- "reserved" in POSIX, "contiguous" in GNU + elseif flag == "x" then return "next file" + elseif flag == "g" then return "global extended header" + elseif flag == "L" then return "long name" + elseif flag == "K" then return "long link name" + end + return "unknown" +end + +local function octal_to_number(octal) + local exp = 0 + local number = 0 + for i = #octal,1,-1 do + local digit = tonumber(octal:sub(i,i)) + if not digit then break end + number = number + (digit * 8^exp) + exp = exp + 1 + end + return number +end + +local function checksum_header(block) + local sum = 256 + for i = 1,148 do + sum = sum + block:byte(i) + end + for i = 157,500 do + sum = sum + block:byte(i) + end + return sum +end + +local function nullterm(s) + return s:match("^[^%z]*") +end + +local function read_header_block(block) + local header = {} + header.name = nullterm(block:sub(1,100)) + header.mode = nullterm(block:sub(101,108)) + header.uid = octal_to_number(nullterm(block:sub(109,116))) + header.gid = octal_to_number(nullterm(block:sub(117,124))) + header.size = octal_to_number(nullterm(block:sub(125,136))) + header.mtime = octal_to_number(nullterm(block:sub(137,148))) + header.chksum = octal_to_number(nullterm(block:sub(149,156))) + header.typeflag = get_typeflag(block:sub(157,157)) + header.linkname = nullterm(block:sub(158,257)) + header.magic = block:sub(258,263) + header.version = block:sub(264,265) + header.uname = nullterm(block:sub(266,297)) + header.gname = nullterm(block:sub(298,329)) + header.devmajor = octal_to_number(nullterm(block:sub(330,337))) + header.devminor = octal_to_number(nullterm(block:sub(338,345))) + header.prefix = block:sub(346,500) + if header.magic ~= "ustar " and header.magic ~= "ustar\0" then + return false, "Invalid header magic "..header.magic + end + if header.version ~= "00" and header.version ~= " \0" then + return false, "Unknown version "..header.version + end + if not checksum_header(block) == header.chksum then + return false, "Failed header checksum" + end + return header +end + +function untar(filename, destdir) + assert(type(filename) == "string") + assert(type(destdir) == "string") + + local tar_handle = io.open(filename, "r") + if not tar_handle then return nil, "Error opening file "..filename end + + local long_name, long_link_name + while true do + local block + repeat + block = tar_handle:read(blocksize) + until (not block) or checksum_header(block) > 256 + if not block then break end + local header, err = read_header_block(block) + if not header then + util.printerr(err) + end + + local file_data = tar_handle:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) + + if header.typeflag == "long name" then + long_name = nullterm(file_data) + elseif header.typeflag == "long link name" then + long_link_name = nullterm(file_data) + else + if long_name then + header.name = long_name + long_name = nil + end + if long_link_name then + header.name = long_link_name + long_link_name = nil + end + end + local pathname = dir.path(destdir, header.name) + if header.typeflag == "directory" then + fs.make_dir(pathname) + elseif header.typeflag == "file" then + local dirname = dir.dir_name(pathname) + if dirname ~= "" then + fs.make_dir(dirname) + end + local file_handle = io.open(pathname, "wb") + file_handle:write(file_data) + file_handle:close() + fs.set_time(pathname, header.mtime) + if fs.chmod then + fs.chmod(pathname, header.mode) + end + end + --[[ + for k,v in pairs(header) do + util.printout("[\""..tostring(k).."\"] = "..(type(v)=="number" and v or "\""..v:gsub("%z", "\\0").."\"")) + end + util.printout() + --]] + end + return true +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/tools/zip.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/tools/zip.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,245 @@ + +--- A Lua implementation of .zip file archiving (used for creating .rock files), +-- using only lua-zlib. +module("luarocks.tools.zip", package.seeall) + +local zlib = require("zlib") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +local function number_to_bytestring(number, nbytes) + local out = {} + for i = 1, nbytes do + local byte = number % 256 + table.insert(out, string.char(byte)) + number = (number - byte) / 256 + end + return table.concat(out) +end + +--- Begin a new file to be stored inside the zipfile. +-- @param self handle of the zipfile being written. +-- @param filename filenome of the file to be added to the zipfile. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_open_new_file_in_zip(self, filename) + if self.in_open_file then + self:close_file_in_zip() + return nil + end + local lfh = {} + self.local_file_header = lfh + lfh.last_mod_file_time = 0 -- TODO + lfh.last_mod_file_date = 0 -- TODO + lfh.crc32 = 0 -- initial value + lfh.compressed_size = 0 -- unknown yet + lfh.uncompressed_size = 0 -- unknown yet + lfh.file_name_length = #filename + lfh.extra_field_length = 0 + lfh.file_name = filename:gsub("\\", "/") + lfh.external_attr = 0 -- TODO properly store permissions + self.in_open_file = true + self.data = {} + return true +end + +--- Write data to the file currently being stored in the zipfile. +-- @param self handle of the zipfile being written. +-- @param buf string containing data to be written. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_write_file_in_zip(self, buf) + if not self.in_open_file then + return nil + end + local lfh = self.local_file_header + local cbuf = zlib.compress(buf):sub(3, -5) + lfh.crc32 = zlib.crc32(lfh.crc32, buf) + lfh.compressed_size = lfh.compressed_size + #cbuf + lfh.uncompressed_size = lfh.uncompressed_size + #buf + table.insert(self.data, cbuf) + return true +end + +--- Complete the writing of a file stored in the zipfile. +-- @param self handle of the zipfile being written. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_close_file_in_zip(self) + local zh = self.ziphandle + + if not self.in_open_file then + return nil + end + + -- Local file header + local lfh = self.local_file_header + lfh.offset = zh:seek() + zh:write(number_to_bytestring(0x04034b50, 4)) -- signature + zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0 + zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag + zh:write(number_to_bytestring(8, 2)) -- compression method: deflate + zh:write(number_to_bytestring(lfh.last_mod_file_time, 2)) + zh:write(number_to_bytestring(lfh.last_mod_file_date, 2)) + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + zh:write(number_to_bytestring(lfh.file_name_length, 2)) + zh:write(number_to_bytestring(lfh.extra_field_length, 2)) + zh:write(lfh.file_name) + + -- File data + for _, cbuf in ipairs(self.data) do + zh:write(cbuf) + end + + -- Data descriptor + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + + table.insert(self.files, lfh) + self.in_open_file = false + + return true +end + +-- @return boolean or (boolean, string): true on success, +-- false and an error message on failure. +local function zipwriter_add(self, file) + local fin + local ok, err = self:open_new_file_in_zip(file) + if not ok then + err = "error in opening "..file.." in zipfile" + else + fin = io.open(fs.absolute_name(file), "rb") + if not fin then + ok = false + err = "error opening "..file.." for reading" + end + end + if ok then + local buf = fin:read("*a") + if not buf then + err = "error reading "..file + ok = false + else + ok = self:write_file_in_zip(buf) + if not ok then + err = "error in writing "..file.." in the zipfile" + end + end + end + if fin then + fin:close() + end + if ok then + ok = self:close_file_in_zip() + if not ok then + err = "error in writing "..file.." in the zipfile" + end + end + return ok == true, err +end + +--- Complete the writing of the zipfile. +-- @param self handle of the zipfile being written. +-- @return true if succeeded, nil in case of failure. +local function zipwriter_close(self) + local zh = self.ziphandle + + local central_directory_offset = zh:seek() + + local size_of_central_directory = 0 + -- Central directory structure + for _, lfh in ipairs(self.files) do + zh:write(number_to_bytestring(0x02014b50, 4)) -- signature + zh:write(number_to_bytestring(3, 2)) -- version made by: UNIX + zh:write(number_to_bytestring(20, 2)) -- version needed to extract: 2.0 + zh:write(number_to_bytestring(0, 2)) -- general purpose bit flag + zh:write(number_to_bytestring(8, 2)) -- compression method: deflate + zh:write(number_to_bytestring(lfh.last_mod_file_time, 2)) + zh:write(number_to_bytestring(lfh.last_mod_file_date, 2)) + zh:write(number_to_bytestring(lfh.crc32, 4)) + zh:write(number_to_bytestring(lfh.compressed_size, 4)) + zh:write(number_to_bytestring(lfh.uncompressed_size, 4)) + zh:write(number_to_bytestring(lfh.file_name_length, 2)) + zh:write(number_to_bytestring(lfh.extra_field_length, 2)) + zh:write(number_to_bytestring(0, 2)) -- file comment length + zh:write(number_to_bytestring(0, 2)) -- disk number start + zh:write(number_to_bytestring(0, 2)) -- internal file attributes + zh:write(number_to_bytestring(lfh.external_attr, 4)) -- external file attributes + zh:write(number_to_bytestring(lfh.offset, 4)) -- relative offset of local header + zh:write(lfh.file_name) + size_of_central_directory = size_of_central_directory + 46 + lfh.file_name_length + end + + -- End of central directory record + zh:write(number_to_bytestring(0x06054b50, 4)) -- signature + zh:write(number_to_bytestring(0, 2)) -- number of this disk + zh:write(number_to_bytestring(0, 2)) -- number of disk with start of central directory + zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir on this disk + zh:write(number_to_bytestring(#self.files, 2)) -- total number of entries in the central dir + zh:write(number_to_bytestring(size_of_central_directory, 4)) + zh:write(number_to_bytestring(central_directory_offset, 4)) + zh:write(number_to_bytestring(0, 2)) -- zip file comment length + zh:close() + + return true +end + +--- Return a zip handle open for writing. +-- @param name filename of the zipfile to be created. +-- @return a zip handle, or nil in case of error. +function new_zipwriter(name) + + local zw = {} + + zw.ziphandle = io.open(fs.absolute_name(name), "wb") + if not zw.ziphandle then + return nil + end + zw.files = {} + zw.in_open_file = false + + zw.add = zipwriter_add + zw.close = zipwriter_close + zw.open_new_file_in_zip = zipwriter_open_new_file_in_zip + zw.write_file_in_zip = zipwriter_write_file_in_zip + zw.close_file_in_zip = zipwriter_close_file_in_zip + + return zw +end + +--- Compress files in a .zip archive. +-- @param zipfile string: pathname of .zip archive to be created. +-- @param ... Filenames to be stored in the archive are given as +-- additional arguments. +-- @return boolean or (boolean, string): true on success, +-- false and an error message on failure. +function zip(zipfile, ...) + local zw = new_zipwriter(zipfile) + if not zw then + return nil, "error opening "..zipfile + end + + local ok, err + for _, file in pairs({...}) do + if fs.is_dir(file) then + for _, entry in pairs(fs.find(file)) do + local fullname = dir.path(file, entry) + if fs.is_file(fullname) then + ok, err = zw:add(fullname) + if not ok then break end + end + end + else + ok, err = zw:add(file) + if not ok then break end + end + end + + local ok = zw:close() + if not ok then + return false, "error closing "..zipfile + end + return ok, err +end + diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/type_check.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/type_check.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,267 @@ + +--- Type-checking functions. +-- Functions and definitions for doing a basic lint check on files +-- loaded by LuaRocks. +module("luarocks.type_check", package.seeall) + +local cfg = require("luarocks.cfg") + +rockspec_format = "1.0" + +rockspec_types = { + rockspec_format = "string", + MUST_package = "string", + MUST_version = "[%w.]+-[%d]+", + description = { + summary = "string", + detailed = "string", + homepage = "string", + license = "string", + maintainer = "string" + }, + dependencies = { + platforms = {}, + ANY = "string" + }, + supported_platforms = { + ANY = "string" + }, + external_dependencies = { + platforms = {}, + ANY = { + program = "string", + header = "string", + library = "string" + } + }, + MUST_source = { + platforms = {}, + MUST_url = "string", + md5 = "string", + file = "string", + dir = "string", + tag = "string", + branch = "string", + module = "string", + cvs_tag = "string", + cvs_module = "string" + }, + build = { + platforms = {}, + type = "string", + install = { + lua = { + MORE = true + }, + lib = { + MORE = true + }, + conf = { + MORE = true + }, + bin = { + MORE = true + } + }, + copy_directories = { + ANY = "string" + }, + MORE = true + }, + hooks = { + platforms = {}, + post_install = "string" + } +} + +function load_extensions() + rockspec_format = "1.1" + rockspec_types.deploy = { + wrap_bin_scripts = true, + } +end + +if cfg.use_extensions then + load_extensions() +end + +rockspec_types.build.platforms.ANY = rockspec_types.build +rockspec_types.dependencies.platforms.ANY = rockspec_types.dependencies +rockspec_types.external_dependencies.platforms.ANY = rockspec_types.external_dependencies +rockspec_types.MUST_source.platforms.ANY = rockspec_types.MUST_source +rockspec_types.hooks.platforms.ANY = rockspec_types.hooks + +manifest_types = { + MUST_repository = { + -- packages + ANY = { + -- versions + ANY = { + -- items + ANY = { + MUST_arch = "string", + modules = { ANY = "string" }, + commands = { ANY = "string" }, + dependencies = { ANY = "string" }, + -- TODO: to be extended with more metadata. + } + } + } + }, + MUST_modules = { + -- modules + ANY = { + -- providers + ANY = "string" + } + }, + MUST_commands = { + -- modules + ANY = { + -- commands + ANY = "string" + } + }, + dependencies = { + -- each module + ANY = { + -- each version + ANY = { + -- each dependency + ANY = { + name = "string", + constraints = { + ANY = { + no_upgrade = "boolean", + op = "string", + version = { + string = "string", + ANY = 0, + } + } + } + } + } + } + } +} + +local type_check_table + +--- Type check an object. +-- The object is compared against an archetypical value +-- matching the expected type -- the actual values don't matter, +-- only their types. Tables are type checked recursively. +-- @param name any: The object name (for error messages). +-- @param item any: The object being checked. +-- @param expected any: The reference object. In case of a table, +-- its is structured as a type reference table. +-- @param context string: A string indicating the "context" where the +-- error occurred (such as the name of the table the item is a part of), +-- to be used by error messages. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +-- @see type_check_table +local function type_check_item(name, item, expected, context) + name = tostring(name) + + local item_type = type(item) + local expected_type = type(expected) + if expected_type == "number" then + if not tonumber(item) then + return nil, "Type mismatch on field "..context..name..": expected a number" + end + elseif expected_type == "string" then + if type(item) ~= "string" then + return nil, "Type mismatch on field "..context..name..": expected a string" + end + if expected ~= "string" then + if not item:match("^"..expected.."$") then + return nil, "Type mismatch on field "..context..name..": invalid value "..item + end + end + elseif expected_type == "table" then + if item_type ~= expected_type then + return nil, "Type mismatch on field "..context..name..": expected a table" + else + return type_check_table(item, expected, context..name..".") + end + elseif item_type ~= expected_type then + return nil, "Type mismatch on field "..context..name..": expected a "..expected_type + end + return true +end + +--- Type check the contents of a table. +-- The table's contents are compared against a reference table, +-- which contains the recognized fields, with archetypical values +-- matching the expected types -- the actual values of items in the +-- reference table don't matter, only their types (ie, for field x +-- in tbl that is correctly typed, type(tbl.x) == type(types.x)). +-- If the reference table contains a field called MORE, then +-- unknown fields in the checked table are accepted. +-- If it contains a field called ANY, then its type will be +-- used to check any unknown fields. If a field is prefixed +-- with MUST_, it is mandatory; its absence from the table is +-- a type error. +-- Tables are type checked recursively. +-- @param tbl table: The table to be type checked. +-- @param types table: The reference table, containing +-- values for recognized fields in the checked table. +-- @param context string: A string indicating the "context" where the +-- error occurred (such as the name of the table the item is a part of), +-- to be used by error messages. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +type_check_table = function(tbl, types, context) + assert(type(tbl) == "table") + assert(type(types) == "table") + for k, v in pairs(tbl) do + local t = types[k] or (type(k) == "string" and types["MUST_"..k]) or types.ANY + if t then + local ok, err = type_check_item(k, v, t, context) + if not ok then return nil, err end + elseif types.MORE then + -- Accept unknown field + else + if not cfg.accept_unknown_fields then + return nil, "Unknown field "..k + end + end + end + for k, v in pairs(types) do + local mandatory_key = k:match("^MUST_(.+)") + if mandatory_key then + if not tbl[mandatory_key] then + return nil, "Mandatory field "..context..mandatory_key.." is missing." + end + end + end + return true +end + +--- Type check a rockspec table. +-- Verify the correctness of elements from a +-- rockspec table, reporting on unknown fields and type +-- mismatches. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +function type_check_rockspec(rockspec) + assert(type(rockspec) == "table") + if rockspec.rockspec_format then + -- relies on global state + load_extensions() + end + return type_check_table(rockspec, rockspec_types, "") +end + +--- Type check a manifest table. +-- Verify the correctness of elements from a +-- manifest table, reporting on unknown fields and type +-- mismatches. +-- @return boolean or (nil, string): true if type checking +-- succeeded, or nil and an error message if it failed. +function type_check_manifest(manifest) + assert(type(manifest) == "table") + return type_check_table(manifest, manifest_types, "") +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/unpack.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/unpack.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,151 @@ + +--- Module implementing the LuaRocks "unpack" command. +-- Unpack the contents of a rock. +module("luarocks.unpack", package.seeall) + +local fetch = require("luarocks.fetch") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local build = require("luarocks.build") +local dir = require("luarocks.dir") + +help_summary = "Unpack the contents of a rock." +help_arguments = "{| []}" +help = [[ +Unpacks the contents of a rock in a newly created directory. +Argument may be a rock file, or the name of a rock in a rocks server. +In the latter case, the app version may be given as a second argument. +]] + +--- Load a rockspec file to the given directory, fetches the source +-- files specified in the rockspec, and unpack them inside the directory. +-- @param rockspec_file string: The URL for a rockspec file. +-- @param dir_name string: The directory where to store and unpack files. +-- @return table or (nil, string): the loaded rockspec table or +-- nil and an error message. +local function unpack_rockspec(rockspec_file, dir_name) + assert(type(rockspec_file) == "string") + assert(type(dir_name) == "string") + + local rockspec, err = fetch.load_rockspec(rockspec_file) + if not rockspec then + return nil, "Failed loading rockspec "..rockspec_file..": "..err + end + fs.change_dir(dir_name) + local ok, sources_dir = fetch.fetch_sources(rockspec, true, ".") + if not ok then + return nil, sources_dir + end + fs.change_dir(dir_name) + build.apply_patches(rockspec) + fs.pop_dir() + return rockspec +end + +--- Load a .rock file to the given directory and unpack it inside it. +-- @param rock_file string: The URL for a .rock file. +-- @param dir_name string: The directory where to unpack. +-- @param kind string: the kind of rock file, as in the second-level +-- extension in the rock filename (eg. "src", "all", "linux-x86") +-- @return table or (nil, string): the loaded rockspec table or +-- nil and an error message. +local function unpack_rock(rock_file, dir_name, kind) + assert(type(rock_file) == "string") + assert(type(dir_name) == "string") + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, dir_name) + if not ok then + return nil, "Failed unzipping rock "..rock_file, errcode + end + fs.change_dir(dir_name) + local rockspec_file = dir_name..".rockspec" + local rockspec, err = fetch.load_rockspec(rockspec_file) + if not rockspec then + return nil, "Failed loading rockspec "..rockspec_file..": "..err + end + if kind == "src" then + if rockspec.source.file then + local ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then + return nil, err + end + fs.change_dir(rockspec.source.dir) + build.apply_patches(rockspec) + fs.pop_dir() + end + end + return rockspec +end + +--- Create a directory and perform the necessary actions so that +-- the sources for the rock and its rockspec are unpacked inside it, +-- laid out properly so that the 'make' command is able to build the module. +-- @param file string: A rockspec or .rock URL. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +local function run_unpacker(file) + assert(type(file) == "string") + + local base_name = dir.base_name(file) + local dir_name, kind, extension = base_name:match("(.*)%.([^.]+)%.(rock)$") + if not extension then + dir_name, extension = base_name:match("(.*)%.(rockspec)$") + kind = "rockspec" + end + if not extension then + return nil, file.." does not seem to be a valid filename." + end + + if (fs.exists(dir_name)) then + return nil, "Directory "..dir_name.." already exists." + end + fs.make_dir(dir_name) + local rollback = util.schedule_function(fs.delete, fs.absolute_name(dir_name)) + + local rockspec, err + if extension == "rock" then + rockspec, err = unpack_rock(file, dir_name, kind) + elseif extension == "rockspec" then + rockspec, err = unpack_rockspec(file, dir_name) + end + if not rockspec then + return nil, err + end + if kind == "src" or kind == "rockspec" then + if rockspec.source.dir ~= "." then + local ok = fs.copy(rockspec.local_filename, rockspec.source.dir) + if not ok then + return nil, "Failed copying unpacked rockspec into unpacked source directory." + end + end + util.printout() + util.printout("Done. You may now enter directory ") + util.printout(dir.path(dir_name, rockspec.source.dir)) + util.printout("and type 'luarocks make' to build.") + end + util.remove_scheduled_function(rollback) + return true +end + +--- Driver function for the "unpack" command. +-- @param name string: may be a rock filename, for unpacking a +-- rock file or the name of a rock to be fetched and unpacked. +-- @param version string or nil: if the name of a package is given, a +-- version may also be passed. +-- @return boolean or (nil, string): true if successful or nil followed +-- by an error message. +function run(...) + local flags, name, version = util.parse_flags(...) + + assert(type(version) == "string" or not version) + if type(name) ~= "string" then + return nil, "Argument missing, see help." + end + + if name:match(".*%.rock") or name:match(".*%.rockspec") then + return run_unpacker(name) + else + local search = require("luarocks.search") + return search.act_on_src_or_rockspec(run_unpacker, name, version) + end +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/util.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/util.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,436 @@ + +--- Assorted utilities for managing tables, plus a scheduler for rollback functions. +-- Does not requires modules directly (only as locals +-- inside specific functions) to avoid interdependencies, +-- as this is used in the bootstrapping stage of luarocks.cfg. + +local global_env = _G + +module("luarocks.util", package.seeall) + +local scheduled_functions = {} + +--- Schedule a function to be executed upon program termination. +-- This is useful for actions such as deleting temporary directories +-- or failure rollbacks. +-- @param f function: Function to be executed. +-- @param ... arguments to be passed to function. +-- @return table: A token representing the scheduled execution, +-- which can be used to remove the item later from the list. +function schedule_function(f, ...) + assert(type(f) == "function") + + local item = { fn = f, args = {...} } + table.insert(scheduled_functions, item) + return item +end + +--- Unschedule a function. +-- This is useful for cancelling a rollback of a completed operation. +-- @param item table: The token representing the scheduled function that was +-- returned from the schedule_function call. +function remove_scheduled_function(item) + for k, v in pairs(scheduled_functions) do + if v == item then + table.remove(scheduled_functions, k) + return + end + end +end + +--- Execute scheduled functions. +-- Some calls create temporary files and/or directories and register +-- corresponding cleanup functions. Calling this function will run +-- these function, erasing temporaries. +-- Functions are executed in the inverse order they were scheduled. +function run_scheduled_functions() + local fs = require("luarocks.fs") + fs.change_dir_to_root() + for i = #scheduled_functions, 1, -1 do + local item = scheduled_functions[i] + item.fn(unpack(item.args)) + end +end + +--- Extract flags from an arguments list. +-- Given string arguments, extract flag arguments into a flags set. +-- For example, given "foo", "--tux=beep", "--bla", "bar", "--baz", +-- it would return the following: +-- {["bla"] = true, ["tux"] = "beep", ["baz"] = true}, "foo", "bar". +function parse_flags(...) + local args = {...} + local flags = {} + for i = #args, 1, -1 do + local flag = args[i]:match("^%-%-(.*)") + if flag then + local var,val = flag:match("([a-z_%-]*)=(.*)") + if val then + flags[var] = val + else + flags[flag] = true + end + table.remove(args, i) + end + end + return flags, unpack(args) +end + +--- Merges contents of src on top of dst's contents. +-- @param dst Destination table, which will receive src's contents. +-- @param src Table which provides new contents to dst. +-- @see platform_overrides +function deep_merge(dst, src) + for k, v in pairs(src) do + if type(v) == "table" then + if not dst[k] then + dst[k] = {} + end + if type(dst[k]) == "table" then + deep_merge(dst[k], v) + else + dst[k] = v + end + else + dst[k] = v + end + end +end + +--- Perform platform-specific overrides on a table. +-- Overrides values of table with the contents of the appropriate +-- subset of its "platforms" field. The "platforms" field should +-- be a table containing subtables keyed with strings representing +-- platform names. Names that match the contents of the global +-- cfg.platforms setting are used. For example, if +-- cfg.platforms= {"foo"}, then the fields of +-- tbl.platforms.foo will overwrite those of tbl with the same +-- names. For table values, the operation is performed recursively +-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of +-- tbl.x are preserved). +-- @param tbl table or nil: Table which may contain a "platforms" field; +-- if it doesn't (or if nil is passed), this function does nothing. +function platform_overrides(tbl) + assert(type(tbl) == "table" or not tbl) + + local cfg = require("luarocks.cfg") + + if not tbl then return end + + if tbl.platforms then + for _, platform in ipairs(cfg.platforms) do + local platform_tbl = tbl.platforms[platform] + if platform_tbl then + deep_merge(tbl, platform_tbl) + end + end + end + tbl.platforms = nil +end + +local var_format_pattern = "%$%((%a[%a%d_]+)%)" + +--- Create a new shallow copy of a table: a new table with +-- the same keys and values. Keys point to the same objects as +-- the original table (ie, does not copy recursively). +-- @param tbl table: the input table +-- @return table: a new table with the same contents. +local function make_shallow_copy(tbl) + local copy = {} + for k,v in pairs(tbl) do + copy[k] = v + end + return copy +end + +-- Check if a set of needed variables are referenced +-- somewhere in a list of definitions, warning the user +-- about any unused ones. Each key in needed_set should +-- appear as a $(XYZ) variable at least once as a +-- substring of some value of var_defs. +-- @param var_defs: a table with string keys and string +-- values, containing variable definitions. +-- @param needed_set: a set where keys are the names of +-- needed variables. +-- @param msg string: the warning message to display. +function warn_if_not_used(var_defs, needed_set, msg) + needed_set = make_shallow_copy(needed_set) + for var,val in pairs(var_defs) do + for used in val:gmatch(var_format_pattern) do + needed_set[used] = nil + end + end + for var,_ in pairs(needed_set) do + warning(msg:format(var)) + end +end + +-- Output any entries that might remain in $(XYZ) format, +-- warning the user that substitutions have failed. +-- @param line string: the input string +local function warn_failed_matches(line) + local any_failed = false + if line:match(var_format_pattern) then + for unmatched in line:gmatch(var_format_pattern) do + warning("unmatched variable " .. unmatched) + any_failed = true + end + end + return any_failed +end + +--- Perform make-style variable substitutions on string values of a table. +-- For every string value tbl.x which contains a substring of the format +-- "$(XYZ)" will have this substring replaced by vars["XYZ"], if that field +-- exists in vars. Only string values are processed; this function +-- does not scan subtables recursively. +-- @param tbl table: Table to have its string values modified. +-- @param vars table: Table containing string-string key-value pairs +-- representing variables to replace in the strings values of tbl. +function variable_substitutions(tbl, vars) + assert(type(tbl) == "table") + assert(type(vars) == "table") + + local updated = {} + for k, v in pairs(tbl) do + if type(v) == "string" then + updated[k] = v:gsub(var_format_pattern, vars) + if warn_failed_matches(updated[k]) then + updated[k] = updated[k]:gsub(var_format_pattern, "") + end + end + end + for k, v in pairs(updated) do + tbl[k] = v + end +end + +--- Return an array of keys of a table. +-- @param tbl table: The input table. +-- @return table: The array of keys. +function keys(tbl) + local ks = {} + for k,_ in pairs(tbl) do + table.insert(ks, k) + end + return ks +end + +local function default_sort(a, b) + local ta = type(a) + local tb = type(b) + if ta == "number" and tb == "number" then + return a < b + elseif ta == "number" then + return true + elseif tb == "number" then + return false + else + return tostring(a) < tostring(b) + end +end + +-- The iterator function used internally by util.sortedpairs. +-- @param tbl table: The table to be iterated. +-- @param sort_function function or nil: An optional comparison function +-- to be used by table.sort when sorting keys. +-- @see sortedpairs +local function sortedpairs_iterator(tbl, sort_function) + local ks = keys(tbl) + if not sort_function or type(sort_function) == "function" then + table.sort(ks, sort_function or default_sort) + for _, k in ipairs(ks) do + coroutine.yield(k, tbl[k]) + end + else + local order = sort_function + local done = {} + for _, k in ipairs(order) do + local sub_order + if type(k) == "table" then + sub_order = k[2] + k = k[1] + end + if tbl[k] then + done[k] = true + coroutine.yield(k, tbl[k], sub_order) + end + end + table.sort(ks, default_sort) + for _, k in ipairs(ks) do + if not done[k] then + coroutine.yield(k, tbl[k]) + end + end + end +end + +--- A table iterator generator that returns elements sorted by key, +-- to be used in "for" loops. +-- @param tbl table: The table to be iterated. +-- @param sort_function function or table or nil: An optional comparison function +-- to be used by table.sort when sorting keys, or an array listing an explicit order +-- for keys. If a value itself is an array, it is taken so that the first element +-- is a string representing the field name, and the second element is a priority table +-- for that key. +-- @return function: the iterator function. +function sortedpairs(tbl, sort_function) + return coroutine.wrap(function() sortedpairs_iterator(tbl, sort_function) end) +end + +function starts_with(s, prefix) + return s:sub(1,#prefix) == prefix +end + +--- Print a line to standard output +function printout(...) + io.stdout:write(table.concat({...},"\t")) + io.stdout:write("\n") +end + +--- Print a line to standard error +function printerr(...) + io.stderr:write(table.concat({...},"\t")) + io.stderr:write("\n") +end + +--- Display a warning message. +-- @param msg string: the warning message +function warning(msg) + printerr("Warning: "..msg) +end + +function title(msg, porcelain, underline) + if porcelain then return end + printout() + printout(msg) + printout((underline or "-"):rep(#msg)) + printout() +end + +-- from http://lua-users.org/wiki/SplitJoin +-- by PhilippeLhoste +function split_string(str, delim, maxNb) + -- Eliminate bad cases... + if string.find(str, delim) == nil then + return { str } + end + if maxNb == nil or maxNb < 1 then + maxNb = 0 -- No limit + end + local result = {} + local pat = "(.-)" .. delim .. "()" + local nb = 0 + local lastPos + for part, pos in string.gmatch(str, pat) do + nb = nb + 1 + result[nb] = part + lastPos = pos + if nb == maxNb then break end + end + -- Handle the last field + if nb ~= maxNb then + result[nb + 1] = string.sub(str, lastPos) + end + return result +end + +--- Remove repeated entries from a path-style string. +-- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d". +-- @param list string: A path string (from $PATH or package.path) +-- @param sep string: The separator +function remove_path_dupes(list, sep) + assert(type(list) == "string") + assert(type(sep) == "string") + local parts = split_string(list, sep) + local final, entries = {}, {} + for _, part in ipairs(parts) do + if not entries[part] then + table.insert(final, part) + entries[part] = true + end + end + return table.concat(final, sep) +end + +--- +-- Formats tables with cycles recursively to any depth. +-- References to other tables are shown as values. +-- Self references are indicated. +-- The string returned is "Lua code", which can be procesed +-- (in the case in which indent is composed by spaces or "--"). +-- Userdata and function keys and values are shown as strings, +-- which logically are exactly not equivalent to the original code. +-- This routine can serve for pretty formating tables with +-- proper indentations, apart from printing them: +-- io.write(table.show(t, "t")) -- a typical use +-- Written by Julio Manuel Fernandez-Diaz, +-- Heavily based on "Saving tables with cycles", PIL2, p. 113. +-- @param t table: is the table. +-- @param name string: is the name of the table (optional) +-- @param indent string: is a first indentation (optional). +-- @return string: the pretty-printed table +function show_table(t, name, indent) + local cart -- a container + local autoref -- for self references + + local function isemptytable(t) return next(t) == nil end + + local function basicSerialize (o) + local so = tostring(o) + if type(o) == "function" then + local info = debug.getinfo(o, "S") + -- info.name is nil because o is not a calling level + if info.what == "C" then + return ("%q"):format(so .. ", C function") + else + -- the information is defined through lines + return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) + end + elseif type(o) == "number" then + return so + else + return ("%q"):format(so) + end + end + + local function addtocart (value, name, indent, saved, field) + indent = indent or "" + saved = saved or {} + field = field or name + + cart = cart .. indent .. field + + if type(value) ~= "table" then + cart = cart .. " = " .. basicSerialize(value) .. ";\n" + else + if saved[value] then + cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n" + autoref = autoref .. name .. " = " .. saved[value] .. ";\n" + else + saved[value] = name + --if tablecount(value) == 0 then + if isemptytable(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basicSerialize(k) + local fname = ("%s[%s]"):format(name, k) + field = ("[%s]"):format(k) + -- three spaces between levels + addtocart(v, fname, indent .. " ", saved, field) + end + cart = cart .. indent .. "};\n" + end + end + end + end + + name = name or "__unnamed__" + if type(t) ~= "table" then + return name .. " = " .. basicSerialize(t) + end + cart, autoref = "", "" + addtocart(t, name, indent) + return cart .. autoref +end diff -r ff65dfb63263 -r d137f631bad5 share/lua/5.2/luarocks/validate.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/lua/5.2/luarocks/validate.lua Fri Dec 14 22:24:27 2012 +0000 @@ -0,0 +1,160 @@ + +--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled). +module("luarocks.validate", package.seeall) + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local cfg = require("luarocks.cfg") +local build = require("luarocks.build") +local install = require("luarocks.install") +local util = require("luarocks.util") + +help_summary = "Sandboxed test of build/install of all packages in a repository." + +help = [[ +, if given, is a local repository pathname. +]] + +local function save_settings(repo) + local protocol, path = dir.split_url(repo) + table.insert(cfg.rocks_servers, 1, protocol.."://"..path) + return { + root_dir = cfg.root_dir, + rocks_dir = cfg.rocks_dir, + deploy_bin_dir = cfg.deploy_bin_dir, + deploy_lua_dir = cfg.deploy_lua_dir, + deploy_lib_dir = cfg.deploy_lib_dir, + } +end + +local function restore_settings(settings) + cfg.root_dir = settings.root_dir + cfg.rocks_dir = settings.rocks_dir + cfg.deploy_bin_dir = settings.deploy_bin_dir + cfg.deploy_lua_dir = settings.deploy_lua_dir + cfg.deploy_lib_dir = settings.deploy_lib_dir + cfg.variables.ROCKS_TREE = settings.rocks_dir + cfg.variables.SCRIPTS_DIR = settings.deploy_bin_dir + table.remove(cfg.rocks_servers, 1) +end + +local function prepare_sandbox(file) + local root_dir = fs.make_temp_dir(file):gsub("/+$", "") + cfg.root_dir = root_dir + cfg.rocks_dir = path.rocks_dir(root_dir) + cfg.deploy_bin_dir = path.deploy_bin_dir(root_dir) + cfg.variables.ROCKS_TREE = cfg.rocks_dir + cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir + return root_dir +end + +local function validate_rockspec(file) + local ok, err, errcode = build.build_rockspec(file, true, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +local function validate_src_rock(file) + local ok, err, errcode = build.build_rock(file, false, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +local function validate_rock(file) + local ok, err, errcode = install.install_binary_rock(file, "one") + if not ok then + util.printerr(err) + end + return ok, err, errcode +end + +local function validate(repo, flags) + local results = { + ok = {} + } + local settings = save_settings(repo) + local sandbox + if flags["quick"] then + sandbox = prepare_sandbox("luarocks_validate") + end + if not fs.exists(repo) then + return nil, repo.." is not a local repository." + end + for _, file in pairs(fs.list_dir(repo)) do for _=1,1 do + if file == "manifest" or file == "index.html" then + break -- continue for + end + local pathname = fs.absolute_name(dir.path(repo, file)) + if not flags["quick"] then + sandbox = prepare_sandbox(file) + end + local ok, err, errcode + util.printout() + util.printout("Verifying "..pathname) + if file:match("%.rockspec$") then + ok, err, errcode = validate_rockspec(pathname, "one") + elseif file:match("%.src%.rock$") then + ok, err, errcode = validate_src_rock(pathname) + elseif file:match("%.rock$") then + ok, err, errcode = validate_rock(pathname) + end + if ok then + table.insert(results.ok, {file=file} ) + else + if not errcode then + errcode = "misc" + end + if not results[errcode] then + results[errcode] = {} + end + table.insert(results[errcode], {file=file, err=err} ) + end + util.run_scheduled_functions() + if not flags["quick"] then + fs.delete(sandbox) + end + repeat until not fs.pop_dir() + end end + if flags["quick"] then + fs.delete(sandbox) + end + restore_settings(settings) + util.title("Results:") + util.printout("OK: "..tostring(#results.ok)) + for _, entry in ipairs(results.ok) do + util.printout(entry.file) + end + for errcode, errors in pairs(results) do + if errcode ~= "ok" then + util.printout() + util.printout(errcode.." errors: "..tostring(#errors)) + for _, entry in ipairs(errors) do + util.printout(entry.file, entry.err) + end + end + end + + util.title("Summary:") + local total = 0 + for errcode, errors in pairs(results) do + util.printout(errcode..": "..tostring(#errors)) + total = total + #errors + end + util.printout("Total: "..total) + return true +end + +function run(...) + local flags, repo = util.parse_flags(...) + repo = repo or cfg.rocks_dir + + util.printout("Verifying contents of "..repo) + + return validate(repo, flags) +end +