diff options
| author | Hisham Muhammad <hisham@gobolinux.org> | 2017-10-08 02:15:14 -0300 |
|---|---|---|
| committer | Hisham Muhammad <hisham@gobolinux.org> | 2017-10-08 02:15:14 -0300 |
| commit | 49fdc6e080637fd9e5d8a9ae355fa06510cb68ee (patch) | |
| tree | ca5b4a63f037f7af70cfb7b4f508f9a220f68bd5 | |
| parent | c5bcb900a8245845dd5cd4fd8bf796591769bbee (diff) | |
| download | luarocks-49fdc6e080637fd9e5d8a9ae355fa06510cb68ee.tar.gz luarocks-49fdc6e080637fd9e5d8a9ae355fa06510cb68ee.tar.bz2 luarocks-49fdc6e080637fd9e5d8a9ae355fa06510cb68ee.zip | |
Reorganize luarocks.core requires and type checking tables
* For each `luarocks.core.x` module, make `luarocks.x` module
load the core module explicitly as `core`, and expose its
relevant methods explicitly as well (instead of using
`setmetatable`).
* Move all type checking out of the core, adjusting the manifest
modules accordingly.
* Create separate modules for the rockspec and manifest
schemas in the `luarocks.type` namespace.
| -rw-r--r-- | src/luarocks/cmd/new_version.lua | 4 | ||||
| -rw-r--r-- | src/luarocks/cmd/write_rockspec.lua | 4 | ||||
| -rw-r--r-- | src/luarocks/core/manif.lua | 16 | ||||
| -rw-r--r-- | src/luarocks/core/type_check.lua | 231 | ||||
| -rw-r--r-- | src/luarocks/dir.lua | 6 | ||||
| -rw-r--r-- | src/luarocks/fetch.lua | 6 | ||||
| -rw-r--r-- | src/luarocks/manif.lua | 37 | ||||
| -rw-r--r-- | src/luarocks/path.lua | 8 | ||||
| -rw-r--r-- | src/luarocks/persist.lua | 4 | ||||
| -rw-r--r-- | src/luarocks/type/manifest.lua | 81 | ||||
| -rw-r--r-- | src/luarocks/type/rockspec.lua | 130 | ||||
| -rw-r--r-- | src/luarocks/type_check.lua | 259 | ||||
| -rw-r--r-- | src/luarocks/util.lua | 14 | ||||
| -rw-r--r-- | src/luarocks/vers.lua | 7 |
14 files changed, 426 insertions, 381 deletions
diff --git a/src/luarocks/cmd/new_version.lua b/src/luarocks/cmd/new_version.lua index b13dbb97..5149f924 100644 --- a/src/luarocks/cmd/new_version.lua +++ b/src/luarocks/cmd/new_version.lua | |||
| @@ -8,7 +8,7 @@ local download = require("luarocks.download") | |||
| 8 | local fetch = require("luarocks.fetch") | 8 | local fetch = require("luarocks.fetch") |
| 9 | local persist = require("luarocks.persist") | 9 | local persist = require("luarocks.persist") |
| 10 | local fs = require("luarocks.fs") | 10 | local fs = require("luarocks.fs") |
| 11 | local type_check = require("luarocks.type_check") | 11 | local type_rockspec = require("luarocks.type.rockspec") |
| 12 | 12 | ||
| 13 | new_version.help_summary = "Auto-write a rockspec for a new version of a rock." | 13 | new_version.help_summary = "Auto-write a rockspec for a new version of a rock." |
| 14 | new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]" | 14 | new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]" |
| @@ -184,7 +184,7 @@ function new_version.command(flags, input, version, url) | |||
| 184 | 184 | ||
| 185 | local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec" | 185 | local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec" |
| 186 | 186 | ||
| 187 | persist.save_from_table(out_filename, out_rs, type_check.rockspec_order) | 187 | persist.save_from_table(out_filename, out_rs, type_rockspec.order) |
| 188 | 188 | ||
| 189 | util.printout("Wrote "..out_filename) | 189 | util.printout("Wrote "..out_filename) |
| 190 | 190 | ||
diff --git a/src/luarocks/cmd/write_rockspec.lua b/src/luarocks/cmd/write_rockspec.lua index 73010f08..06d50c69 100644 --- a/src/luarocks/cmd/write_rockspec.lua +++ b/src/luarocks/cmd/write_rockspec.lua | |||
| @@ -7,7 +7,7 @@ local fetch = require("luarocks.fetch") | |||
| 7 | local fs = require("luarocks.fs") | 7 | local fs = require("luarocks.fs") |
| 8 | local path = require("luarocks.path") | 8 | local path = require("luarocks.path") |
| 9 | local persist = require("luarocks.persist") | 9 | local persist = require("luarocks.persist") |
| 10 | local type_check = require("luarocks.type_check") | 10 | local type_rockspec = require("luarocks.type.rockspec") |
| 11 | local util = require("luarocks.util") | 11 | local util = require("luarocks.util") |
| 12 | local vers = require("luarocks.vers") | 12 | local vers = require("luarocks.vers") |
| 13 | 13 | ||
| @@ -364,7 +364,7 @@ function write_rockspec.command(flags, name, version, url_or_dir) | |||
| 364 | 364 | ||
| 365 | rockspec_cleanup(rockspec) | 365 | rockspec_cleanup(rockspec) |
| 366 | 366 | ||
| 367 | persist.save_from_table(filename, rockspec, type_check.rockspec_order) | 367 | persist.save_from_table(filename, rockspec, type_rockspec.order) |
| 368 | 368 | ||
| 369 | util.printout() | 369 | util.printout() |
| 370 | util.printout("Wrote template at "..filename.." -- you should now edit and finish it.") | 370 | util.printout("Wrote template at "..filename.." -- you should now edit and finish it.") |
diff --git a/src/luarocks/core/manif.lua b/src/luarocks/core/manif.lua index 549cfb4c..cd8d7a06 100644 --- a/src/luarocks/core/manif.lua +++ b/src/luarocks/core/manif.lua | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | local manif = {} | 3 | local manif = {} |
| 4 | 4 | ||
| 5 | local persist = require("luarocks.core.persist") | 5 | local persist = require("luarocks.core.persist") |
| 6 | local type_check = require("luarocks.core.type_check") | ||
| 7 | local cfg = require("luarocks.core.cfg") | 6 | local cfg = require("luarocks.core.cfg") |
| 8 | local dir = require("luarocks.core.dir") | 7 | local dir = require("luarocks.core.dir") |
| 9 | local require = nil | 8 | local require = nil |
| @@ -37,24 +36,15 @@ end | |||
| 37 | -- @param file string: The local filename of the manifest file. | 36 | -- @param file string: The local filename of the manifest file. |
| 38 | -- @param repo_url string: The repository identifier. | 37 | -- @param repo_url string: The repository identifier. |
| 39 | -- @param lua_version string: Lua version in "5.x" format, defaults to installed version. | 38 | -- @param lua_version string: Lua version in "5.x" format, defaults to installed version. |
| 40 | -- @param quick boolean: If given, skips type checking. | ||
| 41 | -- @return table or (nil, string, string): the manifest or nil, | 39 | -- @return table or (nil, string, string): the manifest or nil, |
| 42 | -- error message and error code ("open", "load", "run" or "type"). | 40 | -- error message and error code ("open", "load", "run"). |
| 43 | function manif.manifest_loader(file, repo_url, lua_version, quick) | 41 | function manif.manifest_loader(file, repo_url, lua_version) |
| 44 | local manifest, err, errcode = persist.load_into_table(file) | 42 | local manifest, err, errcode = persist.load_into_table(file) |
| 45 | if not manifest then | 43 | if not manifest then |
| 46 | return nil, "Failed loading manifest for "..repo_url..": "..err, errcode | 44 | return nil, "Failed loading manifest for "..repo_url..": "..err, errcode |
| 47 | end | 45 | end |
| 48 | local globals = err | ||
| 49 | if not quick then | ||
| 50 | local ok, err = type_check.type_check_manifest(manifest, globals) | ||
| 51 | if not ok then | ||
| 52 | return nil, "Error checking manifest: "..err, "type" | ||
| 53 | end | ||
| 54 | end | ||
| 55 | |||
| 56 | manif.cache_manifest(repo_url, lua_version, manifest) | 46 | manif.cache_manifest(repo_url, lua_version, manifest) |
| 57 | return manifest | 47 | return manifest, err, errcode |
| 58 | end | 48 | end |
| 59 | 49 | ||
| 60 | --- Load a local manifest describing a repository. | 50 | --- Load a local manifest describing a repository. |
diff --git a/src/luarocks/core/type_check.lua b/src/luarocks/core/type_check.lua deleted file mode 100644 index 8b103a58..00000000 --- a/src/luarocks/core/type_check.lua +++ /dev/null | |||
| @@ -1,231 +0,0 @@ | |||
| 1 | |||
| 2 | local type_check = {} | ||
| 3 | |||
| 4 | local cfg = require("luarocks.core.cfg") | ||
| 5 | local vers = require("luarocks.core.vers") | ||
| 6 | local require = nil | ||
| 7 | -------------------------------------------------------------------------------- | ||
| 8 | |||
| 9 | type_check.string_1 = { _type = "string" } | ||
| 10 | type_check.number_1 = { _type = "number" } | ||
| 11 | type_check.mandatory_string_1 = { _type = "string", _mandatory = true } | ||
| 12 | |||
| 13 | local number_1 = type_check.number_1 | ||
| 14 | local string_1 = type_check.string_1 | ||
| 15 | local mandatory_string_1 = type_check.mandatory_string_1 | ||
| 16 | |||
| 17 | local manifest_types = { | ||
| 18 | repository = { | ||
| 19 | _mandatory = true, | ||
| 20 | -- packages | ||
| 21 | _any = { | ||
| 22 | -- versions | ||
| 23 | _any = { | ||
| 24 | -- items | ||
| 25 | _any = { | ||
| 26 | arch = mandatory_string_1, | ||
| 27 | modules = { _any = string_1 }, | ||
| 28 | commands = { _any = string_1 }, | ||
| 29 | dependencies = { _any = string_1 }, | ||
| 30 | -- TODO: to be extended with more metadata. | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | }, | ||
| 35 | modules = { | ||
| 36 | _mandatory = true, | ||
| 37 | -- modules | ||
| 38 | _any = { | ||
| 39 | -- providers | ||
| 40 | _any = string_1 | ||
| 41 | } | ||
| 42 | }, | ||
| 43 | commands = { | ||
| 44 | _mandatory = true, | ||
| 45 | -- modules | ||
| 46 | _any = { | ||
| 47 | -- commands | ||
| 48 | _any = string_1 | ||
| 49 | } | ||
| 50 | }, | ||
| 51 | dependencies = { | ||
| 52 | -- each module | ||
| 53 | _any = { | ||
| 54 | -- each version | ||
| 55 | _any = { | ||
| 56 | -- each dependency | ||
| 57 | _any = { | ||
| 58 | name = string_1, | ||
| 59 | constraints = { | ||
| 60 | _any = { | ||
| 61 | no_upgrade = { _type = "boolean" }, | ||
| 62 | op = string_1, | ||
| 63 | version = { | ||
| 64 | string = string_1, | ||
| 65 | _any = number_1, | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | local function check_version(version, typetbl, context) | ||
| 76 | local typetbl_version = typetbl._version or "1.0" | ||
| 77 | if vers.compare_versions(typetbl_version, version) then | ||
| 78 | if context == "" then | ||
| 79 | return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly." | ||
| 80 | else | ||
| 81 | return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly." | ||
| 82 | end | ||
| 83 | end | ||
| 84 | return true | ||
| 85 | end | ||
| 86 | |||
| 87 | --- Type check an object. | ||
| 88 | -- The object is compared against an archetypical value | ||
| 89 | -- matching the expected type -- the actual values don't matter, | ||
| 90 | -- only their types. Tables are type checked recursively. | ||
| 91 | -- @param version string: The version of the item. | ||
| 92 | -- @param item any: The object being checked. | ||
| 93 | -- @param typetbl any: The type-checking table for the object. | ||
| 94 | -- @param context string: A string indicating the "context" where the | ||
| 95 | -- error occurred (the full table path), for error messages. | ||
| 96 | -- @return boolean or (nil, string): true if type checking | ||
| 97 | -- succeeded, or nil and an error message if it failed. | ||
| 98 | -- @see type_check_table | ||
| 99 | local function type_check_item(version, item, typetbl, context) | ||
| 100 | assert(type(version) == "string") | ||
| 101 | |||
| 102 | if typetbl._version and typetbl._version ~= "1.0" then | ||
| 103 | local ok, err = check_version(version, typetbl, context) | ||
| 104 | if not ok then | ||
| 105 | return nil, err | ||
| 106 | end | ||
| 107 | end | ||
| 108 | |||
| 109 | local item_type = type(item) or "nil" | ||
| 110 | local expected_type = typetbl._type or "table" | ||
| 111 | |||
| 112 | if expected_type == "number" then | ||
| 113 | if not tonumber(item) then | ||
| 114 | return nil, "Type mismatch on field "..context..": expected a number" | ||
| 115 | end | ||
| 116 | elseif expected_type == "string" then | ||
| 117 | if item_type ~= "string" then | ||
| 118 | return nil, "Type mismatch on field "..context..": expected a string, got "..item_type | ||
| 119 | end | ||
| 120 | if typetbl._pattern then | ||
| 121 | if not item:match("^"..typetbl._pattern.."$") then | ||
| 122 | return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'" | ||
| 123 | end | ||
| 124 | end | ||
| 125 | elseif expected_type == "table" then | ||
| 126 | if item_type ~= expected_type then | ||
| 127 | return nil, "Type mismatch on field "..context..": expected a table" | ||
| 128 | else | ||
| 129 | return type_check.type_check_table(version, item, typetbl, context) | ||
| 130 | end | ||
| 131 | elseif item_type ~= expected_type then | ||
| 132 | return nil, "Type mismatch on field "..context..": expected "..expected_type | ||
| 133 | end | ||
| 134 | return true | ||
| 135 | end | ||
| 136 | |||
| 137 | local function mkfield(context, field) | ||
| 138 | if context == "" then | ||
| 139 | return tostring(field) | ||
| 140 | elseif type(field) == "string" then | ||
| 141 | return context.."."..field | ||
| 142 | else | ||
| 143 | return context.."["..tostring(field).."]" | ||
| 144 | end | ||
| 145 | end | ||
| 146 | |||
| 147 | --- Type check the contents of a table. | ||
| 148 | -- The table's contents are compared against a reference table, | ||
| 149 | -- which contains the recognized fields, with archetypical values | ||
| 150 | -- matching the expected types -- the actual values of items in the | ||
| 151 | -- reference table don't matter, only their types (ie, for field x | ||
| 152 | -- in tbl that is correctly typed, type(tbl.x) == type(types.x)). | ||
| 153 | -- If the reference table contains a field called MORE, then | ||
| 154 | -- unknown fields in the checked table are accepted. | ||
| 155 | -- If it contains a field called ANY, then its type will be | ||
| 156 | -- used to check any unknown fields. If a field is prefixed | ||
| 157 | -- with MUST_, it is mandatory; its absence from the table is | ||
| 158 | -- a type error. | ||
| 159 | -- Tables are type checked recursively. | ||
| 160 | -- @param version string: The version of tbl. | ||
| 161 | -- @param tbl table: The table to be type checked. | ||
| 162 | -- @param typetbl table: The type-checking table, containing | ||
| 163 | -- values for recognized fields in the checked table. | ||
| 164 | -- @param context string: A string indicating the "context" where the | ||
| 165 | -- error occurred (such as the name of the table the item is a part of), | ||
| 166 | -- to be used by error messages. | ||
| 167 | -- @return boolean or (nil, string): true if type checking | ||
| 168 | -- succeeded, or nil and an error message if it failed. | ||
| 169 | function type_check.type_check_table(version, tbl, typetbl, context) | ||
| 170 | assert(type(version) == "string") | ||
| 171 | assert(type(tbl) == "table") | ||
| 172 | assert(type(typetbl) == "table") | ||
| 173 | |||
| 174 | local ok, err = check_version(version, typetbl, context) | ||
| 175 | if not ok then | ||
| 176 | return nil, err | ||
| 177 | end | ||
| 178 | |||
| 179 | for k, v in pairs(tbl) do | ||
| 180 | local t = typetbl[k] or typetbl._any | ||
| 181 | if t then | ||
| 182 | local ok, err = type_check_item(version, v, t, mkfield(context, k)) | ||
| 183 | if not ok then return nil, err end | ||
| 184 | elseif typetbl._more then | ||
| 185 | -- Accept unknown field | ||
| 186 | else | ||
| 187 | if not cfg.accept_unknown_fields then | ||
| 188 | return nil, "Unknown field "..k | ||
| 189 | end | ||
| 190 | end | ||
| 191 | end | ||
| 192 | for k, v in pairs(typetbl) do | ||
| 193 | if k:sub(1,1) ~= "_" and v._mandatory then | ||
| 194 | if not tbl[k] then | ||
| 195 | return nil, "Mandatory field "..mkfield(context, k).." is missing." | ||
| 196 | end | ||
| 197 | end | ||
| 198 | end | ||
| 199 | return true | ||
| 200 | end | ||
| 201 | |||
| 202 | function type_check.check_undeclared_globals(globals, typetbl) | ||
| 203 | local undeclared = {} | ||
| 204 | for glob, _ in pairs(globals) do | ||
| 205 | if not (typetbl[glob] or typetbl["MUST_"..glob]) then | ||
| 206 | table.insert(undeclared, glob) | ||
| 207 | end | ||
| 208 | end | ||
| 209 | if #undeclared == 1 then | ||
| 210 | return nil, "Unknown variable: "..undeclared[1] | ||
| 211 | elseif #undeclared > 1 then | ||
| 212 | return nil, "Unknown variables: "..table.concat(undeclared, ", ") | ||
| 213 | end | ||
| 214 | return true | ||
| 215 | end | ||
| 216 | |||
| 217 | --- Type check a manifest table. | ||
| 218 | -- Verify the correctness of elements from a | ||
| 219 | -- manifest table, reporting on unknown fields and type | ||
| 220 | -- mismatches. | ||
| 221 | -- @return boolean or (nil, string): true if type checking | ||
| 222 | -- succeeded, or nil and an error message if it failed. | ||
| 223 | function type_check.type_check_manifest(manifest, globals) | ||
| 224 | assert(type(manifest) == "table") | ||
| 225 | local ok, err = type_check.check_undeclared_globals(globals, manifest_types) | ||
| 226 | if not ok then return nil, err end | ||
| 227 | return type_check.type_check_table("1.0", manifest, manifest_types, "") | ||
| 228 | end | ||
| 229 | |||
| 230 | return type_check | ||
| 231 | |||
diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua index 71477804..72395e47 100644 --- a/src/luarocks/dir.lua +++ b/src/luarocks/dir.lua | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | 1 | ||
| 2 | --- Generic utilities for handling pathnames. | 2 | --- Generic utilities for handling pathnames. |
| 3 | local dir = {} | 3 | local dir = {} |
| 4 | setmetatable(dir, { __index = require("luarocks.core.dir") }) | 4 | |
| 5 | local core = require("luarocks.core.dir") | ||
| 6 | |||
| 7 | dir.path = core.path | ||
| 8 | dir.split_url = core.split_url | ||
| 5 | 9 | ||
| 6 | --- Strip the path off a path+filename. | 10 | --- Strip the path off a path+filename. |
| 7 | -- @param pathname string: A path+name, such as "/a/b/c" | 11 | -- @param pathname string: A path+name, such as "/a/b/c" |
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index dc467d19..de4a3dee 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua | |||
| @@ -4,7 +4,7 @@ local fetch = {} | |||
| 4 | 4 | ||
| 5 | local fs = require("luarocks.fs") | 5 | local fs = require("luarocks.fs") |
| 6 | local dir = require("luarocks.dir") | 6 | local dir = require("luarocks.dir") |
| 7 | local type_check = require("luarocks.type_check") | 7 | local type_rockspec = require("luarocks.type.rockspec") |
| 8 | local path = require("luarocks.path") | 8 | local path = require("luarocks.path") |
| 9 | local vers = require("luarocks.vers") | 9 | local vers = require("luarocks.vers") |
| 10 | local persist = require("luarocks.persist") | 10 | local persist = require("luarocks.persist") |
| @@ -199,13 +199,13 @@ function fetch.load_local_rockspec(filename, quick) | |||
| 199 | local globals = err | 199 | local globals = err |
| 200 | 200 | ||
| 201 | if rockspec.rockspec_format then | 201 | if rockspec.rockspec_format then |
| 202 | if vers.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then | 202 | if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then |
| 203 | return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." | 203 | return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." |
| 204 | end | 204 | end |
| 205 | end | 205 | end |
| 206 | 206 | ||
| 207 | if not quick then | 207 | if not quick then |
| 208 | local ok, err = type_check.type_check_rockspec(rockspec, globals) | 208 | local ok, err = type_rockspec.check(rockspec, globals) |
| 209 | if not ok then | 209 | if not ok then |
| 210 | return nil, filename..": "..err | 210 | return nil, filename..": "..err |
| 211 | end | 211 | end |
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua index 7f3085db..df9f22ae 100644 --- a/src/luarocks/manif.lua +++ b/src/luarocks/manif.lua | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | -- They are loaded into manifest tables, which are then used for | 3 | -- They are loaded into manifest tables, which are then used for |
| 4 | -- performing searches, matching dependencies, etc. | 4 | -- performing searches, matching dependencies, etc. |
| 5 | local manif = {} | 5 | local manif = {} |
| 6 | setmetatable(manif, { __index = require("luarocks.core.manif") }) | ||
| 7 | 6 | ||
| 7 | local core = require("luarocks.core.manif") | ||
| 8 | local persist = require("luarocks.persist") | 8 | local persist = require("luarocks.persist") |
| 9 | local fetch = require("luarocks.fetch") | 9 | local fetch = require("luarocks.fetch") |
| 10 | local dir = require("luarocks.dir") | 10 | local dir = require("luarocks.dir") |
| @@ -12,9 +12,32 @@ local fs = require("luarocks.fs") | |||
| 12 | local cfg = require("luarocks.core.cfg") | 12 | local cfg = require("luarocks.core.cfg") |
| 13 | local path = require("luarocks.path") | 13 | local path = require("luarocks.path") |
| 14 | local util = require("luarocks.util") | 14 | local util = require("luarocks.util") |
| 15 | local type_manifest = require("luarocks.type.manifest") | ||
| 16 | |||
| 17 | manif.cache_manifest = core.cache_manifest | ||
| 15 | 18 | ||
| 16 | manif.rock_manifest_cache = {} | 19 | manif.rock_manifest_cache = {} |
| 17 | 20 | ||
| 21 | local function check_manifest(repo_url, manifest, globals) | ||
| 22 | local ok, err = type_manifest.check(manifest, globals) | ||
| 23 | if not ok then | ||
| 24 | core.cache_manifest(repo_url, cfg.lua_version, nil) | ||
| 25 | return nil, "Error checking manifest: "..err, "type" | ||
| 26 | end | ||
| 27 | return manifest | ||
| 28 | end | ||
| 29 | |||
| 30 | function manif.load_local_manifest(repo_url) | ||
| 31 | local manifest, err, errcode = core.load_local_manifest(repo_url) | ||
| 32 | if not manifest then | ||
| 33 | return nil, err, errcode | ||
| 34 | end | ||
| 35 | if err then | ||
| 36 | return check_manifest(repo_url, manifest, err) | ||
| 37 | end | ||
| 38 | return manifest | ||
| 39 | end | ||
| 40 | |||
| 18 | function manif.load_rock_manifest(name, version, root) | 41 | function manif.load_rock_manifest(name, version, root) |
| 19 | assert(type(name) == "string") | 42 | assert(type(name) == "string") |
| 20 | assert(type(version) == "string") | 43 | assert(type(version) == "string") |
| @@ -60,7 +83,7 @@ function manif.load_manifest(repo_url, lua_version) | |||
| 60 | assert(type(lua_version) == "string" or not lua_version) | 83 | assert(type(lua_version) == "string" or not lua_version) |
| 61 | lua_version = lua_version or cfg.lua_version | 84 | lua_version = lua_version or cfg.lua_version |
| 62 | 85 | ||
| 63 | local cached_manifest = manif.get_cached_manifest(repo_url, lua_version) | 86 | local cached_manifest = core.get_cached_manifest(repo_url, lua_version) |
| 64 | if cached_manifest then | 87 | if cached_manifest then |
| 65 | return cached_manifest | 88 | return cached_manifest |
| 66 | end | 89 | end |
| @@ -94,8 +117,8 @@ function manif.load_manifest(repo_url, lua_version) | |||
| 94 | end | 117 | end |
| 95 | if pathname:match(".*%.zip$") then | 118 | if pathname:match(".*%.zip$") then |
| 96 | pathname = fs.absolute_name(pathname) | 119 | pathname = fs.absolute_name(pathname) |
| 97 | local dir = dir.dir_name(pathname) | 120 | local dirname = dir.dir_name(pathname) |
| 98 | fs.change_dir(dir) | 121 | fs.change_dir(dirname) |
| 99 | local nozip = pathname:match("(.*)%.zip$") | 122 | local nozip = pathname:match("(.*)%.zip$") |
| 100 | fs.delete(nozip) | 123 | fs.delete(nozip) |
| 101 | local ok = fs.unzip(pathname) | 124 | local ok = fs.unzip(pathname) |
| @@ -107,7 +130,11 @@ function manif.load_manifest(repo_url, lua_version) | |||
| 107 | end | 130 | end |
| 108 | pathname = nozip | 131 | pathname = nozip |
| 109 | end | 132 | end |
| 110 | return manif.manifest_loader(pathname, repo_url, lua_version) | 133 | local manifest, err, errcode = core.manifest_loader(pathname, repo_url, lua_version) |
| 134 | if not manifest then | ||
| 135 | return nil, err, errcode | ||
| 136 | end | ||
| 137 | return check_manifest(repo_url, manifest, err) | ||
| 111 | end | 138 | end |
| 112 | 139 | ||
| 113 | --- Get type and name of an item (a module or a command) provided by a file. | 140 | --- Get type and name of an item (a module or a command) provided by a file. |
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua index d740331b..8a56233f 100644 --- a/src/luarocks/path.lua +++ b/src/luarocks/path.lua | |||
| @@ -3,12 +3,18 @@ | |||
| 3 | -- All paths are configured in this module, making it a single | 3 | -- All paths are configured in this module, making it a single |
| 4 | -- point where the layout of the local installation is defined in LuaRocks. | 4 | -- point where the layout of the local installation is defined in LuaRocks. |
| 5 | local path = {} | 5 | local path = {} |
| 6 | setmetatable(path, { __index = require("luarocks.core.path") }) | ||
| 7 | 6 | ||
| 7 | local core = require("luarocks.core.path") | ||
| 8 | local dir = require("luarocks.dir") | 8 | local dir = require("luarocks.dir") |
| 9 | local cfg = require("luarocks.core.cfg") | 9 | local cfg = require("luarocks.core.cfg") |
| 10 | local util = require("luarocks.util") | 10 | local util = require("luarocks.util") |
| 11 | 11 | ||
| 12 | path.rocks_dir = core.rocks_dir | ||
| 13 | path.versioned_name = core.versioned_name | ||
| 14 | path.path_to_module = core.path_to_module | ||
| 15 | path.deploy_lua_dir = core.deploy_lua_dir | ||
| 16 | path.deploy_lib_dir = core.deploy_lib_dir | ||
| 17 | |||
| 12 | --- Infer rockspec filename from a rock filename. | 18 | --- Infer rockspec filename from a rock filename. |
| 13 | -- @param rock_name string: Pathname of a rock file. | 19 | -- @param rock_name string: Pathname of a rock file. |
| 14 | -- @return string: Filename of the rockspec, without path. | 20 | -- @return string: Filename of the rockspec, without path. |
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua index 6d5e917b..1460bd15 100644 --- a/src/luarocks/persist.lua +++ b/src/luarocks/persist.lua | |||
| @@ -4,10 +4,12 @@ | |||
| 4 | -- Implemented separately to avoid interdependencies, | 4 | -- Implemented separately to avoid interdependencies, |
| 5 | -- as it is used in the bootstrapping stage of the cfg module. | 5 | -- as it is used in the bootstrapping stage of the cfg module. |
| 6 | local persist = {} | 6 | local persist = {} |
| 7 | setmetatable(persist, { __index = require("luarocks.core.persist") }) | ||
| 8 | 7 | ||
| 8 | local core = require("luarocks.core.persist") | ||
| 9 | local util = require("luarocks.util") | 9 | local util = require("luarocks.util") |
| 10 | 10 | ||
| 11 | persist.load_into_table = core.load_into_table | ||
| 12 | |||
| 11 | local write_table | 13 | local write_table |
| 12 | 14 | ||
| 13 | --- Write a value as Lua code. | 15 | --- Write a value as Lua code. |
diff --git a/src/luarocks/type/manifest.lua b/src/luarocks/type/manifest.lua new file mode 100644 index 00000000..f58ff984 --- /dev/null +++ b/src/luarocks/type/manifest.lua | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | local type_manifest = {} | ||
| 2 | |||
| 3 | local type_check = require("luarocks.type_check") | ||
| 4 | |||
| 5 | local number_1 = type_check.number_1 | ||
| 6 | local string_1 = type_check.string_1 | ||
| 7 | local mandatory_string_1 = type_check.mandatory_string_1 | ||
| 8 | |||
| 9 | local manifest_types = { | ||
| 10 | repository = { | ||
| 11 | _mandatory = true, | ||
| 12 | -- packages | ||
| 13 | _any = { | ||
| 14 | -- versions | ||
| 15 | _any = { | ||
| 16 | -- items | ||
| 17 | _any = { | ||
| 18 | arch = mandatory_string_1, | ||
| 19 | modules = { _any = string_1 }, | ||
| 20 | commands = { _any = string_1 }, | ||
| 21 | dependencies = { _any = string_1 }, | ||
| 22 | -- TODO: to be extended with more metadata. | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } | ||
| 26 | }, | ||
| 27 | modules = { | ||
| 28 | _mandatory = true, | ||
| 29 | -- modules | ||
| 30 | _any = { | ||
| 31 | -- providers | ||
| 32 | _any = string_1 | ||
| 33 | } | ||
| 34 | }, | ||
| 35 | commands = { | ||
| 36 | _mandatory = true, | ||
| 37 | -- modules | ||
| 38 | _any = { | ||
| 39 | -- commands | ||
| 40 | _any = string_1 | ||
| 41 | } | ||
| 42 | }, | ||
| 43 | dependencies = { | ||
| 44 | -- each module | ||
| 45 | _any = { | ||
| 46 | -- each version | ||
| 47 | _any = { | ||
| 48 | -- each dependency | ||
| 49 | _any = { | ||
| 50 | name = string_1, | ||
| 51 | constraints = { | ||
| 52 | _any = { | ||
| 53 | no_upgrade = { _type = "boolean" }, | ||
| 54 | op = string_1, | ||
| 55 | version = { | ||
| 56 | string = string_1, | ||
| 57 | _any = number_1, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | --- Type check a manifest table. | ||
| 69 | -- Verify the correctness of elements from a | ||
| 70 | -- manifest table, reporting on unknown fields and type | ||
| 71 | -- mismatches. | ||
| 72 | -- @return boolean or (nil, string): true if type checking | ||
| 73 | -- succeeded, or nil and an error message if it failed. | ||
| 74 | function type_manifest.check(manifest, globals) | ||
| 75 | assert(type(manifest) == "table") | ||
| 76 | local ok, err = type_check.check_undeclared_globals(globals, manifest_types) | ||
| 77 | if not ok then return nil, err end | ||
| 78 | return type_check.type_check_table("1.0", manifest, manifest_types, "") | ||
| 79 | end | ||
| 80 | |||
| 81 | return type_manifest | ||
diff --git a/src/luarocks/type/rockspec.lua b/src/luarocks/type/rockspec.lua new file mode 100644 index 00000000..5ff48177 --- /dev/null +++ b/src/luarocks/type/rockspec.lua | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | local type_rockspec = {} | ||
| 2 | |||
| 3 | local type_check = require("luarocks.type_check") | ||
| 4 | |||
| 5 | type_rockspec.rockspec_format = "3.0" | ||
| 6 | |||
| 7 | local string_1 = type_check.string_1 | ||
| 8 | local mandatory_string_1 = type_check.mandatory_string_1 | ||
| 9 | |||
| 10 | local string_3 = { _type = "string", _version = "3.0" } | ||
| 11 | local list_of_strings_3 = { _any = string_3, _version = "3.0" } | ||
| 12 | |||
| 13 | -- Syntax for type-checking tables: | ||
| 14 | -- | ||
| 15 | -- A type-checking table describes typing data for a value. | ||
| 16 | -- Any key starting with an underscore has a special meaning: | ||
| 17 | -- _type (string) is the Lua type of the value. Default is "table". | ||
| 18 | -- _version (string) is the minimum rockspec_version that supports this value. Default is "1.0". | ||
| 19 | -- _mandatory (boolean) indicates if the value is a mandatory key in its container table. Default is false. | ||
| 20 | -- For "string" types only: | ||
| 21 | -- _pattern (string) is the string-matching pattern, valid for string types only. Default is ".*". | ||
| 22 | -- For "table" types only: | ||
| 23 | -- _any (table) is the type-checking table for unspecified keys, recursively checked. | ||
| 24 | -- _more (boolean) indicates that the table accepts unspecified keys and does not type-check them. | ||
| 25 | -- Any other string keys that don't start with an underscore represent known keys and are type-checking tables, recursively checked. | ||
| 26 | |||
| 27 | local rockspec_types = { | ||
| 28 | rockspec_format = string_1, | ||
| 29 | package = mandatory_string_1, | ||
| 30 | version = { _type = "string", _pattern = "[%w.]+-[%d]+", _mandatory = true }, | ||
| 31 | description = { | ||
| 32 | summary = string_1, | ||
| 33 | detailed = string_1, | ||
| 34 | homepage = string_1, | ||
| 35 | license = string_1, | ||
| 36 | maintainer = string_1, | ||
| 37 | labels = list_of_strings_3, | ||
| 38 | issues_url = string_3, | ||
| 39 | }, | ||
| 40 | dependencies = { | ||
| 41 | platforms = {}, -- recursively defined below | ||
| 42 | _any = string_1, | ||
| 43 | }, | ||
| 44 | supported_platforms = { | ||
| 45 | _any = string_1, | ||
| 46 | }, | ||
| 47 | external_dependencies = { | ||
| 48 | platforms = {}, -- recursively defined below | ||
| 49 | _any = { | ||
| 50 | program = string_1, | ||
| 51 | header = string_1, | ||
| 52 | library = string_1, | ||
| 53 | } | ||
| 54 | }, | ||
| 55 | source = { | ||
| 56 | _mandatory = true, | ||
| 57 | platforms = {}, -- recursively defined below | ||
| 58 | url = mandatory_string_1, | ||
| 59 | md5 = string_1, | ||
| 60 | file = string_1, | ||
| 61 | dir = string_1, | ||
| 62 | tag = string_1, | ||
| 63 | branch = string_1, | ||
| 64 | module = string_1, | ||
| 65 | cvs_tag = string_1, | ||
| 66 | cvs_module = string_1, | ||
| 67 | }, | ||
| 68 | build = { | ||
| 69 | platforms = {}, -- recursively defined below | ||
| 70 | type = string_1, | ||
| 71 | install = { | ||
| 72 | lua = { | ||
| 73 | _more = true | ||
| 74 | }, | ||
| 75 | lib = { | ||
| 76 | _more = true | ||
| 77 | }, | ||
| 78 | conf = { | ||
| 79 | _more = true | ||
| 80 | }, | ||
| 81 | bin = { | ||
| 82 | _more = true | ||
| 83 | } | ||
| 84 | }, | ||
| 85 | copy_directories = { | ||
| 86 | _any = string_1, | ||
| 87 | }, | ||
| 88 | _more = true, | ||
| 89 | _mandatory = true | ||
| 90 | }, | ||
| 91 | hooks = { | ||
| 92 | platforms = {}, -- recursively defined below | ||
| 93 | post_install = string_1, | ||
| 94 | }, | ||
| 95 | deploy = { | ||
| 96 | _version = "1.1", | ||
| 97 | wrap_bin_scripts = { _type = "boolean", _version = "1.1" }, | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | type_rockspec.order = {"rockspec_format", "package", "version", | ||
| 102 | { "source", { "url", "tag", "branch", "md5" } }, | ||
| 103 | { "description", {"summary", "detailed", "homepage", "license" } }, | ||
| 104 | "supported_platforms", "dependencies", "external_dependencies", | ||
| 105 | { "build", {"type", "modules", "copy_directories", "platforms"} }, | ||
| 106 | "hooks"} | ||
| 107 | |||
| 108 | rockspec_types.build.platforms._any = rockspec_types.build | ||
| 109 | rockspec_types.dependencies.platforms._any = rockspec_types.dependencies | ||
| 110 | rockspec_types.external_dependencies.platforms._any = rockspec_types.external_dependencies | ||
| 111 | rockspec_types.source.platforms._any = rockspec_types.source | ||
| 112 | rockspec_types.hooks.platforms._any = rockspec_types.hooks | ||
| 113 | |||
| 114 | --- Type check a rockspec table. | ||
| 115 | -- Verify the correctness of elements from a | ||
| 116 | -- rockspec table, reporting on unknown fields and type | ||
| 117 | -- mismatches. | ||
| 118 | -- @return boolean or (nil, string): true if type checking | ||
| 119 | -- succeeded, or nil and an error message if it failed. | ||
| 120 | function type_rockspec.check(rockspec, globals) | ||
| 121 | assert(type(rockspec) == "table") | ||
| 122 | if not rockspec.rockspec_format then | ||
| 123 | rockspec.rockspec_format = "1.0" | ||
| 124 | end | ||
| 125 | local ok, err = type_check.check_undeclared_globals(globals, rockspec_types) | ||
| 126 | if not ok then return nil, err end | ||
| 127 | return type_check.type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "") | ||
| 128 | end | ||
| 129 | |||
| 130 | return type_rockspec | ||
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua index 4b7e68d7..250c6258 100644 --- a/src/luarocks/type_check.lua +++ b/src/luarocks/type_check.lua | |||
| @@ -1,132 +1,155 @@ | |||
| 1 | --- Type-checking functions. | ||
| 2 | -- Functions and definitions for doing a basic lint check on files | ||
| 3 | -- loaded by LuaRocks. | ||
| 4 | local type_check = {} | ||
| 5 | setmetatable(type_check, { __index = require("luarocks.core.type_check") }) | ||
| 6 | 1 | ||
| 7 | type_check.rockspec_format = "3.0" | 2 | local type_check = {} |
| 8 | 3 | ||
| 9 | local string_1 = type_check.string_1 | 4 | local cfg = require("luarocks.core.cfg") |
| 10 | local mandatory_string_1 = type_check.mandatory_string_1 | 5 | local vers = require("luarocks.core.vers") |
| 6 | local require = nil | ||
| 7 | -------------------------------------------------------------------------------- | ||
| 11 | 8 | ||
| 12 | local string_3 = { _type = "string", _version = "3.0" } | 9 | type_check.string_1 = { _type = "string" } |
| 13 | local list_of_strings_3 = { _any = string_3, _version = "3.0" } | 10 | type_check.number_1 = { _type = "number" } |
| 11 | type_check.mandatory_string_1 = { _type = "string", _mandatory = true } | ||
| 14 | 12 | ||
| 15 | -- Syntax for type-checking tables: | 13 | local function check_version(version, typetbl, context) |
| 16 | -- | 14 | local typetbl_version = typetbl._version or "1.0" |
| 17 | -- A type-checking table describes typing data for a value. | 15 | if vers.compare_versions(typetbl_version, version) then |
| 18 | -- Any key starting with an underscore has a special meaning: | 16 | if context == "" then |
| 19 | -- _type (string) is the Lua type of the value. Default is "table". | 17 | return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly." |
| 20 | -- _version (string) is the minimum rockspec_version that supports this value. Default is "1.0". | 18 | else |
| 21 | -- _mandatory (boolean) indicates if the value is a mandatory key in its container table. Default is false. | 19 | return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly." |
| 22 | -- For "string" types only: | 20 | end |
| 23 | -- _pattern (string) is the string-matching pattern, valid for string types only. Default is ".*". | 21 | end |
| 24 | -- For "table" types only: | 22 | return true |
| 25 | -- _any (table) is the type-checking table for unspecified keys, recursively checked. | 23 | end |
| 26 | -- _more (boolean) indicates that the table accepts unspecified keys and does not type-check them. | ||
| 27 | -- Any other string keys that don't start with an underscore represent known keys and are type-checking tables, recursively checked. | ||
| 28 | 24 | ||
| 29 | local rockspec_types = { | 25 | --- Type check an object. |
| 30 | rockspec_format = string_1, | 26 | -- The object is compared against an archetypical value |
| 31 | package = mandatory_string_1, | 27 | -- matching the expected type -- the actual values don't matter, |
| 32 | version = { _type = "string", _pattern = "[%w.]+-[%d]+", _mandatory = true }, | 28 | -- only their types. Tables are type checked recursively. |
| 33 | description = { | 29 | -- @param version string: The version of the item. |
| 34 | summary = string_1, | 30 | -- @param item any: The object being checked. |
| 35 | detailed = string_1, | 31 | -- @param typetbl any: The type-checking table for the object. |
| 36 | homepage = string_1, | 32 | -- @param context string: A string indicating the "context" where the |
| 37 | license = string_1, | 33 | -- error occurred (the full table path), for error messages. |
| 38 | maintainer = string_1, | 34 | -- @return boolean or (nil, string): true if type checking |
| 39 | labels = list_of_strings_3, | 35 | -- succeeded, or nil and an error message if it failed. |
| 40 | issues_url = string_3, | 36 | -- @see type_check_table |
| 41 | }, | 37 | local function type_check_item(version, item, typetbl, context) |
| 42 | dependencies = { | 38 | assert(type(version) == "string") |
| 43 | platforms = {}, -- recursively defined below | ||
| 44 | _any = string_1, | ||
| 45 | }, | ||
| 46 | supported_platforms = { | ||
| 47 | _any = string_1, | ||
| 48 | }, | ||
| 49 | external_dependencies = { | ||
| 50 | platforms = {}, -- recursively defined below | ||
| 51 | _any = { | ||
| 52 | program = string_1, | ||
| 53 | header = string_1, | ||
| 54 | library = string_1, | ||
| 55 | } | ||
| 56 | }, | ||
| 57 | source = { | ||
| 58 | _mandatory = true, | ||
| 59 | platforms = {}, -- recursively defined below | ||
| 60 | url = mandatory_string_1, | ||
| 61 | md5 = string_1, | ||
| 62 | file = string_1, | ||
| 63 | dir = string_1, | ||
| 64 | tag = string_1, | ||
| 65 | branch = string_1, | ||
| 66 | module = string_1, | ||
| 67 | cvs_tag = string_1, | ||
| 68 | cvs_module = string_1, | ||
| 69 | }, | ||
| 70 | build = { | ||
| 71 | platforms = {}, -- recursively defined below | ||
| 72 | type = string_1, | ||
| 73 | install = { | ||
| 74 | lua = { | ||
| 75 | _more = true | ||
| 76 | }, | ||
| 77 | lib = { | ||
| 78 | _more = true | ||
| 79 | }, | ||
| 80 | conf = { | ||
| 81 | _more = true | ||
| 82 | }, | ||
| 83 | bin = { | ||
| 84 | _more = true | ||
| 85 | } | ||
| 86 | }, | ||
| 87 | copy_directories = { | ||
| 88 | _any = string_1, | ||
| 89 | }, | ||
| 90 | _more = true, | ||
| 91 | _mandatory = true | ||
| 92 | }, | ||
| 93 | hooks = { | ||
| 94 | platforms = {}, -- recursively defined below | ||
| 95 | post_install = string_1, | ||
| 96 | }, | ||
| 97 | deploy = { | ||
| 98 | _version = "1.1", | ||
| 99 | wrap_bin_scripts = { _type = "boolean", _version = "1.1" }, | ||
| 100 | } | ||
| 101 | } | ||
| 102 | 39 | ||
| 103 | type_check.rockspec_order = {"rockspec_format", "package", "version", | 40 | if typetbl._version and typetbl._version ~= "1.0" then |
| 104 | { "source", { "url", "tag", "branch", "md5" } }, | 41 | local ok, err = check_version(version, typetbl, context) |
| 105 | { "description", {"summary", "detailed", "homepage", "license" } }, | 42 | if not ok then |
| 106 | "supported_platforms", "dependencies", "external_dependencies", | 43 | return nil, err |
| 107 | { "build", {"type", "modules", "copy_directories", "platforms"} }, | 44 | end |
| 108 | "hooks"} | 45 | end |
| 46 | |||
| 47 | local item_type = type(item) or "nil" | ||
| 48 | local expected_type = typetbl._type or "table" | ||
| 49 | |||
| 50 | if expected_type == "number" then | ||
| 51 | if not tonumber(item) then | ||
| 52 | return nil, "Type mismatch on field "..context..": expected a number" | ||
| 53 | end | ||
| 54 | elseif expected_type == "string" then | ||
| 55 | if item_type ~= "string" then | ||
| 56 | return nil, "Type mismatch on field "..context..": expected a string, got "..item_type | ||
| 57 | end | ||
| 58 | if typetbl._pattern then | ||
| 59 | if not item:match("^"..typetbl._pattern.."$") then | ||
| 60 | return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'" | ||
| 61 | end | ||
| 62 | end | ||
| 63 | elseif expected_type == "table" then | ||
| 64 | if item_type ~= expected_type then | ||
| 65 | return nil, "Type mismatch on field "..context..": expected a table" | ||
| 66 | else | ||
| 67 | return type_check.type_check_table(version, item, typetbl, context) | ||
| 68 | end | ||
| 69 | elseif item_type ~= expected_type then | ||
| 70 | return nil, "Type mismatch on field "..context..": expected "..expected_type | ||
| 71 | end | ||
| 72 | return true | ||
| 73 | end | ||
| 109 | 74 | ||
| 110 | rockspec_types.build.platforms._any = rockspec_types.build | 75 | local function mkfield(context, field) |
| 111 | rockspec_types.dependencies.platforms._any = rockspec_types.dependencies | 76 | if context == "" then |
| 112 | rockspec_types.external_dependencies.platforms._any = rockspec_types.external_dependencies | 77 | return tostring(field) |
| 113 | rockspec_types.source.platforms._any = rockspec_types.source | 78 | elseif type(field) == "string" then |
| 114 | rockspec_types.hooks.platforms._any = rockspec_types.hooks | 79 | return context.."."..field |
| 80 | else | ||
| 81 | return context.."["..tostring(field).."]" | ||
| 82 | end | ||
| 83 | end | ||
| 115 | 84 | ||
| 116 | --- Type check a rockspec table. | 85 | --- Type check the contents of a table. |
| 117 | -- Verify the correctness of elements from a | 86 | -- The table's contents are compared against a reference table, |
| 118 | -- rockspec table, reporting on unknown fields and type | 87 | -- which contains the recognized fields, with archetypical values |
| 119 | -- mismatches. | 88 | -- matching the expected types -- the actual values of items in the |
| 89 | -- reference table don't matter, only their types (ie, for field x | ||
| 90 | -- in tbl that is correctly typed, type(tbl.x) == type(types.x)). | ||
| 91 | -- If the reference table contains a field called MORE, then | ||
| 92 | -- unknown fields in the checked table are accepted. | ||
| 93 | -- If it contains a field called ANY, then its type will be | ||
| 94 | -- used to check any unknown fields. If a field is prefixed | ||
| 95 | -- with MUST_, it is mandatory; its absence from the table is | ||
| 96 | -- a type error. | ||
| 97 | -- Tables are type checked recursively. | ||
| 98 | -- @param version string: The version of tbl. | ||
| 99 | -- @param tbl table: The table to be type checked. | ||
| 100 | -- @param typetbl table: The type-checking table, containing | ||
| 101 | -- values for recognized fields in the checked table. | ||
| 102 | -- @param context string: A string indicating the "context" where the | ||
| 103 | -- error occurred (such as the name of the table the item is a part of), | ||
| 104 | -- to be used by error messages. | ||
| 120 | -- @return boolean or (nil, string): true if type checking | 105 | -- @return boolean or (nil, string): true if type checking |
| 121 | -- succeeded, or nil and an error message if it failed. | 106 | -- succeeded, or nil and an error message if it failed. |
| 122 | function type_check.type_check_rockspec(rockspec, globals) | 107 | function type_check.type_check_table(version, tbl, typetbl, context) |
| 123 | assert(type(rockspec) == "table") | 108 | assert(type(version) == "string") |
| 124 | if not rockspec.rockspec_format then | 109 | assert(type(tbl) == "table") |
| 125 | rockspec.rockspec_format = "1.0" | 110 | assert(type(typetbl) == "table") |
| 111 | |||
| 112 | local ok, err = check_version(version, typetbl, context) | ||
| 113 | if not ok then | ||
| 114 | return nil, err | ||
| 115 | end | ||
| 116 | |||
| 117 | for k, v in pairs(tbl) do | ||
| 118 | local t = typetbl[k] or typetbl._any | ||
| 119 | if t then | ||
| 120 | local ok, err = type_check_item(version, v, t, mkfield(context, k)) | ||
| 121 | if not ok then return nil, err end | ||
| 122 | elseif typetbl._more then | ||
| 123 | -- Accept unknown field | ||
| 124 | else | ||
| 125 | if not cfg.accept_unknown_fields then | ||
| 126 | return nil, "Unknown field "..k | ||
| 127 | end | ||
| 128 | end | ||
| 129 | end | ||
| 130 | for k, v in pairs(typetbl) do | ||
| 131 | if k:sub(1,1) ~= "_" and v._mandatory then | ||
| 132 | if not tbl[k] then | ||
| 133 | return nil, "Mandatory field "..mkfield(context, k).." is missing." | ||
| 134 | end | ||
| 135 | end | ||
| 136 | end | ||
| 137 | return true | ||
| 138 | end | ||
| 139 | |||
| 140 | function type_check.check_undeclared_globals(globals, typetbl) | ||
| 141 | local undeclared = {} | ||
| 142 | for glob, _ in pairs(globals) do | ||
| 143 | if not (typetbl[glob] or typetbl["MUST_"..glob]) then | ||
| 144 | table.insert(undeclared, glob) | ||
| 145 | end | ||
| 146 | end | ||
| 147 | if #undeclared == 1 then | ||
| 148 | return nil, "Unknown variable: "..undeclared[1] | ||
| 149 | elseif #undeclared > 1 then | ||
| 150 | return nil, "Unknown variables: "..table.concat(undeclared, ", ") | ||
| 126 | end | 151 | end |
| 127 | local ok, err = type_check.check_undeclared_globals(globals, rockspec_types) | 152 | return true |
| 128 | if not ok then return nil, err end | ||
| 129 | return type_check.type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "") | ||
| 130 | end | 153 | end |
| 131 | 154 | ||
| 132 | return type_check | 155 | return type_check |
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index 59173449..0af23df6 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua | |||
| @@ -5,7 +5,15 @@ | |||
| 5 | -- as this is used in the bootstrapping stage of luarocks.core.cfg. | 5 | -- as this is used in the bootstrapping stage of luarocks.core.cfg. |
| 6 | 6 | ||
| 7 | local util = {} | 7 | local util = {} |
| 8 | setmetatable(util, { __index = require("luarocks.core.util") }) | 8 | |
| 9 | local core = require("luarocks.core.util") | ||
| 10 | |||
| 11 | util.popen_read = core.popen_read | ||
| 12 | util.cleanup_path = core.cleanup_path | ||
| 13 | util.split_string = core.split_string | ||
| 14 | util.keys = core.keys | ||
| 15 | util.printerr = core.printerr | ||
| 16 | util.sortedpairs = core.sortedpairs | ||
| 9 | 17 | ||
| 10 | local unpack = unpack or table.unpack | 18 | local unpack = unpack or table.unpack |
| 11 | 19 | ||
| @@ -223,7 +231,7 @@ function util.platform_overrides(tbl) | |||
| 223 | for _, platform in ipairs(cfg.platforms) do | 231 | for _, platform in ipairs(cfg.platforms) do |
| 224 | local platform_tbl = tbl.platforms[platform] | 232 | local platform_tbl = tbl.platforms[platform] |
| 225 | if platform_tbl then | 233 | if platform_tbl then |
| 226 | util.deep_merge(tbl, platform_tbl) | 234 | core.deep_merge(tbl, platform_tbl) |
| 227 | end | 235 | end |
| 228 | end | 236 | end |
| 229 | end | 237 | end |
| @@ -243,7 +251,7 @@ local var_format_pattern = "%$%((%a[%a%d_]+)%)" | |||
| 243 | -- needed variables. | 251 | -- needed variables. |
| 244 | -- @param msg string: the warning message to display. | 252 | -- @param msg string: the warning message to display. |
| 245 | function util.warn_if_not_used(var_defs, needed_set, msg) | 253 | function util.warn_if_not_used(var_defs, needed_set, msg) |
| 246 | needed_set = util.make_shallow_copy(needed_set) | 254 | needed_set = core.make_shallow_copy(needed_set) |
| 247 | for _, val in pairs(var_defs) do | 255 | for _, val in pairs(var_defs) do |
| 248 | for used in val:gmatch(var_format_pattern) do | 256 | for used in val:gmatch(var_format_pattern) do |
| 249 | needed_set[used] = nil | 257 | needed_set[used] = nil |
diff --git a/src/luarocks/vers.lua b/src/luarocks/vers.lua index d37690a8..c1dfbd39 100644 --- a/src/luarocks/vers.lua +++ b/src/luarocks/vers.lua | |||
| @@ -10,7 +10,12 @@ | |||
| 10 | -- "common sense" heuristics. The precise specification of the | 10 | -- "common sense" heuristics. The precise specification of the |
| 11 | -- comparison criteria is the source code of this module. | 11 | -- comparison criteria is the source code of this module. |
| 12 | local vers = {} | 12 | local vers = {} |
| 13 | setmetatable(vers, { __index = require("luarocks.core.vers") }) | 13 | |
| 14 | local core = require("luarocks.core.vers") | ||
| 15 | |||
| 16 | vers.parse_version = core.parse_version | ||
| 17 | vers.compare_versions = core.compare_versions | ||
| 18 | vers.match_constraints = core.match_constraints | ||
| 14 | 19 | ||
| 15 | --- Check if rockspec format version satisfies version requirement. | 20 | --- Check if rockspec format version satisfies version requirement. |
| 16 | -- @param rockspec table: The rockspec table. | 21 | -- @param rockspec table: The rockspec table. |
