e2-build-numbers e2-cf e2-help
LOCALLUALIBS= digest.lua e2build.lua e2tool.lua environment.lua \
- policy.lua scm.lua
+ policy.lua scm.lua licence.lua
LOCALTOOLS = $(LOCALLUATOOLS)
.PHONY: all install uninstall local install-local doc install-doc
local e2option = require("e2option")
local e2tool = require("e2tool")
local err = require("err")
+local licence = require("licence")
local policy = require("policy")
local scm = require("scm")
pempty(s1, s2, s3)
s2 = "|"
p1(s1, s2, "licences")
- local llen = #info.licences_sorted
- for _,l in pairs(info.licences_sorted) do
- local lic = info.licences[l]
+ local llen = #licence.licences_sorted
+ for _,lic in ipairs(licence.licences_sorted) do
llen = llen - 1
if llen == 0 then
s2 = " "
end
- p2(s1, s2, l)
- for _,f in ipairs(lic.files) do
+ p2(s1, s2, lic:get_name())
+ for f in lic:file_iter() do
p3(s1, s2, "file", string.format("%s:%s", f.server, f.location))
end
end
]]
local e2tool = {}
+package.loaded["e2tool"] = e2tool -- stop e2tool loading loop
+
+local buildconfig = require("buildconfig")
+local cache = require("cache")
+local digest = require("digest")
local e2lib = require("e2lib")
+local e2option = require("e2option")
local eio = require("eio")
-local err = require("err")
-local digest = require("digest")
-local scm = require("scm")
-local tools = require("tools")
local environment = require("environment")
-local plugin = require("plugin")
-local url = require("url")
-local hash = require("hash")
-local e2option = require("e2option")
+local err = require("err")
local generic_git = require("generic_git")
+local hash = require("hash")
+local licence = require("licence")
+local plugin = require("plugin")
local policy = require("policy")
+local scm = require("scm")
local strict = require("strict")
+local tools = require("tools")
local transport = require("transport")
-local cache = require("cache")
-local buildconfig = require("buildconfig")
+local url = require("url")
-- Build function table, see end of file for details.
local e2tool_ftab = {}
-- @field sources_sorted table: sorted list of sources
-- @field results table: results
-- @field results_sorted table: sorted list of results
--- @field licences table: licences keyed by licence names
--- @field licences_sorted table: sorted list of licences
-- @field chroot table: chroot
-- @field project_location string: project location relative to the servers
-- @field env table: env table
-- @name env
-- @class table
---- check if a table is a list of strings
--- @param l table
--- @param unique bool: require strings to be unique
--- @param unify bool: remove duplicate strings
--- @return bool
-local function listofstrings(l, unique, unify)
- if type(l) ~= "table" then
- return false, err.new("not a table")
- end
- local values = {}
- local unified = {}
- for i,s in pairs(l) do
- if type(i) ~= "number" then
- return false, err.new("found non-numeric index")
- end
- if type(s) ~= "string" then
- return false, err.new("found non-string value")
- end
- if unique and values[s] then
- return false, err.new("found non-unique value: '%s'", s)
- end
- if unify and not values[s] then
- table.insert(unified, s)
- end
- values[s] = true
- end
- if unify then
- while #l > 0 do
- table.remove(l, 1)
- end
- for i,s in ipairs(unified) do
- table.insert(l, s)
- end
- end
- return true
-end
-
---- check a table according to a description table
--- @param tab table: the table to check
--- @param keys table: the description table
--- @param inherit table: table with keys to inherit
--- @return bool
--- @return an error object on failure
-local function check_tab(tab, keys, inherit)
- local e = err.new("checking file configuration")
-
- if type(tab) ~= "table" then
- return false, e:append("not a table")
- end
-
- -- keys = {
- -- location = {
- -- mandatory = true,
- -- type = "string",
- -- inherit = false,
- -- },
- -- }
- -- inherit = {
- -- location = "foo",
- -- }
-
- -- inherit keys
- for k,v in pairs(inherit) do
- if not tab[k] and keys[k].inherit ~= false then
- tab[k] = v
- end
- end
-
- -- check types and mandatory
- for k,v in pairs(keys) do
- if keys[k].mandatory and not tab[k] then
- e:append("missing mandatory key: %s", k)
- elseif tab[k] and keys[k].type ~= type(tab[k]) then
- e:append("wrong type: %s", k)
- end
- end
-
- if e:getcount() > 1 then
- return false, e
- end
- return true
-end
-
--- Open debug logfile.
-- @param info Info table.
-- @return True on success, false on error.
"Converting to list")
res.sources = { res.sources }
end
- local rc, re = listofstrings(res.sources, true, false)
+ local rc, re = e2lib.vrfy_listofstrings(res.sources, "sources", true, false)
if not rc then
e:append("source attribute:")
e:cat(re)
"Converting to list")
res.depends = { res.depends }
end
- local rc, re = listofstrings(res.depends, true, false)
+ local rc, re = e2lib.vrfy_listofstrings(res.depends, "depends", true, false)
if not rc then
e:append("dependency attribute:")
e:cat(re)
"Converting to list")
res.chroot = { res.chroot }
end
- local rc, re = listofstrings(res.chroot, true, false)
+ local rc, re = e2lib.vrfy_listofstrings(res.chroot, "chroot", true, false)
if not rc then
e:append("chroot attribute:")
e:cat(re)
table.insert(res.chroot, g)
end
-- The list may have duplicates now. Unify.
- local rc, re = listofstrings(res.chroot, false, true)
+ rc, re = e2lib.vrfy_listofstrings(res.chroot, "chroot", false, true)
if not rc then
e:append("chroot attribute:")
e:cat(re)
"default_results is not set. Defaulting to empty list.")
info.project.default_results = {}
end
- rc, re = listofstrings(info.project.deploy_results, true, true)
+ rc, re = e2lib.vrfy_listofstrings(info.project.deploy_results,
+ "deploy_results", true, true)
if not rc then
e:append("deploy_results is not a valid list of strings")
e:cat(re)
end
- rc, re = listofstrings(info.project.default_results, true, false)
+ rc, re = e2lib.vrfy_listofstrings(info.project.default_results,
+ "default_results", true, false)
if not rc then
e:append("default_results is not a valid list of strings")
e:cat(re)
inherit = false,
},
}
- local rc, re = check_tab(f, keys, inherit)
+ local rc, re = e2lib.vrfy_table_attributes(f, keys, inherit)
if not rc then
e:append("in group: %s", grp.name)
e:cat(re)
return true
end
---- check licence.
-local function check_licence(info, l)
- local e = err.new("in licence: %s", l)
- local lic = info.licences[l]
- if not lic.server then
- e:append("no server attribute")
- end
- if not lic.files then
- e:append("no files attribute")
- elseif type(lic.files) ~= "table" then
- e:append("files attribute is not a table")
- else
- for _,f in ipairs(lic.files) do
- local inherit = {
- server = lic.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 = check_tab(f, keys, inherit)
- if not rc then
- e:cat(re)
- elseif f.server ~= info.root_server_name and
- not f.sha1 then
- e:append("file entry for remote file without"..
- " `sha1` attribute")
- end
- end
- end
- if e:getcount() > 1 then
- return false, e
- end
- return true
-end
-
---- check licences.
-local function check_licences(info)
- local e = err.new("Error while checking licences")
- local rc, re
- for l, lic in pairs(info.licences) do
- rc, re = check_licence(info, l)
- if not rc then
- e:cat(re)
- end
- end
- if e:getcount() > 1 then
- return false, e
- end
- return true
-end
-
--- Checks project information for consistancy.
-- @param info Info table.
-- @return True on success, false on error.
if not rc then
return false, e:cat(re)
end
- local rc, re = check_licences(info)
- if not rc then
- return false, e:cat(re)
- end
for _, r in ipairs(info.project.default_results) do
if not info.results[r] then
e:append("default_results: No such result: %s", r)
end
-- licences
- rc, re = load_user_config(info, e2lib.join(info.root, "proj/licences"),
- info, "licences", "e2licence")
+ rc, re = licence.load_licence_config(info)
if not rc then
return false, e:cat(re)
end
- -- provide sorted list of licences
- info.licences_sorted = {}
- for l,lic in pairs(info.licences) do
- table.insert(info.licences_sorted, l)
- end
- table.sort(info.licences_sorted)
+ -- sources
rc, re = load_source_configs(info)
if not rc then
return false, e:cat(re)
end
+ -- results
rc, re = load_result_configs(info)
if not rc then
return false, e:cat(re)
return fileid
end
---- calculate licence id
--- @param info
--- @param licence
--- @return string, or false on error.
--- @return Error object on failure
-function e2tool.licenceid(info, licence)
- local rc, re
- local e = err.new("calculating licence id failed for licence: %s",
- licence)
- local lic = info.licences[licence]
- if lic.licenceid then
- return lic.licenceid
- end
- local hc = hash.hash_start()
- hash.hash_line(hc, licence) -- licence name
- for _,f in ipairs(lic.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
- lic.licenceid, re = hash.hash_finish(hc)
- if not lic.licenceid then
- return false, e:cat(re)
- end
- return lic.licenceid
-end
-
--- return the first eight digits of buildid hash
-- @param buildid string: hash value
-- @return string: a short representation of the hash value
--- /dev/null
+--- Licence config module.
+-- @module local.licence
+
+-- 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 licence = {}
+local class = require("class")
+local e2lib = require("e2lib")
+local e2tool = require("e2tool")
+local err = require("err")
+local hash = require("hash")
+local strict = require("strict")
+
+--- Licence base class.
+-- @see generic.class
+licence.licence = class("licence")
+
+--- Dictionary of loaded licence objects, indexed by name.
+licence.licences = {}
+--- Vector of loaded licence objects, sorted by name.
+licence.licences_sorted = {}
+
+--- Create a new licence object.
+-- @param name Licence name string.
+-- @return May throw error(err) on invalid input.
+function licence.licence:initialize(name)
+ local ok, re = e2lib.vrfy_string_len(name, "licence name")
+ if not ok then
+ error(re)
+ end
+ self._name = name
+ self._files = {}
+ self._licenceid = false
+end
+
+--- Add a file to a licence.
+-- @param location Path to licence 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 licence.licence:add_file(location, server, sha1)
+ local t, ok, re
+
+ ok, re = e2lib.vrfy_string_len(location, "licence location")
+ if not ok then
+ error(re)
+ end
+
+ ok, re = e2lib.vrfy_string_len(server, "licence server")
+ if not ok then
+ error(re)
+ end
+
+ if sha1 then
+ ok, re = e2lib.vrfy_string_len(sha1, "licence sha1")
+ if not ok then
+ error(re)
+ end
+ end
+
+ self._licenceid = false
+
+ t = {
+ location = location,
+ server = server,
+ sha1 = sha1,
+ }
+ table.insert(self._files, t)
+end
+
+--- Iterator that returns file tables in the order they were added.
+function licence.licence: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
+
+--- Get the licence name.
+-- @return Licence name.
+function licence.licence:get_name()
+ return self._name
+end
+
+--- Calculate the LicenceID
+-- @param info Info table.
+-- @return LicenceID or false on error.
+-- @return Error object on failure.
+function licence.licence:licenceid(info)
+ local rc, re, e, hc, fileid
+
+ if self._licenceid then
+ return self._licenceid
+ end
+
+ e = err.new("calculating licence id failed for licence: %s", self._name)
+
+ hc = hash.hash_start()
+ hash.hash_line(hc, self._name)
+
+ for file in self:file_iter() do
+ hash.hash_line(hc, file.server)
+ hash.hash_line(hc, file.location)
+
+ fileid, re = e2tool.fileid(info, file)
+ if not fileid then
+ return false, e:cat(re)
+ end
+ hash.hash_line(hc, fileid)
+ end
+
+ self._licenceid, re = hash.hash_finish(hc)
+ if not self._licenceid then
+ return false, e:cat(re)
+ end
+
+ return self._licenceid
+end
+
+--- Load project licence config, validate, and populate the licences,
+-- licences_sorted tables with licence objects.
+-- @param info Info table.
+-- @return True on success, false on error
+-- @return Error object on failure.
+function licence.load_licence_config(info)
+ local rc, re, e
+ local path, ltable
+
+ path = e2lib.join(info.root, "proj/licences")
+
+ e2lib.logf(3, "loading licence config %q", path)
+ e = err.new("loading licence config %q failed", path)
+
+ ltable = {}
+ local function assign(table)
+ for k,v in pairs(table) do
+ ltable[k] = v
+ end
+ end
+
+ rc, re = e2lib.dofile2(path,
+ { e2licence = assign, env = info.env, string = string }, false)
+ if not rc then
+ return false, re
+ end
+
+ for k,v in pairs(ltable) do
+ if type(k) ~= "string" then
+ return false, e:append("key %q is not a string", tostring(k))
+ end
+
+ if type(v) ~= "table" then
+ return false, e:append("licence %s is not a table", k)
+ end
+ end
+
+ for name,l in pairs(ltable) do
+ e2lib.logf(4, "in licence.load_licence_config, add %s, %s", tostring(name), tostring(l))
+
+ rc, re = e2lib.vrfy_dict_exp_keys(l, "licence",
+ { "server", "files" })
+ if not rc then
+ return false, e:cat(re)
+ end
+
+ if not l.server then
+ return false, e:append("no server attribute in %s", name)
+ elseif type(l.server) ~= "string" then
+ return false, e:append("server attribute in %s not a string", name)
+ end
+
+ if not l.files then
+ return false, e:append("no files attribute in %s", name)
+ elseif type(l.files) ~= "table" then
+ return false, e:append("files attribute in %s not a table", name)
+ end
+
+ for _,file in ipairs(l.files) do
+ rc, re = e2lib.vrfy_dict_exp_keys(file, "file",
+ { "server", "location", "sha1" })
+ if not rc then
+ return false, e:cat(re)
+ end
+
+ local inherit = {
+ server = l.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(file, keys, inherit)
+ if not rc then
+ return false, e:cat(re)
+ end
+ if file.server ~= info.root_server_name and not file.sha1 then
+ return false, e:append(
+ "file entry for remote file without sha1 attribute")
+ end
+ end
+
+
+ licence.licences[name] = licence.licence:new(name)
+
+ for _,file in ipairs(l.files) do
+ licence.licences[name]:add_file(
+ file.location, file.server, file.sha1)
+ end
+ end
+
+ for _,l in pairs(licence.licences) do
+ table.insert(licence.licences_sorted, l)
+ end
+
+ local function s(a, b)
+ return a:get_name() < b:get_name()
+ end
+ table.sort(licence.licences_sorted, s)
+
+ return true
+end
+
+return strict.lock(licence)
+
+-- vim:sw=4:sts=4:et:
local scm = {}
local e2lib = require("e2lib")
-local err = require("err")
local environment = require("environment")
+local err = require("err")
+local licence = require("licence")
local strict = require("strict")
-- scm modules
end
end
for _,l in ipairs(src.licences) do
- if not info.licences[l] then
+ if not licence.licences[l] then
e:append("unknown licence: %s", l)
return false, e
end
local hash = require("hash")
local scm = require("scm")
local strict = require("strict")
+local licence = require("licence")
--- Collect_project result config. This result config table lives in
-- info.results[resultname]. The fields are merged with e2tool.result
-- @field results table: sorted list of results to be collected
-- @field sources table: sorted list of sources to be collected
-- @field chroot_groups table: sorted list of chroot groups to be collected
--- @field licences table: sorted list of licences to be collected
-- @see cpresults
--- check collect_project configuration
cpres.results = {}
cpres.sources = {}
cpres.chroot_groups = {}
- cpres.licences = {}
strict.lock(cpres)
e2lib.warnf("WDEFAULT", " collect_project takes these results: %s",
table.concat(cpres.results, ","))
- -- store a sorted list of required sources, chroot groups and licences
+ -- store a sorted list of required sources and chroot groups
local tmp_grp = {}
local tmp_src = {}
for _,r in ipairs(cpres.results) do
table.insert(cpres.chroot_groups, g)
end
table.sort(cpres.chroot_groups)
- for _,l in ipairs(info.licences_sorted) do
- table.insert(cpres.licences, l)
- end
- table.sort(cpres.licences)
+
if e:getcount() > 1 then
return false, e
end
rc, re = hash.hash_line(hc, g)
if not rc then return nil, re end
end
- for _,l in ipairs(cpres.licences) do
- rc, re = hash.hash_line(hc, l)
+ for _,l in ipairs(licence.licences_sorted) do
+ rc, re = hash.hash_line(hc, l:get_name())
if not rc then return nil, re end
-- We collect all licences. So we cannot be sure to catch
-- them via results/sources. Include them explicitly here.
- local lid, re = e2tool.licenceid(info, l)
+ local lid, re = l:licenceid(info)
if not lid then
return nil, e:cat(re)
end
end
end
-- project/licences/<licence>/<files>
- for _,l in ipairs(cpres.licences) do
- e2lib.logf(3, "licence: %s", l)
- local lic = info.licences[l]
- local destdir = e2lib.join(res.build_config.T, "project/licences", l)
+ for _,l in ipairs(licence.licences_sorted) do
+ e2lib.logf(3, "licence: %s", l:get_name())
+ local destdir =
+ e2lib.join(res.build_config.T, "project/licences", l:get_name())
rc, re = e2lib.mkdir_recursive(destdir)
if not rc then
return false, e:cat(re)
end
- for _,file in ipairs(lic.files) do
+ for file in l:file_iter() do
local cache_flags = {}
if file.sha1 then
rc, re = e2tool.verify_hash(info, file.server,
local eio = require("eio")
local err = require("err")
local hash = require("hash")
+local licence = require("licence")
local scm = require("scm")
local strict = require("strict")
local tools = require("tools")
function cvs.sourceid(info, sourcename, source_set)
local src = info.sources[sourcename]
- local rc, re
+ local rc, re, lid
rc, re = cvs.validate_source(info, sourcename)
if not rc then
return false, re
hash.hash_line(hc, src.name)
hash.hash_line(hc, src.type)
hash.hash_line(hc, src._env:id())
- for _,l in ipairs(src.licences) do
- hash.hash_line(hc, l)
- local licenceid, re = e2tool.licenceid(info, l)
- if not licenceid then
- return false, re
+ for _,ln in ipairs(src.licences) do
+ lid, re = licence.licences[ln]:licenceid(info)
+ if not lid then
+ return false, e:cat(re)
end
- hash.hash_line(hc, licenceid)
+ hash.hash_line(hc, lid)
end
-- cvs specific
if source_set == "tag" and src.tag ~= "^" then
local scm = require("scm")
local strict = require("strict")
local tools = require("tools")
+local licence = require("licence")
plugin_descriptor = {
description = "Files SCM Plugin",
e:append("source has file entry without `licences' attribute")
end
for _,l in ipairs(f.licences) do
- if not info.licences[l] then
+ if not licence.licences[l] then
e:append("invalid licence assigned to file: %s", l)
end
end
hash.hash_line(hc, src.type)
hash.hash_line(hc, src._env:id())
for _,l in ipairs(src.licences) do
+ local alicence = licence.licences[l]
hash.hash_line(hc, l)
- local licenceid, re = e2tool.licenceid(info, l)
+ local licenceid, re = alicence:licenceid(info)
if not licenceid then
return false, re
end
local err = require("err")
local generic_git = require("generic_git")
local hash = require("hash")
+local licence = require("licence")
local scm = require("scm")
local strict = require("strict")
local tools = require("tools")
hash.hash_line(hc, src.type)
hash.hash_line(hc, src._env:id())
for _,l in ipairs(src.licences) do
- hash.hash_line(hc, l)
- local licenceid, re = e2tool.licenceid(info, l)
+ hash.hash_line(hc, l) -- XXX: redundant
+ local licenceid, re = licence.licences[l]:licenceid(info)
if not licenceid then
return false, re
end
local eio = require("eio")
local err = require("err")
local hash = require("hash")
+local licence = require("licence")
local scm = require("scm")
local strict = require("strict")
local tools = require("tools")
function svn.sourceid(info, sourcename, source_set)
local src = info.sources[sourcename]
local rc, re
- local hc, surl, svnurl, argv, out, svnrev
+ local hc, surl, svnurl, argv, out, svnrev, lid
rc, re = svn.validate_source(info, sourcename)
if not rc then
hash.hash_line(hc, src.name)
hash.hash_line(hc, src.type)
hash.hash_line(hc, src._env:id())
- for _,l in ipairs(src.licences) do
- hash.hash_line(hc, l)
- local licenceid, re = e2tool.licenceid(info, l)
- if not licenceid then
+ for _,ln in pairs(src.licences) do
+ lid, re = licence.licences[ln]:licenceid(info)
+ if not lid then
return false, re
end
- hash.hash_line(hc, licenceid)
+ hash.hash_line(hc, lid)
end
-- svn specific