From: Tobias Ulmer Date: Mon, 24 Jul 2017 13:33:25 +0000 (+0200) Subject: e2project: introduce a class for the local project X-Git-Tag: e2factory-2.3.18rc1~108 X-Git-Url: https://git.e2factory.org/?a=commitdiff_plain;h=c65e98c58d40383cd133934586f2de82e46d4c4e;p=e2factory.git e2project: introduce a class for the local project Signed-off-by: Tobias Ulmer --- diff --git a/local/e2-build-numbers.lua b/local/e2-build-numbers.lua index 98419d4..4d1da11 100644 --- a/local/e2-build-numbers.lua +++ b/local/e2-build-numbers.lua @@ -29,10 +29,7 @@ local function e2_build_numbers(arg) error(re) end - rc, re = e2tool.local_init(nil, "build-numbers") - if not rc then - error(re) - end + e2tool.e2project():init_project("build-numbers") error(err.new("e2-build-numbers is deprecated and has been removed")) end diff --git a/local/e2-build.lua b/local/e2-build.lua index 3737324..3cf24f2 100644 --- a/local/e2-build.lua +++ b/local/e2-build.lua @@ -30,15 +30,14 @@ local project = require("project") local result = require("result") local function e2_build(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "build") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("build") -- list of results with a specific build mode local wc_mode_results = {} @@ -101,8 +100,8 @@ local function e2_build(arg) error(re) end - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end diff --git a/local/e2-cf.lua b/local/e2-cf.lua index 6c38aea..cdc88fe 100644 --- a/local/e2-cf.lua +++ b/local/e2-cf.lua @@ -110,6 +110,7 @@ local function newsource(info, ...) local t = ... local name = t[2] local scm = t[3] + local e2project = e2tool.e2project() if not name then e:append("missing parameter: name") @@ -127,7 +128,7 @@ local function newsource(info, ...) end local cftemplate = - e2lib.join(info.local_template_path, string.format("source.%s", scm)) + e2lib.join(e2project:local_template_path(), string.format("source.%s", scm)) if not e2lib.isfile(cftemplate) then return false, e:append("no template for '%s' available", scm) end @@ -194,6 +195,7 @@ local function newresult(info, ...) local e = err.new("making new result failed") local t = ... local name = t[2] + local e2project = e2tool.e2project() if not name then return false, e:append("missing parameter: name") end @@ -208,8 +210,8 @@ local function newresult(info, ...) local cf = e2tool.resultconfig(pathname, e2tool.root()) local bs = e2tool.resultbuildscript(pathname, e2tool.root()) - local cftemplate = e2lib.join(info.local_template_path, "result") - local bstemplate = e2lib.join(info.local_template_path, "build-script") + local cftemplate = e2lib.join(e2project:local_template_path(), "result") + local bstemplate = e2lib.join(e2project:local_template_path(), "build-script") if not e2lib.isfile(cftemplate) then return false, e:append("config template %s not available", cftemplate) end @@ -307,25 +309,23 @@ local function editbuildscript(info, ...) end local function e2_cf(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "cf") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("cf") local opts, arguments = e2option.parse(arg) if not opts then error(arguments) end - -- initialize some basics in the info structure without actually loading - -- the project configuration. - info, re = e2tool.collect_project_info(info, true) - if not info then + -- initialize some basics without loading the project configuration. + rc, re = e2project:load_project(true) + if not rc then error(re) end @@ -365,7 +365,7 @@ local function e2_cf(arg) table.insert(a, o) end local f = commands[match[1]] - rc, re = f(info, a) + rc, re = f(e2project:info(), a) if not rc then error(re) end diff --git a/local/e2-dlist.lua b/local/e2-dlist.lua index 6fd1b71..7efba72 100644 --- a/local/e2-dlist.lua +++ b/local/e2-dlist.lua @@ -26,15 +26,14 @@ local err = require("err") local result = require("result") local function e2_dlist(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "dlist") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("dlist") e2option.flag("recursive", "show indirect dependencies, too") local opts, arguments = e2option.parse(arg) @@ -45,11 +44,13 @@ local function e2_dlist(arg) if #arguments == 0 then error(err.new( "no result given - enter `e2-dlist --help' for usage information")) - elseif #arguments ~= 1 then e2option.usage(1) end + elseif #arguments ~= 1 then + e2option.usage(1) + end local resultname = arguments[1] - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end diff --git a/local/e2-dsort.lua b/local/e2-dsort.lua index 82a28c5..b582e4b 100644 --- a/local/e2-dsort.lua +++ b/local/e2-dsort.lua @@ -24,23 +24,22 @@ local e2tool = require("e2tool") local e2option = require("e2option") local function e2_dsort(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "dsort") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("dsort") local opts, re = e2option.parse(arg) if not opts then error(re) end - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end diff --git a/local/e2-fetch-sources.lua b/local/e2-fetch-sources.lua index 9011b35..93db678 100644 --- a/local/e2-fetch-sources.lua +++ b/local/e2-fetch-sources.lua @@ -28,15 +28,14 @@ local result = require("result") local source = require("source") local function e2_fetch_source(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "fetch-sources") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("fetch-sources") local e = err.new() @@ -53,8 +52,8 @@ local function e2_fetch_source(arg) error(arguments) end - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end @@ -202,7 +201,7 @@ local function e2_fetch_source(arg) if next(sel) ~= nil then e2lib.log(2, "fetching sources...") - local rc, re = fetch_sources(info, opts, sel) + local rc, re = fetch_sources(e2project:info(), opts, sel) if not rc then e:cat(re) end diff --git a/local/e2-help.lua b/local/e2-help.lua index cc35f6f..74a7d91 100644 --- a/local/e2-help.lua +++ b/local/e2-help.lua @@ -221,23 +221,22 @@ end -- @return Error object on failure. local function e2_help(arg) local rc, re, e + local e2project rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "help") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("help") local opts, arguments = e2option.parse(arg) if not opts then error(arguments) end - info, re = e2tool.collect_project_info(info, true) - if not info then + rc, re = e2project:load_project(true) + if not rc then error(re) end diff --git a/local/e2-ls-project.lua b/local/e2-ls-project.lua index ef53037..f2df89d 100644 --- a/local/e2-ls-project.lua +++ b/local/e2-ls-project.lua @@ -89,15 +89,14 @@ end -- @return Always true. -- @raise error, assert local function e2_ls_project(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "ls-project") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("ls-project") policy.register_commandline_options() e2option.flag("dot", "generate dot(1) graph") @@ -119,8 +118,8 @@ local function e2_ls_project(arg) error(re) end - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end diff --git a/local/e2-new-source.lua b/local/e2-new-source.lua index 68a0a6c..70db615 100644 --- a/local/e2-new-source.lua +++ b/local/e2-new-source.lua @@ -222,15 +222,14 @@ local function new_files_source(c, server, location, source_file, checksum_file, end local function e2_new_source(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "new-source") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("new-source") e2option.flag("git", "create a git repository") e2option.flag("files", "create a new file on a files server") @@ -241,8 +240,8 @@ local function e2_new_source(arg) error(arguments) end - info, re = e2tool.collect_project_info(info) - if not info then + rc, re = e2project:load_project() + if not rc then error(re) end @@ -256,7 +255,8 @@ local function e2_new_source(arg) rserver = opts["server"] end local name = arguments[1] - local rlocation = string.format("%s/git/%s.git", info.project_location, name) + local rlocation = string.format("%s/git/%s.git", + e2project:project_location(), name) -- local local lserver = cache.server_names().dot local llocation = string.format("in/%s/.git", name) diff --git a/local/e2-playground.lua b/local/e2-playground.lua index dbf6fb7..67b2fd8 100644 --- a/local/e2-playground.lua +++ b/local/e2-playground.lua @@ -29,15 +29,14 @@ local policy = require("policy") local result = require("result") local function e2_playground(arg) + local e2project local rc, re = e2lib.init() if not rc then error(re) end - local info, re = e2tool.local_init(nil, "playground") - if not info then - error(re) - end + e2project = e2tool.e2project() + e2project:init_project("playground") local e = err.new("entering playground failed") local rc, re @@ -56,8 +55,9 @@ local function e2_playground(arg) if not build_mode then error(re) end - info, re = e2tool.collect_project_info(info) - if not info then + + rc, re = e2project:load_project() + if not rc then error(re) end diff --git a/local/e2build.lua b/local/e2build.lua index bfc3fe8..69bae44 100644 --- a/local/e2build.lua +++ b/local/e2build.lua @@ -271,7 +271,7 @@ function e2build.build_process_class:_result_available(res, return_flags) local buildid, sbid local e = err.new("error while checking if result is available: %s", res:get_name()) local columns = tonumber(e2lib.globals.osenv["COLUMNS"]) - local info = e2tool.info() + local e2project = e2tool.e2project() buildid, re = res:buildid() if not buildid then @@ -297,7 +297,8 @@ function e2build.build_process_class:_result_available(res, return_flags) end local server, location = - res:build_mode().storage(info.project_location, project.release_id()) + res:build_mode().storage( + e2project:project_location(), project.release_id()) local result_location = e2lib.join(location, res:get_name(), buildid, "result.tar") @@ -598,12 +599,12 @@ end --- function e2build.build_process_class:helper_unpack_result(res, dep, destdir) local rc, re, e - local info, buildid, server, location, resulttarpath, tmpdir - local path, resdir, dt, filesdir + local buildid, server, location, resulttarpath, tmpdir + local path, resdir, dt, filesdir, e2project e = err.new("unpacking result failed: %s", dep:get_name()) - info = e2tool.info() + e2project = e2tool.e2project() buildid, re = dep:buildid() if not buildid then @@ -611,7 +612,7 @@ function e2build.build_process_class:helper_unpack_result(res, dep, destdir) end server, location = - dep:build_mode().storage(info.project_location, project.release_id()) + dep:build_mode().storage(e2project:project_location(), project.release_id()) e2lib.logf(3, "searching for dependency %s in %s:%s", dep:get_name(), server, location) @@ -833,7 +834,7 @@ function e2build.build_process_class:helper_deploy(res, tmpdir) -- result/files/* -- -> releases:////files/* --]] - local info = e2tool.info() + local e2project = e2tool.e2project() if not res:build_mode().deploy then e2lib.log(4, "deployment disabled for this build mode") return true @@ -857,7 +858,7 @@ function e2build.build_process_class:helper_deploy(res, tmpdir) end table.insert(files, "checksums") local server, location = res:build_mode().deploy_storage( - info.project_location, project.release_id()) + e2project:project_location(), project.release_id()) -- do not re-deploy if this release was already done earlier local location1 = e2lib.join(location, res:get_name(), "checksums") @@ -905,9 +906,9 @@ function e2build.build_process_class:_store_result(res, return_flags) local rc, re local e = err.new("fetching build results from chroot") local dt - local info + local e2project - info = e2tool.info() + e2project = e2tool.e2project() -- create a temporary directory to build up the result local tmpdir, re = e2lib.mktempdir() @@ -1009,8 +1010,8 @@ function e2build.build_process_class:_store_result(res, return_flags) return false, e:cat(re) end - local server, location = res:build_mode().storage(info.project_location, - project.release_id()) + local server, location = res:build_mode().storage( + e2project:project_location(), project.release_id()) local buildid, re = res:buildid() if not buildid then @@ -1039,12 +1040,13 @@ end --- function e2build.build_process_class:_linklast(res, return_flags) local rc, re, e - local info, server, location, buildid, dst, lnk + local server, location, buildid, dst, lnk, e2project e = err.new("creating link to last results") - info = e2tool.info() + e2project = e2tool.e2project() -- calculate the path to the result - server, location = res:build_mode().storage(info.project_location, project.release_id()) + server, location = res:build_mode().storage( + e2project:project_location(), project.release_id()) -- compute the "last" link/directory buildid, re = res:buildid() diff --git a/local/e2tool.lua b/local/e2tool.lua index fda1dcb..f37ccf4 100644 --- a/local/e2tool.lua +++ b/local/e2tool.lua @@ -612,156 +612,6 @@ end --- @section end ---- Info table contains servers, caches and more... --- @table info --- @field startup_cwd Current working dir at startup (string). --- @field chroot_umask Umask setting for chroot (decimal number). --- @field host_umask Default umask of the process (decimal number). --- @field project_location string: project location relative to the servers --- @field local_template_path Path to the local templates (string). -local _info = false - ---- Open debug logfile. --- @return True on success, false on error. --- @return Error object on failure. -local function opendebuglogfile() - local rc, re, e, logfile, debuglogfile - - rc, re = e2lib.mkdir_recursive(e2lib.join(e2tool.root(), "log")) - if not rc then - e = err.new("error making log directory") - return false, e:cat(re) - end - logfile = e2lib.join(e2tool.root(), "log/debug.log") - rc, re = e2lib.rotate_log(logfile) - if not rc then - return false, re - end - - debuglogfile, re = eio.fopen(logfile, "w") - if not debuglogfile then - e = err.new("error opening debug logfile") - return false, e:cat(re) - end - - e2lib.globals.debuglogfile = debuglogfile - - return true -end - --- set the umask value to be used in chroot -local _chroot_umask = 18 -- 022 octal -local _host_umask - ---- set umask to value used for build processes -function e2tool.set_umask() - e2lib.umask(_chroot_umask) -end - ---- set umask back to the value used on the host -function e2tool.reset_umask() - e2lib.umask(_host_umask) -end - ---- initialize the umask set/reset mechanism (i.e. store the host umask) -local function init_umask() - -- save the umask value we run with - _host_umask = e2lib.umask(_chroot_umask) - - -- restore the previous umask value again - e2tool.reset_umask() -end - ---- Set a new info table. --- @param t Table to use for info. --- @return The new info table. -local function set_info(t) - assertIsTable(t) - _info = t - return _info -end - ---- Return the info table. --- @return Info table on success, --- false if the info table has not been initialised yet. -function e2tool.info() - return _info -end - -local _current_tool ---- Get current local tool name. --- @param tool Optional new tool name. --- @return Tool name --- @raise Assert if tool not set/invalid. -function e2tool.current_tool(tool) - if tool then - assertIsStringN(tool) - _current_tool = tool - end - - assertIsStringN(_current_tool) - return _current_tool -end - -local _project_root ---- Get (set) project root. --- @param project_root Optional. Set to specify project root. --- @return Project root directory. -function e2tool.root(project_root) - if project_root then - assertIsStringN(project_root) - _project_root = project_root - end - - assertIsStringN(_project_root) - return _project_root -end - ---- initialize the local library, load and initialize local plugins --- @param path string: path to project tree (optional) --- @param tool string: tool name (without the 'e2-' prefix) --- @return table: the info table, or false on failure --- @return an error object on failure -function e2tool.local_init(path, tool) - local rc, re - local e = err.new("initializing local tool") - local info - - info = set_info({}) - - e2tool.current_tool(tool) - - rc, re = e2lib.cwd() - if not rc then - return false, e:cat(re) - end - info.startup_cwd = rc - - init_umask(info) - - rc, re = e2lib.locate_project_root(path) - if not rc then - return false, e:append("not located in a project directory") - end - e2tool.root(rc) - - -- load local plugins - local ctx = { -- plugin context - info = info, - } - local plugindir = e2lib.join(e2tool.root(), ".e2/plugins") - rc, re = plugin.load_plugins(plugindir, ctx) - if not rc then - return false, e:cat(re) - end - rc, re = plugin.init_plugins() - if not rc then - return false, e:cat(re) - end - - return info -end - --- check for configuration syntax compatibility and log informational -- message including list of supported syntaxes if incompatibility is -- detected. @@ -835,129 +685,106 @@ local function check_global_interface_version() return true end ---- Verify that a result or source file pathname in the form --- "group1/group2/name" contains only valid characters. --- Note that the path to the project root does not share the same constraints, --- it's an error to pass it to this function. --- --- @param pathname Relative path to a source or result, including --- sub-directories (string). --- @return True when the path is legal, false otherwise. +--- Open debug logfile. +-- @return True on success, false on error. -- @return Error object on failure. -function e2tool.verify_src_res_pathname_valid_chars(pathname) - local msg = "only alphanumeric characters and '-_/' are allowed" - if not pathname:match("^[-_0-9a-zA-Z/]+$") then - return false, err.new(msg) - end +local function opendebuglogfile() + local rc, re, e, logfile, debuglogfile - return true -end + rc, re = e2lib.mkdir_recursive(e2lib.join(e2tool.root(), "log")) + if not rc then + e = err.new("error making log directory") + return false, e:cat(re) + end + logfile = e2lib.join(e2tool.root(), "log/debug.log") + rc, re = e2lib.rotate_log(logfile) + if not rc then + return false, re + end ---- Verify that a result or source name in the form "group1.group2.name" --- contains only valid characters. --- --- @param name Full source or result name, including groups (string). --- @return True when the name is legal, false otherwise. --- @return Error object on failure. -function e2tool.verify_src_res_name_valid_chars(name) - local msg = "only alphanumeric characters and '-_.' are allowed" - if not name:match("^[-_0-9a-zA-Z.]+$") then - return false, err.new(msg) + debuglogfile, re = eio.fopen(logfile, "w") + if not debuglogfile then + e = err.new("error opening debug logfile") + return false, e:cat(re) end + e2lib.globals.debuglogfile = debuglogfile + return true end ---- Convert source or result name, including groups, to a file system path. --- @param name Name of a src or res, with optional group notation (string). --- @return File system path equivalent of the input. -function e2tool.src_res_name_to_path(name) - return name:gsub("%.", "/") -end +--- @type e2project_class +e2tool.e2project_class = class("e2project_class") ---- Convert file system path of a source or result, including sub-directories --- to group notation separated by dots. --- @param pathname File system path of a src or res, with optional --- sub-directories (string). --- @return Group dot notation equivalent of the input. -function e2tool.src_res_path_to_name(pathname) - return pathname:gsub("/", ".") +function e2tool.e2project_class:initialize() + self._rootdir = false + self._server_project_location = false + self._info = false + + -- set the umask value to be used in chroot + self._chroot_umask = 18 -- 022 + self._host_umask = false + + self._results = false + self._sources = false end ---- Get project-relative directory for a result. --- Returns the relative path to the resultdir and optionally a name and prefix --- (e.g. prefix/res/name). --- @param name Optional result path component (string). --- @param prefix Optional prefix path. --- @return Path of the result. -function e2tool.resultdir(name, prefix) - local p = "res" - if name then - p = e2lib.join(p, name) +--- Initialize the local project, load and initialize local plugins. +-- @param tool string: tool name (without the 'e2-' prefix) +-- @raise Error on failure to initialize the project. +function e2tool.e2project_class:init_project(tool) + assertIsStringN(tool) + + local e = err.new("initializing local project") + local rc, re + local info + + info = self:info({}) + + e2tool.current_tool(tool) + + rc, re = e2lib.cwd() + if not rc then + error(e:cat(re)) end - if prefix then - p = e2lib.join(prefix, p) + info.startup_cwd = rc + + self:_init_umask() + + rc, re = e2lib.locate_project_root() + if not rc then + error(e:cat("not located in a project directory")) end - return p -end + e2tool.root(rc) + self:rootdir(rc) ---- Get project-relative directory for a source. --- Returns the relative path to the sourcedir and optinally a name and prefix --- (e.g. prefix/src/name). --- @param name Optional source path component (string). --- @param prefix Optional prefix path. --- @return Path of the source. -function e2tool.sourcedir(name, prefix) - local p = "src" - if name then - p = e2lib.join(p, name) + -- load local plugins + local ctx = { -- plugin context + info = info, + } + local plugindir = e2lib.join(self:rootdir(), ".e2/plugins") + rc, re = plugin.load_plugins(plugindir, ctx) + if not rc then + error(e:cat(re)) end - if prefix then - p = e2lib.join(prefix, p) + rc, re = plugin.init_plugins() + if not rc then + error(e:cat(re)) end - return p -end ---- Get project-relative path to the result config. --- @param name Result path component. --- @param prefix Optional prefix path. --- @return Path to the resultconfig. -function e2tool.resultconfig(name, prefix) - assert(type(name) == "string") - assert(prefix == nil or type(prefix) == "string") - return e2lib.join(e2tool.resultdir(name, prefix), "config") -end - ---- Get project-relative path to the result build-script --- @param name Result path compnent name. --- @param prefix Optional prefix path. --- @return Path to the result build-script. -function e2tool.resultbuildscript(name, prefix) - assert(type(name) == "string") - assert(prefix == nil or type(prefix) == "string") - return e2lib.join(e2tool.resultdir(name, prefix), "build-script") + strict.lock(info) end ---- Get project-relative path to the source config. --- @param name Source path component. --- @param prefix Optional prefix path. --- @return Path to the sourceconfig. -function e2tool.sourceconfig(name, prefix) - assert(type(name) == "string") - assert(prefix == nil or type(prefix) == "string") - return e2lib.join(e2tool.sourcedir(name, prefix), "config") +function e2tool.e2project_class:_init_umask() + self._host_umask = e2lib.umask(self._chroot_umask) + e2tool.reset_umask() end ---- collect project info. --- @param info Info table. --- @param skip_load_config If true, skip loading config files etc. --- @return True on success, false on error. --- @return Error object on failure. -function e2tool.collect_project_info(info, skip_load_config) +--- Load the project configuration. +function e2tool.e2project_class:load_project(skip_load_config) + local e = err.new("error loading project configuration") local rc, re - local e = err.new("reading project configuration") - -- check for configuration compatibility rc, re = check_config_syntax_compat() if not rc then e2lib.abort(re) @@ -968,7 +795,10 @@ function e2tool.collect_project_info(info, skip_load_config) e2lib.abort(re) end - info.local_template_path = e2lib.join(e2tool.root(), ".e2/lib/e2/templates") + rc, re = opendebuglogfile() + if not rc then + return false, e:cat(re) + end rc, re = e2lib.init2() -- configuration must be available if not rc then @@ -976,29 +806,25 @@ function e2tool.collect_project_info(info, skip_load_config) end if skip_load_config == true then - return info + return true end - rc, re = opendebuglogfile() - if not rc then - return false, e:cat(re) - end e2lib.logf(4, "VERSION: %s", buildconfig.VERSION) e2lib.logf(4, "VERSIONSTRING: %s", buildconfig.VERSIONSTRING) -- read .e2/proj-location - local plf = e2lib.join(e2tool.root(), e2lib.globals.project_location_file) + local plf = e2lib.join(self:rootdir(), e2lib.globals.project_location_file) local line, re = eio.file_read_line(plf) if not line then return false, e:cat(re) end local _, _, l = string.find(line, "^%s*(%S+)%s*$") if not l then - return false, e:append("%s: can't parse project location", plf) + return false, e:cat("%s: can't parse project location", plf) end - info.project_location = l - e2lib.logf(4, "project location is %s", info.project_location) + self:project_location(l) + e2lib.logf(4, "project location is %s", self:project_location()) -- setup cache local config, re = e2lib.get_global_config() @@ -1013,7 +839,8 @@ function e2tool.collect_project_info(info, skip_load_config) cache.cache(rc) - rc, re = cache.setup_cache_local(cache.cache(), e2tool.root(), info.project_location) + rc, re = cache.setup_cache_local( + cache.cache(), self:rootdir(), self:project_location()) if not rc then return false, e:cat(re) end @@ -1023,14 +850,14 @@ function e2tool.collect_project_info(info, skip_load_config) return false, e:cat(re) end - local f = e2lib.join(e2tool.root(), e2lib.globals.e2version_file) + local f = e2lib.join(self:rootdir(), e2lib.globals.e2version_file) local v, re = e2lib.parse_e2versionfile(f) if not v then - return false, re + return false, e:cat(re) end if v.tag ~= buildconfig.VERSIONSTRING then - return false, err.new("local tool version does not match the " .. + return false, e:cat("local tool version does not match the " .. "version configured\n in `%s`\nlocal tool version is %s\n" .. "required version is %s", f, buildconfig.VERSIONSTRING, v.tag) end @@ -1083,10 +910,6 @@ function e2tool.collect_project_info(info, skip_load_config) return false, e:cat(re) end - if e:getcount() > 1 then - return false, e - end - -- warn if deprecated config files still exist local deprecated_files = { "proj/servers", @@ -1099,7 +922,8 @@ function e2tool.collect_project_info(info, skip_load_config) for _,f in ipairs(deprecated_files) do local path = e2lib.join(e2tool.root(), f) if e2lib.exists(path) then - e2lib.warnf("WDEPRECATED", "File exists but is no longer used: `%s'", f) + e2lib.warnf("WDEPRECATED", + "File exists but is no longer used: `%s'", f) end end @@ -1109,40 +933,296 @@ function e2tool.collect_project_info(info, skip_load_config) end if e2option.opts["check"] then - local dirty, mismatch - - rc, re, mismatch = generic_git.verify_head_match_tag(e2tool.root(), - project.release_id()) + rc, re = self:check_local() if not rc then - if mismatch then - e:append("project repository tag does not match " .. - "the ReleaseId given in proj/config") - else - return false, e:cat(re) - end + return false, e:cat(re) end + end - rc, re, dirty = generic_git.verify_clean_repository(e2tool.root()) + if e2option.opts["check-remote"] then + rc, re = self:check_remote() if not rc then - if dirty then - e = err.new("project repository is not clean") - return false, e:cat(re) - else - return false, e:cat(re) - end + return false, e:cat(re) end end - if e2option.opts["check-remote"] then - rc, re = generic_git.verify_remote_tag( - e2lib.join(e2tool.root(), ".git"), project.release_id()) - if not rc then - e:append("verifying remote tag failed") + return true +end + +--- Get or set the root directory of the e2 project. +-- @param r rootdir to set, or nil +-- @return rootdir string. +-- @raise Assert on bad input +function e2tool.e2project_class:rootdir(r) + if r then + assertIsStringN(r) + self._rootdir = r + else + assertIsStringN(self._rootdir) + end + return self._rootdir +end + +--- Get the local template directory. +-- @return local template directory. +function e2tool.e2project_class:local_template_path() + return e2lib.join(self:rootdir(), ".e2/lib/e2/templates") +end + +--- Get or set *server* project location +-- @param l project location to set, or nil. +-- @return project location. +-- @raise Assert on bad input or unset project location. +function e2tool.e2project_class:project_location(l) + if l then + assertIsStringN(l) + self._server_project_location = l + else + assertIsStringN(self._server_project_location) + end + return self._server_project_location +end + +function e2tool.e2project_class:info(i) + if i then + assertIsTable(i) + self._info = i + else + assertIsTable(self._info) + end + return self._info +end + +function e2tool.e2project_class:check_local() + local e, rc, re + local dirty, mismatch + + e = err.new("checking project (local)") + + rc, re, mismatch = generic_git.verify_head_match_tag( + self:rootdir(), project.release_id()) + if not rc then + if mismatch then + e:append("project repository tag does not match " .. + "the ReleaseId given in proj/config") + else return false, e:cat(re) end end - return strict.lock(info) + rc, re, dirty = generic_git.verify_clean_repository(self:rootdir()) + if not rc then + if dirty then + e:append("project repository is not clean") + else + return false, e:cat(re) + end + end + + if e:getcount() > 1 then + return false, e + end + return true +end + +function e2tool.e2project_class:check_remote() + local e, rc, re + e = err.new("checking project (remote)") + + rc, re = generic_git.verify_remote_tag( + e2lib.join(self:rootdir(), ".git"), project.release_id()) + if not rc then + e:append("verifying remote tag failed") + return false, e:cat(re) + end + + return true +end + +--- @section end + +--- Info table contains servers, caches and more... +-- @table info +-- @field startup_cwd Current working dir at startup (string). +-- @field chroot_umask Umask setting for chroot (decimal number). +-- @field host_umask Default umask of the process (decimal number). + + +--- set umask to value used for build processes +function e2tool.set_umask() + e2lib.umask(e2tool.e2project()._chroot_umask) -- XXX: remove hack +end + +--- set umask back to the value used on the host +function e2tool.reset_umask() + e2lib.umask(e2tool.e2project()._host_umask) -- XXX: remove hack +end + +--- Set a new info table. +-- @param t Table to use for info. +-- @return The new info table. +--[[local function set_info(t) + assertIsTable(t) + _info = t + return _info +end]] + +--- Return the info table. +-- @return Info table on success, +-- false if the info table has not been initialised yet. +function e2tool.info() + return e2tool.e2project():info() +end + +local _current_tool +--- Get current local tool name. +-- @param tool Optional new tool name. +-- @return Tool name +-- @raise Assert if tool not set/invalid. +function e2tool.current_tool(tool) + if tool then + assertIsStringN(tool) + _current_tool = tool + end + + assertIsStringN(_current_tool) + return _current_tool +end + +local _project_root +--- Get (set) project root. +-- @param project_root Optional. Set to specify project root. +-- @return Project root directory. +function e2tool.root(project_root) + if project_root then + assertIsStringN(project_root) + _project_root = project_root + end + + assertIsStringN(_project_root) + return _project_root +end + +local _the_e2project +--- Get the e2project singleton. +function e2tool.e2project() + if not _the_e2project then + _the_e2project = e2tool.e2project_class:new() + end + return _the_e2project +end + +--- Verify that a result or source file pathname in the form +-- "group1/group2/name" contains only valid characters. +-- Note that the path to the project root does not share the same constraints, +-- it's an error to pass it to this function. +-- +-- @param pathname Relative path to a source or result, including +-- sub-directories (string). +-- @return True when the path is legal, false otherwise. +-- @return Error object on failure. +function e2tool.verify_src_res_pathname_valid_chars(pathname) + local msg = "only alphanumeric characters and '-_/' are allowed" + if not pathname:match("^[-_0-9a-zA-Z/]+$") then + return false, err.new(msg) + end + + return true +end + +--- Verify that a result or source name in the form "group1.group2.name" +-- contains only valid characters. +-- +-- @param name Full source or result name, including groups (string). +-- @return True when the name is legal, false otherwise. +-- @return Error object on failure. +function e2tool.verify_src_res_name_valid_chars(name) + local msg = "only alphanumeric characters and '-_.' are allowed" + if not name:match("^[-_0-9a-zA-Z.]+$") then + return false, err.new(msg) + end + + return true +end + +--- Convert source or result name, including groups, to a file system path. +-- @param name Name of a src or res, with optional group notation (string). +-- @return File system path equivalent of the input. +function e2tool.src_res_name_to_path(name) + return name:gsub("%.", "/") +end + +--- Convert file system path of a source or result, including sub-directories +-- to group notation separated by dots. +-- @param pathname File system path of a src or res, with optional +-- sub-directories (string). +-- @return Group dot notation equivalent of the input. +function e2tool.src_res_path_to_name(pathname) + return pathname:gsub("/", ".") +end + +--- Get project-relative directory for a result. +-- Returns the relative path to the resultdir and optionally a name and prefix +-- (e.g. prefix/res/name). +-- @param name Optional result path component (string). +-- @param prefix Optional prefix path. +-- @return Path of the result. +function e2tool.resultdir(name, prefix) + local p = "res" + if name then + p = e2lib.join(p, name) + end + if prefix then + p = e2lib.join(prefix, p) + end + return p +end + +--- Get project-relative directory for a source. +-- Returns the relative path to the sourcedir and optinally a name and prefix +-- (e.g. prefix/src/name). +-- @param name Optional source path component (string). +-- @param prefix Optional prefix path. +-- @return Path of the source. +function e2tool.sourcedir(name, prefix) + local p = "src" + if name then + p = e2lib.join(p, name) + end + if prefix then + p = e2lib.join(prefix, p) + end + return p +end + +--- Get project-relative path to the result config. +-- @param name Result path component. +-- @param prefix Optional prefix path. +-- @return Path to the resultconfig. +function e2tool.resultconfig(name, prefix) + assert(type(name) == "string") + assert(prefix == nil or type(prefix) == "string") + return e2lib.join(e2tool.resultdir(name, prefix), "config") +end + +--- Get project-relative path to the result build-script +-- @param name Result path compnent name. +-- @param prefix Optional prefix path. +-- @return Path to the result build-script. +function e2tool.resultbuildscript(name, prefix) + assert(type(name) == "string") + assert(prefix == nil or type(prefix) == "string") + return e2lib.join(e2tool.resultdir(name, prefix), "build-script") +end + +--- Get project-relative path to the source config. +-- @param name Source path component. +-- @param prefix Optional prefix path. +-- @return Path to the sourceconfig. +function e2tool.sourceconfig(name, prefix) + assert(type(name) == "string") + assert(prefix == nil or type(prefix) == "string") + return e2lib.join(e2tool.sourcedir(name, prefix), "config") end --- Returns a sorted vector with all depdencies of result, and all