]> git.e2factory.org Git - e2factory.git/commitdiff
Split chroot config into own module and class
authorTobias Ulmer <tu@emlix.com>
Tue, 11 Feb 2014 17:42:43 +0000 (18:42 +0100)
committerTobias Ulmer <tu@emlix.com>
Wed, 16 Nov 2016 14:41:17 +0000 (15:41 +0100)
Signed-off-by: Tobias Ulmer <tu@emlix.com>
local/Makefile
local/chroot.lua [new file with mode: 0644]
local/e2-fetch-sources.lua
local/e2-ls-project.lua
local/e2build.lua
local/e2tool.lua
plugins/collect_project.lua

index f637884e12923919977c443c296e94405591f93c..3cfa2d419e0190d5f370bc16e6603d89443b9a19 100644 (file)
@@ -41,7 +41,7 @@ LOCALLUATOOLS = e2-build e2-dlist e2-dsort e2-fetch-sources \
                e2-build-numbers e2-cf e2-help
 
 LOCALLUALIBS= digest.lua e2build.lua e2tool.lua environment.lua \
-             policy.lua scm.lua licence.lua
+             policy.lua scm.lua licence.lua chroot.lua
 LOCALTOOLS = $(LOCALLUATOOLS)
 
 .PHONY: all install uninstall local install-local doc install-doc
