From d5eae550c9368bd07008104bdecbcc5eb28814e2 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Sun, 1 Jul 2018 20:14:59 -0300 Subject: rockspec: fix handling of rockspec_format versions * luarocks/type_check.lua: * fix expansion of platforms * luarocks/type/rockspec.lua: * when a version fails checking, try with a later version to produce a hint in the error message. See #823. --- src/luarocks/type/rockspec.lua | 50 +++++++++++++++++++++++++++++++++--------- src/luarocks/type_check.lua | 37 ++++++++++++++----------------- 2 files changed, 56 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/luarocks/type/rockspec.lua b/src/luarocks/type/rockspec.lua index 8b2bdffa..8214516e 100644 --- a/src/luarocks/type/rockspec.lua +++ b/src/luarocks/type/rockspec.lua @@ -17,7 +17,7 @@ type_rockspec.rockspec_format = "3.0" -- _more (boolean) indicates that the table accepts unspecified keys and does not type-check them. -- Any other string keys that don't start with an underscore represent known keys and are type-checking tables, recursively checked. -local rockspec_formats = type_check.declare_schemas({ +local rockspec_formats, versions = type_check.declare_schemas({ ["1.0"] = { rockspec_format = { _type = "string" }, package = { _type = "string", _mandatory = true }, @@ -143,6 +143,22 @@ type_rockspec.order = {"rockspec_format", "package", "version", "test_dependencies", { "test", {"type"} }, "hooks"} +local function check_rockspec_using_version(rockspec, globals, version) + local schema = rockspec_formats[version] + if not schema then + return nil, "unknown rockspec format " .. version + end + local ok, err = type_check.check_undeclared_globals(globals, schema) + if ok then + ok, err = type_check.type_check_table(version, rockspec, schema, "") + end + if ok then + return true + else + return nil, err + end +end + --- Type check a rockspec table. -- Verify the correctness of elements from a -- rockspec table, reporting on unknown fields and type @@ -151,19 +167,33 @@ type_rockspec.order = {"rockspec_format", "package", "version", -- succeeded, or nil and an error message if it failed. function type_rockspec.check(rockspec, globals) assert(type(rockspec) == "table") + local version = rockspec.rockspec_format or "1.0" - local schema = rockspec_formats[version] - if not schema then - return nil, "unknown rockspec format " .. version - end - local ok, err = type_check.check_undeclared_globals(globals, schema) - if ok then - ok, err = type_check.type_check_table(version, rockspec, schema, "") - end + local ok, err = check_rockspec_using_version(rockspec, globals, version) if ok then return true end - return nil, err .. " (rockspec format " .. version .. ")" + + -- Rockspec parsing failed. + -- Let's see if it would pass using a later version. + + local found = false + for _, v in ipairs(versions) do + if not found then + if v == version then + found = true + end + else + local v_ok, v_err = check_rockspec_using_version(rockspec, globals, v) + if v_ok then + return nil, err .. " (using rockspec format " .. version .. " -- " .. + [[adding 'rockspec_format = "]] .. v .. [["' to the rockspec ]] .. + [[will fix this)]] + end + end + end + + return nil, err .. " (using rockspec format " .. version .. ")" end return type_rockspec diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua index b204f5ee..bdf8ecc8 100644 --- a/src/luarocks/type_check.lua +++ b/src/luarocks/type_check.lua @@ -2,11 +2,14 @@ local type_check = {} local cfg = require("luarocks.core.cfg") -local vers = require("luarocks.core.vers") +local fun = require("luarocks.fun") local util = require("luarocks.util") +local vers = require("luarocks.core.vers") -------------------------------------------------------------------------------- -type_check.MAGIC_PLATFORMS = {} +-- A magic constant that is not used anywhere in a schema definition +-- and retains equality when the table is deep-copied. +type_check.MAGIC_PLATFORMS = 0xEBABEFAC do local function fill_in_version(tbl, version) @@ -26,7 +29,7 @@ do tbl[k] = { _any = util.deep_copy(tbl) } - tbl[k]._any[v] = nil + tbl[k]._any[k] = nil elseif type(v) == "table" then expand_magic_platforms(v) end @@ -38,34 +41,26 @@ do -- and the value is a schema specification. Schema versions are considered -- incremental: version "2.0" only needs to specify what's new/changed from -- version "1.0". - function type_check.declare_schemas(versions) + function type_check.declare_schemas(inputs) local schemas = {} local parent_version - local version_list = {} - -- FIXME sorting lexicographically! "1.9" > "1.10" - for version, schema in util.sortedpairs(versions) do - table.insert(version_list, version) + local versions = fun.reverse_in(fun.sort_in(util.keys(inputs), vers.compare_versions)) + + for _, version in ipairs(versions) do + local schema = inputs[version] if parent_version ~= nil then local copy = util.deep_copy(schemas[parent_version]) util.deep_merge(copy, schema) - schemas[version] = copy - else - schemas[version] = schema + schema = copy end - fill_in_version(schemas[version], version) - expand_magic_platforms(schemas[version]) + fill_in_version(schema, version) + expand_magic_platforms(schema) parent_version = version - end - - -- Merge future versions as fallbacks under the old versions, - -- so that error messages can inform users when they try - -- to use new features without bumping rockspec_format in their rockspecs. - for i = #version_list, 2, -1 do - util.deep_merge_under(schemas[version_list[i - 1]], schemas[version_list[i]]) + schemas[version] = schema end - return schemas + return schemas, versions end end -- cgit v1.2.3-55-g6feb