diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/lua/5.2/luarocks/type_check.lua	Fri Dec 14 22:24:27 2012 +0000
@@ -0,0 +1,267 @@
+
+--- Type-checking functions.
+-- Functions and definitions for doing a basic lint check on files
+-- loaded by LuaRocks.
+module("luarocks.type_check", package.seeall)
+
+local cfg = require("luarocks.cfg")
+
+rockspec_format = "1.0"
+
+rockspec_types = {
+   rockspec_format = "string",
+   MUST_package = "string",
+   MUST_version = "[%w.]+-[%d]+",
+   description = {
+      summary = "string",
+      detailed = "string",
+      homepage = "string",
+      license = "string",
+      maintainer = "string"
+   },
+   dependencies = {
+      platforms = {},
+      ANY = "string"
+   },
+   supported_platforms = {
+      ANY = "string"
+   },
+   external_dependencies = {
+      platforms = {},
+      ANY = {
+         program = "string",
+         header = "string",
+         library = "string"
+      }
+   },
+   MUST_source = {
+      platforms = {},
+      MUST_url = "string",
+      md5 = "string",
+      file = "string",
+      dir = "string",
+      tag = "string",
+      branch = "string",
+      module = "string",
+      cvs_tag = "string",
+      cvs_module = "string"
+   },
+   build = {
+      platforms = {},
+      type = "string",
+      install = {
+         lua = {
+            MORE = true
+         },
+         lib = {
+            MORE = true
+         },
+         conf = {
+            MORE = true
+         },
+         bin = {
+            MORE = true
+         }
+      },
+      copy_directories = {
+         ANY = "string"
+      },
+      MORE = true
+   },
+   hooks = {
+      platforms = {},
+      post_install = "string"
+   }
+}
+
+function load_extensions()
+   rockspec_format = "1.1"
+   rockspec_types.deploy = {
+      wrap_bin_scripts = true,
+   }
+end
+
+if cfg.use_extensions then
+   load_extensions()
+end
+
+rockspec_types.build.platforms.ANY = rockspec_types.build
+rockspec_types.dependencies.platforms.ANY = rockspec_types.dependencies
+rockspec_types.external_dependencies.platforms.ANY = rockspec_types.external_dependencies
+rockspec_types.MUST_source.platforms.ANY = rockspec_types.MUST_source
+rockspec_types.hooks.platforms.ANY = rockspec_types.hooks
+
+manifest_types = {
+   MUST_repository = {
+      -- packages
+      ANY = {
+         -- versions
+         ANY = {
+            -- items
+            ANY = {
+               MUST_arch = "string",
+               modules = { ANY = "string" },
+               commands = { ANY = "string" },
+               dependencies = { ANY = "string" },
+               -- TODO: to be extended with more metadata.
+            }
+         }
+      }
+   },
+   MUST_modules = {
+      -- modules
+      ANY = {
+         -- providers
+         ANY = "string"
+      }
+   },
+   MUST_commands = {
+      -- modules
+      ANY = {
+         -- commands
+         ANY = "string"
+      }
+   },
+   dependencies = {
+      -- each module
+      ANY = {
+         -- each version
+         ANY = {
+            -- each dependency
+            ANY = {
+               name = "string",
+               constraints = {
+                  ANY = {
+                     no_upgrade = "boolean",
+                     op = "string",
+                     version = {
+                        string = "string",
+                        ANY = 0,
+                     }
+                  }
+               }
+            }
+         }
+      }
+   }
+}
+
+local type_check_table
+
+--- Type check an object.
+-- The object is compared against an archetypical value
+-- matching the expected type -- the actual values don't matter,
+-- only their types. Tables are type checked recursively.
+-- @param name any: The object name (for error messages).
+-- @param item any: The object being checked.
+-- @param expected any: The reference object. In case of a table,
+-- its is structured as a type reference table.
+-- @param context string: A string indicating the "context" where the
+-- error occurred (such as the name of the table the item is a part of),
+-- to be used by error messages.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+-- @see type_check_table
+local function type_check_item(name, item, expected, context)
+   name = tostring(name)
+
+   local item_type = type(item)
+   local expected_type = type(expected)
+   if expected_type == "number" then
+      if not tonumber(item) then
+         return nil, "Type mismatch on field "..context..name..": expected a number"
+      end
+   elseif expected_type == "string" then
+      if type(item) ~= "string" then
+         return nil, "Type mismatch on field "..context..name..": expected a string"
+      end
+      if expected ~= "string" then
+         if not item:match("^"..expected.."$") then
+            return nil, "Type mismatch on field "..context..name..": invalid value "..item
+         end
+      end
+   elseif expected_type == "table" then
+      if item_type ~= expected_type then
+         return nil, "Type mismatch on field "..context..name..": expected a table"
+      else
+         return type_check_table(item, expected, context..name..".")
+      end
+   elseif item_type ~= expected_type then
+      return nil, "Type mismatch on field "..context..name..": expected a "..expected_type
+   end
+   return true
+end
+
+--- Type check the contents of a table.
+-- The table's contents are compared against a reference table,
+-- which contains the recognized fields, with archetypical values
+-- matching the expected types -- the actual values of items in the
+-- reference table don't matter, only their types (ie, for field x
+-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
+-- If the reference table contains a field called MORE, then
+-- unknown fields in the checked table are accepted.
+-- If it contains a field called ANY, then its type will be 
+-- used to check any unknown fields. If a field is prefixed
+-- with MUST_, it is mandatory; its absence from the table is
+-- a type error.
+-- Tables are type checked recursively.
+-- @param tbl table: The table to be type checked.
+-- @param types table: The reference table, containing
+-- values for recognized fields in the checked table.
+-- @param context string: A string indicating the "context" where the
+-- error occurred (such as the name of the table the item is a part of),
+-- to be used by error messages.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+type_check_table = function(tbl, types, context)
+   assert(type(tbl) == "table")
+   assert(type(types) == "table")
+   for k, v in pairs(tbl) do
+      local t = types[k] or (type(k) == "string" and types["MUST_"..k]) or types.ANY
+      if t then 
+         local ok, err = type_check_item(k, v, t, context)
+         if not ok then return nil, err end
+      elseif types.MORE then
+         -- Accept unknown field
+      else
+         if not cfg.accept_unknown_fields then
+            return nil, "Unknown field "..k
+         end
+      end
+   end
+   for k, v in pairs(types) do
+      local mandatory_key = k:match("^MUST_(.+)")
+      if mandatory_key then
+         if not tbl[mandatory_key] then
+            return nil, "Mandatory field "..context..mandatory_key.." is missing."
+         end
+      end
+   end
+   return true
+end
+
+--- Type check a rockspec table.
+-- Verify the correctness of elements from a 
+-- rockspec table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_check_rockspec(rockspec)
+   assert(type(rockspec) == "table")
+   if rockspec.rockspec_format then
+      -- relies on global state
+      load_extensions()
+   end
+   return type_check_table(rockspec, rockspec_types, "")
+end
+
+--- Type check a manifest table.
+-- Verify the correctness of elements from a 
+-- manifest table, reporting on unknown fields and type
+-- mismatches.
+-- @return boolean or (nil, string): true if type checking
+-- succeeded, or nil and an error message if it failed.
+function type_check_manifest(manifest)
+   assert(type(manifest) == "table")
+   return type_check_table(manifest, manifest_types, "")
+end