comparison share/lua/5.2/luarocks/type_check.lua @ 1132:d137f631bad5

<GreyKnight> (cd luabuild/luarocks-2.0.12; make install)
author HackBot
date Fri, 14 Dec 2012 22:24:27 +0000
parents
children
comparison
equal deleted inserted replaced
1131:ff65dfb63263 1132:d137f631bad5
1
2 --- Type-checking functions.
3 -- Functions and definitions for doing a basic lint check on files
4 -- loaded by LuaRocks.
5 module("luarocks.type_check", package.seeall)
6
7 local cfg = require("luarocks.cfg")
8
9 rockspec_format = "1.0"
10
11 rockspec_types = {
12 rockspec_format = "string",
13 MUST_package = "string",
14 MUST_version = "[%w.]+-[%d]+",
15 description = {
16 summary = "string",
17 detailed = "string",
18 homepage = "string",
19 license = "string",
20 maintainer = "string"
21 },
22 dependencies = {
23 platforms = {},
24 ANY = "string"
25 },
26 supported_platforms = {
27 ANY = "string"
28 },
29 external_dependencies = {
30 platforms = {},
31 ANY = {
32 program = "string",
33 header = "string",
34 library = "string"
35 }
36 },
37 MUST_source = {
38 platforms = {},
39 MUST_url = "string",
40 md5 = "string",
41 file = "string",
42 dir = "string",
43 tag = "string",
44 branch = "string",
45 module = "string",
46 cvs_tag = "string",
47 cvs_module = "string"
48 },
49 build = {
50 platforms = {},
51 type = "string",
52 install = {
53 lua = {
54 MORE = true
55 },
56 lib = {
57 MORE = true
58 },
59 conf = {
60 MORE = true
61 },
62 bin = {
63 MORE = true
64 }
65 },
66 copy_directories = {
67 ANY = "string"
68 },
69 MORE = true
70 },
71 hooks = {
72 platforms = {},
73 post_install = "string"
74 }
75 }
76
77 function load_extensions()
78 rockspec_format = "1.1"
79 rockspec_types.deploy = {
80 wrap_bin_scripts = true,
81 }
82 end
83
84 if cfg.use_extensions then
85 load_extensions()
86 end
87
88 rockspec_types.build.platforms.ANY = rockspec_types.build
89 rockspec_types.dependencies.platforms.ANY = rockspec_types.dependencies
90 rockspec_types.external_dependencies.platforms.ANY = rockspec_types.external_dependencies
91 rockspec_types.MUST_source.platforms.ANY = rockspec_types.MUST_source
92 rockspec_types.hooks.platforms.ANY = rockspec_types.hooks
93
94 manifest_types = {
95 MUST_repository = {
96 -- packages
97 ANY = {
98 -- versions
99 ANY = {
100 -- items
101 ANY = {
102 MUST_arch = "string",
103 modules = { ANY = "string" },
104 commands = { ANY = "string" },
105 dependencies = { ANY = "string" },
106 -- TODO: to be extended with more metadata.
107 }
108 }
109 }
110 },
111 MUST_modules = {
112 -- modules
113 ANY = {
114 -- providers
115 ANY = "string"
116 }
117 },
118 MUST_commands = {
119 -- modules
120 ANY = {
121 -- commands
122 ANY = "string"
123 }
124 },
125 dependencies = {
126 -- each module
127 ANY = {
128 -- each version
129 ANY = {
130 -- each dependency
131 ANY = {
132 name = "string",
133 constraints = {
134 ANY = {
135 no_upgrade = "boolean",
136 op = "string",
137 version = {
138 string = "string",
139 ANY = 0,
140 }
141 }
142 }
143 }
144 }
145 }
146 }
147 }
148
149 local type_check_table
150
151 --- Type check an object.
152 -- The object is compared against an archetypical value
153 -- matching the expected type -- the actual values don't matter,
154 -- only their types. Tables are type checked recursively.
155 -- @param name any: The object name (for error messages).
156 -- @param item any: The object being checked.
157 -- @param expected any: The reference object. In case of a table,
158 -- its is structured as a type reference table.
159 -- @param context string: A string indicating the "context" where the
160 -- error occurred (such as the name of the table the item is a part of),
161 -- to be used by error messages.
162 -- @return boolean or (nil, string): true if type checking
163 -- succeeded, or nil and an error message if it failed.
164 -- @see type_check_table
165 local function type_check_item(name, item, expected, context)
166 name = tostring(name)
167
168 local item_type = type(item)
169 local expected_type = type(expected)
170 if expected_type == "number" then
171 if not tonumber(item) then
172 return nil, "Type mismatch on field "..context..name..": expected a number"
173 end
174 elseif expected_type == "string" then
175 if type(item) ~= "string" then
176 return nil, "Type mismatch on field "..context..name..": expected a string"
177 end
178 if expected ~= "string" then
179 if not item:match("^"..expected.."$") then
180 return nil, "Type mismatch on field "..context..name..": invalid value "..item
181 end
182 end
183 elseif expected_type == "table" then
184 if item_type ~= expected_type then
185 return nil, "Type mismatch on field "..context..name..": expected a table"
186 else
187 return type_check_table(item, expected, context..name..".")
188 end
189 elseif item_type ~= expected_type then
190 return nil, "Type mismatch on field "..context..name..": expected a "..expected_type
191 end
192 return true
193 end
194
195 --- Type check the contents of a table.
196 -- The table's contents are compared against a reference table,
197 -- which contains the recognized fields, with archetypical values
198 -- matching the expected types -- the actual values of items in the
199 -- reference table don't matter, only their types (ie, for field x
200 -- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
201 -- If the reference table contains a field called MORE, then
202 -- unknown fields in the checked table are accepted.
203 -- If it contains a field called ANY, then its type will be
204 -- used to check any unknown fields. If a field is prefixed
205 -- with MUST_, it is mandatory; its absence from the table is
206 -- a type error.
207 -- Tables are type checked recursively.
208 -- @param tbl table: The table to be type checked.
209 -- @param types table: The reference table, containing
210 -- values for recognized fields in the checked table.
211 -- @param context string: A string indicating the "context" where the
212 -- error occurred (such as the name of the table the item is a part of),
213 -- to be used by error messages.
214 -- @return boolean or (nil, string): true if type checking
215 -- succeeded, or nil and an error message if it failed.
216 type_check_table = function(tbl, types, context)
217 assert(type(tbl) == "table")
218 assert(type(types) == "table")
219 for k, v in pairs(tbl) do
220 local t = types[k] or (type(k) == "string" and types["MUST_"..k]) or types.ANY
221 if t then
222 local ok, err = type_check_item(k, v, t, context)
223 if not ok then return nil, err end
224 elseif types.MORE then
225 -- Accept unknown field
226 else
227 if not cfg.accept_unknown_fields then
228 return nil, "Unknown field "..k
229 end
230 end
231 end
232 for k, v in pairs(types) do
233 local mandatory_key = k:match("^MUST_(.+)")
234 if mandatory_key then
235 if not tbl[mandatory_key] then
236 return nil, "Mandatory field "..context..mandatory_key.." is missing."
237 end
238 end
239 end
240 return true
241 end
242
243 --- Type check a rockspec table.
244 -- Verify the correctness of elements from a
245 -- rockspec table, reporting on unknown fields and type
246 -- mismatches.
247 -- @return boolean or (nil, string): true if type checking
248 -- succeeded, or nil and an error message if it failed.
249 function type_check_rockspec(rockspec)
250 assert(type(rockspec) == "table")
251 if rockspec.rockspec_format then
252 -- relies on global state
253 load_extensions()
254 end
255 return type_check_table(rockspec, rockspec_types, "")
256 end
257
258 --- Type check a manifest table.
259 -- Verify the correctness of elements from a
260 -- manifest table, reporting on unknown fields and type
261 -- mismatches.
262 -- @return boolean or (nil, string): true if type checking
263 -- succeeded, or nil and an error message if it failed.
264 function type_check_manifest(manifest)
265 assert(type(manifest) == "table")
266 return type_check_table(manifest, manifest_types, "")
267 end