]> git.e2factory.org Git - e2factory.git/commitdiff
projenv: new module managing project environment
authorTobias Ulmer <tu@emlix.com>
Tue, 21 Jun 2016 18:41:36 +0000 (20:41 +0200)
committerTobias Ulmer <tu@emlix.com>
Wed, 16 Nov 2016 14:41:18 +0000 (15:41 +0100)
Signed-off-by: Tobias Ulmer <tu@emlix.com>
local/Makefile
local/chroot.lua
local/e2tool.lua
local/licence.lua
local/project.lua
local/projenv.lua [new file with mode: 0644]
local/result.lua
local/source.lua

index 22bf28e166d790c0ae4f55f1df3f8c55db7a3e7b..c445e1b5dcec84f157a93bf57acc213aa908cca4 100644 (file)
@@ -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
index 3927023a2697e7723c14c8cb48ef3f5c0c4fa2f5..6b1df60347d3a3e8562388b9f18b428f12da1ab8 100644 (file)
@@ -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(),
     }
 
index 1dd46a2d0f82a6a9a7cef376b442fac5d32bd067..ed1ae95936e13159436016d924491b79b025abe4 100644 (file)
@@ -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
index 03b42e496cafb2ccd88d3ea6f3b43dbc09143202..f9294ab9ba1100483bbd857930f3d01c27fe0d66 100644 (file)
 -- 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(),
     }
 
index 29f39a135a47004d44203d07894dcdc8f6e0700a..c3031a26a7227629b77e50390254e1113276af00 100644 (file)
 -- 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 (file)
index 0000000..9dec7c9
--- /dev/null
@@ -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)
+
index 91db44e3c966fe74d2f7b68635a525c1012d6f87..a29700a1238b576a0ed283414e34cbbaa33116ab 100644 (file)
@@ -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(),
     }
 
index 0bd376f28ce623bf63c4dbd3646732f33b7978fd..fd4a135ef1067334f1b5b4bf7116638021b2092e 100644 (file)
@@ -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(),
         }