Mercurial > repo
view share/lua/5.2/luarocks/build.lua @ 3026:c8ea00fb641d
<shachaf> addquote <mnoqy> the theory\'s probably not bad, but calculus is one of those things that\'s so dang applicable that everyone only ever talks about how to apply it and compute with it and uuuuurgh(barf) <mnoqy> so i stay away from it
author | HackBot |
---|---|
date | Sun, 02 Jun 2013 04:42:47 +0000 |
parents | d137f631bad5 |
children |
line wrap: on
line source
--- 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