diff --git a/local/chroot.lua b/local/chroot.lua
new file mode 100644 (file)
index 0000000..b123ac1
--- /dev/null
@@ -0,0 +1,334 @@
+--- Chroot config module.
+-- @module local.chroot
+
+-- Copyright (C) 2007-2014 emlix GmbH, see file AUTHORS
+--
+-- This file is part of e2factory, the emlix embedded build system.
+-- For more information see http://www.e2factory.org
+--
+-- e2factory is a registered trademark of emlix GmbH.
+--
+-- e2factory is free software: you can redistribute it and/or modify it under
+-- the terms of the GNU General Public License as published by the
+-- Free Software Foundation, either version 3 of the License, or (at your
+-- option) any later version.
+--
+-- This program is distributed in the hope that it will be useful, but WITHOUT
+-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+-- more details.
+
+local chroot = {}
+local cache = require("cache")
+local class = require("class")
+local e2lib = require("e2lib")
+local e2tool = require("e2tool")
+local err = require("err")
+local hash = require("hash")
+local strict = require("strict")
+
+--- On disk chroot configuration.
+-- @table e2chroot
+-- @field default_groups Default group name vector.
+-- @field groups Vector of group tables.
+-- @see group
+
+--- On disk chroot group config.
+-- @table group
+-- @field name Group name
+-- @field server Server name
+-- @field files Vector of file tables.
+-- @see file
+
+--- On disk file config. Note: This dict is used all over factory.
+-- @table file
+-- @field location File location.
+-- @field server Server name.
+-- @field sha1 SHA1 sum. Optional if server:location is local.
+
+--- Default chroot group names applied to all results. Locked.
+chroot.groups_default = {}
+
+--- Chroot group objects indexed by their name.
+chroot.groups_byname = {}
+
+--- Vector of sorted chroot group names. Locked.
+chroot.groups_sorted = {}
+
+--- Chroot class.
+-- @see generic.class
+chroot.chroot = class("chroot")
+
+--- Chroot group object constructor.
+-- @param name Chroot group name.
+-- @return May throw error(err).
+function chroot.chroot:initialize(name)
+    local ok, re = e2lib.vrfy_string_len(name, "chroot group name")
+    if not ok then
+        error(re)
+    end
+    self._name = name
+    self._files = {}
+    self._chrootgroupid = false
+end
+
+--- Get the chroot group name.
+-- @return Chroot group name.
+function chroot.chroot:get_name()
+    return self._name
+end
+
+--- Add a file to a chroot group.
+-- @param location Path to chroot archive file.
+-- @param server Server name.
+-- @param sha1 SHA1 checksum string. If file is local sha1 may be nil
+-- @return May throw error(err) on invalid input.
+function chroot.chroot:add_file(location, server, sha1)
+    local t, ok, re
+
+    ok, re = e2lib.vrfy_string_len(location, "chroot location")
+    if not ok then
+        error(re)
+    end
+
+    ok, re = e2lib.vrfy_string_len(server, "chroot server")
+    if not ok then
+        error(re)
+    end
+
+    if sha1 then
+        ok, re = e2lib.vrfy_string_len(sha1, "chroot sha1")
+        if not ok then
+            error(re)
+        end
+    end
+
+    self._chrootgroupid = false
+    table.insert(self._files, { location=location, server=server, sha1=sha1 })
+end
+
+--- Iterator that returns file tables in the order they were added.
+-- @return Iterator function
+-- @see file
+function chroot.chroot:file_iter()
+    local i = 0
+
+    return function ()
+        i = i + 1
+
+        if self._files[i] then
+            -- return a copy
+            return {
+                location = self._files[i].location,
+                server = self._files[i].server,
+                sha1 = self._files[i].sha1,
+            }
+        end
+
+        return nil
+    end
+end
+
+--- Calculate chroot group id.
+-- @param info Info table.
+-- @return Chroot group ID or false on error.
+-- @return Error object on failure.
+function chroot.chroot:chrootgroupid(info)
+    local rc, re, e, hc
+
+    if self._chrootgroupid then
+        return self._chrootgroupid
+    end
+
+    e = err.new("calculating chroot group id failed for group %s",
+        self._name)
+
+    hc = hash.hash_start()
+    hash.hash_line(hc, self._name)
+
+    local fileid
+    for f in self:file_iter() do
+        hash.hash_line(hc, f.server)
+        hash.hash_line(hc, f.location)
+        fileid, re = e2tool.fileid(info, f)
+        if not fileid then
+            return false, e:cat(re)
+        end
+        hash.hash_line(hc, fileid)
+    end
+
+    self._chrootgroupid = hash.hash_finish(hc)
+    return self._chrootgroupid
+end
+
+--- Load and validate chroot configuration. Populates chroot.groups_byname,
+-- chroot.groups_sorted and chroot.groups_default.
+-- @param info Info table.
+-- @return True on success, false on error.
+-- @return Error object on failure
+function chroot.load_chroot_config(info)
+    local rc, re, e
+    local t, path, cgroup
+
+    path = e2lib.join(info.root, "proj/chroot")
+    e = err.new("loading chroot config %q failed", path)
+
+    t = nil
+    local function assign(table)
+        t = table
+    end
+
+    rc, re = e2lib.dofile2(path,
+        { e2chroot = assign, env = info.env, string = string })
+    if not rc then
+        return false, re
+    end
+
+    if type(t) ~= "table" then
+        return false, e:append("empty or invalid chroot configuration")
+    end
+
+    rc, re = e2lib.vrfy_dict_exp_keys(t, "chroot configuration",
+        { "groups", "default_groups" })
+    if not rc then
+        return false, e:cat(re)
+    end
+
+    if type(t.groups) ~= "table" then
+        return false, e:append("chroot groups configuration is not a table")
+    end
+
+    rc, re = e2lib.vrfy_vector(t.groups, "chroot groups")
+    if not rc then
+        return false, e:cat(re)
+    end
+
+    if type(t.default_groups) ~= "table" then
+        return false, e:append("chroot.default_groups is not a table")
+    end
+
+    rc, re = e2lib.vrfy_listofstrings(t.default_groups,
+        "chroot default_groups", true, false)
+    if not rc then
+        return false, e:cat(re)
+    end
+
+    for _,grp in ipairs(t.groups) do
+        if grp.group then
+            e:append("in group: %s", grp.group)
+            e:append(" `group' attribute is deprecated. Replace by `name'")
+            return false, e
+        end
+
+        if not grp.name then
+            return false, e:append("`name' attribute is missing in a group")
+        end
+
+        if chroot.groups_byname[grp.name] then
+            return false, e:append("duplicate chroot group name: %s", grp.name)
+        end
+
+        rc, re = e2lib.vrfy_dict_exp_keys(grp,
+            string.format("chroot group %q", grp.name),
+            { "name", "server", "files" })
+        if not rc then
+            return false, e:cat(re)
+        end
+
+        if not grp.server then
+            e:append("in group: %s", grp.name)
+            e:append(" `server' attribute missing")
+            return false, e
+        end
+        if not cache.valid_server(info.cache, grp.server) then
+            e:append("in group: %s", grp.name)
+            e:append(" no such server: %s", grp.server)
+            return false, e
+        end
+
+        if not grp.files or #grp.files == 0 then
+            e:append("in group: %s", grp.name)
+            e:append(" list of files is empty")
+            return false, e
+        end
+
+        rc, re = e2lib.vrfy_vector(grp.files,
+                string.format("group %s file entry", grp.name))
+        if not rc then
+            return false, e:cat(re)
+        end
+
+        cgroup = chroot.chroot:new(grp.name)
+
+        for _,f in ipairs(grp.files) do
+            local inherit = {
+                server = grp.server,
+            }
+            local keys = {
+                server = {
+                    mandatory = true,
+                    type = "string",
+                    inherit = true,
+                },
+                location = {
+                    mandatory = true,
+                    type = "string",
+                    inherit = false,
+                },
+                sha1 = {
+                    mandatory = false,
+                    type = "string",
+                    inherit = false,
+                },
+            }
+            rc, re = e2lib.vrfy_table_attributes(f, keys, inherit)
+            if not rc then
+                e:append("in group: %s", grp.name)
+                e:cat(re)
+                return false, e
+            end
+
+            if f.server ~= info.root_server_name and not f.sha1 then
+                e:append("in group: %s", grp.name)
+                e:append("file entry for remote file without `sha1` attribute")
+                return false, e
+            end
+
+            rc, re = e2lib.vrfy_dict_exp_keys(f,
+                string.format("group %q file entry", grp.name),
+                { "server", "location", "sha1" })
+            if not rc then
+                return false, e:cat(re)
+            end
+
+            cgroup:add_file(f.location, f.server, f.sha1)
+        end
+
+        chroot.groups_byname[cgroup:get_name()] = cgroup
+        table.insert(chroot.groups_sorted, cgroup:get_name())
+    end
+    table.sort(chroot.groups_sorted)
+    strict.lock(chroot.groups_sorted)
+
+    for _,g in ipairs(t.default_groups) do
+        if not chroot.groups_byname[g] then
+            return false,
+                e:append("unknown group in default groups list: %q", g)
+        end
+        table.insert(chroot.groups_default, g)
+    end
+    table.sort(chroot.groups_default)
+    strict.lock(chroot.groups_default)
+
+    --- XXX: remove, there is no reason to enforce a default group
+    if #chroot.groups_default == 0 then
+        return false,
+            e:append("`default_groups' attribute is missing or empty list")
+    end
+
+    return true
+end
+
+return strict.lock(chroot)
+
+-- vim:sw=4:sts=4:et:
index d64f43997c824fbd501cee977c06f521993e07f1..9491891dfac411a3b9f95063da3c9a36cd0e39e8 100644 (file)
@@ -36,6 +36,7 @@ local e2option = require("e2option")
 local e2tool = require("e2tool")
 local err = require("err")
 local scm = require("scm")
+local chroot = require("chroot")
 
 local function e2_fetch_source(arg)
     local rc, re = e2lib.init()
@@ -111,16 +112,18 @@ local function e2_fetch_source(arg)
     -- @return bool
     -- @return nil, an error string on error
     local function cache_chroot(info)
-        for _,c in ipairs(info.chroot.groups_sorted) do
-            for _,file in ipairs(info.chroot.groups_byname[c].files) do
-                local rc, e = cache.cache_file(info.cache, file.server,
+        local grp, rc, re
+        for _,g in ipairs(chroot.groups_sorted) do
+            grp = chroot.groups_byname[g]
+            for file in grp:file_iter() do
+                rc, re = cache.cache_file(info.cache, file.server,
                     file.location, {})
                 if not rc then
-                    return false, err.new("caching file failed")
+                    return false, re
                 end
             end
         end
-        return true, nil
+        return true
     end
 
     --- fetch and upgrade sources
index 86173196f799e256fc50b204fd6e523dde85ca26..0739ef22a3092c4e8151524e890a45a3e3868465 100644 (file)
@@ -39,6 +39,7 @@ local err = require("err")
 local licence = require("licence")
 local policy = require("policy")
 local scm = require("scm")
+local chroot = require("chroot")
 
 local function e2_ls_project(arg)
     local rc, re = e2lib.init()
@@ -307,20 +308,20 @@ local function e2_ls_project(arg)
     p1(s1, s2, "chroot groups")
     local s1 = " "
     local s2 = "|"
-    local len = #info.chroot.groups_sorted
-    for _,g in ipairs(info.chroot.groups_sorted) do
-        local grp = info.chroot.groups_byname[g]
+    local len = #chroot.groups_sorted
+    for _,g in ipairs(chroot.groups_sorted) do
+        local grp = chroot.groups_byname[g]
         len = len - 1
         if len == 0 then
             s2 = " "
         end
-        p2(s1, s2, grp.name, grp.name)
-        for _,f in ipairs(grp.files) do
+        p2(s1, s2, grp:get_name(), grp:get_name())
+        for f in grp:file_iter() do
             p3(s1, s2, "file", string.format("%s:%s", f.server, f.location))
         end
-        if grp.groupid then
+        --[[if grp.groupid then
             p3(s1, s2, "groupid", grp.groupid)
-        end
+        end]]
     end
 
     return true
index a226a8e92503950b061c34a2a1e1e551fa166349..7871f91bae9e27ee7060d4628cb9b8b7bddcb50d 100644 (file)
@@ -41,6 +41,7 @@ local scm = require("scm")
 local strict = require("strict")
 local tools = require("tools")
 local transport = require("transport")
+local chroot = require("chroot")
 
 -- Table driving the build process, see documentation at the bottom.
 local build_process = {}
@@ -311,9 +312,9 @@ local function setup_chroot(info, r, return_flags)
 
     local grp
     for _,cgrpnm in ipairs(res.chroot) do
-        grp = info.chroot.groups_byname[cgrpnm]
+        grp = chroot.groups_byname[cgrpnm]
 
-        for _, f in ipairs(grp.files) do
+        for f in grp:file_iter() do
             local flags = { cache = true }
             local rc, re = cache.cache_file(info.cache, f.server,
                 f.location, flags)
index 614e8f7db0d2dd1c0f94bf1415903fc9eb3dade3..83e2f3f8d7d0191a6525b90627aff3f0e1812733 100644 (file)
@@ -49,6 +49,7 @@ local strict = require("strict")
 local tools = require("tools")
 local transport = require("transport")
 local url = require("url")
+local chroot = require("chroot")
 
 -- Build function table, see end of file for details.
 local e2tool_ftab = {}
@@ -69,7 +70,6 @@ local e2tool_ftab = {}
 -- @field sources_sorted table: sorted list of sources
 -- @field results table: results
 -- @field results_sorted table: sorted list of results
--- @field chroot See info.chroot
 -- @field project_location string: project location relative to the servers
 -- @field env table: env table
 -- @field env_files table: list of env files
@@ -116,18 +116,6 @@ local e2tool_ftab = {}
 -- @see e2build.build_config
 -- @see plugins.collect_project
 
---- Table of chroot configuration. Locked.
--- @table info.chroot
--- @field default_groups Chroot groups used in every result. Locked.
--- @field groups_byname Dict mapping group name to group table.
--- @field groups_sorted Vector of sorted group names. Locked.
-
---- chroot group table
--- @table chroot group table
--- @field name string: group name
--- @field server string: server name
--- @field files table: array of file names
-
 --- env - environment table from "proj/env"
 -- @name env
 -- @class table
@@ -336,7 +324,7 @@ local function check_result(info, resultname)
         e:cat(re)
     else
         -- apply default chroot groups
-        for _,g in ipairs(info.chroot.default_groups) do
+        for _,g in ipairs(chroot.groups_default) do
             table.insert(res.chroot, g)
         end
         -- The list may have duplicates now. Unify.
@@ -346,7 +334,7 @@ local function check_result(info, resultname)
             e:cat(re)
         end
         for _,g in ipairs(res.chroot) do
-            if not info.chroot.groups_byname[g] then
+            if not chroot.groups_byname[g] then
                 e:append("chroot group does not exist: %s", g)
             end
         end
@@ -595,55 +583,6 @@ local function load_env_config(info, file)
     return true
 end
 
---- read chroot configuration
--- @param info
--- @return bool
--- @return an error object on failure
-local function read_chroot_config(info)
-    local e = err.new("reading chroot config failed")
-    local t = {}
-    local rc, re =
-        load_user_config(info, e2lib.join(info.root, "proj/chroot"),
-            t, "chroot", "e2chroot")
-    if not rc then
-        return false, e:cat(re)
-    end
-    if type(t.chroot) ~= "table" then
-        return false, e:append("chroot configuration table not available")
-    end
-    if type(t.chroot.groups) ~= "table" then
-        return false, e:append("chroot.groups configuration is not a table")
-    end
-    if type(t.chroot.default_groups) ~= "table" then
-        return false, e:append("chroot.default_groups is not a table")
-    end
-    info.chroot = {}
-    info.chroot.default_groups = t.chroot.default_groups or {}
-    info.chroot.groups_byname = {}
-    info.chroot.groups_sorted = {}
-    strict.lock(info.chroot)
-    for _,grp in ipairs(t.chroot.groups) do
-        if grp.group then
-            e:append("in group: %s", grp.group)
-            e:append(" `group' attribute is deprecated. Replace by `name'")
-            return false, e
-        end
-        if not grp.name then
-            return false, e:append("`name' attribute is missing in a group")
-        end
-        local g = grp.name
-        table.insert(info.chroot.groups_sorted, g)
-        if info.chroot.groups_byname[g] then
-            return false, e:append("duplicate chroot group name: %s", g)
-        end
-        info.chroot.groups_byname[g] = grp
-    end
-    table.sort(info.chroot.groups_sorted)
-    strict.lock(info.chroot.groups_sorted)
-    strict.lock(info.chroot.default_groups)
-    return true
-end
-
 --- Gather source paths.
 -- @param info Info table.
 -- @param basedir Nil or directory from where to start scanning for more
@@ -1022,75 +961,6 @@ local function read_project_config(info)
     return true
 end
 
---- check chroot config
--- @param chroot
--- @return bool
--- @return an error object on failure
-local function check_chroot_config(info)
-    local e = err.new("error validating chroot configuration")
-    local grp
-
-    for _,cgrpnm in ipairs(info.chroot.groups_sorted) do
-        grp = info.chroot.groups_byname[cgrpnm]
-        if not grp.server then
-            e:append("in group: %s", grp.name)
-            e:append(" `server' attribute missing")
-        elseif not cache.valid_server(info.cache, grp.server) then
-            e:append("in group: %s", grp.name)
-            e:append(" no such server: %s", grp.server)
-        end
-        if (not grp.files) or (#grp.files) == 0 then
-            e:append("in group: %s", grp.name)
-            e:append(" list of files is empty")
-        else
-            for _,f in ipairs(grp.files) do
-                local inherit = {
-                    server = grp.server,
-                }
-                local keys = {
-                    server = {
-                        mandatory = true,
-                        type = "string",
-                        inherit = true,
-                    },
-                    location = {
-                        mandatory = true,
-                        type = "string",
-                        inherit = false,
-                    },
-                    sha1 = {
-                        mandatory = false,
-                        type = "string",
-                        inherit = false,
-                    },
-                }
-                local rc, re = e2lib.vrfy_table_attributes(f, keys, inherit)
-                if not rc then
-                    e:append("in group: %s", grp.name)
-                    e:cat(re)
-                end
-                if f.server ~= info.root_server_name and not f.sha1 then
-                    e:append("in group: %s", grp.name)
-                    e:append("file entry for remote file without `sha1` attribute")
-                end
-            end
-        end
-    end
-    if #info.chroot.default_groups == 0 then
-        e:append(" `default_groups' attribute is missing or empty list")
-    else
-        for _,g in ipairs(info.chroot.default_groups) do
-            if not info.chroot.groups_byname[g] then
-                e:append(" unknown group in default groups list: %s", g)
-            end
-        end
-    end
-    if e:getcount() > 1 then
-        return false, e
-    end
-    return true
-end
-
 --- check source.
 local function check_source(info, sourcename)
     local src = info.sources[sourcename]
@@ -1135,10 +1005,6 @@ end
 local function check_project_info(info)
     local rc, re
     local e = err.new("error in project configuration")
-    rc, re = check_chroot_config(info)
-    if not rc then
-        return false, e:cat(re)
-    end
     local rc, re = check_sources(info)
     if not rc then
         return false, e:cat(re)
@@ -1287,7 +1153,7 @@ function e2tool.collect_project_info(info, skip_load_config)
     end
 
     -- chroot config
-    rc, re = read_chroot_config(info)
+    rc, re = chroot.load_chroot_config(info)
     if not rc then
         return false, e:cat(re)
     end
@@ -1761,33 +1627,6 @@ function e2tool.buildid(info, resultname)
     return r.build_mode.buildid(r.buildid)
 end
 
---- chroot group id.
--- @param info Info table.
--- @param groupname
--- @return Chroot group ID or false on error.
--- @return Error object on failure.
-local function chrootgroupid(info, groupname)
-    local e = err.new("calculating chroot group id failed for group %s",
-        groupname)
-    local g = info.chroot.groups_byname[groupname]
-    if g.groupid then
-        return g.groupid
-    end
-    local hc = hash.hash_start()
-    hash.hash_line(hc, g.name)
-    for _,f in ipairs(g.files) do
-        hash.hash_line(hc, f.server)
-        hash.hash_line(hc, f.location)
-        local fileid, re = e2tool.fileid(info, f)
-        if not fileid then
-            return false, e:cat(re)
-        end
-        hash.hash_line(hc, fileid)
-    end
-    g.groupid = hash.hash_finish(hc)
-    return g.groupid
-end
-
 --- envid: calculate a value represennting the environment for a result
 -- @param info the info table
 -- @param resultname string: name of a result
@@ -1828,7 +1667,7 @@ function e2tool.pbuildid(info, resultname)
 
     if r.chroot then
         for _,g in ipairs(r.chroot) do
-            local groupid, re = chrootgroupid(info, g)
+            local groupid, re = chroot.groups_byname[g]:chrootgroupid(info)
             if not groupid then
                 return false, e:cat(re)
             end
index 3ab8f5e1c55e49f7cafb5e0ddcfaabe409b7e6cc..9a43099fb40d666ce2a2d0a2623d21803539bf78 100644 (file)
@@ -30,6 +30,7 @@ local hash = require("hash")
 local scm = require("scm")
 local strict = require("strict")
 local licence = require("licence")
+local chroot = require("chroot")
 
 --- Collect_project result config. This result config table lives in
 -- info.results[resultname]. The fields are merged with e2tool.result
@@ -284,7 +285,7 @@ local function build_collect_project(info, resultname, return_flags)
     -- project/chroot/<group>/<files>
     for _,g in ipairs(cpres.chroot_groups) do
         e2lib.logf(3, "chroot group: %s", g)
-        local grp = info.chroot.groups_byname[g]
+        local grp = chroot.groups_byname[g]
         local destdir = e2lib.join( res.build_config.T, "project/chroot", g)
         rc, re = e2lib.mkdir_recursive(destdir)
         if not rc then
@@ -293,7 +294,7 @@ local function build_collect_project(info, resultname, return_flags)
 
         out = { "place:\n" }
 
-        for _,file in pairs(grp.files) do
+        for file in grp:file_iter() do
             local cache_flags = {}
             rc, re = cache.fetch_file(info.cache, file.server,
             file.location, destdir, nil, cache_flags)