Skip to content
Snippets Groups Projects
Unverified Commit 37a40cbc authored by Andreas Ziegler's avatar Andreas Ziegler Committed by GitHub
Browse files

Merge pull request #2111 from freifunk-gluon/features-fix

Fix two feature handling bugs
parents 9215d289 a9c2db93
No related branches found
No related tags found
No related merge requests found
...@@ -110,5 +110,6 @@ files["package/features"] = { ...@@ -110,5 +110,6 @@ files["package/features"] = {
read_globals = { read_globals = {
"_", "_",
"feature", "feature",
"when",
}, },
} }
...@@ -82,43 +82,43 @@ Each flag *$flag* will include the package the name *gluon-$flag* by default. ...@@ -82,43 +82,43 @@ Each flag *$flag* will include the package the name *gluon-$flag* by default.
The feature definition file can modify the package selection by adding or removing The feature definition file can modify the package selection by adding or removing
packages when certain combinations of flags are set. packages when certain combinations of flags are set.
Feature definitions use Lua syntax. The function *feature* has two arguments: Feature definitions use Lua syntax. Two basic functions are defined:
* A logical expression composed of feature flag names (each prefixed with an underscore before the opening * *feature(name, pkgs)*: Defines a new feature. *feature()* expects a feature
quotation mark), logical operators (*and*, *or*, *not*) and parentheses (flag) name and a list of packages to add or remove when the feature is
* A table with settings that are applied when the logical expression is enabled.
satisfied:
* Setting *nodefault* to *true* suppresses the default of including the *gluon-$flag* package. * Defining a feature using *feature* replaces the default definition of
This setting is only applicable when the logical expression is a single, just including *gluon-$flag*.
non-negated flag name. * A package is removed when the package name is prefixed with a ``-`` (after
* The *packages* field adds or removes packages to install. A package is the opening quotation mark).
removed when the package name is prefixed with a ``-`` (after the opening
quotation mark). * *when(expr, pkgs)*: Adds or removes packages when a given logical expression
of feature flags is satisfied.
* *expr* is a logical expression composed of feature flag names (each prefixed
with an underscore before the opening quotation mark), logical operators
(*and*, *or*, *not*) and parentheses.
* Referencing a feature flag in *expr* has no effect on the default handling
of the flag. When no *feature()* entry for a flag exists, it will still
add *gluon-$flag* by default.
* *pkgs* is handled as for *feature()*.
Example:: Example::
feature(_'web-wizard', { feature('web-wizard', {
nodefault = true, 'gluon-config-mode-hostname',
packages = { 'gluon-config-mode-geo-location',
'gluon-config-mode-hostname', 'gluon-config-mode-contact-info',
'gluon-config-mode-geo-location', 'gluon-config-mode-outdoor',
'gluon-config-mode-contact-info',
'gluon-config-mode-outdoor',
},
}) })
feature(_'web-wizard' and (_'mesh-vpn-fastd' or _'mesh-vpn-tunneldigger'), { when(_'web-wizard' and (_'mesh-vpn-fastd' or _'mesh-vpn-tunneldigger'), {
packages = { 'gluon-config-mode-mesh-vpn',
'gluon-config-mode-mesh-vpn',
},
}) })
feature(_'no-radvd', { feature('no-radvd', {
nodefault = true, '-gluon-radvd',
packages = {
'-gluon-radvd',
},
}) })
......
...@@ -5,65 +5,48 @@ ...@@ -5,65 +5,48 @@
-- file format -- file format
feature(_'web-wizard', { feature('web-wizard', {
nodefault = true, 'gluon-config-mode-hostname',
packages = { 'gluon-config-mode-geo-location',
'gluon-config-mode-hostname', 'gluon-config-mode-contact-info',
'gluon-config-mode-geo-location', 'gluon-config-mode-outdoor',
'gluon-config-mode-contact-info',
'gluon-config-mode-outdoor',
},
}) })
feature(_'web-wizard' and _'autoupdater', { when(_'web-wizard' and _'autoupdater', {
packages = { 'gluon-config-mode-autoupdater',
'gluon-config-mode-autoupdater',
},
}) })
feature(_'web-wizard' and (_'mesh-vpn-fastd' or _'mesh-vpn-tunneldigger'), { when(_'web-wizard' and (_'mesh-vpn-fastd' or _'mesh-vpn-tunneldigger'), {
packages = { 'gluon-config-mode-mesh-vpn',
'gluon-config-mode-mesh-vpn',
},
}) })
feature(_'web-advanced', { feature('web-advanced', {
nodefault = true, 'gluon-web-admin',
packages = { 'gluon-web-network',
'gluon-web-admin', 'gluon-web-wifi-config',
'gluon-web-network',
'gluon-web-wifi-config',
},
}) })
feature(_'web-advanced' and _'autoupdater', { when(_'web-advanced' and _'autoupdater', {
packages = { 'gluon-web-autoupdater',
'gluon-web-autoupdater',
},
}) })
feature(_'status-page' and _'mesh-batman-adv-15', {
packages = { when(_'mesh-batman-adv-15', {
'gluon-status-page-mesh-batman-adv', 'gluon-ebtables-limit-arp',
}, 'gluon-radvd',
}) })
feature(_'mesh-batman-adv-15', { when(_'status-page' and _'mesh-batman-adv-15', {
packages = { 'gluon-status-page-mesh-batman-adv',
'gluon-ebtables-limit-arp',
'gluon-radvd',
},
}) })
feature(_'mesh-babel', {
packages = { when(_'mesh-babel', {
'gluon-radvd', 'gluon-radvd',
},
}) })
feature(not _'wireless-encryption-wpa3', {
packages = { when(not _'wireless-encryption-wpa3', {
'hostapd-mini', 'hostapd-mini',
},
}) })
...@@ -16,43 +16,58 @@ local function collect_keys(t) ...@@ -16,43 +16,58 @@ local function collect_keys(t)
return ret return ret
end end
function M.get_packages(file, features) function M.get_packages(files, features)
local feature_table = to_keys(features) local enabled_features = to_keys(features)
local handled_features = {}
local packages = {}
local funcs = {} local funcs = {}
function funcs._(feature) local function add_pkgs(pkgs)
if feature_table[feature] then for _, pkg in ipairs(pkgs or {}) do
return feature packages[pkg] = true
end end
end end
local nodefault = {} function funcs._(feature)
local packages = {} return enabled_features[feature] ~= nil
function funcs.feature(match, options) end
if not match then
return
end
if options.nodefault then function funcs.feature(feature, pkgs)
nodefault[match] = true assert(
type(feature) == 'string',
'Incorrect use of feature(): pass a feature name without _ as first argument')
if enabled_features[feature] then
handled_features[feature] = true
add_pkgs(pkgs)
end end
for _, package in ipairs(options.packages or {}) do
packages[package] = true end
function funcs.when(cond, pkgs)
assert(
type(cond) == 'boolean',
'Incorrect use of when(): pass a locical expression of _-prefixed strings as first argument')
if cond then
add_pkgs(pkgs)
end end
end end
-- Evaluate the feature definition file -- Evaluate the feature definition files
local f, err = loadfile(file) for _, file in ipairs(files) do
if not f then local f, err = loadfile(file)
error('Failed to parse feature definition: ' .. err) if not f then
error('Failed to parse feature definition: ' .. err)
end
setfenv(f, funcs)
f()
end end
setfenv(f, funcs)
f()
-- Handle default packages -- Handle default packages
for _, feature in ipairs(features) do for _, feature in ipairs(features) do
if not nodefault[feature] then if not handled_features[feature] then
packages['gluon-' .. feature] = true packages['gluon-' .. feature] = true
end end
end end
......
...@@ -91,21 +91,15 @@ local function site_packages(image) ...@@ -91,21 +91,15 @@ local function site_packages(image)
end end
local function feature_packages(features) local function feature_packages(features)
local pkgs = {} local files = {'package/features'}
local function handle_feature_file(file)
pkgs = concat_list(pkgs, feature_lib.get_packages(file, features))
end
handle_feature_file('package/features')
for _, feed in ipairs(feeds) do for _, feed in ipairs(feeds) do
local path = string.format('packages/%s/features', feed) local path = string.format('packages/%s/features', feed)
if file_exists(path) then if file_exists(path) then
handle_feature_file(path) table.insert(files, path)
end end
end end
return pkgs return feature_lib.get_packages(files, features)
end end
-- This involves running a few processes to evaluate site.mk, so we add a simple cache -- This involves running a few processes to evaluate site.mk, so we add a simple cache
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment