From: Tobias Ulmer Date: Tue, 21 Jun 2016 18:41:36 +0000 (+0200) Subject: projenv: new module managing project environment X-Git-Tag: e2factory-2.3.15rc1~145 X-Git-Url: https://git.e2factory.org/?a=commitdiff_plain;h=48f6b69d0172930d3a1ce77f06b52784f640da1e;p=e2factory.git projenv: new module managing project environment Signed-off-by: Tobias Ulmer --- diff --git a/local/Makefile b/local/Makefile index 22bf28e..c445e1b 100644 --- a/local/Makefile +++ b/local/Makefile @@ -42,7 +42,7 @@ LOCALLUATOOLS = e2-build e2-dlist e2-dsort e2-fetch-sources \ LOCALLUALIBS= digest.lua e2build.lua e2tool.lua environment.lua \ policy.lua scm.lua licence.lua chroot.lua project.lua \ - source.lua sl.lua result.lua + source.lua sl.lua result.lua projenv.lua LOCALTOOLS = $(LOCALLUATOOLS) .PHONY: all install uninstall local install-local doc install-doc diff --git a/local/chroot.lua b/local/chroot.lua index 3927023..6b1df60 100644 --- a/local/chroot.lua +++ b/local/chroot.lua @@ -26,6 +26,7 @@ local e2lib = require("e2lib") local e2tool = require("e2tool") local err = require("err") local hash = require("hash") +local projenv = require("projenv") local strict = require("strict") --- On disk chroot configuration. @@ -177,7 +178,7 @@ function chroot.load_chroot_config(info) t = nil local g = { e2chroot = function (data) t = data end, - env = info.env, + env = projenv.safe_global_res_env_table(), string = e2lib.safe_string_table(), } diff --git a/local/e2tool.lua b/local/e2tool.lua index 1dd46a2..ed1ae95 100644 --- a/local/e2tool.lua +++ b/local/e2tool.lua @@ -46,6 +46,7 @@ local licence = require("licence") local plugin = require("plugin") local policy = require("policy") local project = require("project") +local projenv = require("projenv") local result = require("result") local scm = require("scm") local source = require("source") @@ -70,15 +71,9 @@ local e2tool_ftab = {} -- @field default_files_server string: name of the default files server -- @field result_storage (deprecated) -- @field project_location string: project location relative to the servers --- @field env table: env table --- @field env_files table: list of env files -- @field local_template_path Path to the local templates (string). local _info = false ---- env - environment table from "proj/env" --- @name env --- @class table - --- Open debug logfile. -- @param info Info table. -- @return True on success, false on error. @@ -231,78 +226,6 @@ Configuration syntax versions supported by this version of the tools are:]] return false, e:append("configuration syntax mismatch") end ---- load env config. -local function load_env_config(info, file) - e2lib.logf(4, "loading environment: %s", file) - local e = err.new("loading environment: %s", file) - local rc, re - - local load_env_config = load_env_config - local merge_error = false - local function mergeenv(data) - -- upvalues: info, load_env_config(), merge_error - local rc, re - if type(data) == "string" then - -- include file - rc, re = load_env_config(info, data) - if not rc then - -- no error checking in place, so set upvalue and return - merge_error = re - return - end - else - -- environment table - for var, val in pairs(data) do - if type(var) ~= "string" or - (type(val) ~= "string" and type(val) ~= "table") then - merge_error = err.new("invalid environment entry in %s: %s=%s", - file, tostring(var), tostring(val)) - return nil - end - if type(val) == "string" then - e2lib.logf(4, "global env: %-15s = %-15s", var, val) - info.env[var] = val - info.global_env:set(var, val) - elseif type(val) == "table" then - for var1, val1 in pairs(val) do - if type(var1) ~= "string" or - (type(val1) ~= "string" and type(val1) ~= "table") then - merge_error = err.new( - "invalid environment entry in %s [%s]: %s=%s", - file, var, tostring(var1), tostring(val1)) - return nil - end - e2lib.logf(4, "result env: %-15s = %-15s [%s]", - var1, val1, var) - info.env[var] = info.env[var] or {} - info.env[var][var1] = val1 - info.result_env[var] = info.result_env[var] or environment.new() - info.result_env[var]:set(var1, val1) - end - end - end - end - return true - end - - table.insert(info.env_files, file) - local path = e2lib.join(info.root, file) - local g = { - e2env = info.env, - env = mergeenv, - string = e2lib.safe_string_table(), - } - rc, re = e2lib.dofile2(path, g) - if not rc then - return false, e:cat(re) - end - if merge_error then - return false, merge_error - end - e2lib.logf(4, "loading environment done: %s", file) - return true -end - --- Gather source paths. -- @param info Info table. -- @param basedir Nil or directory from where to start scanning for more @@ -625,11 +548,7 @@ function e2tool.collect_project_info(info, skip_load_config) end -- read environment configuration - info.env = {} -- global and result specfic env (deprecated) - info.env_files = {} -- a list of environment files - info.global_env = environment.new() - info.result_env = {} -- result specific env only - rc, re = load_env_config(info, "proj/env") + rc, re = projenv.load_env_config("proj/env") if not rc then return false, e:cat(re) end @@ -664,21 +583,12 @@ function e2tool.collect_project_info(info, skip_load_config) return false, e:cat(re) end - -- distribute result specific environment to the results, - -- provide environment for all results, even if it is empty - for r, res in pairs(info.results) do - if not info.result_env[r] then - info.result_env[r] = environment.new() - end - res._env = info.result_env[r] + -- project result envs must be checked after loading results + projenv.verify_result_envs() + if not rc then + return false, e:cat(re) end - -- check for environment for non-existent results - for r, t in pairs(info.result_env) do - if not info.results[r] then - e:append("configured environment for non existent result: %s", r) - end - end if e:getcount() > 1 then return false, e end diff --git a/local/licence.lua b/local/licence.lua index 03b42e4..f9294ab 100644 --- a/local/licence.lua +++ b/local/licence.lua @@ -19,11 +19,14 @@ -- more details. local licence = {} +package.loaded["licence"] = licence + local class = require("class") local e2lib = require("e2lib") local e2tool = require("e2tool") local err = require("err") local hash = require("hash") +local projenv = require("projenv") local strict = require("strict") --- Licence base class. @@ -163,7 +166,7 @@ function licence.load_licence_config(info) ltable = nil local g = { e2licence = function(data) ltable = data end, - env = info.env, + env = projenv.safe_global_res_env_table(), string = e2lib.safe_string_table(), } diff --git a/local/project.lua b/local/project.lua index 29f39a1..c3031a2 100644 --- a/local/project.lua +++ b/local/project.lua @@ -19,11 +19,13 @@ -- more details. local project = {} + local buildconfig = require("buildconfig") local e2lib = require("e2lib") local e2tool = require("e2tool") local err = require("err") local hash = require("hash") +local projenv = require("projenv") local strict = require("strict") local _prj = {} @@ -138,7 +140,7 @@ function project.load_project_config(info) prj = nil local g = { e2project = function(data) prj = data end, - env = info.env, + env = projenv.safe_global_res_env_table(), string = e2lib.safe_string_table(), } diff --git a/local/projenv.lua b/local/projenv.lua new file mode 100644 index 0000000..9dec7c9 --- /dev/null +++ b/local/projenv.lua @@ -0,0 +1,176 @@ +--- Project environment module. Deals with the project-wide global and result +-- specific configuration. It handles evaluating and verifying the file +-- 'proj/env' and its include directives. +-- @module local.projenv +local projenv = {} +package.loaded["projenv"] = projenv + +local e2lib = require("e2lib") +local e2tool = require("e2tool") +local environment = require("environment") +local err = require("err") +local result = require("result") +local strict = require("strict") + +local _global_env = false +local _result_env = {} + +--- Get the project wide global environment +-- @return Environment object +function projenv.get_global_env() + if not _global_env then + _global_env = environment.new() + end + return _global_env +end + +--- Get the project wide *result* environment. +-- Note that an unknown resultname will return a new environment. +-- @param resultname Result name +-- @return Environment object +function projenv.get_result_env(resultname) + assertIsStringN(resultname) + + if not _result_env[resultname] then + _result_env[resultname] = environment.new() + end + return _result_env[resultname] +end + +--- Get a *copy* of the project wide environment and project wide result +-- environment merged into one. Very similar to proj/env and friends. +-- Writes to this table do not propagate to other results etc. +-- @return Table filled just like proj/env +function projenv.safe_global_res_env_table() + local gt = projenv.get_global_env():get_dict() + + for resultname, resenv in pairs(_result_env) do + gt[resultname] = resenv:get_dict() + end + + return gt +end + +local function _load_env_config(file) + e2lib.logf(3, "loading environment: %s", file) + local e = err.new("loading environment: %s", file) + local rc, re + local merge_error = false + + local function mergeenv(data) + -- upvalues: file, _load_env_config(), merge_error + local rc, re + + if type(data) == "string" then + -- filename + rc, re = _load_env_config(data) + if not rc then + merge_error = re + return + end + elseif type(data) == "table" then + -- environment table + for key, value in pairs(data) do + + if type(key) ~= "string" or + (type(value) ~= "string" and type(value) ~= "table") then + merge_error = err.new("invalid environment entry in %s: %s=%s", + file, tostring(key), tostring(value)) + return + end + + if type(value) == "string" then + + e2lib.logf(3, "global env: %-15s = %-15s", key, value) + projenv.get_global_env():set(key, value) + + else + local resultname = key + + for key1, value1 in pairs(value) do + if type(key1) ~= "string" or type(value1) ~= "string" then + merge_error = err.new( + "invalid environment entry in %s [%s]: %s=%s", + file, key, tostring(key1), tostring(value1)) + return + end + + e2lib.logf(3, "result env: %-15s = %-15s [%s]", key1, value1, key) + + projenv.get_result_env(key):set(key1, value1) + end + end + end + else + merge_error = err.new("invalid environment type: %s", tostring(data)) + end + end + + local info = e2tool.info() + local path = e2lib.join(info.root, file) + + local mt = { + __index = function(t, key) + -- simulate a table that's updating itself as we read the config + -- called for env[key] and e2env[key] + return projenv.safe_global_res_env_table()[key] + end, + __call = function(t, data) + -- called for env "string" and env {} + -- use not documented for e2env + mergeenv(data) + end + } + + local g = { + e2env = setmetatable({}, mt), -- XXX: no longer necessary, alias for env + env = setmetatable({}, mt), + string = e2lib.safe_string_table(), + } + rc, re = e2lib.dofile2(path, g) + if not rc then + return false, e:cat(re) + end + + if merge_error then + return false, merge_error + end + return true +end + + +--- Load the environment config. Follows includes. +-- @param file File name of config +-- @return True on success, false on failure +-- @return Err object on failure. +-- @see projenv.verify_result_envs +function projenv.load_env_config(file) + return _load_env_config(file) +end + +--- Check load_env_config() didn't create any result environments for unknown +-- results. +-- @return True on success, false on failure +-- @return Err object on failure. +function projenv.verify_result_envs() + local e + + e = err.new("in project environment config:") + + -- check for environment for non-existent results + for resultname in pairs(_result_env) do + if not result.results[resultname] then + e:append("found environment for unknown result: %s", + resultname) + end + end + + if e:getcount() > 1 then + return false, e + end + + return true +end + +return strict.lock(projenv) + diff --git a/local/result.lua b/local/result.lua index 91db44e..a29700a 100644 --- a/local/result.lua +++ b/local/result.lua @@ -28,6 +28,7 @@ local environment = require("environment") local err = require("err") local hash = require("hash") local project = require("project") +local projenv = require("projenv") local sl = require("sl") local source = require("source") local strict = require("strict") @@ -571,7 +572,7 @@ local function load_rawres(cfg) loadcnt = 0 g = { e2result = function(data) rawres = data loadcnt = loadcnt + 1 end, - env = info.env, + env = projenv.safe_global_res_env_table(), string = e2lib.safe_string_table(), } diff --git a/local/source.lua b/local/source.lua index 0bd376f..fd4a135 100644 --- a/local/source.lua +++ b/local/source.lua @@ -28,6 +28,7 @@ local e2tool = require("e2tool") local environment = require("environment") local err = require("err") local licence = require("licence") +local projenv = require("projenv") local sl = require("sl") local strict = require("strict") @@ -193,7 +194,7 @@ function source.load_source_configs(info) loadcnt = 0 g = { e2source = function(data) rawsrc = data loadcnt = loadcnt + 1 end, - env = info.env, + env = projenv.safe_global_res_env_table(), string = e2lib.safe_string_table(), }