From f2beb5ee1fd2c54d59a43f4f2a8fe0f7a1701daa Mon Sep 17 00:00:00 2001 From: Hisham Date: Thu, 30 Jun 2016 01:15:01 -0300 Subject: Core modules reorganization. Isolate all modules used by luarocks.loader in a luarocks.core.* namespace. Core modules can only require other core modules, and they only use require() at the top-level chunk. In other words, after luarocks.loader is setup, package.path can be altered at will and it should not affect the ability of luarocks.loader to run, and the luarocks.loader modules should not interfere with modules loaded later. This was motivated by @robooo's GSoC work on porting the LuaRocks test suite to Lua using Busted. Busted itself runs using luarocks.loader, and we need to ensure that the modules loaded by the tests do not conflict with the ones used by luarocks.loader. A circular dependency between luarocks.manif and luarocks.search was removed by creating a separate luarocks.manif.writer module. Also, luarocks-admin commands were moved to a luarocks.admin.* namespace. --- src/bin/luarocks | 2 +- src/bin/luarocks-admin | 10 +- src/luarocks/add.lua | 121 ------ src/luarocks/admin/add.lua | 129 ++++++ src/luarocks/admin/cache.lua | 77 ++++ src/luarocks/admin/make_manifest.lua | 51 +++ src/luarocks/admin/refresh_cache.lua | 30 ++ src/luarocks/admin/remove.lua | 90 +++++ src/luarocks/admin_remove.lua | 91 ----- src/luarocks/build.lua | 9 +- src/luarocks/build/builtin.lua | 2 +- src/luarocks/build/cmake.lua | 2 +- src/luarocks/build/make.lua | 2 +- src/luarocks/cache.lua | 78 ---- src/luarocks/cfg.lua | 741 ----------------------------------- src/luarocks/command_line.lua | 2 +- src/luarocks/config_cmd.lua | 2 +- src/luarocks/core/cfg.lua | 741 +++++++++++++++++++++++++++++++++++ src/luarocks/core/deps.lua | 192 +++++++++ src/luarocks/core/dir.lua | 55 +++ src/luarocks/core/manif.lua | 107 +++++ src/luarocks/core/path.lua | 149 +++++++ src/luarocks/core/persist.lua | 81 ++++ src/luarocks/core/type_check.lua | 226 +++++++++++ src/luarocks/core/util.lua | 202 ++++++++++ src/luarocks/deps.lua | 215 +--------- src/luarocks/dir.lua | 49 +-- src/luarocks/doc.lua | 1 - src/luarocks/download.lua | 3 +- src/luarocks/fetch.lua | 3 +- src/luarocks/fs.lua | 3 +- src/luarocks/fs/lua.lua | 2 +- src/luarocks/fs/tools.lua | 2 +- src/luarocks/fs/unix.lua | 2 +- src/luarocks/fs/unix/tools.lua | 2 +- src/luarocks/fs/win32.lua | 2 +- src/luarocks/fs/win32/tools.lua | 2 +- src/luarocks/help.lua | 2 +- src/luarocks/index.lua | 1 - src/luarocks/install.lua | 9 +- src/luarocks/lint.lua | 1 - src/luarocks/list.lua | 3 +- src/luarocks/loader.lua | 31 +- src/luarocks/make.lua | 3 +- src/luarocks/make_manifest.lua | 52 --- src/luarocks/manif.lua | 367 +---------------- src/luarocks/manif/writer.lua | 360 +++++++++++++++++ src/luarocks/manif_core.lua | 107 ----- src/luarocks/pack.lua | 3 +- src/luarocks/path.lua | 142 +------ src/luarocks/path_cmd.lua | 2 +- src/luarocks/persist.lua | 75 +--- src/luarocks/purge.lua | 9 +- src/luarocks/refresh_cache.lua | 31 -- src/luarocks/remove.lua | 7 +- src/luarocks/repos.lua | 3 +- src/luarocks/search.lua | 4 +- src/luarocks/show.lua | 3 +- src/luarocks/type_check.lua | 224 +---------- src/luarocks/unpack.lua | 3 +- src/luarocks/upload.lua | 2 +- src/luarocks/upload/api.lua | 2 +- src/luarocks/util.lua | 203 +--------- src/luarocks/validate.lua | 158 -------- src/luarocks/write_rockspec.lua | 3 +- 65 files changed, 2595 insertions(+), 2693 deletions(-) delete mode 100644 src/luarocks/add.lua create mode 100644 src/luarocks/admin/add.lua create mode 100644 src/luarocks/admin/cache.lua create mode 100644 src/luarocks/admin/make_manifest.lua create mode 100644 src/luarocks/admin/refresh_cache.lua create mode 100644 src/luarocks/admin/remove.lua delete mode 100644 src/luarocks/admin_remove.lua delete mode 100644 src/luarocks/cache.lua delete mode 100644 src/luarocks/cfg.lua create mode 100644 src/luarocks/core/cfg.lua create mode 100644 src/luarocks/core/deps.lua create mode 100644 src/luarocks/core/dir.lua create mode 100644 src/luarocks/core/manif.lua create mode 100644 src/luarocks/core/path.lua create mode 100644 src/luarocks/core/persist.lua create mode 100644 src/luarocks/core/type_check.lua create mode 100644 src/luarocks/core/util.lua delete mode 100644 src/luarocks/make_manifest.lua create mode 100644 src/luarocks/manif/writer.lua delete mode 100644 src/luarocks/manif_core.lua delete mode 100644 src/luarocks/refresh_cache.lua delete mode 100644 src/luarocks/validate.lua (limited to 'src') diff --git a/src/bin/luarocks b/src/bin/luarocks index be6c2b81..21f17da9 100755 --- a/src/bin/luarocks +++ b/src/bin/luarocks @@ -1,7 +1,7 @@ #!/usr/bin/env lua -- this should be loaded first. -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local loader = require("luarocks.loader") local command_line = require("luarocks.command_line") diff --git a/src/bin/luarocks-admin b/src/bin/luarocks-admin index 2890d1f1..660c0a70 100755 --- a/src/bin/luarocks-admin +++ b/src/bin/luarocks-admin @@ -1,7 +1,7 @@ #!/usr/bin/env lua -- this should be loaded first. -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local loader = require("luarocks.loader") local command_line = require("luarocks.command_line") @@ -10,10 +10,10 @@ program_description = "LuaRocks repository administration interface" commands = { help = "luarocks.help", - make_manifest = "luarocks.make_manifest", - add = "luarocks.add", - remove = "luarocks.admin_remove", - refresh_cache = "luarocks.refresh_cache", + make_manifest = "luarocks.admin.make_manifest", + add = "luarocks.admin.add", + remove = "luarocks.admin.remove", + refresh_cache = "luarocks.admin.refresh_cache", } command_line.run_command(...) diff --git a/src/luarocks/add.lua b/src/luarocks/add.lua deleted file mode 100644 index 66f7504f..00000000 --- a/src/luarocks/add.lua +++ /dev/null @@ -1,121 +0,0 @@ - ---- Module implementing the luarocks-admin "add" command. --- Adds a rock or rockspec to a rocks server. -local add = {} -package.loaded["luarocks.add"] = add - -local cfg = require("luarocks.cfg") -local util = require("luarocks.util") -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") - -add.help_summary = "Add a rock or rockspec to a rocks server." -add.help_arguments = "[--server=] [--no-refresh] {|...}" -add.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 - - local ok, err = fs.change_dir(at) - if not ok then return nil, err end - - local files = {} - for _, 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, cfg.perm_read) - 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 - - local ok, err = fs.change_dir(local_cache) - if not ok then return nil, err end - - util.printout("Updating manifest...") - manif.make_manifest(local_cache, "one", true) - - manif.zip_manifests() - - 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 - - table.insert(files, "index.html") - table.insert(files, "manifest") - for ver in util.lua_versions() do - table.insert(files, "manifest-"..ver) - table.insert(files, "manifest-"..ver..".zip") - end - - -- TODO abstract away explicit 'curl' call - - local cmd - if protocol == "rsync" then - local srv, path = server_path:match("([^/]+)(/.+)") - cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." -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.." "..table.concat(files, " ").." "..user.."@"..part1..":/"..part2 - else - cmd = cfg.variables.CURL.." "..login_info.." -T '{"..table.concat(files, ",").."}' "..login_url - end - - util.printout(cmd) - fs.execute(cmd) - - return true -end - -function add.command(flags, ...) - local files = {...} - if #files < 1 then - return nil, "Argument missing. "..util.see_help("add", "luarocks-admin") - 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 - - -return add diff --git a/src/luarocks/admin/add.lua b/src/luarocks/admin/add.lua new file mode 100644 index 00000000..daf46c1d --- /dev/null +++ b/src/luarocks/admin/add.lua @@ -0,0 +1,129 @@ + +--- Module implementing the luarocks-admin "add" command. +-- Adds a rock or rockspec to a rocks server. +local add = {} + +local cfg = require("luarocks.core.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local writer = require("luarocks.manif.writer") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.admin.cache") + +add.help_summary = "Add a rock or rockspec to a rocks server." +add.help_arguments = "[--server=] [--no-refresh] {|...}" +add.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 zip_manifests() + for ver in util.lua_versions() do + local file = "manifest-"..ver + local zip = file..".zip" + fs.delete(dir.path(fs.current_dir(), zip)) + fs.zip(zip, file) + end +end + +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 + + local ok, err = fs.change_dir(at) + if not ok then return nil, err end + + local files = {} + for _, 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, cfg.perm_read) + 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 + + local ok, err = fs.change_dir(local_cache) + if not ok then return nil, err end + + util.printout("Updating manifest...") + writer.make_manifest(local_cache, "one", true) + + zip_manifests() + + 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 + + table.insert(files, "index.html") + table.insert(files, "manifest") + for ver in util.lua_versions() do + table.insert(files, "manifest-"..ver) + table.insert(files, "manifest-"..ver..".zip") + end + + -- TODO abstract away explicit 'curl' call + + local cmd + if protocol == "rsync" then + local srv, path = server_path:match("([^/]+)(/.+)") + cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." -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.." "..table.concat(files, " ").." "..user.."@"..part1..":/"..part2 + else + cmd = cfg.variables.CURL.." "..login_info.." -T '{"..table.concat(files, ",").."}' "..login_url + end + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function add.command(flags, ...) + local files = {...} + if #files < 1 then + return nil, "Argument missing. "..util.see_help("add", "luarocks-admin") + 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 + + +return add diff --git a/src/luarocks/admin/cache.lua b/src/luarocks/admin/cache.lua new file mode 100644 index 00000000..0daa0fc0 --- /dev/null +++ b/src/luarocks/admin/cache.lua @@ -0,0 +1,77 @@ + +--- Module handling the LuaRocks local cache. +-- Adds a rock or rockspec to a rocks server. +local cache = {} + +local fs = require("luarocks.fs") +local cfg = require("luarocks.core.cfg") +local dir = require("luarocks.dir") +local util = require("luarocks.util") + +function cache.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 cache.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 cache.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 = cfg.local_cache .. "/" .. server + return local_cache, protocol, server_path, user, password +end + +function cache.refresh_local_cache(server, url, user, password) + local local_cache, protocol, server_path, user, password = cache.split_server_url(server, url, user, password) + local ok, err = fs.make_dir(local_cache) + if not ok then + return nil, "Failed creating local cache dir: "..err + end + fs.change_dir(local_cache) + if not ok then return nil, err end + 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.." "..cfg.variables.RSYNCFLAGS.." -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 + +return cache diff --git a/src/luarocks/admin/make_manifest.lua b/src/luarocks/admin/make_manifest.lua new file mode 100644 index 00000000..57851942 --- /dev/null +++ b/src/luarocks/admin/make_manifest.lua @@ -0,0 +1,51 @@ + +--- Module implementing the luarocks-admin "make_manifest" command. +-- Compile a manifest file for a repository. +local make_manifest = {} + +local writer = require("luarocks.manif.writer") +local index = require("luarocks.index") +local cfg = require("luarocks.core.cfg") +local util = require("luarocks.util") +local deps = require("luarocks.deps") +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +make_manifest.help_summary = "Compile a manifest file for a repository." + +make_manifest.help = [[ +, if given, is a local repository pathname. + +--local-tree If given, do not write versioned versions of the manifest file. + Use this when rebuilding the manifest of a local rocks tree. +]] + +--- 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 make_manifest.command(flags, repo) + assert(type(repo) == "string" or not repo) + repo = repo or cfg.rocks_dir + + util.printout("Making manifest for "..repo) + + if repo:match("/lib/luarocks") and not flags["local-tree"] then + util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") + end + + local ok, err = writer.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"]) + if ok and not flags["local-tree"] then + util.printout("Generating index.html for "..repo) + index.make_index(repo) + end + if flags["local-tree"] then + for luaver in util.lua_versions() do + fs.delete(dir.path(repo, "manifest-"..luaver)) + end + end + return ok, err +end + +return make_manifest diff --git a/src/luarocks/admin/refresh_cache.lua b/src/luarocks/admin/refresh_cache.lua new file mode 100644 index 00000000..947dbfb0 --- /dev/null +++ b/src/luarocks/admin/refresh_cache.lua @@ -0,0 +1,30 @@ + +--- Module implementing the luarocks-admin "refresh_cache" command. +local refresh_cache = {} + +local cfg = require("luarocks.core.cfg") +local cache = require("luarocks.admin.cache") + +refresh_cache.help_summary = "Refresh local cache of a remote rocks server." +refresh_cache.help_arguments = "[--from=]" +refresh_cache.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 refresh_cache.command(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 + + +return refresh_cache diff --git a/src/luarocks/admin/remove.lua b/src/luarocks/admin/remove.lua new file mode 100644 index 00000000..763a166f --- /dev/null +++ b/src/luarocks/admin/remove.lua @@ -0,0 +1,90 @@ + +--- Module implementing the luarocks-admin "remove" command. +-- Removes a rock or rockspec from a rocks server. +local admin_remove = {} + +local cfg = require("luarocks.core.cfg") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local writer = require("luarocks.manif.writer") +local index = require("luarocks.index") +local fs = require("luarocks.fs") +local cache = require("luarocks.admin.cache") + +admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." +admin_remove.help_arguments = "[--server=] [--no-refresh] {|...}" +admin_remove.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 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 + + local ok, err = fs.change_dir(at) + if not ok then return nil, err end + + local nr_files = 0 + for _, rockfile in ipairs(rockfiles) do + local basename = dir.base_name(rockfile) + local file = dir.path(local_cache, basename) + util.printout("Removing file "..file.."...") + fs.delete(file) + if not fs.exists(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 + + local ok, err = fs.change_dir(local_cache) + if not ok then return nil, err end + + util.printout("Updating manifest...") + writer.make_manifest(local_cache, "one", true) + util.printout("Updating index.html...") + index.make_index(local_cache) + + local srv, path = server_path:match("([^/]+)(/.+)") + local cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." --delete -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" + + util.printout(cmd) + fs.execute(cmd) + + return true +end + +function admin_remove.command(flags, ...) + local files = {...} + if #files < 1 then + return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin") + 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 + + +return admin_remove diff --git a/src/luarocks/admin_remove.lua b/src/luarocks/admin_remove.lua deleted file mode 100644 index be1e7cbc..00000000 --- a/src/luarocks/admin_remove.lua +++ /dev/null @@ -1,91 +0,0 @@ - ---- Module implementing the luarocks-admin "remove" command. --- Removes a rock or rockspec from a rocks server. -local admin_remove = {} -package.loaded["luarocks.admin_remove"] = admin_remove - -local cfg = require("luarocks.cfg") -local util = require("luarocks.util") -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") - -admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." -admin_remove.help_arguments = "[--server=] [--no-refresh] {|...}" -admin_remove.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 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 - - local ok, err = fs.change_dir(at) - if not ok then return nil, err end - - local nr_files = 0 - for _, rockfile in ipairs(rockfiles) do - local basename = dir.base_name(rockfile) - local file = dir.path(local_cache, basename) - util.printout("Removing file "..file.."...") - fs.delete(file) - if not fs.exists(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 - - local ok, err = fs.change_dir(local_cache) - if not ok then return nil, err end - - util.printout("Updating manifest...") - manif.make_manifest(local_cache, "one", true) - util.printout("Updating index.html...") - index.make_index(local_cache) - - local srv, path = server_path:match("([^/]+)(/.+)") - local cmd = cfg.variables.RSYNC.." "..cfg.variables.RSYNCFLAGS.." --delete -e ssh "..local_cache.."/ "..user.."@"..srv..":"..path.."/" - - util.printout(cmd) - fs.execute(cmd) - - return true -end - -function admin_remove.command(flags, ...) - local files = {...} - if #files < 1 then - return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin") - 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 - - -return admin_remove diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua index 2d29e23f..d7d8ed07 100644 --- a/src/luarocks/build.lua +++ b/src/luarocks/build.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "build" command. -- Builds a rock, compiling its C parts if any. local build = {} -package.loaded["luarocks.build"] = build local pack = require("luarocks.pack") local path = require("luarocks.path") @@ -12,9 +11,9 @@ 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 writer = require("luarocks.manif.writer") local remove = require("luarocks.remove") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") build.help_summary = "Build/compile a rock." build.help_arguments = "[--pack-binary-rock] [--keep] {|| []}" @@ -346,7 +345,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m fs.pop_dir() end - ok, err = manif.make_rock_manifest(name, version) + ok, err = writer.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)) @@ -360,7 +359,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m 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) + ok, err = writer.update_manifest(name, version, nil, deps_mode) if err then return nil, err end util.announce_install(rockspec) diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua index 81fa8b13..d9785b0c 100644 --- a/src/luarocks/build/builtin.lua +++ b/src/luarocks/build/builtin.lua @@ -7,7 +7,7 @@ local unpack = unpack or table.unpack local fs = require("luarocks.fs") local path = require("luarocks.path") local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") --- Run a command displaying its execution on standard output. diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua index c2712bb2..43702979 100644 --- a/src/luarocks/build/cmake.lua +++ b/src/luarocks/build/cmake.lua @@ -4,7 +4,7 @@ local cmake = {} local fs = require("luarocks.fs") local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local deps = require("luarocks.deps") --- Driver function for the "cmake" build back-end. diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua index 69e73c2e..ded015b7 100644 --- a/src/luarocks/build/make.lua +++ b/src/luarocks/build/make.lua @@ -6,7 +6,7 @@ local unpack = unpack or table.unpack local fs = require("luarocks.fs") local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") --- Call "make" with given target and variables -- @param make_cmd string: the make command to be used (typically diff --git a/src/luarocks/cache.lua b/src/luarocks/cache.lua deleted file mode 100644 index 4a95f70e..00000000 --- a/src/luarocks/cache.lua +++ /dev/null @@ -1,78 +0,0 @@ - ---- Module handling the LuaRocks local cache. --- Adds a rock or rockspec to a rocks server. -local cache = {} -package.loaded["luarocks.cache"] = cache - -local fs = require("luarocks.fs") -local cfg = require("luarocks.cfg") -local dir = require("luarocks.dir") -local util = require("luarocks.util") - -function cache.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 cache.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 cache.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 = cfg.local_cache .. "/" .. server - return local_cache, protocol, server_path, user, password -end - -function cache.refresh_local_cache(server, url, user, password) - local local_cache, protocol, server_path, user, password = cache.split_server_url(server, url, user, password) - local ok, err = fs.make_dir(local_cache) - if not ok then - return nil, "Failed creating local cache dir: "..err - end - fs.change_dir(local_cache) - if not ok then return nil, err end - 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.." "..cfg.variables.RSYNCFLAGS.." -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 - -return cache diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua deleted file mode 100644 index 53387276..00000000 --- a/src/luarocks/cfg.lua +++ /dev/null @@ -1,741 +0,0 @@ ---- 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") -local cfg = {} -package.loaded["luarocks.cfg"] = cfg - -local util = require("luarocks.util") - -cfg.lua_version = _VERSION:sub(5) -local version_suffix = cfg.lua_version:gsub("%.", "_") - --- Load site-local global configurations -local ok, site_config = pcall(require, "luarocks.site_config_"..version_suffix) -if not ok then - ok, site_config = pcall(require, "luarocks.site_config") -end -if not ok then - io.stderr:write("Site-local luarocks/site_config.lua file not found. Incomplete installation?\n") - site_config = {} -end - -cfg.program_version = "scm" -cfg.program_series = "2.2" -cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series -cfg.variables = {} -cfg.rocks_trees = {} -cfg.platforms = {} - -local persist = require("luarocks.persist") - -cfg.errorcodes = setmetatable({ - OK = 0, - UNSPECIFIED = 1, - PERMISSIONDENIED = 2, - CONFIGFILE = 3, - CRASH = 99 -},{ - __index = function(t, key) - local val = rawget(t, key) - if not val then - error("'"..tostring(key).."' is not a valid errorcode", 2) - end - return val - end -}) - - -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(cfg.errorcodes.UNSPECIFIED) -end - --- System detection: - --- 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). -local system = site_config.LUAROCKS_UNAME_S or util.popen_read("uname -s") -local proc = site_config.LUAROCKS_UNAME_M or util.popen_read("uname -m") -if proc:match("i[%d]86") then - cfg.target_cpu = "x86" -elseif proc:match("amd64") or proc:match("x86_64") then - cfg.target_cpu = "x86_64" -elseif proc:match("Power Macintosh") then - cfg.target_cpu = "powerpc" - else - cfg.target_cpu = proc -end - -if system == "FreeBSD" then - cfg.platforms.unix = true - cfg.platforms.freebsd = true - cfg.platforms.bsd = true -elseif system == "OpenBSD" then - cfg.platforms.unix = true - cfg.platforms.openbsd = true - cfg.platforms.bsd = true -elseif system == "NetBSD" then - cfg.platforms.unix = true - cfg.platforms.netbsd = true - cfg.platforms.bsd = true -elseif system == "Darwin" then - cfg.platforms.unix = true - cfg.platforms.macosx = true - cfg.platforms.bsd = true -elseif system == "Linux" then - cfg.platforms.unix = true - cfg.platforms.linux = true -elseif system == "SunOS" then - cfg.platforms.unix = true - cfg.platforms.solaris = true -elseif system and system:match("^CYGWIN") then - cfg.platforms.unix = true - cfg.platforms.cygwin = true -elseif system and system:match("^MSYS") then - cfg.platforms.unix = true - cfg.platforms.msys = true - cfg.platforms.cygwin = true -elseif system and system:match("^Windows") then - cfg.platforms.windows = true - cfg.platforms.win32 = true -elseif system and system:match("^MINGW") then - cfg.platforms.windows = true - cfg.platforms.mingw32 = true - cfg.platforms.win32 = true -elseif system == "Haiku" then - cfg.platforms.unix = true - cfg.platforms.haiku = true -else - cfg.platforms.unix = true - -- Fall back to Unix in unknown systems. -end - --- Set order for platform overrides -local platform_order = { - -- Unixes - unix = 1, - bsd = 2, - solaris = 3, - netbsd = 4, - openbsd = 5, - freebsd = 6, - linux = 7, - macosx = 8, - cygwin = 9, - msys = 10, - haiku = 11, - -- Windows - win32 = 12, - mingw32 = 13, - windows = 14 } - --- Path configuration: -local sys_config_file, home_config_file -local sys_config_file_default, home_config_file_default -local sys_config_dir, home_config_dir -local sys_config_ok, home_config_ok = false, false -local extra_luarocks_module_dir -sys_config_dir = site_config.LUAROCKS_SYSCONFDIR or site_config.LUAROCKS_PREFIX -if cfg.platforms.windows then - cfg.home = os.getenv("APPDATA") or "c:" - sys_config_dir = sys_config_dir or "c:/luarocks" - home_config_dir = cfg.home.."/luarocks" - cfg.home_tree = cfg.home.."/luarocks/" -else - cfg.home = os.getenv("HOME") or "" - sys_config_dir = sys_config_dir or "/etc/luarocks" - home_config_dir = cfg.home.."/.luarocks" - cfg.home_tree = (os.getenv("USER") ~= "root") and cfg.home.."/.luarocks/" -end - --- Create global environment for the config files; -local env_for_config_file = function() - local e - e = { - home = cfg.home, - lua_version = cfg.lua_version, - platforms = util.make_shallow_copy(cfg.platforms), - processor = cfg.target_cpu, -- remains for compat reasons - target_cpu = cfg.target_cpu, -- replaces `processor` - os_getenv = os.getenv, - dump_env = function() - -- debug function, calling it from a config file will show all - -- available globals to that config file - print(util.show_table(e, "global environment")) - end, - } - return e -end - --- Merge values from config files read into the `cfg` table -local merge_overrides = function(overrides) - -- remove some stuff we do not want to integrate - overrides.os_getenv = nil - overrides.dump_env = nil - -- remove tables to be copied verbatim instead of deeply merged - if overrides.rocks_trees then cfg.rocks_trees = nil end - if overrides.rocks_servers then cfg.rocks_servers = nil end - -- perform actual merge - util.deep_merge(cfg, overrides) -end - --- load config file from a list until first succesful one. Info is --- added to `cfg` module table, returns filepath of succesfully loaded --- file or nil if it failed -local load_config_file = function(list) - for _, filepath in ipairs(list) do - local result, err, errcode = persist.load_into_table(filepath, env_for_config_file()) - if (not result) and errcode ~= "open" then - -- errcode is either "load" or "run"; bad config file, so error out - io.stderr:write(err.."\n") - os.exit(cfg.errorcodes.CONFIGFILE) - end - if result then - -- succes in loading and running, merge contents and exit - merge_overrides(result) - return filepath - end - end - return nil -- nothing was loaded -end - - --- Load system configuration file -do - sys_config_file_default = sys_config_dir.."/config-"..cfg.lua_version..".lua" - sys_config_file = load_config_file({ - site_config.LUAROCKS_SYSCONFIG or sys_config_file_default, - sys_config_dir.."/config.lua", - }) - sys_config_ok = (sys_config_file ~= nil) -end - --- Load user configuration file (if allowed) -if not site_config.LUAROCKS_FORCE_CONFIG then - - home_config_file_default = home_config_dir.."/config-"..cfg.lua_version..".lua" - - local config_env_var = "LUAROCKS_CONFIG_" .. version_suffix - local config_env_value = os.getenv(config_env_var) - if not config_env_value then - config_env_var = "LUAROCKS_CONFIG" - config_env_value = os.getenv(config_env_var) - end - - -- first try environment provided file, so we can explicitly warn when it is missing - if config_env_value then - local list = { config_env_value } - home_config_file = load_config_file(list) - home_config_ok = (home_config_file ~= nil) - if not home_config_ok then - io.stderr:write("Warning: could not load configuration file `"..config_env_value.."` given in environment variable "..config_env_var.."\n") - end - end - - -- try the alternative defaults if there was no environment specified file or it didn't work - if not home_config_ok then - local list = { - home_config_file_default, - home_config_dir.."/config.lua", - } - home_config_file = load_config_file(list) - home_config_ok = (home_config_file ~= nil) - end -end - - -if not next(cfg.rocks_trees) then - if cfg.home_tree then - table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } ) - end - if site_config.LUAROCKS_ROCKS_TREE then - table.insert(cfg.rocks_trees, { name = "system", root = site_config.LUAROCKS_ROCKS_TREE } ) - end -end - - --- update platforms list; keyed -> array -do - local lst = {} -- use temp array to not confuse `pairs` in loop - for plat in pairs(cfg.platforms) do - if cfg.platforms[plat] then -- entries set to 'false' skipped - if not platform_order[plat] then - local pl = "" - for k,_ in pairs(platform_order) do pl = pl .. ", " .. k end - io.stderr:write("Bad platform given; "..tostring(plat)..". Valid entries are: "..pl:sub(3,-1) ..".\n") - os.exit(cfg.errorcodes.CONFIGFILE) - end - table.insert(lst, plat) - else - cfg.platforms[plat] = nil - end - end - -- platform overrides depent on the order, so set priorities - table.sort(lst, function(key1, key2) return platform_order[key1] < platform_order[key2] end) - util.deep_merge(cfg.platforms, lst) -end - --- Configure defaults: -local defaults = { - - local_by_default = false, - accept_unknown_fields = false, - fs_use_modules = true, - hooks_enabled = true, - deps_mode = "one", - check_certificates = false, - perm_read = "0644", - perm_exec = "0755", - - lua_modules_path = "/share/lua/"..cfg.lua_version, - lib_modules_path = "/lib/lua/"..cfg.lua_version, - rocks_subdir = site_config.LUAROCKS_ROCKS_SUBDIR or "/lib/luarocks/rocks", - - arch = "unknown", - lib_extension = "unknown", - obj_extension = "unknown", - - rocks_servers = { - { - "https://luarocks.org", - "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/", - "http://luafr.org/moonrocks/", - "http://luarocks.logiceditor.com/rocks", - } - }, - disabled_servers = {}, - - upload = { - server = "https://luarocks.org", - tool_version = "1.0.0", - api_version = "1", - }, - - 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", - connection_timeout = 30, -- 0 = no timeout - - variables = { - MAKE = "make", - CC = "cc", - LD = "ld", - AR = "ar", - RANLIB = "ranlib", - - 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", - MKTEMP = "mktemp", - - ZIP = "zip", - UNZIP = "unzip -n", - GUNZIP = "gunzip", - BUNZIP2 = "bunzip2", - TAR = "tar", - - MD5SUM = "md5sum", - OPENSSL = "openssl", - MD5 = "md5", - STAT = "stat", - TOUCH = "touch", - - CMAKE = "cmake", - SEVENZ = "7z", - - RSYNCFLAGS = "--exclude=.git -Oavz", - STATFLAG = "-c '%a'", - CURLNOCERTFLAG = "", - WGETNOCERTFLAG = "", - }, - - external_deps_subdirs = site_config.LUAROCKS_EXTERNAL_DEPS_SUBDIRS or { - bin = "bin", - lib = "lib", - include = "include" - }, - runtime_external_deps_subdirs = site_config.LUAROCKS_RUNTIME_EXTERNAL_DEPS_SUBDIRS or { - bin = "bin", - lib = "lib", - include = "include" - }, - - rocks_provided = {}, - rocks_provided_3_0 = {}, -} - -if cfg.platforms.windows then - local full_prefix = (site_config.LUAROCKS_PREFIX or (os.getenv("PROGRAMFILES")..[[\LuaRocks]])) - extra_luarocks_module_dir = full_prefix.."\\lua\\?.lua" - - home_config_file = home_config_file and home_config_file:gsub("\\","/") - defaults.fs_use_modules = false - defaults.arch = "win32-"..cfg.target_cpu - defaults.lib_extension = "dll" - defaults.external_lib_extension = "dll" - defaults.static_lib_extension = "lib" - 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"..cfg.lua_version.."/bin" - defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR and site_config.LUA_INCDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/include" - defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR and site_config.LUA_LIBDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/lib" - - defaults.makefile = "Makefile.win" - defaults.variables.MAKE = "nmake" - defaults.variables.CC = "cl" - defaults.variables.RC = "rc" - defaults.variables.WRAPPER = full_prefix.."\\rclauncher.c" - defaults.variables.LD = "link" - defaults.variables.MT = "mt" - defaults.variables.AR = "lib" - defaults.variables.LUALIB = "lua"..cfg.lua_version..".lib" - defaults.variables.CFLAGS = "/nologo /MD /O2" - defaults.variables.LIBFLAG = "/nologo /dll" - - local bins = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", - "MKDIR", "MV", "PWD", "RMDIR", "TEST", "UNAME", "WGET" } - for _, var in ipairs(bins) do - if defaults.variables[var] then - defaults.variables[var] = full_prefix.."\\tools\\"..defaults.variables[var] - end - end - - 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.wrapper_suffix = ".bat" - - local localappdata = os.getenv("LOCALAPPDATA") - if not localappdata then - -- for Windows versions below Vista - localappdata = os.getenv("USERPROFILE").."/Local Settings/Application Data" - end - defaults.local_cache = localappdata.."/LuaRocks/Cache" - defaults.web_browser = "start" -end - -if cfg.platforms.mingw32 then - defaults.obj_extension = "o" - defaults.static_lib_extension = "a" - defaults.cmake_generator = "MinGW Makefiles" - defaults.variables.MAKE = "mingw32-make" - defaults.variables.CC = "mingw32-gcc" - defaults.variables.RC = "windres" - defaults.variables.LD = "mingw32-gcc" - defaults.variables.AR = "ar" - defaults.variables.RANLIB = "ranlib" - defaults.variables.CFLAGS = "-O2" - defaults.variables.LIBFLAG = "-shared" - defaults.external_deps_patterns = { - bin = { "?.exe", "?.bat" }, - -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220 - -- ...should we keep ?.lib at the end? It's not in the above list. - lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" }, - include = { "?.h" } - } - defaults.runtime_external_deps_patterns = { - bin = { "?.exe", "?.bat" }, - lib = { "cyg?.dll", "?.dll", "lib?.dll" }, - include = { "?.h" } - } - -end - -if cfg.platforms.unix then - defaults.lib_extension = "so" - defaults.static_lib_extension = "a" - 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.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.wrapper_suffix = "" - defaults.local_cache = cfg.home.."/.cache/luarocks" - if not defaults.variables.CFLAGS:match("-fPIC") then - defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" - end - defaults.web_browser = "xdg-open" -end - -if cfg.platforms.cygwin then - defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds - defaults.arch = "cygwin-"..cfg.target_cpu - 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 cfg.platforms.msys then - -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish - -- enough, yet we can freely mix with native win32 - defaults.external_deps_patterns = { - bin = { "?.exe", "?.bat", "?" }, - lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a", - "lib?.a", "lib?.dll", "?.dll", "?.lib" }, - include = { "?.h" } - } - defaults.runtime_external_deps_patterns = { - bin = { "?.exe", "?.bat" }, - lib = { "lib?.so", "?.dll", "lib?.dll" }, - include = { "?.h" } - } -end - - -if cfg.platforms.bsd then - defaults.variables.MAKE = "gmake" - defaults.variables.STATFLAG = "-f '%OLp'" -end - -if cfg.platforms.macosx then - defaults.variables.MAKE = "make" - defaults.external_lib_extension = "dylib" - defaults.arch = "macosx-"..cfg.target_cpu - defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" - defaults.variables.STAT = "/usr/bin/stat" - defaults.variables.STATFLAG = "-f '%A'" - local version = util.popen_read("sw_vers -productVersion") - version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3 - if version >= 10 then - version = 8 - elseif version >= 5 then - version = 5 - else - defaults.gcc_rpath = false - end - defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" - defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" - defaults.web_browser = "open" -end - -if cfg.platforms.linux then - defaults.arch = "linux-"..cfg.target_cpu -end - -if cfg.platforms.freebsd then - defaults.arch = "freebsd-"..cfg.target_cpu - defaults.gcc_rpath = false - defaults.variables.CC = "cc" - defaults.variables.LD = "cc" -end - -if cfg.platforms.openbsd then - defaults.arch = "openbsd-"..cfg.target_cpu -end - -if cfg.platforms.netbsd then - defaults.arch = "netbsd-"..cfg.target_cpu -end - -if cfg.platforms.solaris then - defaults.arch = "solaris-"..cfg.target_cpu - --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 - --- Add built-in modules to rocks_provided -defaults.rocks_provided["lua"] = cfg.lua_version.."-1" - -if bit32 then -- Lua 5.2+ - defaults.rocks_provided["bit32"] = cfg.lua_version.."-1" -end - -if utf8 then -- Lua 5.3+ - defaults.rocks_provided["utf8"] = cfg.lua_version.."-1" -end - -if package.loaded.jit then - -- LuaJIT - local lj_version = package.loaded.jit.version:match("LuaJIT (.*)"):gsub("%-","") - defaults.rocks_provided["luabitop"] = lj_version.."-1" - defaults.rocks_provided_3_0["luajit"] = lj_version.."-1" -end - --- Use defaults: - --- Populate some arrays with values from their 'defaults' counterparts --- if they were not already set by user. -for _, entry in ipairs({"variables", "rocks_provided"}) do - if not cfg[entry] then - cfg[entry] = {} - end - for k,v in pairs(defaults[entry]) do - if not cfg[entry][k] then - cfg[entry][k] = v - end - end -end -setmetatable(defaults.rocks_provided_3_0, { __index = cfg.rocks_provided }) - --- 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(cfg, cfg_mt) - -if not cfg.check_certificates then - cfg.variables.CURLNOCERTFLAG = "-k" - cfg.variables.WGETNOCERTFLAG = "--no-check-certificate" -end - -function cfg.make_paths_from_tree(tree) - local lua_path, lib_path, bin_path - if type(tree) == "string" then - lua_path = tree..cfg.lua_modules_path - lib_path = tree..cfg.lib_modules_path - bin_path = tree.."/bin" - else - lua_path = tree.lua_dir or tree.root..cfg.lua_modules_path - lib_path = tree.lib_dir or tree.root..cfg.lib_modules_path - bin_path = tree.bin_dir or tree.root.."/bin" - end - return lua_path, lib_path, bin_path -end - -function cfg.package_paths(current) - local new_path, new_cpath, new_bin = {}, {}, {} - local function add_tree_to_paths(tree) - local lua_path, lib_path, bin_path = cfg.make_paths_from_tree(tree) - table.insert(new_path, lua_path.."/?.lua") - table.insert(new_path, lua_path.."/?/init.lua") - table.insert(new_cpath, lib_path.."/?."..cfg.lib_extension) - table.insert(new_bin, bin_path) - end - if current then - add_tree_to_paths(current) - end - for _,tree in ipairs(cfg.rocks_trees) do - add_tree_to_paths(tree) - end - if extra_luarocks_module_dir then - table.insert(new_path, extra_luarocks_module_dir) - end - return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator) -end - -function cfg.init_package_paths() - local lr_path, lr_cpath, lr_bin = cfg.package_paths() - package.path = util.remove_path_dupes(package.path .. ";" .. lr_path, ";") - package.cpath = util.remove_path_dupes(package.cpath .. ";" .. lr_cpath, ";") -end - -function cfg.which_config() - local ret = { - system = { - file = sys_config_file or sys_config_file_default, - ok = sys_config_ok, - }, - user = { - file = home_config_file or home_config_file_default, - ok = home_config_ok, - } - } - ret.nearest = (ret.user.ok and ret.user.file) or ret.system.file - return ret -end - -cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch - -cfg.http_proxy = os.getenv("http_proxy") -cfg.https_proxy = os.getenv("https_proxy") -cfg.no_proxy = os.getenv("no_proxy") - ---- 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 cfg.is_platform(query) - assert(type(query) == "string") - - for _, platform in ipairs(cfg.platforms) do - if platform == query then - return true - end - end -end - -return cfg diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua index 1a8c0fe7..936e9950 100644 --- a/src/luarocks/command_line.lua +++ b/src/luarocks/command_line.lua @@ -5,7 +5,7 @@ local command_line = {} local unpack = unpack or table.unpack local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local path = require("luarocks.path") local dir = require("luarocks.dir") local deps = require("luarocks.deps") diff --git a/src/luarocks/config_cmd.lua b/src/luarocks/config_cmd.lua index 9e73d228..b68f7898 100644 --- a/src/luarocks/config_cmd.lua +++ b/src/luarocks/config_cmd.lua @@ -2,7 +2,7 @@ -- Queries information about the LuaRocks configuration. local config_cmd = {} -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local dir = require("luarocks.dir") diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua new file mode 100644 index 00000000..42508b9e --- /dev/null +++ b/src/luarocks/core/cfg.lua @@ -0,0 +1,741 @@ + +--- 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 + +local cfg = {} + +cfg.lua_version = _VERSION:sub(5) +local version_suffix = cfg.lua_version:gsub("%.", "_") + +-- Load site-local global configurations +local ok, site_config = pcall(require, "luarocks.site_config_"..version_suffix) +if not ok then + ok, site_config = pcall(require, "luarocks.site_config") +end +if not ok then + io.stderr:write("Site-local luarocks/site_config.lua file not found. Incomplete installation?\n") + site_config = {} +end + +local util = require("luarocks.core.util") +local persist = require("luarocks.core.persist") +local require = nil +-------------------------------------------------------------------------------- + +cfg.program_version = "scm" +cfg.program_series = "3.0" +cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series +cfg.variables = {} +cfg.rocks_trees = {} +cfg.platforms = {} + +cfg.errorcodes = setmetatable({ + OK = 0, + UNSPECIFIED = 1, + PERMISSIONDENIED = 2, + CONFIGFILE = 3, + CRASH = 99 +},{ + __index = function(t, key) + local val = rawget(t, key) + if not val then + error("'"..tostring(key).."' is not a valid errorcode", 2) + end + return val + end +}) + + +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(cfg.errorcodes.UNSPECIFIED) +end + +-- System detection: + +-- 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). +local system = site_config.LUAROCKS_UNAME_S or util.popen_read("uname -s") +local proc = site_config.LUAROCKS_UNAME_M or util.popen_read("uname -m") +if proc:match("i[%d]86") then + cfg.target_cpu = "x86" +elseif proc:match("amd64") or proc:match("x86_64") then + cfg.target_cpu = "x86_64" +elseif proc:match("Power Macintosh") then + cfg.target_cpu = "powerpc" + else + cfg.target_cpu = proc +end + +if system == "FreeBSD" then + cfg.platforms.unix = true + cfg.platforms.freebsd = true + cfg.platforms.bsd = true +elseif system == "OpenBSD" then + cfg.platforms.unix = true + cfg.platforms.openbsd = true + cfg.platforms.bsd = true +elseif system == "NetBSD" then + cfg.platforms.unix = true + cfg.platforms.netbsd = true + cfg.platforms.bsd = true +elseif system == "Darwin" then + cfg.platforms.unix = true + cfg.platforms.macosx = true + cfg.platforms.bsd = true +elseif system == "Linux" then + cfg.platforms.unix = true + cfg.platforms.linux = true +elseif system == "SunOS" then + cfg.platforms.unix = true + cfg.platforms.solaris = true +elseif system and system:match("^CYGWIN") then + cfg.platforms.unix = true + cfg.platforms.cygwin = true +elseif system and system:match("^MSYS") then + cfg.platforms.unix = true + cfg.platforms.msys = true + cfg.platforms.cygwin = true +elseif system and system:match("^Windows") then + cfg.platforms.windows = true + cfg.platforms.win32 = true +elseif system and system:match("^MINGW") then + cfg.platforms.windows = true + cfg.platforms.mingw32 = true + cfg.platforms.win32 = true +elseif system == "Haiku" then + cfg.platforms.unix = true + cfg.platforms.haiku = true +else + cfg.platforms.unix = true + -- Fall back to Unix in unknown systems. +end + +-- Set order for platform overrides +local platform_order = { + -- Unixes + unix = 1, + bsd = 2, + solaris = 3, + netbsd = 4, + openbsd = 5, + freebsd = 6, + linux = 7, + macosx = 8, + cygwin = 9, + msys = 10, + haiku = 11, + -- Windows + win32 = 12, + mingw32 = 13, + windows = 14 } + +-- Path configuration: +local sys_config_file, home_config_file +local sys_config_file_default, home_config_file_default +local sys_config_dir, home_config_dir +local sys_config_ok, home_config_ok = false, false +local extra_luarocks_module_dir +sys_config_dir = site_config.LUAROCKS_SYSCONFDIR or site_config.LUAROCKS_PREFIX +if cfg.platforms.windows then + cfg.home = os.getenv("APPDATA") or "c:" + sys_config_dir = sys_config_dir or "c:/luarocks" + home_config_dir = cfg.home.."/luarocks" + cfg.home_tree = cfg.home.."/luarocks/" +else + cfg.home = os.getenv("HOME") or "" + sys_config_dir = sys_config_dir or "/etc/luarocks" + home_config_dir = cfg.home.."/.luarocks" + cfg.home_tree = (os.getenv("USER") ~= "root") and cfg.home.."/.luarocks/" +end + +-- Create global environment for the config files; +local env_for_config_file = function() + local e + e = { + home = cfg.home, + lua_version = cfg.lua_version, + platforms = util.make_shallow_copy(cfg.platforms), + processor = cfg.target_cpu, -- remains for compat reasons + target_cpu = cfg.target_cpu, -- replaces `processor` + os_getenv = os.getenv, + dump_env = function() + -- debug function, calling it from a config file will show all + -- available globals to that config file + print(util.show_table(e, "global environment")) + end, + } + return e +end + +-- Merge values from config files read into the `cfg` table +local merge_overrides = function(overrides) + -- remove some stuff we do not want to integrate + overrides.os_getenv = nil + overrides.dump_env = nil + -- remove tables to be copied verbatim instead of deeply merged + if overrides.rocks_trees then cfg.rocks_trees = nil end + if overrides.rocks_servers then cfg.rocks_servers = nil end + -- perform actual merge + util.deep_merge(cfg, overrides) +end + +-- load config file from a list until first succesful one. Info is +-- added to `cfg` module table, returns filepath of succesfully loaded +-- file or nil if it failed +local load_config_file = function(list) + for _, filepath in ipairs(list) do + local result, err, errcode = persist.load_into_table(filepath, env_for_config_file()) + if (not result) and errcode ~= "open" then + -- errcode is either "load" or "run"; bad config file, so error out + io.stderr:write(err.."\n") + os.exit(cfg.errorcodes.CONFIGFILE) + end + if result then + -- succes in loading and running, merge contents and exit + merge_overrides(result) + return filepath + end + end + return nil -- nothing was loaded +end + + +-- Load system configuration file +do + sys_config_file_default = sys_config_dir.."/config-"..cfg.lua_version..".lua" + sys_config_file = load_config_file({ + site_config.LUAROCKS_SYSCONFIG or sys_config_file_default, + sys_config_dir.."/config.lua", + }) + sys_config_ok = (sys_config_file ~= nil) +end + +-- Load user configuration file (if allowed) +if not site_config.LUAROCKS_FORCE_CONFIG then + + home_config_file_default = home_config_dir.."/config-"..cfg.lua_version..".lua" + + local config_env_var = "LUAROCKS_CONFIG_" .. version_suffix + local config_env_value = os.getenv(config_env_var) + if not config_env_value then + config_env_var = "LUAROCKS_CONFIG" + config_env_value = os.getenv(config_env_var) + end + + -- first try environment provided file, so we can explicitly warn when it is missing + if config_env_value then + local list = { config_env_value } + home_config_file = load_config_file(list) + home_config_ok = (home_config_file ~= nil) + if not home_config_ok then + io.stderr:write("Warning: could not load configuration file `"..config_env_value.."` given in environment variable "..config_env_var.."\n") + end + end + + -- try the alternative defaults if there was no environment specified file or it didn't work + if not home_config_ok then + local list = { + home_config_file_default, + home_config_dir.."/config.lua", + } + home_config_file = load_config_file(list) + home_config_ok = (home_config_file ~= nil) + end +end + + +if not next(cfg.rocks_trees) then + if cfg.home_tree then + table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } ) + end + if site_config.LUAROCKS_ROCKS_TREE then + table.insert(cfg.rocks_trees, { name = "system", root = site_config.LUAROCKS_ROCKS_TREE } ) + end +end + + +-- update platforms list; keyed -> array +do + local lst = {} -- use temp array to not confuse `pairs` in loop + for plat in pairs(cfg.platforms) do + if cfg.platforms[plat] then -- entries set to 'false' skipped + if not platform_order[plat] then + local pl = "" + for k,_ in pairs(platform_order) do pl = pl .. ", " .. k end + io.stderr:write("Bad platform given; "..tostring(plat)..". Valid entries are: "..pl:sub(3,-1) ..".\n") + os.exit(cfg.errorcodes.CONFIGFILE) + end + table.insert(lst, plat) + else + cfg.platforms[plat] = nil + end + end + -- platform overrides depent on the order, so set priorities + table.sort(lst, function(key1, key2) return platform_order[key1] < platform_order[key2] end) + util.deep_merge(cfg.platforms, lst) +end + +-- Configure defaults: +local defaults = { + + local_by_default = false, + accept_unknown_fields = false, + fs_use_modules = true, + hooks_enabled = true, + deps_mode = "one", + check_certificates = false, + perm_read = "0644", + perm_exec = "0755", + + lua_modules_path = "/share/lua/"..cfg.lua_version, + lib_modules_path = "/lib/lua/"..cfg.lua_version, + rocks_subdir = site_config.LUAROCKS_ROCKS_SUBDIR or "/lib/luarocks/rocks", + + arch = "unknown", + lib_extension = "unknown", + obj_extension = "unknown", + + rocks_servers = { + { + "https://luarocks.org", + "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/", + "http://luafr.org/moonrocks/", + "http://luarocks.logiceditor.com/rocks", + } + }, + disabled_servers = {}, + + upload = { + server = "https://luarocks.org", + tool_version = "1.0.0", + api_version = "1", + }, + + 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", + connection_timeout = 30, -- 0 = no timeout + + variables = { + MAKE = "make", + CC = "cc", + LD = "ld", + AR = "ar", + RANLIB = "ranlib", + + 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", + MKTEMP = "mktemp", + + ZIP = "zip", + UNZIP = "unzip -n", + GUNZIP = "gunzip", + BUNZIP2 = "bunzip2", + TAR = "tar", + + MD5SUM = "md5sum", + OPENSSL = "openssl", + MD5 = "md5", + STAT = "stat", + TOUCH = "touch", + + CMAKE = "cmake", + SEVENZ = "7z", + + RSYNCFLAGS = "--exclude=.git -Oavz", + STATFLAG = "-c '%a'", + CURLNOCERTFLAG = "", + WGETNOCERTFLAG = "", + }, + + external_deps_subdirs = site_config.LUAROCKS_EXTERNAL_DEPS_SUBDIRS or { + bin = "bin", + lib = "lib", + include = "include" + }, + runtime_external_deps_subdirs = site_config.LUAROCKS_RUNTIME_EXTERNAL_DEPS_SUBDIRS or { + bin = "bin", + lib = "lib", + include = "include" + }, + + rocks_provided = {}, + rocks_provided_3_0 = {}, +} + +if cfg.platforms.windows then + local full_prefix = (site_config.LUAROCKS_PREFIX or (os.getenv("PROGRAMFILES")..[[\LuaRocks]])) + extra_luarocks_module_dir = full_prefix.."\\lua\\?.lua" + + home_config_file = home_config_file and home_config_file:gsub("\\","/") + defaults.fs_use_modules = false + defaults.arch = "win32-"..cfg.target_cpu + defaults.lib_extension = "dll" + defaults.external_lib_extension = "dll" + defaults.static_lib_extension = "lib" + 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"..cfg.lua_version.."/bin" + defaults.variables.LUA_INCDIR = site_config.LUA_INCDIR and site_config.LUA_INCDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/include" + defaults.variables.LUA_LIBDIR = site_config.LUA_LIBDIR and site_config.LUA_LIBDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/lib" + + defaults.makefile = "Makefile.win" + defaults.variables.MAKE = "nmake" + defaults.variables.CC = "cl" + defaults.variables.RC = "rc" + defaults.variables.WRAPPER = full_prefix.."\\rclauncher.c" + defaults.variables.LD = "link" + defaults.variables.MT = "mt" + defaults.variables.AR = "lib" + defaults.variables.LUALIB = "lua"..cfg.lua_version..".lib" + defaults.variables.CFLAGS = "/nologo /MD /O2" + defaults.variables.LIBFLAG = "/nologo /dll" + + local bins = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", + "MKDIR", "MV", "PWD", "RMDIR", "TEST", "UNAME", "WGET" } + for _, var in ipairs(bins) do + if defaults.variables[var] then + defaults.variables[var] = full_prefix.."\\tools\\"..defaults.variables[var] + end + end + + 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.wrapper_suffix = ".bat" + + local localappdata = os.getenv("LOCALAPPDATA") + if not localappdata then + -- for Windows versions below Vista + localappdata = os.getenv("USERPROFILE").."/Local Settings/Application Data" + end + defaults.local_cache = localappdata.."/LuaRocks/Cache" + defaults.web_browser = "start" +end + +if cfg.platforms.mingw32 then + defaults.obj_extension = "o" + defaults.static_lib_extension = "a" + defaults.cmake_generator = "MinGW Makefiles" + defaults.variables.MAKE = "mingw32-make" + defaults.variables.CC = "mingw32-gcc" + defaults.variables.RC = "windres" + defaults.variables.LD = "mingw32-gcc" + defaults.variables.AR = "ar" + defaults.variables.RANLIB = "ranlib" + defaults.variables.CFLAGS = "-O2" + defaults.variables.LIBFLAG = "-shared" + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220 + -- ...should we keep ?.lib at the end? It's not in the above list. + lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "cyg?.dll", "?.dll", "lib?.dll" }, + include = { "?.h" } + } + +end + +if cfg.platforms.unix then + defaults.lib_extension = "so" + defaults.static_lib_extension = "a" + 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.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.wrapper_suffix = "" + defaults.local_cache = cfg.home.."/.cache/luarocks" + if not defaults.variables.CFLAGS:match("-fPIC") then + defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" + end + defaults.web_browser = "xdg-open" +end + +if cfg.platforms.cygwin then + defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds + defaults.arch = "cygwin-"..cfg.target_cpu + 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 cfg.platforms.msys then + -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish + -- enough, yet we can freely mix with native win32 + defaults.external_deps_patterns = { + bin = { "?.exe", "?.bat", "?" }, + lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a", + "lib?.a", "lib?.dll", "?.dll", "?.lib" }, + include = { "?.h" } + } + defaults.runtime_external_deps_patterns = { + bin = { "?.exe", "?.bat" }, + lib = { "lib?.so", "?.dll", "lib?.dll" }, + include = { "?.h" } + } +end + + +if cfg.platforms.bsd then + defaults.variables.MAKE = "gmake" + defaults.variables.STATFLAG = "-f '%OLp'" +end + +if cfg.platforms.macosx then + defaults.variables.MAKE = "make" + defaults.external_lib_extension = "dylib" + defaults.arch = "macosx-"..cfg.target_cpu + defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" + defaults.variables.STAT = "/usr/bin/stat" + defaults.variables.STATFLAG = "-f '%A'" + local version = util.popen_read("sw_vers -productVersion") + version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3 + if version >= 10 then + version = 8 + elseif version >= 5 then + version = 5 + else + defaults.gcc_rpath = false + end + defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" + defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET=10."..version.." gcc" + defaults.web_browser = "open" +end + +if cfg.platforms.linux then + defaults.arch = "linux-"..cfg.target_cpu +end + +if cfg.platforms.freebsd then + defaults.arch = "freebsd-"..cfg.target_cpu + defaults.gcc_rpath = false + defaults.variables.CC = "cc" + defaults.variables.LD = "cc" +end + +if cfg.platforms.openbsd then + defaults.arch = "openbsd-"..cfg.target_cpu +end + +if cfg.platforms.netbsd then + defaults.arch = "netbsd-"..cfg.target_cpu +end + +if cfg.platforms.solaris then + defaults.arch = "solaris-"..cfg.target_cpu + --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 + +-- Add built-in modules to rocks_provided +defaults.rocks_provided["lua"] = cfg.lua_version.."-1" + +if bit32 then -- Lua 5.2+ + defaults.rocks_provided["bit32"] = cfg.lua_version.."-1" +end + +if utf8 then -- Lua 5.3+ + defaults.rocks_provided["utf8"] = cfg.lua_version.."-1" +end + +if package.loaded.jit then + -- LuaJIT + local lj_version = package.loaded.jit.version:match("LuaJIT (.*)"):gsub("%-","") + defaults.rocks_provided["luabitop"] = lj_version.."-1" + defaults.rocks_provided_3_0["luajit"] = lj_version.."-1" +end + +-- Use defaults: + +-- Populate some arrays with values from their 'defaults' counterparts +-- if they were not already set by user. +for _, entry in ipairs({"variables", "rocks_provided"}) do + if not cfg[entry] then + cfg[entry] = {} + end + for k,v in pairs(defaults[entry]) do + if not cfg[entry][k] then + cfg[entry][k] = v + end + end +end +setmetatable(defaults.rocks_provided_3_0, { __index = cfg.rocks_provided }) + +-- 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(cfg, cfg_mt) + +if not cfg.check_certificates then + cfg.variables.CURLNOCERTFLAG = "-k" + cfg.variables.WGETNOCERTFLAG = "--no-check-certificate" +end + +function cfg.make_paths_from_tree(tree) + local lua_path, lib_path, bin_path + if type(tree) == "string" then + lua_path = tree..cfg.lua_modules_path + lib_path = tree..cfg.lib_modules_path + bin_path = tree.."/bin" + else + lua_path = tree.lua_dir or tree.root..cfg.lua_modules_path + lib_path = tree.lib_dir or tree.root..cfg.lib_modules_path + bin_path = tree.bin_dir or tree.root.."/bin" + end + return lua_path, lib_path, bin_path +end + +function cfg.package_paths(current) + local new_path, new_cpath, new_bin = {}, {}, {} + local function add_tree_to_paths(tree) + local lua_path, lib_path, bin_path = cfg.make_paths_from_tree(tree) + table.insert(new_path, lua_path.."/?.lua") + table.insert(new_path, lua_path.."/?/init.lua") + table.insert(new_cpath, lib_path.."/?."..cfg.lib_extension) + table.insert(new_bin, bin_path) + end + if current then + add_tree_to_paths(current) + end + for _,tree in ipairs(cfg.rocks_trees) do + add_tree_to_paths(tree) + end + if extra_luarocks_module_dir then + table.insert(new_path, extra_luarocks_module_dir) + end + return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator) +end + +function cfg.init_package_paths() + local lr_path, lr_cpath, lr_bin = cfg.package_paths() + package.path = util.remove_path_dupes(package.path .. ";" .. lr_path, ";") + package.cpath = util.remove_path_dupes(package.cpath .. ";" .. lr_cpath, ";") +end + +function cfg.which_config() + local ret = { + system = { + file = sys_config_file or sys_config_file_default, + ok = sys_config_ok, + }, + user = { + file = home_config_file or home_config_file_default, + ok = home_config_ok, + } + } + ret.nearest = (ret.user.ok and ret.user.file) or ret.system.file + return ret +end + +cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch + +cfg.http_proxy = os.getenv("http_proxy") +cfg.https_proxy = os.getenv("https_proxy") +cfg.no_proxy = os.getenv("no_proxy") + +--- 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 cfg.is_platform(query) + assert(type(query) == "string") + + for _, platform in ipairs(cfg.platforms) do + if platform == query then + return true + end + end +end + +return cfg diff --git a/src/luarocks/core/deps.lua b/src/luarocks/core/deps.lua new file mode 100644 index 00000000..6d539eb8 --- /dev/null +++ b/src/luarocks/core/deps.lua @@ -0,0 +1,192 @@ + +local deps = {} + +local util = require("luarocks.core.util") +local require = nil +-------------------------------------------------------------------------------- + +local deltas = { + scm = 1100, + 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 deps.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 + 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 deps.compare_versions(a, b) + return deps.parse_version(a) > deps.parse_version(b) +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 = deps.parse_version(version) end + if type(requested) ~= "table" then requested = deps.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 deps.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 + if type(constr.version) == "string" then + constr.version = deps.parse_version(constr.version) + end + local constr_version, constr_op = constr.version, constr.op + 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 + +return deps + diff --git a/src/luarocks/core/dir.lua b/src/luarocks/core/dir.lua new file mode 100644 index 00000000..240bb38a --- /dev/null +++ b/src/luarocks/core/dir.lua @@ -0,0 +1,55 @@ + +local dir = {} + +local require = nil +-------------------------------------------------------------------------------- + +dir.separator = "/" + +--- 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 dir.path(...) + local t = {...} + while t[1] == "" do + table.remove(t, 1) + end + return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", "")) +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 dir.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 + +--- Normalize a url or local path. +-- URLs should be in the "protocol://path" format. System independent +-- forward slashes are used, removing trailing and double slashes +-- @param url string: an URL or a local pathname. +-- @return string: Normalized result. +function dir.normalize(name) + local protocol, pathname = dir.split_url(name) + pathname = pathname:gsub("\\", "/"):gsub("(.)/*$", "%1"):gsub("//", "/") + if protocol ~= "file" then pathname = protocol .."://"..pathname end + return pathname +end + +return dir + diff --git a/src/luarocks/core/manif.lua b/src/luarocks/core/manif.lua new file mode 100644 index 00000000..f0912bfd --- /dev/null +++ b/src/luarocks/core/manif.lua @@ -0,0 +1,107 @@ + +--- Core functions for querying manifest files. +local manif = {} + +local persist = require("luarocks.core.persist") +local type_check = require("luarocks.core.type_check") +local cfg = require("luarocks.core.cfg") +local dir = require("luarocks.core.dir") +local util = require("luarocks.core.util") +local path = require("luarocks.core.path") +local require = nil +-------------------------------------------------------------------------------- + +-- Table with repository identifiers as keys and tables mapping +-- Lua versions to cached loaded manifests as values. +local manifest_cache = {} + +--- Cache a loaded manifest. +-- @param repo_url string: The repository identifier. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @param manifest table: the manifest to be cached. +function manif.cache_manifest(repo_url, lua_version, manifest) + lua_version = lua_version or cfg.lua_version + manifest_cache[repo_url] = manifest_cache[repo_url] or {} + manifest_cache[repo_url][lua_version] = manifest +end + +--- Attempt to get cached loaded manifest. +-- @param repo_url string: The repository identifier. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return table or nil: loaded manifest or nil if cache is empty. +function manif.get_cached_manifest(repo_url, lua_version) + lua_version = lua_version or cfg.lua_version + return manifest_cache[repo_url] and manifest_cache[repo_url][lua_version] +end + +--- 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 lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @param quick boolean: If given, skips type checking. +-- @return table or (nil, string, string): the manifest or nil, +-- error message and error code ("open", "load", "run" or "type"). +function manif.manifest_loader(file, repo_url, lua_version, quick) + local manifest, err, errcode = persist.load_into_table(file) + if not manifest then + return nil, "Failed loading manifest for "..repo_url..": "..err, errcode + end + local globals = err + if not quick then + local ok, err = type_check.type_check_manifest(manifest, globals) + if not ok then + return nil, "Error checking manifest: "..err, "type" + end + end + + manif.cache_manifest(repo_url, lua_version, 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, string): A table representing the manifest, +-- or nil followed by an error message and an error code, see manifest_loader. +function manif.load_local_manifest(repo_url) + assert(type(repo_url) == "string") + + local cached_manifest = manif.get_cached_manifest(repo_url) + if cached_manifest then + return cached_manifest + end + + local pathname = dir.path(repo_url, "manifest") + return manif.manifest_loader(pathname, repo_url, nil, 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 manif.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 = manif.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 + +return manif diff --git a/src/luarocks/core/path.lua b/src/luarocks/core/path.lua new file mode 100644 index 00000000..ffde2c68 --- /dev/null +++ b/src/luarocks/core/path.lua @@ -0,0 +1,149 @@ + +--- Core LuaRocks-specific path handling functions. +local path = {} + +local cfg = require("luarocks.core.cfg") +local dir = require("luarocks.core.dir") +local require = nil +-------------------------------------------------------------------------------- + +function path.rocks_dir(tree) + if type(tree) == "string" then + return dir.path(tree, cfg.rocks_subdir) + else + assert(type(tree) == "table") + return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir) + end +end + +--- Produce a versioned version of a filename. +-- @param file string: filename (must start with prefix) +-- @param prefix string: Path prefix for file +-- @param name string: Rock name +-- @param version string: Rock version +-- @return string: a pathname with the same directory parts and a versioned basename. +function path.versioned_name(file, prefix, name, version) + assert(type(file) == "string") + assert(type(name) == "string") + 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 + +--- 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.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, ".") + else + name = file:match("(.*)%."..cfg.static_lib_extension.."$") + if name then + name = name:gsub(dir.separator, ".") + end + end + end + if not name then name = file end + name = name:gsub("^%.+", ""):gsub("%.+$", "") + return name +end + +function path.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 path.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 + +local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true } + +--- Return the pathname of the file that would be loaded for a module, indexed. +-- @param file_name string: module file name as in manifest (eg. "socket/core.so") +-- @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 path.which_i(file_name, name, version, tree, i) + local deploy_dir + local extension = file_name:match("%.[a-z]+$") + if is_src_extension[extension] then + deploy_dir = path.deploy_lua_dir(tree) + file_name = dir.path(deploy_dir, file_name) + else + deploy_dir = path.deploy_lib_dir(tree) + file_name = dir.path(deploy_dir, file_name) + end + if i > 1 then + file_name = path.versioned_name(file_name, deploy_dir, name, version) + end + return file_name +end + +function path.rocks_tree_to_string(tree) + if type(tree) == "string" then + return tree + else + assert(type(tree) == "table") + return tree.root + end +end + +--- Apply a given function to the active rocks trees based on chosen dependency mode. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for no trees (this function becomes a nop). +-- @param fn function: function to be applied, with the tree dir (string) as the first +-- argument and the remaining varargs of map_trees as the following arguments. +-- @return a table with all results of invocations of fn collected. +function path.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(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then + use = true + end + if use then + table.insert(result, (fn(tree, ...)) or 0) + end + end + end + return result +end + +return path diff --git a/src/luarocks/core/persist.lua b/src/luarocks/core/persist.lua new file mode 100644 index 00000000..48979184 --- /dev/null +++ b/src/luarocks/core/persist.lua @@ -0,0 +1,81 @@ + +local persist = {} + +local require = nil +-------------------------------------------------------------------------------- + +--- Load and run a Lua file in an environment. +-- @param filename string: the name of the file. +-- @param env table: the environment table. +-- @return (true, any) or (nil, string, string): true and the return value +-- of the file, or nil, an error message and an error code ("open", "load" +-- or "run") in case of errors. +local function run_file(filename, env) + local fd, err = io.open(filename) + if not fd then + return nil, err, "open" + end + local str, err = fd:read("*a") + fd:close() + if not str then + return nil, err, "open" + end + str = str:gsub("^#![^\n]*\n", "") + local chunk, ran + if _VERSION == "Lua 5.1" then -- Lua 5.1 + chunk, err = loadstring(str, filename) + if chunk then + setfenv(chunk, env) + ran, err = pcall(chunk) + end + else -- Lua 5.2 + chunk, err = load(str, filename, "t", env) + if chunk then + ran, err = pcall(chunk) + end + end + if not chunk then + return nil, "Error loading file: "..err, "load" + end + if not ran then + return nil, "Error running file: "..err, "run" + end + return true, err +end + +--- 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, table) or (nil, string, string): a table with the file's assignments +-- as fields and set of undefined globals accessed in file, +-- or nil, an error message and an error code ("open"; couldn't open the file, +-- "load"; compile-time error, or "run"; run-time error) +-- in case of errors. +function persist.load_into_table(filename, tbl) + assert(type(filename) == "string") + assert(type(tbl) == "table" or not tbl) + + local result = tbl or {} + local globals = {} + local globals_mt = { + __index = function(t, k) + globals[k] = true + end + } + local save_mt = getmetatable(result) + setmetatable(result, globals_mt) + + local ok, err, errcode = run_file(filename, result) + + setmetatable(result, save_mt) + + if not ok then + return nil, err, errcode + end + return result, globals +end + +return persist + diff --git a/src/luarocks/core/type_check.lua b/src/luarocks/core/type_check.lua new file mode 100644 index 00000000..a2e14efd --- /dev/null +++ b/src/luarocks/core/type_check.lua @@ -0,0 +1,226 @@ + +local type_check = {} + +local cfg = require("luarocks.core.cfg") +local deps = require("luarocks.core.deps") +local require = nil +-------------------------------------------------------------------------------- + +type_check.string_1 = { _type = "string" } +type_check.number_1 = { _type = "number" } +type_check.mandatory_string_1 = { _type = "string", _mandatory = true } + +local number_1 = type_check.number_1 +local string_1 = type_check.string_1 +local mandatory_string_1 = type_check.mandatory_string_1 + +local manifest_types = { + repository = { + _mandatory = true, + -- packages + _any = { + -- versions + _any = { + -- items + _any = { + arch = mandatory_string_1, + modules = { _any = string_1 }, + commands = { _any = string_1 }, + dependencies = { _any = string_1 }, + -- TODO: to be extended with more metadata. + } + } + } + }, + modules = { + _mandatory = true, + -- modules + _any = { + -- providers + _any = string_1 + } + }, + commands = { + _mandatory = true, + -- modules + _any = { + -- commands + _any = string_1 + } + }, + dependencies = { + -- each module + _any = { + -- each version + _any = { + -- each dependency + _any = { + name = string_1, + constraints = { + _any = { + no_upgrade = { _type = "boolean" }, + op = string_1, + version = { + string = string_1, + _any = number_1, + } + } + } + } + } + } + } +} + +local function check_version(version, typetbl, context) + local typetbl_version = typetbl._version or "1.0" + if deps.compare_versions(typetbl_version, version) then + if context == "" then + return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly." + else + return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly." + end + end + return true +end + +--- 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 version string: The version of the item. +-- @param item any: The object being checked. +-- @param typetbl any: The type-checking table for the object. +-- @param context string: A string indicating the "context" where the +-- error occurred (the full table path), for 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(version, item, typetbl, context) + assert(type(version) == "string") + + local ok, err = check_version(version, typetbl, context) + if not ok then + return nil, err + end + + local item_type = type(item) or "nil" + local expected_type = typetbl._type or "table" + + if expected_type == "number" then + if not tonumber(item) then + return nil, "Type mismatch on field "..context..": expected a number" + end + elseif expected_type == "string" then + if item_type ~= "string" then + return nil, "Type mismatch on field "..context..": expected a string, got "..item_type + end + if typetbl._pattern then + if not item:match("^"..typetbl._pattern.."$") then + return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'" + end + end + elseif expected_type == "table" then + if item_type ~= expected_type then + return nil, "Type mismatch on field "..context..": expected a table" + else + return type_check.type_check_table(version, item, typetbl, context) + end + elseif item_type ~= expected_type then + return nil, "Type mismatch on field "..context..": expected "..expected_type + end + return true +end + +local function mkfield(context, field) + if context == "" then + return field + end + return context.."."..field +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 version string: The version of tbl. +-- @param tbl table: The table to be type checked. +-- @param typetbl table: The type-checking 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. +function type_check.type_check_table(version, tbl, typetbl, context) + assert(type(version) == "string") + assert(type(tbl) == "table") + assert(type(typetbl) == "table") + + local ok, err = check_version(version, typetbl, context) + if not ok then + return nil, err + end + + for k, v in pairs(tbl) do + local t = typetbl[k] or typetbl._any + if t then + local ok, err = type_check_item(version, v, t, mkfield(context, k)) + if not ok then return nil, err end + elseif typetbl._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(typetbl) do + if k:sub(1,1) ~= "_" and v._mandatory then + if not tbl[k] then + return nil, "Mandatory field "..mkfield(context, k).." is missing." + end + end + end + return true +end + +function type_check.check_undeclared_globals(globals, typetbl) + local undeclared = {} + for glob, _ in pairs(globals) do + if not (typetbl[glob] or typetbl["MUST_"..glob]) then + table.insert(undeclared, glob) + end + end + if #undeclared == 1 then + return nil, "Unknown variable: "..undeclared[1] + elseif #undeclared > 1 then + return nil, "Unknown variables: "..table.concat(undeclared, ", ") + end + return true +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.type_check_manifest(manifest, globals) + assert(type(manifest) == "table") + local ok, err = type_check.check_undeclared_globals(globals, manifest_types) + if not ok then return nil, err end + return type_check.type_check_table("1.0", manifest, manifest_types, "") +end + +return type_check + diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua new file mode 100644 index 00000000..4f896b17 --- /dev/null +++ b/src/luarocks/core/util.lua @@ -0,0 +1,202 @@ + +local util = {} + +local require = nil +-------------------------------------------------------------------------------- + +--- Run a process and read a its output. +-- Equivalent to io.popen(cmd):read("*l"), except that it +-- closes the fd right away. +-- @param cmd string: The command to execute +-- @param spec string: "*l" by default, to read a single line. +-- May be used to read more, passing, for instance, "*a". +-- @return string: the output of the program. +function util.popen_read(cmd, spec) + local fd = io.popen(cmd) + local out = fd:read(spec or "*l") + fd:close() + return out +end + +--- 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. +function util.make_shallow_copy(tbl) + local copy = {} + for k,v in pairs(tbl) do + copy[k] = v + end + return copy +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 util.show_table(t, name, indent) + local cart -- a container + local autoref -- for self references + + local function is_empty_table(t) return next(t) == nil end + + local function basic_serialize (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 add_to_cart (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 .. " = " .. basic_serialize(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 is_empty_table(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basic_serialize(k) + local fname = ("%s[%s]"):format(name, k) + field = ("[%s]"):format(k) + -- three spaces between levels + add_to_cart(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 .. " = " .. basic_serialize(t) + end + cart, autoref = "", "" + add_to_cart(t, name, indent) + return cart .. autoref +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 util.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 + util.deep_merge(dst[k], v) + else + dst[k] = v + end + else + dst[k] = v + end + end +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 util.remove_path_dupes(list, sep) + assert(type(list) == "string") + assert(type(sep) == "string") + local parts = util.split_string(list, sep) + local final, entries = {}, {} + for _, part in ipairs(parts) do + part = part:gsub("//", "/") + if not entries[part] then + table.insert(final, part) + entries[part] = true + end + end + return table.concat(final, sep) +end + +-- from http://lua-users.org/wiki/SplitJoin +-- by Philippe Lhoste +function util.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 + +--- Return an array of keys of a table. +-- @param tbl table: The input table. +-- @return table: The array of keys. +function util.keys(tbl) + local ks = {} + for k,_ in pairs(tbl) do + table.insert(ks, k) + end + return ks +end + +--- Print a line to standard error +function util.printerr(...) + io.stderr:write(table.concat({...},"\t")) + io.stderr:write("\n") +end + +return util + diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index 0d85d33e..acbf1dd6 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua @@ -12,14 +12,23 @@ -- test/test_deps.lua file included with LuaRocks provides some -- insights on what these criteria are. local deps = {} -package.loaded["luarocks.deps"] = deps +setmetatable(deps, { __index = require("luarocks.core.deps") }) -local cfg = require("luarocks.cfg") -local manif_core = require("luarocks.manif_core") +local cfg = require("luarocks.core.cfg") +local manif = require("luarocks.core.manif") local path = require("luarocks.path") local dir = require("luarocks.dir") local util = require("luarocks.util") +--- Check if rockspec format version satisfies version requirement. +-- @param rockspec table: The rockspec table. +-- @param version string: required version. +-- @return boolean: true if rockspec format matches version or is newer, false otherwise. +function deps.format_is_at_least(rockspec, version) + local rockspec_format = rockspec.rockspec_format or "1.0" + return deps.parse_version(rockspec_format) >= deps.parse_version(version) +end + local operators = { ["=="] = "==", ["~="] = "~=", @@ -34,139 +43,6 @@ local operators = { ["!="] = "~=" } -local deltas = { - scm = 1100, - 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 deps.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 - 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 deps.compare_versions(a, b) - return deps.parse_version(a) > deps.parse_version(b) -end - ---- Check if rockspec format version satisfies version requirement. --- @param rockspec table: The rockspec table. --- @param version string: required version. --- @return boolean: true if rockspec format matches version or is newer, false otherwise. -function deps.format_is_at_least(rockspec, version) - local rockspec_format = rockspec.rockspec_format or "1.0" - return deps.parse_version(rockspec_format) >= deps.parse_version(version) -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 @@ -201,7 +77,7 @@ end function deps.parse_constraints(input) assert(type(input) == "string") - local constraints, constraint, oinput = {}, nil, input + local constraints, oinput, constraint = {}, input while #input > 0 do constraint, input = parse_constraint(input) if constraint then @@ -267,65 +143,6 @@ function deps.show_dep(dep, internal) end 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 = deps.parse_version(version) end - if type(requested) ~= "table" then requested = deps.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 deps.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 - if type(constr.version) == "string" then - constr.version = deps.parse_version(constr.version) - end - local constr_version, constr_op = constr.version, constr.op - 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 @@ -344,7 +161,7 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided) -- Provided rocks have higher priority than manifest's rocks. versions = { provided } else - versions = manif_core.get_versions(dep.name, deps_mode) + versions = manif.get_versions(dep.name, deps_mode) end local latest_version @@ -431,7 +248,8 @@ function deps.fulfill_dependencies(rockspec, deps_mode) end local supported = nil for _, plat in pairs(rockspec.supported_platforms) do - local neg, plat = plat:match("^(!?)(.*)") + local neg + neg, plat = plat:match("^(!?)(.*)") if neg == "!" then if deps.platforms_set[plat] then return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." @@ -704,7 +522,6 @@ function deps.scan_deps(results, missing, manifest, name, version, deps_mode) local fetch = require("luarocks.fetch") - local err if results[name] then return results, missing end diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua index f72ebd6c..ad7fb870 100644 --- a/src/luarocks/dir.lua +++ b/src/luarocks/dir.lua @@ -1,9 +1,7 @@ --- Generic utilities for handling pathnames. local dir = {} -package.loaded["luarocks.dir"] = dir - -dir.separator = "/" +setmetatable(dir, { __index = require("luarocks.core.dir") }) --- Strip the path off a path+filename. -- @param pathname string: A path+name, such as "/a/b/c" @@ -26,49 +24,4 @@ function dir.dir_name(pathname) 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 dir.path(...) - local t = {...} - while t[1] == "" do - table.remove(t, 1) - end - return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", "")) -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 dir.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 - ---- Normalize a url or local path. --- URLs should be in the "protocol://path" format. System independent --- forward slashes are used, removing trailing and double slashes --- @param url string: an URL or a local pathname. --- @return string: Normalized result. -function dir.normalize(name) - local protocol, pathname = dir.split_url(name) - pathname = pathname:gsub("\\", "/"):gsub("(.)/*$", "%1"):gsub("//", "/") - if protocol ~= "file" then pathname = protocol .."://"..pathname end - return pathname -end - return dir diff --git a/src/luarocks/doc.lua b/src/luarocks/doc.lua index 758fd9c5..8378bbc2 100644 --- a/src/luarocks/doc.lua +++ b/src/luarocks/doc.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "doc" command. -- Shows documentation for an installed rock. local doc = {} -package.loaded["luarocks.doc"] = doc local util = require("luarocks.util") local show = require("luarocks.show") diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua index d793cab7..c81958de 100644 --- a/src/luarocks/download.lua +++ b/src/luarocks/download.lua @@ -2,7 +2,6 @@ --- Module implementing the luarocks "download" command. -- Download a rock from the repository. local download = {} -package.loaded["luarocks.download"] = download local util = require("luarocks.util") local path = require("luarocks.path") @@ -10,7 +9,7 @@ local fetch = require("luarocks.fetch") local search = require("luarocks.search") local fs = require("luarocks.fs") local dir = require("luarocks.dir") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") download.help_summary = "Download a specific rock file from a rocks server." download.help_arguments = "[--all] [--arch= | --source | --rockspec] [ []]" diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index 2590afd4..9bf1922a 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua @@ -1,7 +1,6 @@ --- Functions related to fetching and loading local and remote files. local fetch = {} -package.loaded["luarocks.fetch"] = fetch local fs = require("luarocks.fs") local dir = require("luarocks.dir") @@ -10,7 +9,7 @@ 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") +local cfg = require("luarocks.core.cfg") function fetch.is_basic_protocol(protocol, remote) return protocol == "http" or protocol == "https" or protocol == "ftp" or (not remote and protocol == "file") diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua index 54cc7d73..7322e552 100644 --- a/src/luarocks/fs.lua +++ b/src/luarocks/fs.lua @@ -8,9 +8,10 @@ local pairs = pairs local fs = {} +-- To avoid a loop when loading the other fs modules. package.loaded["luarocks.fs"] = fs -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local pack = table.pack or function(...) return { n = select("#", ...), ... } end local unpack = table.unpack or unpack diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index a31cbb4e..770da2b7 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -6,7 +6,7 @@ local fs_lua = {} local fs = require("luarocks.fs") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") local path = require("luarocks.path") diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua index ed51b545..d2062ed8 100644 --- a/src/luarocks/fs/tools.lua +++ b/src/luarocks/fs/tools.lua @@ -4,7 +4,7 @@ local tools = {} local fs = require("luarocks.fs") local dir = require("luarocks.dir") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local vars = cfg.variables diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua index 5c6b542c..df9d256d 100644 --- a/src/luarocks/fs/unix.lua +++ b/src/luarocks/fs/unix.lua @@ -4,7 +4,7 @@ local unix = {} local fs = require("luarocks.fs") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua index d0802725..d9dc009f 100644 --- a/src/luarocks/fs/unix/tools.lua +++ b/src/luarocks/fs/unix/tools.lua @@ -4,7 +4,7 @@ local tools = {} local fs = require("luarocks.fs") local dir = require("luarocks.dir") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local vars = cfg.variables diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua index 8debaeef..c03db6a0 100644 --- a/src/luarocks/fs/win32.lua +++ b/src/luarocks/fs/win32.lua @@ -5,7 +5,7 @@ local win32 = {} local fs = require("luarocks.fs") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") local util = require("luarocks.util") diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 4adc78d1..7f6b853e 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua @@ -6,7 +6,7 @@ local tools = {} local fs = require("luarocks.fs") local dir = require("luarocks.dir") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local vars = cfg.variables diff --git a/src/luarocks/help.lua b/src/luarocks/help.lua index 5bac77ce..51e2cf57 100644 --- a/src/luarocks/help.lua +++ b/src/luarocks/help.lua @@ -7,7 +7,7 @@ local help = {} local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") local program = util.this_program("luarocks") diff --git a/src/luarocks/index.lua b/src/luarocks/index.lua index e1f563ef..468f5cf8 100644 --- a/src/luarocks/index.lua +++ b/src/luarocks/index.lua @@ -1,7 +1,6 @@ --- Module which builds the index.html page to be used in rocks servers. local index = {} -package.loaded["luarocks.index"] = index local util = require("luarocks.util") local fs = require("luarocks.fs") diff --git a/src/luarocks/install.lua b/src/luarocks/install.lua index 10d57f37..c4139fd0 100644 --- a/src/luarocks/install.lua +++ b/src/luarocks/install.lua @@ -1,7 +1,6 @@ --- Module implementing the LuaRocks "install" command. -- Installs binary rocks. local install = {} -package.loaded["luarocks.install"] = install local path = require("luarocks.path") local repos = require("luarocks.repos") @@ -9,9 +8,9 @@ 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 writer = require("luarocks.manif.writer") local remove = require("luarocks.remove") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") install.help_summary = "Install a rock." @@ -74,7 +73,7 @@ function install.install_binary_rock(rock_file, deps_mode) -- 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) + ok, err = writer.make_rock_manifest(name, version) if err then return nil, err end end @@ -94,7 +93,7 @@ function install.install_binary_rock(rock_file, deps_mode) 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) + ok, err = writer.update_manifest(name, version, nil, deps_mode) if err then return nil, err end util.announce_install(rockspec) diff --git a/src/luarocks/lint.lua b/src/luarocks/lint.lua index 4c30804b..742f1736 100644 --- a/src/luarocks/lint.lua +++ b/src/luarocks/lint.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "lint" command. -- Utility function that checks syntax of the rockspec. local lint = {} -package.loaded["luarocks.lint"] = lint local util = require("luarocks.util") local download = require("luarocks.download") diff --git a/src/luarocks/list.lua b/src/luarocks/list.lua index 8c9c5107..45f1a26f 100644 --- a/src/luarocks/list.lua +++ b/src/luarocks/list.lua @@ -2,11 +2,10 @@ --- Module implementing the LuaRocks "list" command. -- Lists currently installed rocks. local list = {} -package.loaded["luarocks.list"] = list local search = require("luarocks.search") local deps = require("luarocks.deps") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local path = require("luarocks.path") diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua index 26280e94..0faaebda 100644 --- a/src/luarocks/loader.lua +++ b/src/luarocks/loader.lua @@ -6,21 +6,24 @@ -- used to load previous modules, so that the loader chooses versions -- that are declared to be compatible with the ones loaded earlier. local loaders = package.loaders or package.searchers -local package, require, ipairs, table, type, next, tostring, error = - package, require, ipairs, table, type, next, tostring, error +local require, ipairs, table, type, next, tostring, error = + require, ipairs, table, type, next, tostring, error local unpack = unpack or table.unpack ---module("luarocks.loader") local loader = {} -package.loaded["luarocks.loader"] = loader -local cfg = require("luarocks.cfg") +local is_clean = not package.loaded["luarocks.core.cfg"] + +-- This loader module depends only on core modules. +local cfg = require("luarocks.core.cfg") cfg.init_package_paths() -local path = require("luarocks.path") -local manif_core = require("luarocks.manif_core") -local deps = require("luarocks.deps") -local util = require("luarocks.util") +local path = require("luarocks.core.path") +local manif = require("luarocks.core.manif") +local deps = require("luarocks.core.deps") +local util = require("luarocks.core.util") +local require = nil +-------------------------------------------------------------------------------- loader.context = {} @@ -33,7 +36,7 @@ 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)) + local manifest, err = manif.load_local_manifest(path.rocks_dir(tree)) if manifest then any_ok = true table.insert(trees, {tree=tree, manifest=manifest}) @@ -217,4 +220,12 @@ end table.insert(loaders, 1, loader.luarocks_loader) +if is_clean then + for modname, _ in pairs(package.loaded) do + if modname:match("^luarocks%.") then + package.loaded[modname] = nil + end + end +end + return loader diff --git a/src/luarocks/make.lua b/src/luarocks/make.lua index 476150eb..eb38bff0 100644 --- a/src/luarocks/make.lua +++ b/src/luarocks/make.lua @@ -4,12 +4,11 @@ -- it does not fetch sources, etc., assuming everything is -- available in the current directory. local make = {} -package.loaded["luarocks.make"] = make local build = require("luarocks.build") local fs = require("luarocks.fs") local util = require("luarocks.util") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local fetch = require("luarocks.fetch") local pack = require("luarocks.pack") local remove = require("luarocks.remove") diff --git a/src/luarocks/make_manifest.lua b/src/luarocks/make_manifest.lua deleted file mode 100644 index b89ba47f..00000000 --- a/src/luarocks/make_manifest.lua +++ /dev/null @@ -1,52 +0,0 @@ - ---- Module implementing the luarocks-admin "make_manifest" command. --- Compile a manifest file for a repository. -local make_manifest = {} -package.loaded["luarocks.make_manifest"] = make_manifest - -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") -local fs = require("luarocks.fs") -local dir = require("luarocks.dir") - -make_manifest.help_summary = "Compile a manifest file for a repository." - -make_manifest.help = [[ -, if given, is a local repository pathname. - ---local-tree If given, do not write versioned versions of the manifest file. - Use this when rebuilding the manifest of a local rocks tree. -]] - ---- 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 make_manifest.command(flags, repo) - assert(type(repo) == "string" or not repo) - repo = repo or cfg.rocks_dir - - util.printout("Making manifest for "..repo) - - if repo:match("/lib/luarocks") and not flags["local-tree"] then - util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") - end - - local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"]) - if ok and not flags["local-tree"] then - util.printout("Generating index.html for "..repo) - index.make_index(repo) - end - if flags["local-tree"] then - for luaver in util.lua_versions() do - fs.delete(dir.path(repo, "manifest-"..luaver)) - end - end - return ok, err -end - -return make_manifest diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua index e30c2a33..c4da9a8e 100644 --- a/src/luarocks/manif.lua +++ b/src/luarocks/manif.lua @@ -3,41 +3,18 @@ -- They are loaded into manifest tables, which are then used for -- performing searches, matching dependencies, etc. local manif = {} -package.loaded["luarocks.manif"] = manif +setmetatable(manif, { __index = require("luarocks.core.manif") }) -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 cfg = require("luarocks.core.cfg") local path = require("luarocks.path") -local repos = require("luarocks.repos") -local deps = require("luarocks.deps") manif.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 manif.load_rock_manifest(name, version, root) assert(type(name) == "string") assert(type(version) == "string") @@ -53,38 +30,6 @@ function manif.load_rock_manifest(name, version, root) return rock_manifest.rock_manifest end -function manif.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 - local sum, err = fs.get_md5(full_path) - if not sum then - return nil, "Failed producing checksum: "..tostring(err) - end - last[last_name] = sum - end - end - rock_manifest = { rock_manifest=tree } - manif.rock_manifest_cache[name.."/"..version] = rock_manifest - save_table(install_dir, "rock_manifest", rock_manifest ) -end - local function fetch_manifest_from(repo_url, filename) local url = dir.path(repo_url, filename) local name = repo_url:gsub("[/:]","_") @@ -112,7 +57,7 @@ function manif.load_manifest(repo_url, lua_version) assert(type(lua_version) == "string" or not lua_version) lua_version = lua_version or cfg.lua_version - local cached_manifest = manif_core.get_cached_manifest(repo_url, lua_version) + local cached_manifest = manif.get_cached_manifest(repo_url, lua_version) if cached_manifest then return cached_manifest end @@ -159,316 +104,14 @@ function manif.load_manifest(repo_url, lua_version) end pathname = nozip end - return manif_core.manifest_loader(pathname, repo_url, lua_version) -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. --- @param deps_mode string: Dependency mode: "one" for the current default tree, --- "all" for all trees, "order" for all trees with priority >= the current default, --- "none" for no trees. -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) - elseif deps_mode ~= "none" then - util.printerr("Missing dependency for "..pkg.." "..version..": "..miss) - end - end - end - end - end - end - end -end - ---- Filter manifest table by Lua version, removing rockspecs whose Lua version --- does not match. --- @param manifest table: a manifest table. --- @param lua_version string or nil: filter by Lua version --- @param repodir string: directory of repository being scanned --- @param cache table: temporary rockspec cache table -local function filter_by_lua_version(manifest, lua_version, repodir, cache) - assert(type(manifest) == "table") - assert(type(repodir) == "string") - assert((not cache) or type(cache) == "table") - - cache = cache or {} - lua_version = deps.parse_version(lua_version) - for pkg, versions in pairs(manifest.repository) do - local to_remove = {} - for version, repositories in pairs(versions) do - for _, repo in ipairs(repositories) do - if repo.arch == "rockspec" then - local pathname = dir.path(repodir, pkg.."-"..version..".rockspec") - local rockspec, err = cache[pathname] - if not rockspec then - rockspec, err = fetch.load_local_rockspec(pathname, true) - end - if rockspec then - cache[pathname] = rockspec - for _, dep in ipairs(rockspec.dependencies) do - if dep.name == "lua" then - if not deps.match_constraints(lua_version, dep.constraints) then - table.insert(to_remove, version) - end - break - end - end - else - util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err) - end - end - end - end - if next(to_remove) then - for _, incompat in ipairs(to_remove) do - versions[incompat] = nil - end - if not next(versions) then - manifest.repository[pkg] = nil - 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. --- @param dep_handler: dependency handler function --- @return boolean or (nil, string): true in case of success, or nil followed by an error message. -local function store_results(results, manifest, dep_handler) - assert(type(results) == "table") - assert(type(manifest) == "table") - assert((not dep_handler) or type(dep_handler) == "function") - - 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 = 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 - 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 - if dep_handler then - dep_handler(manifest) - end - 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. --- @param deps_mode string: Dependency mode: "one" for the current default tree, --- "all" for all trees, "order" for all trees with priority >= the current default, --- "none" for the default dependency mode from the configuration. --- @param versioned boolean: if versioned versions of the manifest should be created. --- @return boolean or (nil, string): True if manifest was generated, --- or nil and an error message. -function manif.make_manifest(repo, deps_mode, remote) - 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.cache_manifest(repo, nil, manifest) - - local dep_handler = nil - if not remote then - dep_handler = function(manifest) - update_dependencies(manifest, deps_mode) - end - end - local ok, err = store_results(results, manifest, dep_handler) - if not ok then return nil, err end - - if remote then - local cache = {} - for luaver in util.lua_versions() do - local vmanifest = { repository = {}, modules = {}, commands = {} } - local dep_handler = function(manifest) - filter_by_lua_version(manifest, luaver, repo, cache) - end - local ok, err = store_results(results, vmanifest, dep_handler) - save_table(repo, "manifest-"..luaver, vmanifest) - end - 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 is used. --- @param deps_mode string: Dependency mode: "one" for the current default tree, --- "all" for all trees, "order" for all trees with priority >= the current default, --- "none" for using the default dependency mode from the configuration. --- @return boolean or (nil, string): True if manifest was generated, --- or nil and an error message. -function manif.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 - - local manifest, err = manif.load_manifest(repo) - if not manifest then - util.printerr("No existing manifest. Attempting to rebuild...") - local ok, err = manif.make_manifest(repo, deps_mode) - if not ok then - return nil, err - end - manifest, err = manif.load_manifest(repo) - if not manifest then - return nil, err - end - end - - local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}} - - local dep_handler = function(manifest) - update_dependencies(manifest, deps_mode) - end - local ok, err = store_results(results, manifest, dep_handler) - if not ok then return nil, err end - - return save_table(repo, "manifest", manifest) -end - -function manif.zip_manifests() - for ver in util.lua_versions() do - local file = "manifest-"..ver - local zip = file..".zip" - fs.delete(dir.path(fs.current_dir(), zip)) - fs.zip(zip, file) - end + return manif.manifest_loader(pathname, repo_url, lua_version) 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)) + local manifest, err = manif.load_local_manifest(path.rocks_dir(root)) if not manifest then return nil, "untracked" end diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua new file mode 100644 index 00000000..75ea3b81 --- /dev/null +++ b/src/luarocks/manif/writer.lua @@ -0,0 +1,360 @@ + +local writer = {} + +local cfg = require("luarocks.core.cfg") +local search = require("luarocks.search") +local repos = require("luarocks.repos") +local deps = require("luarocks.deps") +local fs = require("luarocks.fs") +local util = require("luarocks.util") +local dir = require("luarocks.dir") +local fetch = require("luarocks.fetch") +local path = require("luarocks.path") +local persist = require("luarocks.persist") +local manif = require("luarocks.manif") + +--- 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 + + +--- 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. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for no trees. +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) + elseif deps_mode ~= "none" then + util.printerr("Missing dependency for "..pkg.." "..version..": "..miss) + end + end + end + end + end + end + end +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 + +--- Filter manifest table by Lua version, removing rockspecs whose Lua version +-- does not match. +-- @param manifest table: a manifest table. +-- @param lua_version string or nil: filter by Lua version +-- @param repodir string: directory of repository being scanned +-- @param cache table: temporary rockspec cache table +local function filter_by_lua_version(manifest, lua_version, repodir, cache) + assert(type(manifest) == "table") + assert(type(repodir) == "string") + assert((not cache) or type(cache) == "table") + + cache = cache or {} + lua_version = deps.parse_version(lua_version) + for pkg, versions in pairs(manifest.repository) do + local to_remove = {} + for version, repositories in pairs(versions) do + for _, repo in ipairs(repositories) do + if repo.arch == "rockspec" then + local pathname = dir.path(repodir, pkg.."-"..version..".rockspec") + local rockspec, err = cache[pathname] + if not rockspec then + rockspec, err = fetch.load_local_rockspec(pathname, true) + end + if rockspec then + cache[pathname] = rockspec + for _, dep in ipairs(rockspec.dependencies) do + if dep.name == "lua" then + if not deps.match_constraints(lua_version, dep.constraints) then + table.insert(to_remove, version) + end + break + end + end + else + util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err) + end + end + end + end + if next(to_remove) then + for _, incompat in ipairs(to_remove) do + versions[incompat] = nil + end + if not next(versions) then + manifest.repository[pkg] = nil + 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. +-- @param dep_handler: dependency handler function +-- @return boolean or (nil, string): true in case of success, or nil followed by an error message. +local function store_results(results, manifest, dep_handler) + assert(type(results) == "table") + assert(type(manifest) == "table") + assert((not dep_handler) or type(dep_handler) == "function") + + 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 = 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 + 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 + if dep_handler then + dep_handler(manifest) + end + sort_package_matching_table(manifest.modules) + sort_package_matching_table(manifest.commands) + return true +end + +--- 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 writer.make_rock_manifest(name, version) + local install_dir = path.install_dir(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 filename in file:gmatch("[^/]+") do + local next = walk[filename] + if not next then + next = {} + walk[filename] = next + end + last = walk + last_name = filename + walk = next + end + if fs.is_file(full_path) then + local sum, err = fs.get_md5(full_path) + if not sum then + return nil, "Failed producing checksum: "..tostring(err) + end + last[last_name] = sum + end + end + local rock_manifest = { rock_manifest=tree } + manif.rock_manifest_cache[name.."/"..version] = rock_manifest + save_table(install_dir, "rock_manifest", rock_manifest ) +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. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for the default dependency mode from the configuration. +-- @param versioned boolean: if versioned versions of the manifest should be created. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function writer.make_manifest(repo, deps_mode, remote) + 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.cache_manifest(repo, nil, manifest) + + local dep_handler = nil + if not remote then + dep_handler = function(manifest) + update_dependencies(manifest, deps_mode) + end + end + local ok, err = store_results(results, manifest, dep_handler) + if not ok then return nil, err end + + if remote then + local cache = {} + for luaver in util.lua_versions() do + local vmanifest = { repository = {}, modules = {}, commands = {} } + local dep_handler = function(manifest) + filter_by_lua_version(manifest, luaver, repo, cache) + end + store_results(results, vmanifest, dep_handler) + save_table(repo, "manifest-"..luaver, vmanifest) + end + 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 is used. +-- @param deps_mode string: Dependency mode: "one" for the current default tree, +-- "all" for all trees, "order" for all trees with priority >= the current default, +-- "none" for using the default dependency mode from the configuration. +-- @return boolean or (nil, string): True if manifest was generated, +-- or nil and an error message. +function writer.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 + + local manifest, err = manif.load_manifest(repo) + if not manifest then + util.printerr("No existing manifest. Attempting to rebuild...") + local ok, err = writer.make_manifest(repo, deps_mode) + if not ok then + return nil, err + end + manifest, err = manif.load_manifest(repo) + if not manifest then + return nil, err + end + end + + local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}} + + local dep_handler = function(manifest) + update_dependencies(manifest, deps_mode) + end + local ok, err = store_results(results, manifest, dep_handler) + if not ok then return nil, err end + + return save_table(repo, "manifest", manifest) +end + +return writer diff --git a/src/luarocks/manif_core.lua b/src/luarocks/manif_core.lua deleted file mode 100644 index 5c8928d4..00000000 --- a/src/luarocks/manif_core.lua +++ /dev/null @@ -1,107 +0,0 @@ - ---- Core functions for querying manifest files. --- This module requires no specific 'fs' functionality. -local manif_core = {} -package.loaded["luarocks.manif_core"] = manif_core - -local persist = require("luarocks.persist") -local type_check = require("luarocks.type_check") -local cfg = require("luarocks.cfg") -local dir = require("luarocks.dir") -local util = require("luarocks.util") -local path = require("luarocks.path") - --- Table with repository identifiers as keys and tables mapping --- Lua versions to cached loaded manifests as values. -local manifest_cache = {} - ---- Cache a loaded manifest. --- @param repo_url string: The repository identifier. --- @param lua_version string: Lua version in "5.x" format, defaults to installed version. --- @param manifest table: the manifest to be cached. -function manif_core.cache_manifest(repo_url, lua_version, manifest) - lua_version = lua_version or cfg.lua_version - manifest_cache[repo_url] = manifest_cache[repo_url] or {} - manifest_cache[repo_url][lua_version] = manifest -end - ---- Attempt to get cached loaded manifest. --- @param repo_url string: The repository identifier. --- @param lua_version string: Lua version in "5.x" format, defaults to installed version. --- @return table or nil: loaded manifest or nil if cache is empty. -function manif_core.get_cached_manifest(repo_url, lua_version) - lua_version = lua_version or cfg.lua_version - return manifest_cache[repo_url] and manifest_cache[repo_url][lua_version] -end - ---- 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 lua_version string: Lua version in "5.x" format, defaults to installed version. --- @param quick boolean: If given, skips type checking. --- @return table or (nil, string, string): the manifest or nil, --- error message and error code ("open", "load", "run" or "type"). -function manif_core.manifest_loader(file, repo_url, lua_version, quick) - local manifest, err, errcode = persist.load_into_table(file) - if not manifest then - return nil, "Failed loading manifest for "..repo_url..": "..err, errcode - end - local globals = err - if not quick then - local ok, err = type_check.type_check_manifest(manifest, globals) - if not ok then - return nil, "Error checking manifest: "..err, "type" - end - end - - manif_core.cache_manifest(repo_url, lua_version, 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, string): A table representing the manifest, --- or nil followed by an error message and an error code, see manifest_loader. -function manif_core.load_local_manifest(repo_url) - assert(type(repo_url) == "string") - - local cached_manifest = manif_core.get_cached_manifest(repo_url) - if cached_manifest then - return cached_manifest - end - - local pathname = dir.path(repo_url, "manifest") - return manif_core.manifest_loader(pathname, repo_url, nil, 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 manif_core.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 = manif_core.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 - -return manif_core diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua index 3a163e92..b85653e9 100644 --- a/src/luarocks/pack.lua +++ b/src/luarocks/pack.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "pack" command. -- Creates a rock, packing sources or binaries. local pack = {} -package.loaded["luarocks.pack"] = pack local unpack = unpack or table.unpack @@ -10,7 +9,7 @@ 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 cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local dir = require("luarocks.dir") local manif = require("luarocks.manif") diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua index 6219d8c6..83e9c295 100644 --- a/src/luarocks/path.lua +++ b/src/luarocks/path.lua @@ -3,9 +3,10 @@ -- All paths are configured in this module, making it a single -- point where the layout of the local installation is defined in LuaRocks. local path = {} +setmetatable(path, { __index = require("luarocks.core.path") }) local dir = require("luarocks.dir") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") --- Infer rockspec filename from a rock filename. @@ -17,29 +18,11 @@ function path.rockspec_name_from_rock(rock_name) return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec" end -function path.rocks_dir(tree) - if type(tree) == "string" then - return dir.path(tree, cfg.rocks_subdir) - else - assert(type(tree) == "table") - return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir) - end -end - function path.root_dir(rocks_dir) assert(type(rocks_dir) == "string") return rocks_dir:match("(.*)" .. util.matchquote(cfg.rocks_subdir) .. ".*$") end -function path.rocks_tree_to_string(tree) - if type(tree) == "string" then - return tree - else - assert(type(tree) == "table") - return tree.root - end -end - function path.deploy_bin_dir(tree) if type(tree) == "string" then return dir.path(tree, "bin") @@ -49,24 +32,6 @@ function path.deploy_bin_dir(tree) end end -function path.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 path.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 path.manifest_file(tree) if type(tree) == "string" then return dir.path(tree, cfg.rocks_subdir, "manifest") @@ -229,39 +194,6 @@ function path.make_url(pathname, name, version, arch) 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.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, ".") - else - name = file:match("(.*)%."..cfg.static_lib_extension.."$") - if name then - name = name:gsub(dir.separator, ".") - end - 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. @@ -291,22 +223,6 @@ function path.configure_paths(rockspec) rockspec.variables = vars end ---- Produce a versioned version of a filename. --- @param file string: filename (must start with prefix) --- @param prefix string: Path prefix for file --- @param name string: Rock name --- @param version string: Rock version --- @return string: a pathname with the same directory parts and a versioned basename. -function path.versioned_name(file, prefix, name, version) - assert(type(file) == "string") - assert(type(name) == "string") - 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 path.use_tree(tree) cfg.root_dir = tree cfg.rocks_dir = path.rocks_dir(tree) @@ -315,60 +231,6 @@ function path.use_tree(tree) cfg.deploy_lib_dir = path.deploy_lib_dir(tree) end ---- Apply a given function to the active rocks trees based on chosen dependency mode. --- @param deps_mode string: Dependency mode: "one" for the current default tree, --- "all" for all trees, "order" for all trees with priority >= the current default, --- "none" for no trees (this function becomes a nop). --- @param fn function: function to be applied, with the tree dir (string) as the first --- argument and the remaining varargs of map_trees as the following arguments. --- @return a table with all results of invocations of fn collected. -function path.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(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then - use = true - end - if use then - table.insert(result, (fn(tree, ...)) or 0) - end - end - end - return result -end - -local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true } - ---- Return the pathname of the file that would be loaded for a module, indexed. --- @param file_name string: module file name as in manifest (eg. "socket/core.so") --- @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 path.which_i(file_name, name, version, tree, i) - local deploy_dir - local extension = file_name:match("%.[a-z]+$") - if is_src_extension[extension] then - deploy_dir = path.deploy_lua_dir(tree) - file_name = dir.path(deploy_dir, file_name) - else - deploy_dir = path.deploy_lib_dir(tree) - file_name = dir.path(deploy_dir, file_name) - end - if i > 1 then - file_name = path.versioned_name(file_name, deploy_dir, name, version) - end - return file_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. diff --git a/src/luarocks/path_cmd.lua b/src/luarocks/path_cmd.lua index c0329977..1f5bb07f 100644 --- a/src/luarocks/path_cmd.lua +++ b/src/luarocks/path_cmd.lua @@ -5,7 +5,7 @@ local path_cmd = {} local util = require("luarocks.util") local deps = require("luarocks.deps") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") path_cmd.help_summary = "Return the currently configured package path." path_cmd.help_arguments = "" diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua index c2adb570..16ff5065 100644 --- a/src/luarocks/persist.lua +++ b/src/luarocks/persist.lua @@ -4,83 +4,10 @@ -- Implemented separately to avoid interdependencies, -- as it is used in the bootstrapping stage of the cfg module. local persist = {} -package.loaded["luarocks.persist"] = persist +setmetatable(persist, { __index = require("luarocks.core.persist") }) local util = require("luarocks.util") ---- Load and run a Lua file in an environment. --- @param filename string: the name of the file. --- @param env table: the environment table. --- @return (true, any) or (nil, string, string): true and the return value --- of the file, or nil, an error message and an error code ("open", "load" --- or "run") in case of errors. -local function run_file(filename, env) - local fd, err = io.open(filename) - if not fd then - return nil, err, "open" - end - local str, err = fd:read("*a") - fd:close() - if not str then - return nil, err, "open" - end - str = str:gsub("^#![^\n]*\n", "") - local chunk, ran - if _VERSION == "Lua 5.1" then -- Lua 5.1 - chunk, err = loadstring(str, filename) - if chunk then - setfenv(chunk, env) - ran, err = pcall(chunk) - end - else -- Lua 5.2 - chunk, err = load(str, filename, "t", env) - if chunk then - ran, err = pcall(chunk) - end - end - if not chunk then - return nil, "Error loading file: "..err, "load" - end - if not ran then - return nil, "Error running file: "..err, "run" - end - return true, err -end - ---- 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, table) or (nil, string, string): a table with the file's assignments --- as fields and set of undefined globals accessed in file, --- or nil, an error message and an error code ("open"; couldn't open the file, --- "load"; compile-time error, or "run"; run-time error) --- in case of errors. -function persist.load_into_table(filename, tbl) - assert(type(filename) == "string") - assert(type(tbl) == "table" or not tbl) - - local result = tbl or {} - local globals = {} - local globals_mt = { - __index = function(t, k) - globals[k] = true - end - } - local save_mt = getmetatable(result) - setmetatable(result, globals_mt) - - local ok, err, errcode = run_file(filename, result) - - setmetatable(result, save_mt) - - if not ok then - return nil, err, errcode - end - return result, globals -end - local write_table --- Write a value as Lua code. diff --git a/src/luarocks/purge.lua b/src/luarocks/purge.lua index 18043cc3..7647a243 100644 --- a/src/luarocks/purge.lua +++ b/src/luarocks/purge.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "purge" command. -- Remove all rocks from a given tree. local purge = {} -package.loaded["luarocks.purge"] = purge local util = require("luarocks.util") local fs = require("luarocks.fs") @@ -10,8 +9,8 @@ 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") +local writer = require("luarocks.manif.writer") +local cfg = require("luarocks.core.cfg") local remove = require("luarocks.remove") purge.help_summary = "Remove all installed rocks from a tree." @@ -55,7 +54,7 @@ function purge.command(flags) end for package, versions in util.sortedpairs(results) do - for version, repositories in util.sortedpairs(versions, sort) do + for version, _ in util.sortedpairs(versions, sort) do if flags["old-versions"] then util.printout("Keeping "..package.." "..version.."...") local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"]) @@ -72,7 +71,7 @@ function purge.command(flags) end end end - return manif.make_manifest(cfg.rocks_dir, "one") + return writer.make_manifest(cfg.rocks_dir, "one") end return purge diff --git a/src/luarocks/refresh_cache.lua b/src/luarocks/refresh_cache.lua deleted file mode 100644 index 1261044f..00000000 --- a/src/luarocks/refresh_cache.lua +++ /dev/null @@ -1,31 +0,0 @@ - ---- Module implementing the luarocks-admin "refresh_cache" command. -local refresh_cache = {} -package.loaded["luarocks.refresh_cache"] = refresh_cache - -local cfg = require("luarocks.cfg") -local cache = require("luarocks.cache") - -refresh_cache.help_summary = "Refresh local cache of a remote rocks server." -refresh_cache.help_arguments = "[--from=]" -refresh_cache.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 refresh_cache.command(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 - - -return refresh_cache diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua index 3f62e89e..e2c05176 100644 --- a/src/luarocks/remove.lua +++ b/src/luarocks/remove.lua @@ -2,7 +2,6 @@ --- Module implementing the LuaRocks "remove" command. -- Uninstalls rocks. local remove = {} -package.loaded["luarocks.remove"] = remove local search = require("luarocks.search") local deps = require("luarocks.deps") @@ -10,8 +9,8 @@ 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 cfg = require("luarocks.core.cfg") +local writer = require("luarocks.manif.writer") local fs = require("luarocks.fs") remove.help_summary = "Uninstall a rock." @@ -113,7 +112,7 @@ function remove.remove_search_results(results, name, deps_mode, force, fast) 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) + ok, err = writer.make_manifest(cfg.rocks_dir, deps_mode) if not ok then return nil, err end util.printout("Removal successful.") diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 86126a13..7acb00b9 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua @@ -1,11 +1,10 @@ --- Functions for managing the repository on disk. local repos = {} -package.loaded["luarocks.repos"] = repos local fs = require("luarocks.fs") local path = require("luarocks.path") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local dir = require("luarocks.dir") local manif = require("luarocks.manif") diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua index c3f00a7c..7d4f3e81 100644 --- a/src/luarocks/search.lua +++ b/src/luarocks/search.lua @@ -2,13 +2,13 @@ --- Module implementing the LuaRocks "search" command. -- Queries LuaRocks servers. local search = {} -package.loaded["luarocks.search"] = search + 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 cfg = require("luarocks.core.cfg") local util = require("luarocks.util") search.help_summary = "Query the LuaRocks servers." diff --git a/src/luarocks/show.lua b/src/luarocks/show.lua index df992f5c..f0bf2164 100644 --- a/src/luarocks/show.lua +++ b/src/luarocks/show.lua @@ -1,10 +1,9 @@ --- Module implementing the LuaRocks "show" command. -- Shows information about an installed rock. local show = {} -package.loaded["luarocks.show"] = show local search = require("luarocks.search") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local path = require("luarocks.path") local deps = require("luarocks.deps") diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua index 287d8151..382d3f0a 100644 --- a/src/luarocks/type_check.lua +++ b/src/luarocks/type_check.lua @@ -2,16 +2,12 @@ -- Functions and definitions for doing a basic lint check on files -- loaded by LuaRocks. local type_check = {} -package.loaded["luarocks.type_check"] = type_check - -local cfg = require("luarocks.cfg") -local deps = require("luarocks.deps") +setmetatable(type_check, { __index = require("luarocks.core.type_check") }) type_check.rockspec_format = "3.0" -local string_1 = { _type = "string" } -local number_1 = { _type = "number" } -local mandatory_string_1 = { _type = "string", _mandatory = true } +local string_1 = type_check.string_1 +local mandatory_string_1 = type_check.mandatory_string_1 -- Syntax for type-checking tables: -- @@ -112,203 +108,6 @@ rockspec_types.external_dependencies.platforms._any = rockspec_types.external_de rockspec_types.source.platforms._any = rockspec_types.source rockspec_types.hooks.platforms._any = rockspec_types.hooks -local manifest_types = { - repository = { - _mandatory = true, - -- packages - _any = { - -- versions - _any = { - -- items - _any = { - arch = mandatory_string_1, - modules = { _any = string_1 }, - commands = { _any = string_1 }, - dependencies = { _any = string_1 }, - -- TODO: to be extended with more metadata. - } - } - } - }, - modules = { - _mandatory = true, - -- modules - _any = { - -- providers - _any = string_1 - } - }, - commands = { - _mandatory = true, - -- modules - _any = { - -- commands - _any = string_1 - } - }, - dependencies = { - -- each module - _any = { - -- each version - _any = { - -- each dependency - _any = { - name = string_1, - constraints = { - _any = { - no_upgrade = { _type = "boolean" }, - op = string_1, - version = { - string = string_1, - _any = number_1, - } - } - } - } - } - } - } -} - -local function check_version(version, typetbl, context) - local typetbl_version = typetbl._version or "1.0" - if deps.compare_versions(typetbl_version, version) then - if context == "" then - return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly." - else - return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly." - end - end - return true -end - -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 version string: The version of the item. --- @param item any: The object being checked. --- @param typetbl any: The type-checking table for the object. --- @param context string: A string indicating the "context" where the --- error occurred (the full table path), for 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(version, item, typetbl, context) - assert(type(version) == "string") - - local ok, err = check_version(version, typetbl, context) - if not ok then - return nil, err - end - - local item_type = type(item) or "nil" - local expected_type = typetbl._type or "table" - - if expected_type == "number" then - if not tonumber(item) then - return nil, "Type mismatch on field "..context..": expected a number" - end - elseif expected_type == "string" then - if item_type ~= "string" then - return nil, "Type mismatch on field "..context..": expected a string, got "..item_type - end - if typetbl._pattern then - if not item:match("^"..typetbl._pattern.."$") then - return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'" - end - end - elseif expected_type == "table" then - if item_type ~= expected_type then - return nil, "Type mismatch on field "..context..": expected a table" - else - return type_check_table(version, item, typetbl, context) - end - elseif item_type ~= expected_type then - return nil, "Type mismatch on field "..context..": expected "..expected_type - end - return true -end - -local function mkfield(context, field) - if context == "" then - return field - end - return context.."."..field -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 version string: The version of tbl. --- @param tbl table: The table to be type checked. --- @param typetbl table: The type-checking 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(version, tbl, typetbl, context) - assert(type(version) == "string") - assert(type(tbl) == "table") - assert(type(typetbl) == "table") - - local ok, err = check_version(version, typetbl, context) - if not ok then - return nil, err - end - - for k, v in pairs(tbl) do - local t = typetbl[k] or typetbl._any - if t then - local ok, err = type_check_item(version, v, t, mkfield(context, k)) - if not ok then return nil, err end - elseif typetbl._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(typetbl) do - if k:sub(1,1) ~= "_" and v._mandatory then - if not tbl[k] then - return nil, "Mandatory field "..mkfield(context, k).." is missing." - end - end - end - return true -end - -local function check_undeclared_globals(globals, typetbl) - local undeclared = {} - for glob, _ in pairs(globals) do - if not (typetbl[glob] or typetbl["MUST_"..glob]) then - table.insert(undeclared, glob) - end - end - if #undeclared == 1 then - return nil, "Unknown variable: "..undeclared[1] - elseif #undeclared > 1 then - return nil, "Unknown variables: "..table.concat(undeclared, ", ") - end - return true -end - --- Type check a rockspec table. -- Verify the correctness of elements from a -- rockspec table, reporting on unknown fields and type @@ -320,22 +119,9 @@ function type_check.type_check_rockspec(rockspec, globals) if not rockspec.rockspec_format then rockspec.rockspec_format = "1.0" end - local ok, err = check_undeclared_globals(globals, rockspec_types) - if not ok then return nil, err end - return type_check_table(rockspec.rockspec_format, 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.type_check_manifest(manifest, globals) - assert(type(manifest) == "table") - local ok, err = check_undeclared_globals(globals, manifest_types) + local ok, err = type_check.check_undeclared_globals(globals, rockspec_types) if not ok then return nil, err end - return type_check_table("1.0", manifest, manifest_types, "") + return type_check.type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "") end return type_check diff --git a/src/luarocks/unpack.lua b/src/luarocks/unpack.lua index 4e4d9a06..22b3f49b 100644 --- a/src/luarocks/unpack.lua +++ b/src/luarocks/unpack.lua @@ -2,14 +2,13 @@ --- Module implementing the LuaRocks "unpack" command. -- Unpack the contents of a rock. local unpack = {} -package.loaded["luarocks.unpack"] = unpack 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") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") unpack.help_summary = "Unpack the contents of a rock." unpack.help_arguments = "[--force] {| []}" diff --git a/src/luarocks/upload.lua b/src/luarocks/upload.lua index 5031b1ef..4bda4303 100644 --- a/src/luarocks/upload.lua +++ b/src/luarocks/upload.lua @@ -4,7 +4,7 @@ local upload = {} local util = require("luarocks.util") local fetch = require("luarocks.fetch") local pack = require("luarocks.pack") -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local Api = require("luarocks.upload.api") upload.help_summary = "Upload a rockspec to the public rocks repository." diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua index 6df24569..3e28bbda 100644 --- a/src/luarocks/upload/api.lua +++ b/src/luarocks/upload/api.lua @@ -1,7 +1,7 @@ local api = {} -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local fs = require("luarocks.fs") local util = require("luarocks.util") local persist = require("luarocks.persist") diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index d27710c1..f41b1c38 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua @@ -2,26 +2,13 @@ --- 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. +-- as this is used in the bootstrapping stage of luarocks.core.cfg. local util = {} +setmetatable(util, { __index = require("luarocks.core.util") }) local unpack = unpack or table.unpack ---- Run a process and read a its output. --- Equivalent to io.popen(cmd):read("*l"), except that it --- closes the fd right away. --- @param cmd string: The command to execute --- @param spec string: "*l" by default, to read a single line. --- May be used to read more, passing, for instance, "*a". --- @return string: the output of the program. -function util.popen_read(cmd, spec) - local fd = io.popen(cmd) - local out = fd:read(spec or "*l") - fd:close() - return out -end - local scheduled_functions = {} local debug = require("debug") @@ -210,27 +197,6 @@ function util.parse_flags(...) return flags, unpack(out) 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 util.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 - util.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 @@ -247,7 +213,7 @@ end function util.platform_overrides(tbl) assert(type(tbl) == "table" or not tbl) - local cfg = require("luarocks.cfg") + local cfg = require("luarocks.core.cfg") if not tbl then return end @@ -264,19 +230,6 @@ 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. -function util.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 @@ -339,17 +292,6 @@ function util.variable_substitutions(tbl, vars) end end ---- Return an array of keys of a table. --- @param tbl table: The input table. --- @return table: The array of keys. -function util.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) @@ -431,12 +373,6 @@ function util.printout(...) io.stdout:write("\n") end ---- Print a line to standard error -function util.printerr(...) - io.stderr:write(table.concat({...},"\t")) - io.stderr:write("\n") -end - --- Display a warning message. -- @param msg string: the warning message function util.warning(msg) @@ -465,7 +401,7 @@ function util.this_program(default) end function util.deps_mode_help(program) - local cfg = require("luarocks.cfg") + local cfg = require("luarocks.core.cfg") return [[ --deps-mode= How to handle dependencies. Four modes are supported: * all - use all trees from the rocks_trees list @@ -488,7 +424,7 @@ function util.see_help(command, program) end function util.announce_install(rockspec) - local cfg = require("luarocks.cfg") + local cfg = require("luarocks.core.cfg") local path = require("luarocks.path") local suffix = "" @@ -566,135 +502,6 @@ function util.get_default_rockspec() end end --- from http://lua-users.org/wiki/SplitJoin --- by PhilippeLhoste -function util.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 util.remove_path_dupes(list, sep) - assert(type(list) == "string") - assert(type(sep) == "string") - local parts = util.split_string(list, sep) - local final, entries = {}, {} - for _, part in ipairs(parts) do - part = part:gsub("//", "/") - 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 util.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 - function util.array_contains(tbl, value) for _, v in ipairs(tbl) do if v == value then diff --git a/src/luarocks/validate.lua b/src/luarocks/validate.lua deleted file mode 100644 index f0452bbd..00000000 --- a/src/luarocks/validate.lua +++ /dev/null @@ -1,158 +0,0 @@ - ---- Sandboxed test of build/install of all packages in a repository (unfinished and disabled). -local validate = {} -package.loaded["luarocks.validate"] = validate - -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") - -validate.help_summary = "Sandboxed test of build/install of all packages in a repository." - -validate.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 - -function validate.command(flags, repo) - repo = repo or cfg.rocks_dir - - util.printout("Verifying contents of "..repo) - - 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 fs.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 - - -return validate diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/write_rockspec.lua index 68c00cce..d6075dbd 100644 --- a/src/luarocks/write_rockspec.lua +++ b/src/luarocks/write_rockspec.lua @@ -1,8 +1,7 @@ local write_rockspec = {} -package.loaded["luarocks.write_rockspec"] = write_rockspec -local cfg = require("luarocks.cfg") +local cfg = require("luarocks.core.cfg") local dir = require("luarocks.dir") local fetch = require("luarocks.fetch") local fs = require("luarocks.fs") -- cgit v1.2.3-55-g6feb