diff luabuild/luarocks-2.0.12/src/luarocks/build.lua @ 1125:87f6d05d4b4a

<GreyKnight> (cd luabuild; tar xf luarocks-2.0.12.tar.gz)
author HackBot
date Fri, 14 Dec 2012 22:07:40 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/luabuild/luarocks-2.0.12/src/luarocks/build.lua	Fri Dec 14 22:07:40 2012 +0000
@@ -0,0 +1,335 @@
+
+--- Module implementing the LuaRocks "build" command.
+-- Builds a rock, compiling its C parts if any.
+module("luarocks.build", package.seeall)
+
+local pack = require("luarocks.pack")
+local path = require("luarocks.path")
+local util = require("luarocks.util")
+local repos = require("luarocks.repos")
+local fetch = require("luarocks.fetch")
+local fs = require("luarocks.fs")
+local dir = require("luarocks.dir")
+local deps = require("luarocks.deps")
+local manif = require("luarocks.manif")
+local cfg = require("luarocks.cfg")
+
+help_summary = "Build/compile a rock."
+help_arguments = "[--pack-binary-rock] {<rockspec>|<rock>|<name> [<version>]}"
+help = [[
+Build and install a rock, compiling its C parts if any.
+Argument may be a rockspec file, a source rock file
+or the name of a rock to be fetched from a repository.
+
+If --pack-binary-rock is passed, the rock is not installed;
+instead, a .rock file with the contents of compilation is produced
+in the current directory.
+]]
+
+--- Install files to a given location.
+-- Takes a table where the array part is a list of filenames to be copied.
+-- In the hash part, other keys, if is_module_path is set, are identifiers
+-- in Lua module format, to indicate which subdirectory the file should be
+-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo")
+-- will copy src/bar.lua to boo/foo.
+-- @param files table or nil: A table containing a list of files to copy in
+-- the format described above. If nil is passed, this function is a no-op.
+-- Directories should be delimited by forward slashes as in internet URLs.
+-- @param location string: The base directory files should be copied to.
+-- @param is_module_path boolean: True if string keys in files should be
+-- interpreted as dotted module paths.
+-- @return boolean or (nil, string): True if succeeded or 
+-- nil and an error message.
+local function install_files(files, location, is_module_path)
+   assert(type(files) == "table" or not files)
+   assert(type(location) == "string")
+   if files then
+      for k, file in pairs(files) do
+         local dest = location
+         if type(k) == "string" then
+            if is_module_path then
+               dest = dir.path(location, path.module_to_path(k))
+               fs.make_dir(dest)
+            else
+               dest = dir.path(location, dir.dir_name(k))
+               fs.make_dir(dest)
+               dest = dir.path(dest, dir.base_name(k))
+            end
+         else
+            fs.make_dir(dest)
+         end
+         local ok = fs.copy(dir.path(file), dest)
+         if not ok then
+            return nil, "Failed copying "..file
+         end
+      end
+   end
+   return true
+end
+
+--- Write to the current directory the contents of a table,
+-- where each key is a file name and its value is the file content.
+-- @param files table: The table of files to be written.
+local function extract_from_rockspec(files)
+   for name, content in pairs(files) do
+      local fd = io.open(dir.path(fs.current_dir(), name), "w+")
+      fd:write(content)
+      fd:close()
+   end
+end
+
+--- Applies patches inlined in the build.patches section
+-- and extracts files inlined in the build.extra_files section
+-- of a rockspec. 
+-- @param rockspec table: A rockspec table.
+-- @return boolean or (nil, string): True if succeeded or 
+-- nil and an error message.
+function apply_patches(rockspec)
+   assert(type(rockspec) == "table")
+
+   local build = rockspec.build
+   if build.extra_files then
+      extract_from_rockspec(build.extra_files)
+   end
+   if build.patches then
+      extract_from_rockspec(build.patches)
+      for patch, patchdata in util.sortedpairs(build.patches) do
+         util.printout("Applying patch "..patch.."...")
+         local ok, err = fs.apply_patch(tostring(patch), patchdata)
+         if not ok then
+            return nil, "Failed applying patch "..patch
+         end
+      end
+   end
+   return true
+end
+
+--- Build and install a rock given a rockspec.
+-- @param rockspec_file string: local or remote filename of a rockspec.
+-- @param need_to_fetch boolean: true if sources need to be fetched,
+-- false if the rockspec was obtained from inside a source rock.
+-- @param minimal_mode boolean: true if there's no need to fetch,
+-- unpack or change dir (this is used by "luarocks make"). Implies
+-- need_to_fetch = false.
+-- @param deps_mode: string: Which trees to check dependencies for:
+-- "none", "one", "order" or "all".
+-- @return boolean or (nil, string, [string]): True if succeeded or 
+-- nil and an error message followed by an error code.
+function build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode)
+   assert(type(rockspec_file) == "string")
+   assert(type(need_to_fetch) == "boolean")
+
+   local rockspec, err, errcode = fetch.load_rockspec(rockspec_file)
+   if err then
+      return nil, err, errcode
+   elseif not rockspec.build then
+      return nil, "Rockspec error: build table not specified"
+   elseif not rockspec.build.type then
+      return nil, "Rockspec error: build type not specified"
+   end
+
+   if deps_mode == "none" then
+      util.printerr("Warning: skipping dependency checks.")
+   else
+      local ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode)
+      if err then
+         return nil, err, errcode
+      end
+   end
+
+   ok, err, errcode = deps.check_external_deps(rockspec, "build")
+   if err then
+      return nil, err, errcode
+   end
+
+   local name, version = rockspec.name, rockspec.version
+   if repos.is_installed(name, version) then
+      repos.delete_version(name, version)
+   end
+
+   if not minimal_mode then
+      local _, source_dir
+      if need_to_fetch then
+         ok, source_dir, errcode = fetch.fetch_sources(rockspec, true)
+         if not ok then
+            return nil, source_dir, errcode
+         end
+         fs.change_dir(source_dir)
+      elseif rockspec.source.file then
+         local ok, err = fs.unpack_archive(rockspec.source.file)
+         if not ok then
+            return nil, err
+         end
+      end
+      fs.change_dir(rockspec.source.dir)
+   end
+   
+   local dirs = {
+      lua = { name = path.lua_dir(name, version), is_module_path = true },
+      lib = { name = path.lib_dir(name, version), is_module_path = true },
+      conf = { name = path.conf_dir(name, version), is_module_path = false },
+      bin = { name = path.bin_dir(name, version), is_module_path = false },
+   }
+   
+   for _, d in pairs(dirs) do
+      fs.make_dir(d.name)
+   end
+   local rollback = util.schedule_function(function()
+      fs.delete(path.install_dir(name, version))
+      fs.remove_dir_if_empty(path.versions_dir(name))
+   end)
+
+   local build = rockspec.build
+   
+   if not minimal_mode then
+      ok, err = apply_patches(rockspec)
+      if err then
+         return nil, err
+      end
+   end
+   
+   if build.type ~= "none" then
+
+      -- Temporary compatibility
+      if build.type == "module" then
+         util.printout("Do not use 'module' as a build type. Use 'builtin' instead.")
+         build.type = "builtin"
+      end
+
+      local build_type
+      ok, build_type = pcall(require, "luarocks.build." .. build.type)
+      if not ok or not type(build_type) == "table" then
+         return nil, "Failed initializing build back-end for build type '"..build.type.."': "..build_type
+      end
+  
+      ok, err = build_type.run(rockspec)
+      if not ok then
+         return nil, "Build error: " .. err
+      end
+   end
+
+   if build.install then
+      for id, install_dir in pairs(dirs) do
+         ok, err = install_files(build.install[id], install_dir.name, install_dir.is_module_path)
+         if not ok then 
+            return nil, err
+         end
+      end
+   end
+   
+   local copy_directories = build.copy_directories or {"doc"}
+
+   for _, copy_dir in pairs(copy_directories) do
+      if fs.is_dir(copy_dir) then
+         local dest = dir.path(path.install_dir(name, version), copy_dir)
+         fs.make_dir(dest)
+         fs.copy_contents(copy_dir, dest)
+      else
+         util.warning("Directory '"..copy_dir.."' not found")
+      end
+   end
+
+   for _, d in pairs(dirs) do
+      fs.remove_dir_if_empty(d.name)
+   end
+
+   fs.pop_dir()
+   
+   fs.copy(rockspec.local_filename, path.rockspec_file(name, version))
+   if need_to_fetch then
+      fs.pop_dir()
+   end
+
+   ok, err = manif.make_rock_manifest(name, version)
+   if err then return nil, err end
+
+   ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec))
+   if err then return nil, err end
+   
+   util.remove_scheduled_function(rollback)
+   rollback = util.schedule_function(function()
+      repos.delete_version(name, version)
+   end)
+
+   ok, err = repos.run_hook(rockspec, "post_install")
+   if err then return nil, err end
+
+   ok, err = manif.update_manifest(name, version, nil, deps_mode)
+   if err then return nil, err end
+
+   local license = ""
+   if rockspec.description and rockspec.description.license then
+      license = ("(license: "..rockspec.description.license..")")
+   end
+
+   local root_dir = path.root_dir(cfg.rocks_dir)
+   util.printout()
+   util.printout(name.." "..version.." is now built and installed in "..root_dir.." "..license)
+   
+   util.remove_scheduled_function(rollback)
+   return true
+end
+
+--- Build and install a rock.
+-- @param rock_file string: local or remote filename of a rock.
+-- @param need_to_fetch boolean: true if sources need to be fetched,
+-- false if the rockspec was obtained from inside a source rock.
+-- @param deps_mode: string: Which trees to check dependencies for:
+-- "none", "one", "order" or "all".
+-- @return boolean or (nil, string, [string]): True if build was successful,
+-- or false and an error message and an optional error code.
+function build_rock(rock_file, need_to_fetch, deps_mode)
+   assert(type(rock_file) == "string")
+   assert(type(need_to_fetch) == "boolean")
+  
+   local unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file)
+   if not unpack_dir then
+      return nil, err, errcode
+   end
+   local rockspec_file = path.rockspec_name_from_rock(rock_file)
+   fs.change_dir(unpack_dir)
+   local ok, err, errcode = build_rockspec(rockspec_file, need_to_fetch, false, deps_mode)
+   fs.pop_dir()
+   return ok, err, errcode
+end
+ 
+local function do_build(name, version, deps_mode)
+   if name:match("%.rockspec$") then
+      return build_rockspec(name, true, false, deps_mode)
+   elseif name:match("%.src%.rock$") then
+      return build_rock(name, false, deps_mode)
+   elseif name:match("%.all%.rock$") then
+      local install = require("luarocks.install")
+      return install.install_binary_rock(name, deps_mode)
+   elseif name:match("%.rock$") then
+      return build_rock(name, true, deps_mode)
+   elseif not name:match(dir.separator) then
+      local search = require("luarocks.search")
+      return search.act_on_src_or_rockspec(run, name:lower(), version, deps.deps_mode_to_flag(deps_mode))
+   end
+   return nil, "Don't know what to do with "..name
+end
+
+--- Driver function for "build" command.
+-- @param name string: A local or remote rockspec or rock file.
+-- If a package name is given, forwards the request to "search" and,
+-- if returned a result, installs the matching rock.
+-- @param version string: When passing a package name, a version number may
+-- also be given.
+-- @return boolean or (nil, string): True if build was successful; nil and an
+-- error message otherwise.
+function run(...)
+   local flags, name, version = util.parse_flags(...)
+   if type(name) ~= "string" then
+      return nil, "Argument missing, see help."
+   end
+   assert(type(version) == "string" or not version)
+
+   if flags["pack-binary-rock"] then
+      return pack.pack_binary_rock(name, version, do_build, name, version, deps.get_deps_mode(flags))
+   else
+      local ok, err = fs.check_command_permissions(flags)
+      if not ok then return nil, err end
+      return do_build(name, version, deps.get_deps_mode(flags))
+   end
+end