From 35d139407db87349e8ccc11e0e1696b610d9582e Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 5 Jun 2018 01:58:48 -0300 Subject: General refactor introducing Rockspec and Build.Opts objects Adds a Rockspec object responsible for constructing all Rockspec tables in the manner of the Queries and Results objects, and a type-checked Build.Opts tables for build options, since the number of attributes passed around was getting out of hand. This allowed a major cleanup in the luarocks.build, luarocks.fetch and luarocks.cmd.write_rockspec modules. --- Makefile.setup.inc | 2 +- spec/dir_spec.lua | 13 +- spec/fetch_spec.lua | 9 - spec/util_spec.lua | 1 - src/luarocks/build.lua | 536 ++++++++++++++++++++---------------- src/luarocks/build/builtin.lua | 2 +- src/luarocks/build/cmake.lua | 2 +- src/luarocks/build/command.lua | 2 +- src/luarocks/build/make.lua | 2 +- src/luarocks/cmd/build.lua | 115 +++++--- src/luarocks/cmd/make.lua | 38 ++- src/luarocks/cmd/unpack.lua | 27 +- src/luarocks/cmd/write_rockspec.lua | 173 ++++++------ src/luarocks/command_line.lua | 6 +- src/luarocks/core/util.lua | 1 - src/luarocks/deps.lua | 41 ++- src/luarocks/dir.lua | 16 ++ src/luarocks/fetch.lua | 143 ++-------- src/luarocks/fetch/cvs.lua | 2 +- src/luarocks/fetch/git.lua | 2 +- src/luarocks/fetch/hg.lua | 2 +- src/luarocks/fetch/sscm.lua | 2 +- src/luarocks/fetch/svn.lua | 2 +- src/luarocks/manif/writer.lua | 1 + src/luarocks/pack.lua | 2 +- src/luarocks/path.lua | 20 -- src/luarocks/remove.lua | 2 +- src/luarocks/repos.lua | 4 +- src/luarocks/rockspecs.lua | 159 +++++++++++ src/luarocks/search.lua | 32 +-- src/luarocks/type_check.lua | 4 +- src/luarocks/util.lua | 31 --- 32 files changed, 767 insertions(+), 627 deletions(-) create mode 100644 src/luarocks/rockspecs.lua diff --git a/Makefile.setup.inc b/Makefile.setup.inc index e4c15b64..127898cf 100644 --- a/Makefile.setup.inc +++ b/Makefile.setup.inc @@ -23,5 +23,5 @@ fetch/cvs.lua fetch/git_https.lua fetch/git_ssh.lua fetch/hg_http.lua \ fetch/git_http.lua fetch/svn.lua fetch/git.lua fetch/hg_ssh.lua \ fetch/hg_https.lua fetch/hg.lua core/vers.lua cmd/which.lua \ fun.lua type/manifest.lua type/rockspec.lua queries.lua results.lua \ -test/busted.lua test/command.lua cmd/init.lua +test/busted.lua test/command.lua cmd/init.lua rockspecs.lua diff --git a/spec/dir_spec.lua b/spec/dir_spec.lua index 04e26b57..27966777 100644 --- a/spec/dir_spec.lua +++ b/spec/dir_spec.lua @@ -12,8 +12,19 @@ describe("Luarocks dir test #unit", function() assert.truthy(dir.is_basic_protocol("https")) assert.truthy(dir.is_basic_protocol("ftp")) assert.truthy(dir.is_basic_protocol("file")) - assert.falsy(dir.is_basic_protocol("file", true)) + assert.falsy(dir.is_basic_protocol("git")) + assert.falsy(dir.is_basic_protocol("git+https")) assert.falsy(dir.is_basic_protocol("invalid")) end) end) + + describe("dir.deduce_base_dir", function() + assert.are.same("v0.3", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3.zip")) + assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.zip")) + assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.gz")) + assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.bz2")) + assert.are.same("parser.moon", dir.deduce_base_dir("git://example.com/Cirru/parser.moon")) + assert.are.same("v0.3", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3")) + end) + end) diff --git a/spec/fetch_spec.lua b/spec/fetch_spec.lua index c02c5736..aa107970 100644 --- a/spec/fetch_spec.lua +++ b/spec/fetch_spec.lua @@ -208,15 +208,6 @@ describe("Luarocks fetch test #unit", function() end) end) - describe("fetch.url_to_base_dir", function() - assert.are.same("v0.3", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3.zip")) - assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.zip")) - assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.gz")) - assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.bz2")) - assert.are.same("parser.moon", fetch.url_to_base_dir("git://example.com/Cirru/parser.moon")) - assert.are.same("v0.3", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3")) - end) - describe("fetch.load_local_rockspec", function() it("returns a table representing the rockspec from the given file skipping some checks if the quick argument is enabled", function() local rockspec = fetch.load_local_rockspec(testing_paths.fixtures_dir .. "/a_rock-1.0-1.rockspec", true) diff --git a/spec/util_spec.lua b/spec/util_spec.lua index 28f99550..3bb97a5b 100644 --- a/spec/util_spec.lua +++ b/spec/util_spec.lua @@ -2,7 +2,6 @@ local test_env = require("spec.util.test_env") local lfs = require("lfs") local run = test_env.run local testing_paths = test_env.testing_paths -local env_variables = test_env.env_variables describe("Basic tests #integration", function() diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua index 25e73b0d..ac4ecfad 100644 --- a/src/luarocks/build.lua +++ b/src/luarocks/build.lua @@ -12,26 +12,226 @@ local cfg = require("luarocks.core.cfg") local repos = require("luarocks.repos") local writer = require("luarocks.manif.writer") ---- Install files to a given location. --- Takes a table where the array part is a list of filenames to be copied. --- In the hash part, other keys, if is_module_path is set, are identifiers --- in Lua module format, to indicate which subdirectory the file should be --- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo") --- will copy src/bar.lua to boo/foo. --- @param files table or nil: A table containing a list of files to copy in --- the format described above. If nil is passed, this function is a no-op. --- Directories should be delimited by forward slashes as in internet URLs. --- @param location string: The base directory files should be copied to. --- @param is_module_path boolean: True if string keys in files should be --- interpreted as dotted module paths. --- @param perms string ("read" or "exec"): Permissions of the newly created files installed. --- Directories are always created with the default permissions. --- @return boolean or (nil, string): True if succeeded or --- nil and an error message. -local function install_files(files, location, is_module_path, perms) - assert(type(files) == "table" or not files) - assert(type(location) == "string") - if files then +local opts_mt = {} + +opts_mt.__index = opts_mt + +function opts_mt.type() + return "build.opts" +end + +function build.opts(opts) + local valid_opts = { + need_to_fetch = "boolean", + minimal_mode = "boolean", + deps_mode = "string", + build_only_deps = "boolean", + namespace = "string?", + branch = "boolean", + } + for k, v in pairs(opts) do + local tv = type(v) + if not valid_opts[k] then + error("invalid build option: "..k) + end + local vo, optional = valid_opts[k]:match("^(.-)(%??)$") + if not (tv == vo or (optional == "?" and tv == nil)) then + error("invalid type build option: "..k.." - got "..tv..", expected "..vo) + end + end + for k, v in pairs(valid_opts) do + if (not v:find("?", 1, true)) and opts[k] == nil then + error("missing build option: "..k) + end + end + return setmetatable(opts, opts_mt) +end + +do + --- Write to the current directory the contents of a table, + -- where each key is a file name and its value is the file content. + -- @param files table: The table of files to be written. + local function extract_from_rockspec(files) + for name, content in pairs(files) do + local fd = io.open(dir.path(fs.current_dir(), name), "w+") + fd:write(content) + fd:close() + end + end + + --- Applies patches inlined in the build.patches section + -- and extracts files inlined in the build.extra_files section + -- of a rockspec. + -- @param rockspec table: A rockspec table. + -- @return boolean or (nil, string): True if succeeded or + -- nil and an error message. + function build.apply_patches(rockspec) + assert(rockspec:type() == "rockspec") + + if rockspec.build.extra_files then + extract_from_rockspec(rockspec.build.extra_files) + end + if rockspec.build.patches then + extract_from_rockspec(rockspec.build.patches) + for patch, patchdata in util.sortedpairs(rockspec.build.patches) do + util.printout("Applying patch "..patch.."...") + local create_delete = rockspec:format_is_at_least("3.0") + local ok, err = fs.apply_patch(tostring(patch), patchdata, create_delete) + if not ok then + return nil, "Failed applying patch "..patch + end + end + end + return true + end +end + +local function check_macosx_deployment_target(rockspec) + local target = rockspec.build.macosx_deployment_target + local function minor(version) + return tonumber(version and version:match("^[^.]+%.([^.]+)")) + end + local function patch_variable(var) + if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then + rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target) + else + rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var] + end + end + if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then + local version = util.popen_read("sw_vers -productVersion") + local versionminor = minor(version) + local targetminor = minor(target) + if targetminor > versionminor then + return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor) + end + patch_variable("CC", target) + patch_variable("LD", target) + end + return true +end + +local function process_dependencies(rockspec, opts) + if not opts.build_only_deps then + local ok, err, errcode = deps.check_external_deps(rockspec, "build") + if err then + return nil, err, errcode + end + end + if opts.deps_mode == "none" then + util.warning("skipping dependency checks.") + return true + end + if not opts.build_only_deps then + if next(rockspec.build_dependencies) then + local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", opts.deps_mode) + if err then + return nil, err, errcode + end + end + end + local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode) + if err then + return nil, err, errcode + end + return true +end + +local function fetch_and_change_to_source_dir(rockspec, opts) + if opts.minimal_mode then + return true + end + if opts.need_to_fetch then + if opts.branch then + rockspec.source.branch = opts.branch + end + local ok, source_dir, errcode = fetch.fetch_sources(rockspec, true) + if not ok then + return nil, source_dir, errcode + end + local err + ok, err = fs.change_dir(source_dir) + if not ok then + return nil, err + end + elseif rockspec.source.file then + local ok, err = fs.unpack_archive(rockspec.source.file) + if not ok then + return nil, err + end + end + fs.change_dir(rockspec.source.dir) + return true +end + +local function prepare_install_dirs(name, version) + local dirs = { + lua = { name = path.lua_dir(name, version), is_module_path = true, perms = "read" }, + lib = { name = path.lib_dir(name, version), is_module_path = true, perms = "exec" }, + bin = { name = path.bin_dir(name, version), is_module_path = false, perms = "exec" }, + conf = { name = path.conf_dir(name, version), is_module_path = false, perms = "read" }, + } + + for _, d in pairs(dirs) do + local ok, err = fs.make_dir(d.name) + if not ok then + return nil, err + end + end + + return dirs +end + +local function run_build_driver(rockspec) + local btype = rockspec.build.type + if btype == "none" then + return true + end + -- Temporary compatibility + if btype == "module" then + util.printout("Do not use 'module' as a build type. Use 'builtin' instead.") + btype = "builtin" + rockspec.build.type = btype + end + if cfg.accepted_build_types and not fun.contains(cfg.accepted_build_types, btype) then + return nil, "This rockspec uses the '"..btype.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration." + end + local pok, driver = pcall(require, "luarocks.build." .. btype) + if not pok or type(driver) ~= "table" then + return nil, "Failed initializing build back-end for build type '"..btype.."': "..driver + end + local ok, err = driver.run(rockspec) + if not ok then + return nil, "Build error: " .. err + end + return true +end + +local install_files +do + --- Install files to a given location. + -- Takes a table where the array part is a list of filenames to be copied. + -- In the hash part, other keys, if is_module_path is set, are identifiers + -- in Lua module format, to indicate which subdirectory the file should be + -- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo") + -- will copy src/bar.lua to boo/foo. + -- @param files table or nil: A table containing a list of files to copy in + -- the format described above. If nil is passed, this function is a no-op. + -- Directories should be delimited by forward slashes as in internet URLs. + -- @param location string: The base directory files should be copied to. + -- @param is_module_path boolean: True if string keys in files should be + -- interpreted as dotted module paths. + -- @param perms string ("read" or "exec"): Permissions of the newly created + -- files installed. + -- Directories are always created with the default permissions. + -- @return boolean or (nil, string): True if succeeded or + -- nil and an error message. + local function install_to(files, location, is_module_path, perms) + assert(type(files) == "table" or not files) + assert(type(location) == "string") + if not files then + return true + end for k, file in pairs(files) do local dest = location local filename = dir.base_name(file) @@ -60,88 +260,76 @@ local function install_files(files, location, is_module_path, perms) return nil, "Failed copying "..file end end + return true end - return true -end ---- Write to the current directory the contents of a table, --- where each key is a file name and its value is the file content. --- @param files table: The table of files to be written. -local function extract_from_rockspec(files) - for name, content in pairs(files) do - local fd = io.open(dir.path(fs.current_dir(), name), "w+") - fd:write(content) - fd:close() + local function install_default_docs(name, version) + local patterns = { "readme", "license", "copying", ".*%.md" } + local dest = dir.path(path.install_dir(name, version), "doc") + local has_dir = false + for file in fs.dir() do + for _, pattern in ipairs(patterns) do + if file:lower():match("^"..pattern) then + if not has_dir then + fs.make_dir(dest) + has_dir = true + end + fs.copy(file, dest, "read") + break + end + end + end end -end ---- Applies patches inlined in the build.patches section --- and extracts files inlined in the build.extra_files section --- of a rockspec. --- @param rockspec table: A rockspec table. --- @return boolean or (nil, string): True if succeeded or --- nil and an error message. -function build.apply_patches(rockspec) - assert(type(rockspec) == "table") - - local build_spec = rockspec.build - if build_spec.extra_files then - extract_from_rockspec(build_spec.extra_files) - end - if build_spec.patches then - extract_from_rockspec(build_spec.patches) - for patch, patchdata in util.sortedpairs(build_spec.patches) do - util.printout("Applying patch "..patch.."...") - local create_delete = rockspec:format_is_at_least("3.0") - local ok, err = fs.apply_patch(tostring(patch), patchdata, create_delete) - if not ok then - return nil, "Failed applying patch "..patch + install_files = function(rockspec, dirs) + local name, version = rockspec.name, rockspec.version + + if rockspec.build.install then + for k, d in pairs(dirs) do + local ok, err = install_to(rockspec.build.install[k], d.name, d.is_module_path, d.perms) + if not ok then return nil, err end end end - end - return true -end -local function install_default_docs(name, version) - local patterns = { "readme", "license", "copying", ".*%.md" } - local dest = dir.path(path.install_dir(name, version), "doc") - local has_dir = false - for file in fs.dir() do - for _, pattern in ipairs(patterns) do - if file:lower():match("^"..pattern) then - if not has_dir then - fs.make_dir(dest) - has_dir = true + local copy_directories = rockspec.build.copy_directories + local copying_default = false + if not copy_directories then + copy_directories = {"doc"} + copying_default = true + end + + local any_docs = false + for _, copy_dir in pairs(copy_directories) do + if fs.is_dir(copy_dir) then + local dest = dir.path(path.install_dir(name, version), copy_dir) + fs.make_dir(dest) + fs.copy_contents(copy_dir, dest) + any_docs = true + else + if not copying_default then + return nil, "Directory '"..copy_dir.."' not found" end - fs.copy(file, dest, "read") - break end end + if not any_docs then + install_default_docs(name, version) + end + + return true end end -local function check_macosx_deployment_target(rockspec) - local target = rockspec.build.macosx_deployment_target - local function minor(version) - return tonumber(version and version:match("^[^.]+%.([^.]+)")) - end - local function patch_variable(var, target) - if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then - rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target) - else - rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var] - end - end - if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then - local version = util.popen_read("sw_vers -productVersion") - local versionminor = minor(version) - local targetminor = minor(target) - if targetminor > versionminor then - return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor) - end - patch_variable("CC", target) - patch_variable("LD", target) - end +local function write_rock_dir_files(rockspec, opts) + local name, version = rockspec.name, rockspec.version + + fs.copy(rockspec.local_abs_filename, path.rockspec_file(name, version), "read") + + local ok, err = writer.make_rock_manifest(name, version) + if not ok then return nil, err end + + ok, err = writer.make_namespace_file(name, version, opts.namespace) + if not ok then return nil, err end + return true end @@ -157,18 +345,14 @@ end -- "none" for no trees. -- @param build_only_deps boolean: true to build the listed dependencies only. -- @param namespace string?: a namespace for the rockspec +-- @param branch string?: a forced branch to use -- @return (string, string) or (nil, string, [string]): Name and version of -- installed rock if succeeded or nil and an error message followed by an error code. -function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode, build_only_deps, namespace) - assert(type(rockspec_file) == "string") - assert(type(need_to_fetch) == "boolean") - assert(type(namespace) == "string" or not namespace) +function build.build_rockspec(rockspec, opts) + assert(rockspec:type() == "rockspec") + assert(opts:type() == "build.opts") - local ok - local rockspec, err, errcode = fetch.load_rockspec(rockspec_file) - if err then - return nil, err, errcode - elseif not rockspec.build then + if not rockspec.build then return nil, "Rockspec error: build table not specified" end @@ -180,175 +364,65 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m end end - if not build_only_deps then - local ok, err, errcode = deps.check_external_deps(rockspec, "build") - if err then - return nil, err, errcode - end - end - - if deps_mode == "none" then - util.warning("skipping dependency checks.") - else - if not build_only_deps then - if next(rockspec.build_dependencies) then - local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", deps_mode) - if err then - return nil, err, errcode - end - end - end - - local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode) - if err then - return nil, err, errcode - end - end + local ok, err = process_dependencies(rockspec, opts) + if not ok then return nil, err end local name, version = rockspec.name, rockspec.version - if build_only_deps then - util.printout("Stopping after installing dependencies for " ..name.." "..version) - util.printout() + if opts.build_only_deps then return name, version end if repos.is_installed(name, version) then - repos.delete_version(name, version, deps_mode) + repos.delete_version(name, version, opts.deps_mode) end - if not minimal_mode then - local source_dir - if need_to_fetch then - ok, source_dir, errcode = fetch.fetch_sources(rockspec, true) - if not ok then - return nil, source_dir, errcode - end - local ok, err = fs.change_dir(source_dir) - if not ok then return nil, err end - elseif rockspec.source.file then - local ok, err = fs.unpack_archive(rockspec.source.file) - if not ok then - return nil, err - end - end - fs.change_dir(rockspec.source.dir) - end + ok, err = fetch_and_change_to_source_dir(rockspec, opts) + if not ok then return nil, err end - local dirs = { - lua = { name = path.lua_dir(name, version), is_module_path = true, perms = "read" }, - lib = { name = path.lib_dir(name, version), is_module_path = true, perms = "exec" }, - conf = { name = path.conf_dir(name, version), is_module_path = false, perms = "read" }, - bin = { name = path.bin_dir(name, version), is_module_path = false, perms = "exec" }, - } + local dirs, err = prepare_install_dirs(name, version) + if not dirs then return nil, err end - for _, d in pairs(dirs) do - local ok, err = fs.make_dir(d.name) - if not ok then return nil, err end - end local rollback = util.schedule_function(function() fs.delete(path.install_dir(name, version)) fs.remove_dir_if_empty(path.versions_dir(name)) end) - local build_spec = rockspec.build - - if not minimal_mode then - ok, err = build.apply_patches(rockspec) - if err then - return nil, err - end + if not opts.minimal_mode then + local ok, err = build.apply_patches(rockspec) + if not ok then return nil, err end end ok, err = check_macosx_deployment_target(rockspec) - if not ok then - return nil, err - end - - if build_spec.type ~= "none" then - - -- Temporary compatibility - if build_spec.type == "module" then - util.printout("Do not use 'module' as a build type. Use 'builtin' instead.") - build_spec.type = "builtin" - end - - if cfg.accepted_build_types and fun.contains(cfg.accepted_build_types, build_spec.type) then - return nil, "This rockspec uses the '"..build_spec.type.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration." - end - - local build_type - ok, build_type = pcall(require, "luarocks.build." .. build_spec.type) - if not ok or not type(build_type) == "table" then - return nil, "Failed initializing build back-end for build type '"..build_spec.type.."': "..build_type - end - - ok, err = build_type.run(rockspec) - if not ok then - return nil, "Build error: " .. err - end - end - - if build_spec.install then - for id, install_dir in pairs(dirs) do - ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path, install_dir.perms) - if not ok then - return nil, err - end - end - end + if not ok then return nil, err end - local copy_directories = build_spec.copy_directories - local copying_default = false - if not copy_directories then - copy_directories = {"doc"} - copying_default = true - end - - local any_docs = false - for _, copy_dir in pairs(copy_directories) do - if fs.is_dir(copy_dir) then - local dest = dir.path(path.install_dir(name, version), copy_dir) - fs.make_dir(dest) - fs.copy_contents(copy_dir, dest) - any_docs = true - else - if not copying_default then - return nil, "Directory '"..copy_dir.."' not found" - end - end - end + ok, err = run_build_driver(rockspec) + if not ok then return nil, err end - if not any_docs then - install_default_docs(name, version) - end + ok, err = install_files(rockspec, dirs) + if not ok then return nil, err end for _, d in pairs(dirs) do fs.remove_dir_if_empty(d.name) end fs.pop_dir() - - fs.copy(rockspec.local_filename, path.rockspec_file(name, version), "read") - if need_to_fetch then + if opts.need_to_fetch then fs.pop_dir() end - ok, err = writer.make_rock_manifest(name, version) - if err then return nil, err end - - ok, err = writer.make_namespace_file(name, version, namespace) - if err then return nil, err end + ok, err = write_rock_dir_files(rockspec, opts) + if not ok then return nil, err end - ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) - if err then return nil, err end + ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), opts.deps_mode) + if not ok then return nil, err end util.remove_scheduled_function(rollback) rollback = util.schedule_function(function() - repos.delete_version(name, version, deps_mode) + repos.delete_version(name, version, opts.deps_mode) end) ok, err = repos.run_hook(rockspec, "post_install") - if err then return nil, err end + if not ok then return nil, err end util.announce_install(rockspec) util.remove_scheduled_function(rollback) diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua index e8b0943d..41cc31b0 100644 --- a/src/luarocks/build/builtin.lua +++ b/src/luarocks/build/builtin.lua @@ -23,7 +23,7 @@ end -- @return boolean or (nil, string): true if no errors ocurred, -- nil and an error message otherwise. function builtin.run(rockspec) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") local compile_object, compile_library, compile_static_library local build = rockspec.build diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua index 8ee6b6b2..e5db695c 100644 --- a/src/luarocks/build/cmake.lua +++ b/src/luarocks/build/cmake.lua @@ -11,7 +11,7 @@ local cfg = require("luarocks.core.cfg") -- @return boolean or (nil, string): true if no errors ocurred, -- nil and an error message otherwise. function cmake.run(rockspec) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") local build = rockspec.build local variables = build.variables or {} diff --git a/src/luarocks/build/command.lua b/src/luarocks/build/command.lua index 62dbc282..23d6d80d 100644 --- a/src/luarocks/build/command.lua +++ b/src/luarocks/build/command.lua @@ -10,7 +10,7 @@ local util = require("luarocks.util") -- @return boolean or (nil, string): true if no errors ocurred, -- nil and an error message otherwise. function command.run(rockspec) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") local build = rockspec.build diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua index ded015b7..22b8628b 100644 --- a/src/luarocks/build/make.lua +++ b/src/luarocks/build/make.lua @@ -39,7 +39,7 @@ end -- @return boolean or (nil, string): true if no errors ocurred, -- nil and an error message otherwise. function make.run(rockspec) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") local build = rockspec.build diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua index 0c8c4d47..08a05296 100644 --- a/src/luarocks/cmd/build.lua +++ b/src/luarocks/cmd/build.lua @@ -41,7 +41,7 @@ or the name of a rock to be fetched from a repository. ]]..util.deps_mode_help() --- Build and install a rock. --- @param rock_file string: local or remote filename of a rock. +-- @param rock_filename string: local or remote filename of a rock. -- @param need_to_fetch boolean: true if sources need to be fetched, -- false if the rockspec was obtained from inside a source rock. -- @param deps_mode: string: Which trees to check dependencies for: @@ -51,42 +51,65 @@ or the name of a rock to be fetched from a repository. -- @param namespace string?: an optional namespace -- @return boolean or (nil, string, [string]): True if build was successful, -- or false and an error message and an optional error code. -local function build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps, namespace) - assert(type(rock_file) == "string") - assert(type(need_to_fetch) == "boolean") +local function build_rock(rock_filename, opts) + assert(type(rock_filename) == "string") + assert(opts:type() == "build.opts") local ok, err, errcode + local unpack_dir - unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file) + unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename) if not unpack_dir then return nil, err, errcode end - local rockspec_file = path.rockspec_name_from_rock(rock_file) + + local rockspec_filename = path.rockspec_name_from_rock(rock_filename) + ok, err = fs.change_dir(unpack_dir) if not ok then return nil, err end - ok, err, errcode = build.build_rockspec(rockspec_file, need_to_fetch, false, deps_mode, build_only_deps, namespace) + + local rockspec + rockspec, err, errcode = fetch.load_rockspec(rockspec_filename) + if not rockspec then + return nil, err, errcode + end + + ok, err, errcode = build.build_rockspec(rockspec, opts) + fs.pop_dir() return ok, err, errcode end -local function build_file(filename, namespace, deps_mode, build_only_deps) - if filename:match("%.rockspec$") then - return build.build_rockspec(filename, true, false, deps_mode, build_only_deps, namespace) - elseif filename:match("%.src%.rock$") then - return build_rock(filename, false, deps_mode, build_only_deps, namespace) - elseif filename:match("%.all%.rock$") then - return build_rock(filename, true, deps_mode, build_only_deps, namespace) - elseif filename:match("%.rock$") then - return build_rock(filename, true, deps_mode, build_only_deps, namespace) - end -end +local function do_build(ns_name, version, opts) + assert(type(ns_name) == "string") + assert(version == nil or type(version) == "string") + assert(opts:type() == "build.opts") -local function do_build(name, version, namespace, deps_mode, build_only_deps) - if name:match("%.rockspec$") or name:match("%.rock$") then - return build_file(name, namespace, deps_mode, build_only_deps) + local url, err + if ns_name:match("%.rockspec$") or ns_name:match("%.rock$") then + url = ns_name else - return search.act_on_src_or_rockspec(build_file, name, version, deps_mode, build_only_deps) + url, err = search.find_src_or_rockspec(ns_name, version) + if not url then + return nil, err + end + local _, namespace = util.split_namespace(ns_name) + opts.namespace = namespace + end + + if url:match("%.rockspec$") then + local rockspec, err, errcode = fetch.load_rockspec(url) + if not rockspec then + return nil, err, errcode + end + return build.build_rockspec(rockspec, opts) + end + + if url:match("%.src%.rock$") then + opts.need_to_fetch = false end + + return build_rock(url, opts) end --- Driver function for "build" command. @@ -106,28 +129,46 @@ function cmd_build.command(flags, name, version) end name = util.adjust_name_and_namespace(name, flags) - local deps_mode = deps.get_deps_mode(flags) - local namespace = flags["namespace"] - local build_only_deps = flags["only-deps"] + + local opts = build.opts({ + need_to_fetch = true, + minimal_mode = false, + deps_mode = deps.get_deps_mode(flags), + build_only_deps = not not flags["only-deps"], + namespace = flags["namespace"], + branch = not not flags["branch"], + }) if flags["pack-binary-rock"] then - return pack.pack_binary_rock(name, version, function() return do_build(name, version, namespace, deps_mode) end) - else - local ok, err = fs.check_command_permissions(flags) - if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end + return pack.pack_binary_rock(name, version, function() + opts.build_only_deps = false + return do_build(name, version, opts) + end) + end + + local ok, err = fs.check_command_permissions(flags) + if not ok then + return nil, err, cfg.errorcodes.PERMISSIONDENIED + end - ok, err = do_build(name, version, namespace, deps_mode, build_only_deps) - if not ok then return nil, err end - name, version = ok, err + ok, err = do_build(name, version, opts) + if not ok then return nil, err end + name, version = ok, err - if (not build_only_deps) and (not flags["keep"]) and not cfg.keep_other_versions then + if opts.build_only_deps then + util.printout("Stopping after installing dependencies for " ..name.." "..version) + util.printout() + else + if (not flags["keep"]) and not cfg.keep_other_versions then local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) - if not ok then util.printerr(err) end + if not ok then + util.printerr(err) + end end - - writer.check_dependencies(nil, deps.get_deps_mode(flags)) - return name, version end + + writer.check_dependencies(nil, deps.get_deps_mode(flags)) + return name, version end return cmd_build diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua index 850da6f4..caf64721 100644 --- a/src/luarocks/cmd/make.lua +++ b/src/luarocks/cmd/make.lua @@ -53,30 +53,44 @@ only dependencies of the rockspec (see `luarocks help install`). -- @param name string: A local rockspec. -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an -- error message otherwise. exitcode is optionally returned. -function make.command(flags, rockspec) - assert(type(rockspec) == "string" or not rockspec) +function make.command(flags, rockspec_filename) + assert(type(rockspec_filename) == "string" or not rockspec_filename) - if not rockspec then + if not rockspec_filename then local err - rockspec, err = util.get_default_rockspec() - if not rockspec then + rockspec_filename, err = util.get_default_rockspec() + if not rockspec_filename then return nil, err end end - if not rockspec:match("rockspec$") then + if not rockspec_filename:match("rockspec$") then return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make") end + + local rockspec, err, errcode = fetch.load_rockspec(rockspec_filename) + if not rockspec then + return nil, err + end + + local name = util.adjust_name_and_namespace(rockspec.name, flags) + + local opts = build.opts({ + need_to_fetch = false, + minimal_mode = true, + deps_mode = deps.get_deps_mode(flags), + build_only_deps = false, + namespace = flags["namespace"], + branch = not not flags["branch"], + }) if flags["pack-binary-rock"] then - local rspec, err, errcode = fetch.load_rockspec(rockspec) - if not rspec then - return nil, err - end - return pack.pack_binary_rock(rspec.name, rspec.version, function() return build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) end) + return pack.pack_binary_rock(name, rockspec.version, function() + return build.build_rockspec(rockspec, opts) + end) else local ok, err = fs.check_command_permissions(flags) if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end - ok, err = build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) + ok, err = build.build_rockspec(rockspec, opts) if not ok then return nil, err end local name, version = ok, err diff --git a/src/luarocks/cmd/unpack.lua b/src/luarocks/cmd/unpack.lua index 3e512d5d..83dec7fe 100644 --- a/src/luarocks/cmd/unpack.lua +++ b/src/luarocks/cmd/unpack.lua @@ -8,7 +8,7 @@ local fs = require("luarocks.fs") local util = require("luarocks.util") local build = require("luarocks.build") local dir = require("luarocks.dir") -local cfg = require("luarocks.core.cfg") +local search = require("luarocks.search") unpack.help_summary = "Unpack the contents of a rock." unpack.help_arguments = "[--force] {| []}" @@ -92,7 +92,7 @@ end -- @param file string: A rockspec or .rock URL. -- @return boolean or (nil, string): true if successful or nil followed -- by an error message. -local function run_unpacker(file, namespace, force) +local function run_unpacker(file, force) assert(type(file) == "string") local base_name = dir.base_name(file) @@ -126,7 +126,7 @@ local function run_unpacker(file, namespace, force) end if kind == "src" or kind == "rockspec" then if rockspec.source.dir ~= "." then - local ok = fs.copy(rockspec.local_filename, rockspec.source.dir, "read") + local ok = fs.copy(rockspec.local_abs_filename, rockspec.source.dir, "read") if not ok then return nil, "Failed copying unpacked rockspec into unpacked source directory." end @@ -141,26 +141,31 @@ local function run_unpacker(file, namespace, force) end --- Driver function for the "unpack" command. --- @param name string: may be a rock filename, for unpacking a +-- @param ns_name string: may be a rock filename, for unpacking a -- rock file or the name of a rock to be fetched and unpacked. -- @param version string or nil: if the name of a package is given, a -- version may also be passed. -- @return boolean or (nil, string): true if successful or nil followed -- by an error message. -function unpack.command(flags, name, version) +function unpack.command(flags, ns_name, version) assert(type(version) == "string" or not version) - if type(name) ~= "string" then + if type(ns_name) ~= "string" then return nil, "Argument missing. "..util.see_help("unpack") end - name = util.adjust_name_and_namespace(name, flags) + ns_name = util.adjust_name_and_namespace(ns_name, flags) - if name:match(".*%.rock") or name:match(".*%.rockspec") then - return run_unpacker(name, flags["namespace"], flags["force"]) + local url, err + if ns_name:match(".*%.rock") or ns_name:match(".*%.rockspec") then + url = ns_name else - local search = require("luarocks.search") - return search.act_on_src_or_rockspec(run_unpacker, name, version) + url, err = search.find_src_or_rockspec(ns_name, version) + if not url then + return nil, err + end end + + return run_unpacker(url, flags["force"]) end return unpack diff --git a/src/luarocks/cmd/write_rockspec.lua b/src/luarocks/cmd/write_rockspec.lua index f3398a6a..36beffd0 100644 --- a/src/luarocks/cmd/write_rockspec.lua +++ b/src/luarocks/cmd/write_rockspec.lua @@ -7,9 +7,9 @@ local fetch = require("luarocks.fetch") local fs = require("luarocks.fs") local path = require("luarocks.path") local persist = require("luarocks.persist") +local rockspecs = require("luarocks.rockspecs") local type_rockspec = require("luarocks.type.rockspec") local util = require("luarocks.util") -local vers = require("luarocks.core.vers") write_rockspec.help_summary = "Write a template for a rockspec file." write_rockspec.help_arguments = "[--output= ...] [] [] [|]" @@ -46,7 +46,7 @@ local function open_file(name) return io.open(dir.path(fs.current_dir(), name), "r") end -local function get_url(rockspec) +local function fetch_url(rockspec) local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false) if err_code == "source.dir" then file, temp_dir = err_file, err_temp_dir @@ -55,37 +55,78 @@ local function get_url(rockspec) return false end util.printout("File successfully downloaded. Making checksum and checking base dir...") - if fetch.is_basic_protocol(rockspec.source.protocol) then + if dir.is_basic_protocol(rockspec.source.protocol) then rockspec.source.md5 = fs.get_md5(file) end local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url) return true, found_dir or inferred_dir, temp_dir end -local function configure_lua_version(rockspec, luaver) - if luaver == "5.1" then - table.insert(rockspec.dependencies, "lua ~> 5.1") - elseif luaver == "5.2" then - table.insert(rockspec.dependencies, "lua ~> 5.2") - elseif luaver == "5.3" then - table.insert(rockspec.dependencies, "lua ~> 5.3") - elseif luaver == "5.4" then - table.insert(rockspec.dependencies, "lua ~> 5.4") - elseif luaver == "5.1,5.2" then - table.insert(rockspec.dependencies, "lua >= 5.1, < 5.3") - elseif luaver == "5.2,5.3" then - table.insert(rockspec.dependencies, "lua >= 5.2, < 5.4") - elseif luaver == "5.3,5.4" then - table.insert(rockspec.dependencies, "lua >= 5.3, < 5.5") - elseif luaver == "5.1,5.2,5.3" then - table.insert(rockspec.dependencies, "lua >= 5.1, < 5.4") - elseif luaver == "5.2,5.3,5.4" then - table.insert(rockspec.dependencies, "lua >= 5.2, < 5.5") - elseif luaver == "5.1,5.2,5.3,5.4" then - table.insert(rockspec.dependencies, "lua >= 5.1, < 5.5") - else - util.warning("Please specify supported Lua version with --lua-version=. "..util.see_help("write_rockspec")) +local lua_version_dep = { + ["5.1"] = "lua ~> 5.1", + ["5.2"] = "lua ~> 5.2", + ["5.3"] = "lua ~> 5.3", + ["5.4"] = "lua ~> 5.4", + ["5.1,5.2"] = "lua >= 5.1, < 5.3", + ["5.2,5.3"] = "lua >= 5.2, < 5.4", + ["5.3,5.4"] = "lua >= 5.3, < 5.5", + ["5.1,5.2,5.3"] = "lua >= 5.1, < 5.4", + ["5.2,5.3,5.4"] = "lua >= 5.2, < 5.5", + ["5.1,5.2,5.3,5.4"] = "lua >= 5.1, < 5.5", +} + +local simple_scm_protocols = { + git = true, ["git+http"] = true, ["git+https"] = true, + hg = true, ["hg+http"] = true, ["hg+https"] = true +} + +local detect_url +do + local function detect_url_from_command(program, args, directory) + local command = fs.Q(cfg.variables[program:upper()]).. " "..args + local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command))) + if not pipe then return nil end + local url = pipe:read("*a"):match("^([^\r\n]+)") + pipe:close() + if not url then return nil end + if not util.starts_with(url, program.."://") then + url = program.."+"..url + end + + if simple_scm_protocols[dir.split_url(url)] then + return url + end + end + + local function detect_scm_url(directory) + return detect_url_from_command("git", "config --get remote.origin.url", directory) or + detect_url_from_command("hg", "paths default", directory) end + + detect_url = function(url_or_dir) + if url_or_dir:match("://") then + return url_or_dir + else + return detect_scm_url(url_or_dir) or "*** please add URL for source tarball, zip or repository here ***" + end + end +end + +local function detect_homepage(url, homepage) + if homepage then + return homepage + end + local url_protocol, url_path = dir.split_url(url) + + if simple_scm_protocols[url_protocol] then + for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do + if util.starts_with(url_path, domain) then + return "https://"..url_path:gsub("%.git$", "") + end + end + end + + return "*** please enter a project homepage ***" end local function detect_description() @@ -120,32 +161,6 @@ local function detect_mit_license(data) return sum == 78656 end -local simple_scm_protocols = { - git = true, ["git+http"] = true, ["git+https"] = true, - hg = true, ["hg+http"] = true, ["hg+https"] = true -} - -local function detect_url_from_command(program, args, directory) - local command = fs.Q(cfg.variables[program:upper()]).. " "..args - local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command))) - if not pipe then return nil end - local url = pipe:read("*a"):match("^([^\r\n]+)") - pipe:close() - if not url then return nil end - if not util.starts_with(url, program.."://") then - url = program.."+"..url - end - - if simple_scm_protocols[dir.split_url(url)] then - return url - end -end - -local function detect_scm_url(directory) - return detect_url_from_command("git", "config --get remote.origin.url", directory) or - detect_url_from_command("hg", "paths default", directory) -end - local function check_license() local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") if not fd then return nil end @@ -182,7 +197,7 @@ local function fill_as_builtin(rockspec, libs) break end end - + local incdirs, libdirs if libs then incdirs, libdirs = {}, {} @@ -259,7 +274,7 @@ function write_rockspec.command(flags, name, version, url_or_dir) if pathname == "." then name = name or dir.base_name(fs.current_dir()) end - elseif fetch.is_basic_protocol(protocol) then + elseif dir.is_basic_protocol(protocol) then local filename = dir.base_name(url_or_dir) local newname, newversion = filename:match("(.*)-([^-]+)") if newname then @@ -276,48 +291,47 @@ function write_rockspec.command(flags, name, version, url_or_dir) version = version or "dev" local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") - - local rockspec = { + + local url = detect_url(url_or_dir) + local homepage = detect_homepage(url, flags["homepage"]) + + local rockspec, err = rockspecs.from_persisted_table(filename, { rockspec_format = flags["rockspec-format"], package = name, - name = name:lower(), version = version.."-1", source = { - url = "*** please add URL for source tarball, zip or repository here ***", + url = url, tag = flags["tag"], }, description = { summary = flags["summary"] or "*** please specify description summary ***", detailed = flags["detailed"] or "*** please enter a detailed description ***", - homepage = flags["homepage"] or "*** please enter a project homepage ***", + homepage = homepage, license = flags["license"] or "*** please specify a license ***", }, - dependencies = {}, + dependencies = { + lua_version_dep[flags["lua-version"]], + }, build = {}, - } - path.configure_paths(rockspec) + }) + assert(not err, err) rockspec.source.protocol = protocol - local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") - rockspec.format_is_at_least = function(_, v) - return parsed_format >= vers.parse_version(v) + if not next(rockspec.dependencies) then + util.warning("Please specify supported Lua version with --lua-version=. "..util.see_help("write_rockspec")) end - configure_lua_version(rockspec, flags["lua-version"]) - local local_dir = url_or_dir if url_or_dir:match("://") then - rockspec.source.url = url_or_dir rockspec.source.file = dir.base_name(url_or_dir) - rockspec.source.dir = "dummy" - if not fetch.is_basic_protocol(rockspec.source.protocol) then + if not dir.is_basic_protocol(rockspec.source.protocol) then if version ~= "dev" then rockspec.source.tag = flags["tag"] or "v" .. version end end rockspec.source.dir = nil - local ok, base_dir, temp_dir = get_url(rockspec) + local ok, base_dir, temp_dir = fetch_url(rockspec) if ok then if base_dir ~= dir.base_name(url_or_dir) then rockspec.source.dir = base_dir @@ -328,26 +342,11 @@ function write_rockspec.command(flags, name, version, url_or_dir) else local_dir = nil end - else - rockspec.source.url = detect_scm_url(local_dir) or rockspec.source.url end if not local_dir then local_dir = "." end - - if not flags["homepage"] then - local url_protocol, url_path = dir.split_url(rockspec.source.url) - - if simple_scm_protocols[url_protocol] then - for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do - if util.starts_with(url_path, domain) then - rockspec.description.homepage = "https://"..url_path:gsub("%.git$", "") - break - end - end - end - end local libs = nil if flags["lib"] then @@ -364,7 +363,7 @@ function write_rockspec.command(flags, name, version, url_or_dir) local ok, err = fs.change_dir(local_dir) if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end - if (not flags["summary"]) or (not flags["detailed"]) then + if not (flags["summary"] and flags["detailed"]) then local summary, detailed = detect_description() rockspec.description.summary = flags["summary"] or summary rockspec.description.detailed = flags["detailed"] or detailed diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua index a9cf9968..7d9cc4af 100644 --- a/src/luarocks/command_line.lua +++ b/src/luarocks/command_line.lua @@ -23,7 +23,7 @@ end -- @param message string: The error message. -- @param exitcode number: the exitcode to use local function die(message, exitcode) - assert(type(message) == "string") + assert(type(message) == "string", "bad error, expected string, got: " .. type(message)) util.printerr("\nError: "..message) local ok, err = xpcall(util.run_scheduled_functions, error_handler) @@ -138,10 +138,6 @@ function command_line.run_command(...) die("Invalid entry for --deps-mode.") end - if flags["branch"] then - cfg.branch = flags["branch"] - end - if flags["tree"] then local named = false for _, tree in ipairs(cfg.rocks_trees) do diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua index 68fd931d..3582cb54 100644 --- a/src/luarocks/core/util.lua +++ b/src/luarocks/core/util.lua @@ -116,7 +116,6 @@ 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 diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index b1ff6c47..3ec1aa93 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua @@ -14,7 +14,7 @@ local queries = require("luarocks.queries") -- @param dep table: A dependency parsed in table format. -- @param blacklist table: Versions that can't be accepted. Table where keys -- are program versions and values are 'true'. --- @param rocks_provided table: A table of auto-dependencies provided +-- @param rocks_provided table: A table of auto-provided dependencies. -- by this Lua implementation for the given dependency. -- @return string or nil: latest installed version of the rock matching the dependency -- or nil if it could not be matched. @@ -48,7 +48,8 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided) end --- Attempt to match dependencies of a rockspec to installed rocks. --- @param rockspec table: The rockspec loaded as a table. +-- @param dependencies table: The table of dependencies. +-- @param rocks_provided table: The table of auto-provided dependencies. -- @param blacklist table or nil: Program versions to not use as valid matches. -- Table where keys are program names and values are tables where keys -- are program versions and values are 'true'. @@ -58,15 +59,14 @@ end -- parsed as tables; and a table of "no-upgrade" missing dependencies -- (to be used in plugin modules so that a plugin does not force upgrade of -- its parent application). -function deps.match_deps(rockspec, blacklist, deps_mode) - assert(type(rockspec) == "table") +function deps.match_deps(dependencies, rocks_provided, blacklist, deps_mode) assert(type(blacklist) == "table" or not blacklist) local matched, missing, no_upgrade = {}, {}, {} - for _, dep in ipairs(rockspec.dependencies) do - local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rockspec.rocks_provided) + for _, dep in ipairs(dependencies) do + local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rocks_provided) if found then - if not rockspec.rocks_provided[dep.name] then + if not rocks_provided[dep.name] then matched[dep] = {name = dep.name, version = found} end else @@ -266,7 +266,7 @@ end -- @return boolean or (nil, string): True if no errors occurred, or -- nil and an error message if any test failed. function deps.check_external_deps(rockspec, mode) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") local fs = require("luarocks.fs") @@ -431,25 +431,24 @@ function deps.scan_deps(results, manifest, name, version, deps_mode) return end if not manifest.dependencies then manifest.dependencies = {} end - local dependencies = manifest.dependencies - if not dependencies[name] then dependencies[name] = {} end - local dependencies_name = dependencies[name] - local deplist = dependencies_name[version] - local rockspec, err - if not deplist then - rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) + local md = manifest.dependencies + if not md[name] then md[name] = {} end + local mdn = md[name] + local dependencies = mdn[version] + local rocks_provided + if not dependencies then + local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) if not rockspec then util.printerr("Couldn't load rockspec for "..name.." "..version..": "..err) return end - dependencies_name[version] = rockspec.dependencies + dependencies = rockspec.dependencies + rocks_provided = rockspec.rocks_provided + mdn[version] = dependencies else - rockspec = { - dependencies = deplist, - rocks_provided = setmetatable({}, { __index = cfg.rocks_provided_3_0 }) - } + rocks_provided = setmetatable({}, { __index = cfg.rocks_provided_3_0 }) end - local matched = deps.match_deps(rockspec, nil, deps_mode) + local matched = deps.match_deps(dependencies, rocks_provided, nil, deps_mode) results[name] = version for _, match in pairs(matched) do deps.scan_deps(results, manifest, match.name, match.version, deps_mode) diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua index 72395e47..679e8f0d 100644 --- a/src/luarocks/dir.lua +++ b/src/luarocks/dir.lua @@ -40,4 +40,20 @@ function dir.normalize(name) return pathname end +--- Returns true if protocol does not require additional tools. +-- @param protocol The protocol name +function dir.is_basic_protocol(protocol) + return protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" +end + +function dir.deduce_base_dir(url) + -- for extensions like foo.tar.gz, "gz" is stripped first + local known_exts = {} + for _, ext in ipairs{"zip", "git", "tgz", "tar", "gz", "bz2"} do + known_exts[ext] = "" + end + local base = dir.base_name(url) + return (base:gsub("%.([^.]*)$", known_exts):gsub("%.tar", "")) +end + return dir diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index 9ea2b487..074b0e45 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua @@ -4,18 +4,11 @@ local fetch = {} local fs = require("luarocks.fs") local dir = require("luarocks.dir") -local type_rockspec = require("luarocks.type.rockspec") -local path = require("luarocks.path") -local vers = require("luarocks.core.vers") -local queries = require("luarocks.queries") +local rockspecs = require("luarocks.rockspecs") local persist = require("luarocks.persist") local util = require("luarocks.util") 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") -end - --- Fetch a local or remote file. -- Make a remote or local URL/pathname local, fetching the file if necessary. -- Other "fetch" and "load" functions use this function to obtain files. @@ -37,7 +30,7 @@ function fetch.fetch_url(url, filename, cache) local protocol, pathname = dir.split_url(url) if protocol == "file" then return fs.absolute_name(pathname) - elseif fetch.is_basic_protocol(protocol, true) then + elseif dir.is_basic_protocol(protocol) then local ok, name = fs.download(url, filename, cache) if not ok then return nil, "Failed downloading "..url..(filename and " - "..filename or ""), "network" @@ -105,7 +98,7 @@ function fetch.find_base_dir(file, temp_dir, src_url, src_dir) local ok, err = fs.change_dir(temp_dir) if not ok then return nil, err end fs.unpack_archive(file) - local inferred_dir = src_dir or fetch.url_to_base_dir(src_url) + local inferred_dir = src_dir or dir.deduce_base_dir(src_url) local found_dir = nil if fs.exists(inferred_dir) then found_dir = inferred_dir @@ -170,131 +163,39 @@ function fetch.fetch_and_unpack_rock(rock_file, dest) return unpack_dir end -function fetch.url_to_base_dir(url) - -- for extensions like foo.tar.gz, "gz" is stripped first - local known_exts = {} - for _, ext in ipairs{"zip", "git", "tgz", "tar", "gz", "bz2"} do - known_exts[ext] = "" - end - local base = dir.base_name(url) - return (base:gsub("%.([^.]*)$", known_exts):gsub("%.tar", "")) -end - -local function convert_dependencies(rockspec, key) - if rockspec[key] then - for i = 1, #rockspec[key] do - local parsed, err = queries.from_dep_string(rockspec[key][i]) - if not parsed then - return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err) - end - rockspec[key][i] = parsed - end - else - rockspec[key] = {} - end -end - --- Back-end function that actually loads the local rockspec. -- Performs some validation and postprocessing of the rockspec contents. --- @param filename string: The local filename of the rockspec file. +-- @param rel_filename string: The local filename of the rockspec file. -- @param quick boolean: if true, skips some steps when loading -- rockspec. -- @return table or (nil, string): A table representing the rockspec -- or nil followed by an error message. -function fetch.load_local_rockspec(filename, quick) - assert(type(filename) == "string") - filename = fs.absolute_name(filename) - local rockspec, err = persist.load_into_table(filename) - if not rockspec then - return nil, "Could not load rockspec file "..filename.." ("..err..")" - end - if cfg.branch and (type(rockspec.source) == "table") then - rockspec.source.branch = cfg.branch - end - local globals = err - - if rockspec.rockspec_format then - if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then - return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." - end - end - - if not quick then - local ok, err = type_rockspec.check(rockspec, globals) - if not ok then - return nil, filename..": "..err - end - 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. - do - local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") - rockspec.format_is_at_least = function(self, version) - return parsed_format >= vers.parse_version(version) - end - end +function fetch.load_local_rockspec(rel_filename, quick) + assert(type(rel_filename) == "string") + local abs_filename = fs.absolute_name(rel_filename) - util.platform_overrides(rockspec.build) - util.platform_overrides(rockspec.dependencies) - util.platform_overrides(rockspec.build_dependencies) - util.platform_overrides(rockspec.test_dependencies) - util.platform_overrides(rockspec.external_dependencies) - util.platform_overrides(rockspec.source) - util.platform_overrides(rockspec.hooks) - util.platform_overrides(rockspec.test) - - local basename = dir.base_name(filename) - if basename == "rockspec" then - rockspec.name = rockspec.package:lower() - else - rockspec.name = basename:match("(.*)-[^-]*-[0-9]*") - if not rockspec.name then + local basename = dir.base_name(abs_filename) + if basename ~= "rockspec" then + if not basename:match("(.*)%-[^-]*%-[0-9]*") then return nil, "Expected filename in format 'name-version-revision.rockspec'." end end - local protocol, pathname = dir.split_url(rockspec.source.url) - if fetch.is_basic_protocol(protocol) then - rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) + local tbl, err = persist.load_into_table(abs_filename) + if not tbl then + return nil, "Could not load rockspec file "..abs_filename.." ("..err..")" + end + + local rockspec, err = rockspecs.from_persisted_table(abs_filename, tbl, err, quick) + if not rockspec then + return nil, abs_filename .. ": " .. err end - rockspec.source.protocol, rockspec.source.pathname = protocol, pathname - - -- Temporary compatibility - if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end - if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end local name_version = rockspec.package:lower() .. "-" .. rockspec.version if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." end - - rockspec.local_filename = filename - local filebase = rockspec.source.file or rockspec.source.url - local base = fetch.url_to_base_dir(filebase) - rockspec.source.dir_set = rockspec.source.dir ~= nil - rockspec.source.dir = rockspec.source.dir - or rockspec.source.module - or ( (filebase:match("%.lua$") or filebase:match("%.c$")) - and (rockspec:format_is_at_least("3.0") - and (fetch.is_basic_protocol(protocol) and "." or base) - or ".") ) - or base - - rockspec.rocks_provided = (rockspec:format_is_at_least("3.0") - and cfg.rocks_provided_3_0 - or cfg.rocks_provided) - - convert_dependencies(rockspec, "dependencies") - convert_dependencies(rockspec, "build_dependencies") - convert_dependencies(rockspec, "test_dependencies") - - if not quick then - path.configure_paths(rockspec) - end - + return rockspec end @@ -347,7 +248,7 @@ end -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message and optional error code. function fetch.get_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(extract) == "boolean") assert(type(dest_dir) == "string" or not dest_dir) @@ -417,13 +318,13 @@ end -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function fetch.fetch_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(extract) == "boolean") assert(type(dest_dir) == "string" or not dest_dir) local protocol = rockspec.source.protocol local ok, proto - if fetch.is_basic_protocol(protocol) then + if dir.is_basic_protocol(protocol) then proto = fetch else ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) diff --git a/src/luarocks/fetch/cvs.lua b/src/luarocks/fetch/cvs.lua index ece711b6..d78e6e60 100644 --- a/src/luarocks/fetch/cvs.lua +++ b/src/luarocks/fetch/cvs.lua @@ -16,7 +16,7 @@ local util = require("luarocks.util") -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function cvs.get_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(dest_dir) == "string" or not dest_dir) local cvs_cmd = rockspec.variables.CVS diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua index a14a5bfb..49ee7183 100644 --- a/src/luarocks/fetch/git.lua +++ b/src/luarocks/fetch/git.lua @@ -77,7 +77,7 @@ end -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function git.get_sources(rockspec, extract, dest_dir, depth) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(dest_dir) == "string" or not dest_dir) local git_cmd = rockspec.variables.GIT diff --git a/src/luarocks/fetch/hg.lua b/src/luarocks/fetch/hg.lua index 4cf8d028..0ef0f5e4 100644 --- a/src/luarocks/fetch/hg.lua +++ b/src/luarocks/fetch/hg.lua @@ -16,7 +16,7 @@ local util = require("luarocks.util") -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function hg.get_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(dest_dir) == "string" or not dest_dir) local hg_cmd = rockspec.variables.HG diff --git a/src/luarocks/fetch/sscm.lua b/src/luarocks/fetch/sscm.lua index 5add10db..32bb2ecc 100644 --- a/src/luarocks/fetch/sscm.lua +++ b/src/luarocks/fetch/sscm.lua @@ -13,7 +13,7 @@ local dir = require("luarocks.dir") -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function sscm.get_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(dest_dir) == "string" or not dest_dir) local sscm_cmd = rockspec.variables.SSCM diff --git a/src/luarocks/fetch/svn.lua b/src/luarocks/fetch/svn.lua index 29bce1b5..ceb15350 100644 --- a/src/luarocks/fetch/svn.lua +++ b/src/luarocks/fetch/svn.lua @@ -16,7 +16,7 @@ local util = require("luarocks.util") -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function svn.get_sources(rockspec, extract, dest_dir) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(dest_dir) == "string" or not dest_dir) local svn_cmd = rockspec.variables.SVN diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua index 8e8d5525..6f70338b 100644 --- a/src/luarocks/manif/writer.lua +++ b/src/luarocks/manif/writer.lua @@ -275,6 +275,7 @@ function writer.make_rock_manifest(name, version) local rock_manifest = { rock_manifest=tree } manif.rock_manifest_cache[name.."/"..version] = rock_manifest save_table(install_dir, "rock_manifest", rock_manifest ) + return true end -- Writes a 'rock_namespace' file in a locally installed rock directory. diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua index 6423de2c..cec370db 100644 --- a/src/luarocks/pack.lua +++ b/src/luarocks/pack.lua @@ -29,7 +29,7 @@ function pack.pack_source_rock(rockspec_file) if err then return nil, "Error loading rockspec: "..err end - rockspec_file = rockspec.local_filename + rockspec_file = rockspec.local_abs_filename local name_version = rockspec.name .. "-" .. rockspec.version local rock_file = fs.absolute_name(name_version .. ".src.rock") diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua index a8426090..8fe6da8d 100644 --- a/src/luarocks/path.lua +++ b/src/luarocks/path.lua @@ -211,26 +211,6 @@ function path.module_to_path(mod) return (mod:gsub("[^.]*$", ""):gsub("%.", "/")) end ---- Set up path-related variables for a given rock. --- Create a "variables" table in the rockspec table, containing --- adjusted variables according to the configuration file. --- @param rockspec table: The rockspec table. -function path.configure_paths(rockspec) - assert(type(rockspec) == "table") - local vars = {} - for k,v in pairs(cfg.variables) do - vars[k] = v - end - local name, version = rockspec.name, rockspec.version - vars.PREFIX = path.install_dir(name, version) - vars.LUADIR = path.lua_dir(name, version) - vars.LIBDIR = path.lib_dir(name, version) - vars.CONFDIR = path.conf_dir(name, version) - vars.BINDIR = path.bin_dir(name, version) - vars.DOCDIR = path.doc_dir(name, version) - rockspec.variables = vars -end - function path.use_tree(tree) cfg.root_dir = tree cfg.rocks_dir = path.rocks_dir(tree) diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua index 1b4e3562..9ae89da4 100644 --- a/src/luarocks/remove.lua +++ b/src/luarocks/remove.lua @@ -30,7 +30,7 @@ local function check_dependents(name, versions, deps_mode) for rock_version, _ in pairs(rock_versions) do local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version)) if rockspec then - local _, missing = deps.match_deps(rockspec, blacklist, deps_mode) + local _, missing = deps.match_deps(rockspec.dependencies, rockspec.rocks_provided, blacklist, deps_mode) if missing[name] then table.insert(dependents, { name = rock_name, version = rock_version }) end diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 54610489..454ec79f 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua @@ -147,7 +147,7 @@ function repos.has_binaries(name, version) end function repos.run_hook(rockspec, hook_name) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") assert(type(hook_name) == "string") local hooks = rockspec.hooks @@ -174,7 +174,7 @@ function repos.run_hook(rockspec, hook_name) end function repos.should_wrap_bin_scripts(rockspec) - assert(type(rockspec) == "table") + assert(rockspec:type() == "rockspec") if cfg.wrap_bin_scripts ~= nil then return cfg.wrap_bin_scripts diff --git a/src/luarocks/rockspecs.lua b/src/luarocks/rockspecs.lua new file mode 100644 index 00000000..373f6caa --- /dev/null +++ b/src/luarocks/rockspecs.lua @@ -0,0 +1,159 @@ +local rockspecs = {} + +local cfg = require("luarocks.core.cfg") +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local queries = require("luarocks.queries") +local type_rockspec = require("luarocks.type.rockspec") +local util = require("luarocks.core.util") +local vers = require("luarocks.core.vers") + +local rockspec_mt = {} + +rockspec_mt.__index = rockspec_mt + +function rockspec_mt.type() + return "rockspec" +end + +--- Perform platform-specific overrides on a table. +-- Overrides values of table with the contents of the appropriate +-- subset of its "platforms" field. The "platforms" field should +-- be a table containing subtables keyed with strings representing +-- platform names. Names that match the contents of the global +-- cfg.platforms setting are used. For example, if +-- cfg.platforms= {"foo"}, then the fields of +-- tbl.platforms.foo will overwrite those of tbl with the same +-- names. For table values, the operation is performed recursively +-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of +-- tbl.x are preserved). +-- @param tbl table or nil: Table which may contain a "platforms" field; +-- if it doesn't (or if nil is passed), this function does nothing. +local function platform_overrides(tbl) + assert(type(tbl) == "table" or not tbl) + + if not tbl then return end + + if tbl.platforms then + for _, platform in ipairs(cfg.platforms) do + local platform_tbl = tbl.platforms[platform] + if platform_tbl then + util.deep_merge(tbl, platform_tbl) + end + end + end + tbl.platforms = nil +end + +local function convert_dependencies(rockspec, key) + if rockspec[key] then + for i = 1, #rockspec[key] do + local parsed, err = queries.from_dep_string(rockspec[key][i]) + if not parsed then + return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err) + end + rockspec[key][i] = parsed + end + else + rockspec[key] = {} + end +end + +--- Set up path-related variables for a given rock. +-- Create a "variables" table in the rockspec table, containing +-- adjusted variables according to the configuration file. +-- @param rockspec table: The rockspec table. +local function configure_paths(rockspec) + local vars = {} + for k,v in pairs(cfg.variables) do + vars[k] = v + end + local name, version = rockspec.name, rockspec.version + vars.PREFIX = path.install_dir(name, version) + vars.LUADIR = path.lua_dir(name, version) + vars.LIBDIR = path.lib_dir(name, version) + vars.CONFDIR = path.conf_dir(name, version) + vars.BINDIR = path.bin_dir(name, version) + vars.DOCDIR = path.doc_dir(name, version) + rockspec.variables = vars +end + +function rockspecs.from_persisted_table(filename, rockspec, globals, quick) + assert(type(rockspec) == "table") + assert(type(globals) == "table" or globals == nil) + assert(type(filename) == "string") + assert(type(quick) == "boolean" or quick == nil) + + if rockspec.rockspec_format then + if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then + return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." + end + end + + if not quick then + local ok, err = type_rockspec.check(rockspec, globals or {}) + if not ok then + return nil, err + end + 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. + do + local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") + rockspec.format_is_at_least = function(self, version) + return parsed_format >= vers.parse_version(version) + end + end + + platform_overrides(rockspec.build) + platform_overrides(rockspec.dependencies) + platform_overrides(rockspec.build_dependencies) + platform_overrides(rockspec.test_dependencies) + platform_overrides(rockspec.external_dependencies) + platform_overrides(rockspec.source) + platform_overrides(rockspec.hooks) + platform_overrides(rockspec.test) + + rockspec.name = rockspec.package:lower() + + local protocol, pathname = dir.split_url(rockspec.source.url) + if dir.is_basic_protocol(protocol) then + rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) + end + rockspec.source.protocol, rockspec.source.pathname = protocol, pathname + + -- Temporary compatibility + if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end + if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end + + rockspec.local_abs_filename = filename + local filebase = rockspec.source.file or rockspec.source.url + local base = dir.deduce_base_dir(filebase) + rockspec.source.dir_set = rockspec.source.dir ~= nil + rockspec.source.dir = rockspec.source.dir + or rockspec.source.module + or ( (filebase:match("%.lua$") or filebase:match("%.c$")) + and (rockspec:format_is_at_least("3.0") + and (dir.is_basic_protocol(protocol) and "." or base) + or ".") ) + or base + + rockspec.rocks_provided = (rockspec:format_is_at_least("3.0") + and cfg.rocks_provided_3_0 + or cfg.rocks_provided) + + convert_dependencies(rockspec, "dependencies") + convert_dependencies(rockspec, "build_dependencies") + convert_dependencies(rockspec, "test_dependencies") + + if not quick then + configure_paths(rockspec) + end + + return setmetatable(rockspec, rockspec_mt) +end + +return rockspecs \ No newline at end of file diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua index 90626f3c..da527bc6 100644 --- a/src/luarocks/search.lua +++ b/src/luarocks/search.lua @@ -221,6 +221,15 @@ local function supported_lua_versions(query) return result_tree end +function search.find_src_or_rockspec(ns_name, version) + local query = queries.new(ns_name, version, false, "src|rockspec") + local url, err = search.find_suitable_rock(query) + if not url then + return nil, "Could not find a result named "..tostring(query)..": "..err + end + return url +end + --- Attempt to get a single URL for a given search for a rock. -- @param query table: a query object. -- @return string or (nil, string): URL for latest matching version @@ -308,29 +317,6 @@ function search.print_result_tree(result_tree, porcelain) end end ---- Given a name and optionally a version, try to find in the rocks --- servers a single .src.rock or .rockspec file that satisfies --- the request, and run the given function on it; or display to the --- user possibilities if it couldn't narrow down a single match. --- @param action function: A function that takes a .src.rock or --- .rockspec URL as a parameter. --- @param ns_name string: A rock name, may be namespaced --- @param version string or nil: A version number may also be given. --- @return The result of the action function, or nil and an error message. -function search.act_on_src_or_rockspec(action, ns_name, version, ...) - assert(type(action) == "function") - assert(type(ns_name) == "string") - assert(type(version) == "string" or not version) - - local query = queries.new(ns_name, version, false, "src|rockspec") - local url, err = search.find_suitable_rock(query) - if not url then - return nil, "Could not find a result named "..tostring(query)..": "..err - end - local _, namespace = util.split_namespace(ns_name) - return action(url, namespace, ...) -end - function search.pick_installed_rock(query, given_tree) assert(query:type() == "query") diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua index 9e3b7c9e..ebd59f85 100644 --- a/src/luarocks/type_check.lua +++ b/src/luarocks/type_check.lua @@ -110,12 +110,12 @@ 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 diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index ea18071f..cd946451 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua @@ -215,37 +215,6 @@ function util.parse_flags(...) return flags, unpack(out) end ---- Perform platform-specific overrides on a table. --- Overrides values of table with the contents of the appropriate --- subset of its "platforms" field. The "platforms" field should --- be a table containing subtables keyed with strings representing --- platform names. Names that match the contents of the global --- cfg.platforms setting are used. For example, if --- cfg.platforms= {"foo"}, then the fields of --- tbl.platforms.foo will overwrite those of tbl with the same --- names. For table values, the operation is performed recursively --- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of --- tbl.x are preserved). --- @param tbl table or nil: Table which may contain a "platforms" field; --- if it doesn't (or if nil is passed), this function does nothing. -function util.platform_overrides(tbl) - assert(type(tbl) == "table" or not tbl) - - local cfg = require("luarocks.core.cfg") - - if not tbl then return end - - if tbl.platforms then - for _, platform in ipairs(cfg.platforms) do - local platform_tbl = tbl.platforms[platform] - if platform_tbl then - core.deep_merge(tbl, platform_tbl) - end - end - end - tbl.platforms = nil -end - local var_format_pattern = "%$%((%a[%a%d_]+)%)" -- Check if a set of needed variables are referenced -- cgit v1.2.3-55-g6feb