Mercurial > repo
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 |