Switch to Lua for target definitions

The old bash-based parsing code was way too complex. Replace it with Lua.
parent a44a5dce
......@@ -87,18 +87,14 @@ GLUON_CONFIG_VARS := \
BOARD='$(BOARD)' \
SUBTARGET='$(SUBTARGET)'
OPENWRT_TARGET := $(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
export OPENWRT_TARGET
CheckTarget := [ '$(OPENWRT_TARGET)' ] \
CheckTarget := [ '$(BOARD)' ] \
|| (echo 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:'; $(foreach target,$(GLUON_TARGETS),echo ' * $(target)';) false)
CheckExternal := test -d openwrt || (echo 'You don'"'"'t seem to have obtained the external repositories needed by Gluon; please call `make update` first!'; false)
define CheckSite
@GLUON_SITEDIR='$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' $(LUA) scripts/site_config.lua \
@GLUON_SITEDIR='$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' $(LUA) -e 'assert(dofile("scripts/site_config.lua")(os.getenv("GLUON_SITE_CONFIG")))' \
|| (echo 'Your site configuration ($(1).conf) did not pass validation.'; false)
endef
......@@ -123,18 +119,6 @@ define merge_packages
endef
$(eval $(call merge_packages,$(GLUON_DEFAULT_PACKAGES) $(GLUON_FEATURE_PACKAGES) $(GLUON_SITE_PACKAGES)))
config: FORCE
@$(CheckExternal)
@$(CheckTarget)
@$(GLUON_CONFIG_VARS) \
scripts/target_config.sh '$(GLUON_TARGET)' '$(GLUON_PACKAGES)' \
> openwrt/.config
+@$(OPENWRTMAKE) defconfig
@$(GLUON_CONFIG_VARS) \
scripts/target_config_check.sh '$(GLUON_TARGET)' '$(GLUON_PACKAGES)'
LUA := openwrt/staging_dir/hostpkg/bin/lua
......@@ -145,14 +129,27 @@ $(LUA):
+@$(OPENWRTMAKE) tools/install
+@$(OPENWRTMAKE) package/lua/host/compile
prepare-target: config $(LUA) ;
all: prepare-target
config: $(LUA) FORCE
@$(CheckExternal)
@$(CheckTarget)
$(foreach conf,site $(patsubst $(GLUON_SITEDIR)/%.conf,%,$(wildcard $(GLUON_SITEDIR)/domains/*.conf)),$(call CheckSite,$(conf)))
@scripts/clean_output.sh
@$(GLUON_CONFIG_VARS) \
$(LUA) scripts/target_config.lua '$(GLUON_TARGET)' '$(GLUON_PACKAGES)' \
> openwrt/.config
+@$(OPENWRTMAKE) defconfig
@$(GLUON_CONFIG_VARS) \
$(LUA) scripts/target_config_check.lua '$(GLUON_TARGET)' '$(GLUON_PACKAGES)'
all: config
@$(GLUON_CONFIG_VARS) \
$(LUA) scripts/clean_output.lua
+@$(OPENWRTMAKE)
@GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/copy_output.sh '$(GLUON_TARGET)'
@$(GLUON_CONFIG_VARS) \
$(LUA) scripts/copy_output.lua '$(GLUON_TARGET)'
clean download: config
+@$(OPENWRTMAKE) $@
......@@ -173,7 +170,7 @@ manifest: $(LUA) FORCE
echo 'PRIORITY=$(GLUON_PRIORITY)' && \
echo && \
$(foreach GLUON_TARGET,$(GLUON_TARGETS), \
GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/generate_manifest.sh '$(GLUON_TARGET)' && \
GLUON_SITEDIR='$(GLUON_SITEDIR)' $(LUA) scripts/generate_manifest.lua '$(GLUON_TARGET)' && \
) : \
) > 'tmp/$(GLUON_BRANCH).manifest.tmp'
......
......@@ -37,7 +37,9 @@ config GLUON_MULTIDOMAIN
endef
define GenerateJSON
GLUON_SITEDIR='$$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' lua -e 'print(require("cjson").encode(assert(dofile("../../scripts/site_config.lua"))))' > '$$(PKG_BUILD_DIR)/$(1).json'
GLUON_SITEDIR='$$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' \
lua -e 'print(require("cjson").encode(assert(dofile("../../scripts/site_config.lua")(os.getenv("GLUON_SITE_CONFIG")))))' \
> '$$(PKG_BUILD_DIR)/$(1).json'
endef
define Build/Compile
......
dofile('scripts/common.inc.lua')
local subtarget = env.SUBTARGET
if subtarget == '' then
subtarget = 'generic'
end
local bindir = env.BOARD .. '/' .. subtarget
exec({'rm', '-f', 'openwrt/bin/targets/'..bindir..'/\0'}, true, '2>/dev/null')
-- Full builds will output the "packages" directory, so clean up first
if (env.GLUON_DEVICES or '') == '' then
exec {'rm', '-rf', 'openwrt/bin/targets/'..bindir..'/packages'}
end
#!/usr/bin/env bash
set -e
[ "$OPENWRT_TARGET" ] || exit 1
. scripts/common.inc.sh
if [ "$(expr match "$OPENWRT_TARGET" '.*-.*')" -gt 0 ]; then
OPENWRT_BINDIR="${OPENWRT_TARGET//-/\/}"
else
OPENWRT_BINDIR="${OPENWRT_TARGET}/generic"
fi
rm -f "openwrt/bin/targets/${OPENWRT_BINDIR}"/* 2>/dev/null || true
# Full builds will output the "packages" directory, so clean up first
[ "$GLUON_DEVICES" ] || rm -rf "openwrt/bin/targets/${OPENWRT_BINDIR}/packages"
env = setmetatable({}, {
__index = function(t, k) return os.getenv(k) end
})
envtrue = setmetatable({}, {
__index = function(t, k) return (tonumber(os.getenv(k)) or 0) > 0 end
})
assert(env.GLUON_SITEDIR)
assert(env.GLUON_TARGETSDIR)
assert(env.GLUON_RELEASE)
site_code = assert(assert(dofile('scripts/site_config.lua')('site.conf')).site_code)
target_packages = {}
local default_options = {
profile = false,
factory = '-squashfs-factory',
factory_ext = '.bin',
sysupgrade = '-squashfs-sysupgrade',
sysupgrade_ext = '.bin',
extra_images = {},
aliases = {},
manifest_aliases = {},
packages = {},
broken = false,
}
local gluon_devices, unknown_devices = {}, {}
for dev in string.gmatch(env.GLUON_DEVICES or '', '%S+') do
gluon_devices[dev] = true
unknown_devices[dev] = true
end
local function want_device(dev, options)
if options.broken and not envtrue.BROKEN then
return false
end
if (env.GLUON_DEVICES or '') == '' then
return true
end
unknown_devices[dev] = nil
return gluon_devices[dev]
end
local function merge(a, b)
local ret = {}
for k, v in pairs(a) do
ret[k] = v
end
for k, v in pairs(b or {}) do
assert(ret[k] ~= nil, string.format("unknown option '%s'", k))
ret[k] = v
end
return ret
end
-- Escapes a single argument to be used in a shell command
-- The argument is surrounded by single quotes, single quotes inside the
-- argument are replaced by '\''.
-- To allow using shell wildcards, zero bytes in the arguments are replaced
-- by unquoted asterisks.
function escape(s)
s = string.gsub(s, "'", "'\\''")
s = string.gsub(s, "%z", "'*'")
return "'" .. s .. "'"
end
local function escape_command(command, raw)
local ret = 'exec'
for _, arg in ipairs(command) do
ret = ret .. ' ' .. escape(arg)
end
if raw then
ret = ret .. ' ' .. raw
end
return ret
end
function exec_raw(command, may_fail)
local ret = os.execute(command)
assert((ret == 0) or may_fail)
return ret
end
function exec(command, may_fail, raw)
return exec_raw(escape_command(command, raw), may_fail)
end
function exec_capture_raw(command)
local f = io.popen(command)
assert(f)
local data = f:read('*a')
f:close()
return data
end
function exec_capture(command, raw)
return exec_capture_raw(escape_command(command, raw))
end
local image_mt = {
__index = {
dest_name = function(image, name, site, release)
return env.GLUON_IMAGEDIR..'/'..image.subdir, 'gluon-'..(site or site_code)..'-'..(release or env.GLUON_RELEASE)..'-'..name..image.out_suffix..image.extension
end,
},
}
local function add_image(image)
table.insert(images, setmetatable(image, image_mt))
end
-- Variables to be consumed by scripts using common.inc.lua
devices = {}
images = {}
opkg = true
function config() end
function try_config() end
function packages(pkgs)
for _, pkg in ipairs(pkgs) do
table.insert(target_packages, pkg)
end
end
function device(image, name, options)
options = merge(default_options, options)
if not want_device(image, options) then
return
end
table.insert(devices, {
image = image,
name = name,
options = options,
})
if options.factory then
add_image {
image = image,
name = name,
subdir = 'factory',
in_suffix = options.factory,
out_suffix = '',
extension = options.factory_ext,
aliases = options.aliases,
manifest_aliases = options.manifest_aliases,
}
end
if options.sysupgrade then
add_image {
image = image,
name = name,
subdir = 'sysupgrade',
in_suffix = options.sysupgrade,
out_suffix = '-sysupgrade',
extension = options.sysupgrade_ext,
aliases = options.aliases,
manifest_aliases = options.manifest_aliases,
}
end
for _, extra_image in ipairs(options.extra_images) do
add_image {
image = image,
name = name,
subdir = 'other',
in_suffix = extra_image[1],
out_suffix = extra_image[2],
extension = extra_image[3],
aliases = options.aliases,
manifest_aliases = options.manifest_aliases,
}
end
end
function factory_image(image, name, ext, options)
options = merge(default_options, options)
if not want_device(image, options) then
return
end
add_image {
image = image,
name = name,
subdir = 'factory',
in_suffix = '',
out_suffix = '',
extension = ext,
aliases = options.aliases,
manifest_aliases = options.manifest_aliases,
}
end
function sysupgrade_image(image, name, ext, options)
options = merge(default_options, options)
if not want_device(image, options) then
return
end
add_image {
image = image,
name = name,
subdir = 'sysupgrade',
in_suffix = '',
out_suffix = '-sysupgrade',
extension = ext,
aliases = options.aliases,
manifest_aliases = options.manifest_aliases,
}
end
function no_opkg()
opkg = false
end
function defaults(options)
default_options = merge(default_options, options)
end
function check_devices()
local device_list = {}
for device in pairs(unknown_devices) do
table.insert(device_list, device)
end
if #device_list ~= 0 then
table.sort(device_list)
io.stderr:write('Error: unknown devices given: ', table.concat(device_list, ' '), '\n')
os.exit(1)
end
end
config() {
:
}
try_config() {
:
}
device() {
:
}
factory_image() {
:
}
sysupgrade_image() {
:
}
alias() {
:
}
manifest_alias() {
:
}
packages() {
:
}
factory() {
:
}
sysupgrade() {
:
}
extra_image() {
:
}
no_opkg() {
:
}
unknown_devices="$GLUON_DEVICES"
want_device() {
[ "$GLUON_DEVICES" ] || return 0
local new_devices=''
for device in $unknown_devices; do
if [ "$device" != "$1" ]; then
new_devices="${new_devices:+${new_devices} }$device"
fi
done
unknown_devices=$new_devices
for device in $GLUON_DEVICES; do
if [ "$device" = "$1" ]; then
return 0
fi
done
return 1
}
check_devices() {
if [ "$unknown_devices" ]; then
echo "Error: unknown devices given: ${unknown_devices}" >&2
exit 1
fi
}
dofile('scripts/common.inc.lua')
assert(env.GLUON_IMAGEDIR)
assert(env.GLUON_PACKAGEDIR)
assert(env.GLUON_TARGETSDIR)
local target = arg[1]
local openwrt_target
local subtarget = env.SUBTARGET
if subtarget ~= '' then
openwrt_target = env.BOARD .. '-' .. subtarget
else
openwrt_target = env.BOARD
subtarget = 'generic'
end
local bindir = env.BOARD .. '/' .. subtarget
local function mkdir(dir)
exec {'mkdir', '-p', dir}
end
mkdir(env.GLUON_IMAGEDIR..'/factory')
mkdir(env.GLUON_IMAGEDIR..'/sysupgrade')
mkdir(env.GLUON_IMAGEDIR..'/other')
dofile(env.GLUON_TARGETSDIR..'/'..target)
local function clean(image, name)
local dir, file = image:dest_name(name, '\0', '\0')
exec {'rm', '-f', dir..'/'..file}
end
for _, image in ipairs(images) do
clean(image, image.image)
local destdir, destname = image:dest_name(image.image)
local source = string.format('openwrt/bin/targets/%s/openwrt-%s-%s%s%s', bindir, openwrt_target, image.name, image.in_suffix, image.extension)
exec {'cp', source, destdir..'/'..destname}
for _, alias in ipairs(image.aliases) do
clean(image, alias)
local _, aliasname = image:dest_name(alias)
exec {'ln', '-s', destname, destdir..'/'..aliasname}
end
end
-- Copy opkg repo
if opkg and (env.GLUON_DEVICES or '') == '' then
local package_prefix = string.format('gluon-%s-%s', site_code, env.GLUON_RELEASE)
local function dest_dir(prefix)
return env.GLUON_PACKAGEDIR..'/'..prefix..'/'..bindir
end
exec {'rm', '-f', dest_dir('\0')..'/\0'}
exec({'rmdir', '-p', dest_dir('\0')}, true, '2>/dev/null')
mkdir(dest_dir(package_prefix))
exec {'cp', 'openwrt/bin/targets/'..bindir..'/packages/\0', dest_dir(package_prefix)}
end
#!/usr/bin/env bash
set -e
[ "$GLUON_IMAGEDIR" -a "$GLUON_PACKAGEDIR" -a "$OPENWRT_TARGET" -a "$GLUON_RELEASE" -a "$GLUON_SITEDIR" -a "$GLUON_TARGETSDIR" ] || exit 1
default_factory_ext='.bin'
default_factory_suffix='-squashfs-factory'
default_sysupgrade_ext='.bin'
default_sysupgrade_suffix='-squashfs-sysupgrade'
default_extra_images=
output=
profile=
aliases=
factory_ext=
factory_suffix=
sysupgrade_ext=
sysupgrade_suffix=
extra_images=
no_opkg=
mkdir -p "${GLUON_IMAGEDIR}/factory" "${GLUON_IMAGEDIR}/sysupgrade" "${GLUON_IMAGEDIR}/other"
if [ "$(expr match "$OPENWRT_TARGET" '.*-.*')" -gt 0 ]; then
OPENWRT_BINDIR="${OPENWRT_TARGET//-/\/}"
else
OPENWRT_BINDIR="${OPENWRT_TARGET}/generic"
fi
SITE_CODE="$(scripts/site.sh site_code)"
PACKAGE_PREFIX="gluon-${SITE_CODE}-${GLUON_RELEASE}"
do_clean() {
local dir="$1"
local out_suffix="$2"
local ext="$3"
local name="$4"
rm -f "${GLUON_IMAGEDIR}/${dir}/gluon-"*"-${name}${out_suffix}${ext}"
}
get_file() {
local dir="$1"
local out_suffix="$2"
local ext="$3"
local name="$4"
echo "${GLUON_IMAGEDIR}/${dir}/gluon-${SITE_CODE}-${GLUON_RELEASE}-${name}${out_suffix}${ext}"
}
do_copy() {
local dir="$1"
local in_suffix="$2"
local out_suffix="$3"
local ext="$4"
local aliases="$5"
local file="$(get_file "$dir" "$out_suffix" "$ext" "$output")"
do_clean "$dir" "$out_suffix" "$ext" "$output"
cp "openwrt/bin/targets/${OPENWRT_BINDIR}/openwrt-${OPENWRT_TARGET}${profile}${in_suffix}${ext}" "$file"
for alias in $aliases; do
do_clean "$dir" "$out_suffix" "$ext" "$alias"
ln -s "$(basename "$file")" "$(get_file "$dir" "$out_suffix" "$ext" "$alias")"
done
}
copy() {
[ "$output" ] || return 0
want_device "$output" || return 0
[ -z "$factory_ext" ] || do_copy 'factory' "$factory_suffix" '' "$factory_ext" "$aliases"
[ -z "$sysupgrade_ext" ] || do_copy 'sysupgrade' "$sysupgrade_suffix" '-sysupgrade' "$sysupgrade_ext" "$aliases"
echo -n "$extra_images" | while read in_suffix && read out_suffix && read ext; do
do_copy 'other' "$in_suffix" "$out_suffix" "$ext" "$aliases"
done
}
. scripts/common.inc.sh
device() {
copy
output="$1"
profile="-$2"
aliases=
factory_ext="$default_factory_ext"
factory_suffix="$default_factory_suffix"
sysupgrade_ext="$default_sysupgrade_ext"
sysupgrade_suffix="$default_sysupgrade_suffix"
extra_images="$default_extra_images"
}
factory_image() {
copy
output="$1"
aliases=
if [ "$3" ]; then
profile="-$2"
factory_ext="$3"
else
profile=""
factory_ext="$2"