From: Tobias Ulmer Date: Wed, 5 Feb 2014 14:24:44 +0000 (+0100) Subject: Create licence class and move all licence handling into own module X-Git-Tag: e2factory-2.3.15rc1~231 X-Git-Url: https://git.e2factory.org/?a=commitdiff_plain;h=fa36bc15abbc83af6f389c7e0bd44779dfae18d4;p=e2factory.git Create licence class and move all licence handling into own module In addition to all the motions of moving licence out of e2tool, the following bugs should be fixed in this commit: svn plugin: Fix bz#123, include LicenceID in SourceID calculation cvs plugin: Fix bz#126, backtrace when calculating LicenceID Signed-off-by: Tobias Ulmer --- diff --git a/local/Makefile b/local/Makefile index fbb3b51..f637884 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 + policy.lua scm.lua licence.lua LOCALTOOLS = $(LOCALLUATOOLS) .PHONY: all install uninstall local install-local doc install-doc diff --git a/local/e2-ls-project.lua b/local/e2-ls-project.lua index 5fb0f08..50277a3 100644 --- a/local/e2-ls-project.lua +++ b/local/e2-ls-project.lua @@ -36,6 +36,7 @@ local e2lib = require("e2lib") local e2option = require("e2option") local e2tool = require("e2tool") local err = require("err") +local licence = require("licence") local policy = require("policy") local scm = require("scm") @@ -286,15 +287,14 @@ local function e2_ls_project(arg) 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 diff --git a/local/e2tool.lua b/local/e2tool.lua index 5ae11a8..f5ac6dd 100644 --- a/local/e2tool.lua +++ b/local/e2tool.lua @@ -29,23 +29,26 @@ ]] 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 = {} @@ -66,8 +69,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 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 @@ -131,89 +132,6 @@ local e2tool_ftab = {} -- @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. @@ -389,7 +307,7 @@ local function check_result(info, resultname) "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) @@ -411,7 +329,7 @@ local function check_result(info, resultname) "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) @@ -433,7 +351,7 @@ local function check_result(info, resultname) "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) @@ -443,7 +361,7 @@ local function check_result(info, resultname) 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) @@ -1094,12 +1012,14 @@ local function read_project_config(info) "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) @@ -1165,7 +1085,7 @@ local function check_chroot_config(info) 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) @@ -1229,71 +1149,6 @@ local function check_sources(info) 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. @@ -1313,10 +1168,6 @@ local function check_project_info(info) 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) @@ -1440,23 +1291,18 @@ function e2tool.collect_project_info(info, skip_load_config) 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) @@ -1911,37 +1757,6 @@ function e2tool.fileid(info, file) 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 diff --git a/local/licence.lua b/local/licence.lua new file mode 100644 index 0000000..7cebaee --- /dev/null +++ b/local/licence.lua @@ -0,0 +1,268 @@ +--- 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: diff --git a/local/scm.lua b/local/scm.lua index 7dd0f53..e646663 100644 --- a/local/scm.lua +++ b/local/scm.lua @@ -30,8 +30,9 @@ 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 @@ -176,7 +177,7 @@ local function source_apply_default_licences(info, sourcename) 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 diff --git a/plugins/collect_project.lua b/plugins/collect_project.lua index 8dd83f1..a98c096 100644 --- a/plugins/collect_project.lua +++ b/plugins/collect_project.lua @@ -29,6 +29,7 @@ local err = require("err") 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 @@ -46,7 +47,6 @@ local cpresults = {} -- @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 @@ -68,7 +68,6 @@ local function check_collect_project(info, resultname) cpres.results = {} cpres.sources = {} cpres.chroot_groups = {} - cpres.licences = {} strict.lock(cpres) @@ -95,7 +94,7 @@ local function check_collect_project(info, resultname) 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 @@ -117,10 +116,7 @@ local function check_collect_project(info, resultname) 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 @@ -159,13 +155,13 @@ local function collect_project_resultid(info, resultname) 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 @@ -337,16 +333,16 @@ local function build_collect_project(info, resultname, return_flags) end end -- project/licences// - 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, diff --git a/plugins/cvs.lua b/plugins/cvs.lua index 5bc4be0..fd32d88 100644 --- a/plugins/cvs.lua +++ b/plugins/cvs.lua @@ -34,6 +34,7 @@ local e2lib = require("e2lib") 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") @@ -339,7 +340,7 @@ end 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 @@ -356,13 +357,12 @@ function cvs.sourceid(info, sourcename, source_set) 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 diff --git a/plugins/files.lua b/plugins/files.lua index a1b77cc..c214adc 100644 --- a/plugins/files.lua +++ b/plugins/files.lua @@ -38,6 +38,7 @@ local hash = require("hash") local scm = require("scm") local strict = require("strict") local tools = require("tools") +local licence = require("licence") plugin_descriptor = { description = "Files SCM Plugin", @@ -82,7 +83,7 @@ function files.validate_source(info, sourcename) 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 @@ -495,8 +496,9 @@ function files.sourceid(info, sourcename, sourceset) 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 diff --git a/plugins/git.lua b/plugins/git.lua index e6cb578..6382373 100644 --- a/plugins/git.lua +++ b/plugins/git.lua @@ -37,6 +37,7 @@ local eio = require("eio") 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") @@ -536,8 +537,8 @@ function git.sourceid(info, sourcename, sourceset) 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 diff --git a/plugins/svn.lua b/plugins/svn.lua index db53536..939751a 100644 --- a/plugins/svn.lua +++ b/plugins/svn.lua @@ -34,6 +34,7 @@ local e2lib = require("e2lib") 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") @@ -291,7 +292,7 @@ end 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 @@ -310,13 +311,12 @@ function svn.sourceid(info, sourcename, source_set) 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