Skip to content
Snippets Groups Projects
target_lib.lua 6.64 KiB
Newer Older
  • Learn to ignore specific revisions
  • local image_customization_lib = dofile('scripts/image_customization_lib.lua')
    
    
    -- Functions for use in targets/*
    local F = {}
    
    -- To be accessed by scripts using target_lib
    local M = setmetatable({}, { __index = F })
    
    local funcs = setmetatable({}, {
    	__index = function(_, k)
    		return F[k] or _G[k]
    	end,
    
    
    local env = setmetatable({}, {
    	__index = function(_, k) return os.getenv(k) end
    
    assert(env.GLUON_SITEDIR)
    assert(env.GLUON_TARGETSDIR)
    assert(env.GLUON_RELEASE)
    
    assert(env.GLUON_DEPRECATED)
    
    M.site_code = assert(
    	dofile('scripts/site_config.lua')('site.conf').site_code, 'site_code missing in site.conf'
    )
    
    M.target_packages = {}
    M.configs = {}
    M.devices = {}
    M.images = {}
    
    
    
    local default_options = {
    	factory = '-squashfs-factory',
    	factory_ext = '.bin',
    	sysupgrade = '-squashfs-sysupgrade',
    	sysupgrade_ext = '.bin',
    	extra_images = {},
    	aliases = {},
    	manifest_aliases = {},
    	packages = {},
    
    	deprecated = false,
    
    	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
    
    
    function F.istrue(v)
    	return (tonumber(v) or 0) > 0
    end
    
    
    local function get_device_overrides(device_info)
    	return image_customization_lib.device_overrides(env, device_info)
    end
    
    local function device_broken(device_info, overrides)
    	if F.istrue(env.BROKEN) then
    
    
    	if overrides['broken'] ~= nil then
    		return overrides['broken'] == true
    	elseif device_info.options.broken then
    		return true
    	end
    
    	return false
    end
    
    local function want_device(device_info)
    	local overrides = get_device_overrides(device_info)
    
    	-- Check if device is disabled via image-customization in site
    	if overrides['disabled'] then
    		return false
    	end
    
    	if device_broken(device_info, overrides) then
    		return false
    	end
    
    	if device_info.options.deprecated and env.GLUON_DEPRECATED == '0' then
    
    		return false
    	end
    
    
    	if (env.GLUON_DEVICES or '') == '' then
    		return true
    	end
    
    
    	unknown_devices[device_info.image] = nil
    	return gluon_devices[device_info.image]
    
    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.
    
    	s = string.gsub(s, "'", "'\\''")
    	s = string.gsub(s, "%z", "'*'")
    	return "'" .. s .. "'"
    end
    
    local function escape_command(command, raw)
    
    	local ret = ''
    	if not raw then
    		ret = 'exec'
    	end
    
    	for _, arg in ipairs(command) do
    
    		ret = ret .. ' ' .. F.escape(arg)
    
    	end
    	if raw then
    		ret = ret .. ' ' .. raw
    	end
    	return ret
    end
    
    
    function F.exec_raw(command, may_fail)
    
    	local ret = os.execute(command)
    	assert((ret == 0) or may_fail)
    	return ret
    end
    
    
    function F.exec(command, may_fail, raw)
    	return F.exec_raw(escape_command(command, raw), may_fail)
    
    function F.exec_capture_raw(command)
    
    	local f = io.popen(command)
    	assert(f)
    
    	local data = f:read('*a')
    	f:close()
    	return data
    end
    
    
    function F.exec_capture(command, raw)
    	return F.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 M.site_code)..'-'..(release or env.GLUON_RELEASE)..'-'..name..image.out_suffix..image.extension
    
    		end,
    	},
    }
    
    local function add_image(image)
    
    	local device = image.image
    	M.images[device] = M.images[device] or {}
    	table.insert(M.images[device], setmetatable(image, image_mt))
    
    
    local function format_config(k, v)
    	local format
    	if type(v) == 'string' then
    		format = '%s=%q'
    	elseif v == true then
    		format = '%s=y'
    	elseif v == nil then
    		format = '%s=m'
    	elseif v == false then
    		format = '# %s is not set'
    	else
    		format = '%s=%d'
    	end
    
    	return string.format(format, 'CONFIG_' .. k, v)
    
    end
    
    local config_mt = {
    	__index = {
    		format = function(config)
    			return format_config(config.key, config.value)
    		end,
    	}
    }
    
    local function do_config(k, v, required)
    	M.configs[k] = setmetatable({
    		key = k,
    		value = v,
    		required = required,
    	}, config_mt)
    end
    
    function F.try_config(k, v)
    	do_config(k, v)
    
    function F.config(k, v, message)
    	if not message then
    		message = string.format("unable to set '%s'", format_config(k, v))
    	end
    	do_config(k, v, message)
    
    	for _, pkg in ipairs(pkgs) do
    
    		table.insert(M.target_packages, pkg)
    
    local function as_table(v)
    	if type(v) == 'table' then
    		return v
    	else
    		return {v}
    	end
    end
    
    
    local function disable_factory_image(device_info)
    	if device_info.options.deprecated and env.GLUON_DEPRECATED ~= 'full' then
    		return true
    	end
    
    	local overrides = get_device_overrides(device_info)
    	if overrides["disable_factory"] then
    		return true
    
    	return false
    end
    
    function F.device(image, name, options)
    	options = merge(default_options, options)
    
    	local device_info = {
    
    		image = image,
    		name = name,
    		options = options,
    
    	}
    
    	if not want_device(device_info) then
    		return
    	end
    
    	table.insert(M.devices, device_info)
    
    	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
    
    	if disable_factory_image(device_info) then
    
    		return
    	end
    
    	if options.factory then
    
    		for _, ext in ipairs(as_table(options.factory_ext)) do
    			add_image {
    				image = image,
    				name = name,
    				subdir = 'factory',
    				in_suffix = options.factory,
    				out_suffix = '',
    				extension = ext,
    				aliases = options.aliases,
    			}
    		end
    
    	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,
    		}
    	end
    end
    
    
    function F.defaults(options)
    
    	default_options = merge(default_options, options)
    end
    
    
    function F.include(name)
    	local f = assert(loadfile(env.GLUON_TARGETSDIR .. '/' .. name))
    	setfenv(f, funcs)
    	return f()
    end
    
    	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