Skip to content

Commit

Permalink
build: implement flexible site-selection system
Browse files Browse the repository at this point in the history
Implement a flexible system for handling site-defined features as well
as packages.

This system is inspired by the existing feature-system and allows for a
more flexible approach for selecting specific packages for devices.

Features are now defined in a `features` file in the site-root. The same
goes for packages.

These files are sequentially evaluated and the device-package list is
evaluated for each device independently.

Signed-off-by: David Bauer <mail@david-bauer.net>
  • Loading branch information
blocktrron committed Nov 6, 2023
1 parent 0e9f9e7 commit 92ac0bb
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 45 deletions.
16 changes: 16 additions & 0 deletions docs/site-example/features
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
default({
'autoupdater',
'ebtables-filter-multicast',
'ebtables-filter-ra-dhcp',
'ebtables-limit-arp',
'mesh-batman-adv-15',
'mesh-vpn-fastd',
'respondd',
'status-page',
'web-advanced',
'web-wizard'
})

when(not device_class('tiny'), {
'wireless-encryption-wpa3'
})
3 changes: 3 additions & 0 deletions docs/site-example/packages
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
default({
'iwinfo',
})
28 changes: 0 additions & 28 deletions docs/site-example/site.mk
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
## gluon site.mk makefile example

## GLUON_FEATURES
# Specify Gluon features/packages to enable;
# Gluon will automatically enable a set of packages
# depending on the combination of features listed

GLUON_FEATURES := \
autoupdater \
ebtables-filter-multicast \
ebtables-filter-ra-dhcp \
ebtables-limit-arp \
mesh-batman-adv-15 \
mesh-vpn-fastd \
respondd \
status-page \
web-advanced \
web-wizard

GLUON_FEATURES_standard := \
wireless-encryption-wpa3

## GLUON_SITE_PACKAGES
# Specify additional Gluon/OpenWrt packages to include here;
# A minus sign may be prepended to remove a packages from the
# selection that would be enabled by default or due to the
# chosen feature flags

GLUON_SITE_PACKAGES := iwinfo

## DEFAULT_GLUON_RELEASE
# version string to use for images
# gluon relies on
Expand Down
87 changes: 87 additions & 0 deletions scripts/site_selection_lib.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
local M = {}

local function collect_keys(t)
local ret = {}
for v in pairs(t) do
table.insert(ret, v)
end
return ret
end

function M.get_selection(files, env, dev)
local selections = {}

local funcs = {}

local function add_pkgs(pkgs)
for _, pkg in ipairs(pkgs or {}) do
selections[pkg] = true
end
end

function funcs.default(pkgs)
assert(
type(pkgs) == 'table',
'Incorrect use of default(): pass a list of packages as argument')

add_pkgs(pkgs)
end

function funcs.when(cond, pkgs)
assert(
type(cond) == 'boolean',
'Incorrect use of when(): pass a conditional expression as first argument')

if cond then
add_pkgs(pkgs)
end
end

function funcs.device(device_names)
assert(
type(device_names) == 'table',
'Incorrect use of device(): pass a list of device-names as argument')

for _, device_name in ipairs(device_names) do
if device_name == dev.image then
return true
end
end

return false
end

function funcs.target(target, subtarget)
assert(
type(target) == 'string',
'Incorrect use of target(): pass a target-name as first argument')

if target ~= env.BOARD then
return false
end

if subtarget and subtarget ~= env.SUBTARGET then
return false
end

return true
end

function funcs.device_class(class)
return dev.options.class == class
end

-- Evaluate the feature definition files
for _, file in ipairs(files) do
local f, err = loadfile(file)
if not f then
error('Failed to parse feature definition: ' .. err)
end
setfenv(f, funcs)
f()
end

return collect_keys(selections)
end

return M
31 changes: 14 additions & 17 deletions scripts/target_config_lib.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local lib = dofile('scripts/target_lib.lua')
local feature_lib = dofile('scripts/feature_lib.lua')
local site_selection_lib = dofile('scripts/site_selection_lib.lua')
local env = lib.env

local target = env.GLUON_TARGET
Expand Down Expand Up @@ -86,10 +87,6 @@ END_MAKE
lib.escape(var)))
end

local function site_packages(image)
return split(site_vars(string.format('$(GLUON_%s_SITE_PACKAGES)', image)))
end

local function feature_packages(features)
local files = {'package/features'}
for _, feed in ipairs(feeds) do
Expand All @@ -102,20 +99,21 @@ local function feature_packages(features)
return feature_lib.get_packages(files, features)
end

-- This involves running a few processes to evaluate site.mk, so we add a simple cache
local class_cache = {}
local function class_packages(class)
if class_cache[class] then
return class_cache[class]
end
local function site_specific_packages(dev_info)
-- First read enabled features from site
local features = site_selection_lib.get_selection({env.GLUON_SITEDIR .. '/features'}, env, dev_info)
features = compact_list(features, false)

-- Create List from packages inherited from features
local feature_inherited_pkgs = feature_packages(features)

local features = site_vars(string.format('$(GLUON_FEATURES) $(GLUON_FEATURES_%s)', class))
features = compact_list(split(features), false)
-- Read list of packages from site
local site_packages = site_selection_lib.get_selection({env.GLUON_SITEDIR .. '/packages'}, env, dev_info)

local pkgs = feature_packages(features)
pkgs = concat_list(pkgs, split(site_vars(string.format('$(GLUON_SITE_PACKAGES) $(GLUON_SITE_PACKAGES_%s)', class))))
-- Concat feature-packages with site-packages
local pkgs = concat_list(feature_inherited_pkgs, site_packages)

class_cache[class] = pkgs
-- Negations for the resulting package-list are dealt with in the calling function
return pkgs
end

Expand Down Expand Up @@ -192,9 +190,8 @@ for _, dev in ipairs(lib.devices) do
end

handle_pkgs(lib.target_packages)
handle_pkgs(class_packages(dev.options.class))
handle_pkgs(dev.options.packages or {})
handle_pkgs(site_packages(dev.image))
handle_pkgs(site_specific_packages(dev))

local profile_config = string.format('%s_DEVICE_%s', openwrt_config_target, dev.name)
lib.config(
Expand Down

0 comments on commit 92ac0bb

Please sign in to comment.