From: Tobias Ulmer Date: Tue, 11 Feb 2014 17:42:43 +0000 (+0100) Subject: Split chroot config into own module and class X-Git-Tag: e2factory-2.3.15rc1~220 X-Git-Url: https://git.e2factory.org/?a=commitdiff_plain;h=e08f7fb71018c42cd4dd1f2f4c16ed4a735e35c1;p=e2factory.git Split chroot config into own module and class Signed-off-by: Tobias Ulmer --- diff --git a/local/Makefile b/local/Makefile index f637884..3cfa2d4 100644 --- a/local/Makefile +++ b/local/Makefile @@ -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 index 0000000..b123ac1 --- /dev/null +++ b/local/chroot.lua @@ -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: diff --git a/local/e2-fetch-sources.lua b/local/e2-fetch-sources.lua index d64f439..9491891 100644 --- a/local/e2-fetch-sources.lua +++ b/local/e2-fetch-sources.lua @@ -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 diff --git a/local/e2-ls-project.lua b/local/e2-ls-project.lua index 8617319..0739ef2 100644 --- a/local/e2-ls-project.lua +++ b/local/e2-ls-project.lua @@ -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 diff --git a/local/e2build.lua b/local/e2build.lua index a226a8e..7871f91 100644 --- a/local/e2build.lua +++ b/local/e2build.lua @@ -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) diff --git a/local/e2tool.lua b/local/e2tool.lua index 614e8f7..83e2f3f 100644 --- a/local/e2tool.lua +++ b/local/e2tool.lua @@ -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 diff --git a/plugins/collect_project.lua b/plugins/collect_project.lua index 3ab8f5e..9a43099 100644 --- a/plugins/collect_project.lua +++ b/plugins/collect_project.lua @@ -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// 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)