From 0834985205e1a26d86dab8122693ef657798b06d Mon Sep 17 00:00:00 2001 From: lemoer Date: Sat, 28 Oct 2017 17:05:53 +0200 Subject: [PATCH] check_site_lib: merge site & domain and provide restricting feature - provide in_domain() and in_site() functions to restrict usage: need_string('foo.bar') -- allowed in both domain and site config need_string(in_site('foo.bar')) -- only allowed in site config need_string(in_domain('foo.bar')) -- only allowed in domain config - need_* merge the domain and site configs while prefering the domain values --- package/gluon-site/Makefile | 7 +- package/gluon.mk | 19 +++++- scripts/check_site_lib.lua | 128 +++++++++++++++++++++++++++--------- scripts/domain_config.lua | 13 ++++ 4 files changed, 133 insertions(+), 34 deletions(-) create mode 100644 scripts/domain_config.lua diff --git a/package/gluon-site/Makefile b/package/gluon-site/Makefile index 124dc49b..8118b5f8 100644 --- a/package/gluon-site/Makefile +++ b/package/gluon-site/Makefile @@ -8,7 +8,7 @@ PKG_VERSION:=$(if $(DUMP),x,$(GLUON_SITE_VERSION)) PKG_CONFIG_DEPENDS := CONFIG_GLUON_RELEASE CONFIG_GLUON_SITEDIR -PKG_FILE_DEPENDS := $(GLUON_SITEDIR)/site.conf $(GLUON_SITEDIR)/i18n/ +PKG_FILE_DEPENDS := $(GLUON_SITEDIR)/site.conf $(GLUON_SITEDIR)/domains/ $(GLUON_SITEDIR)/i18n/ PKG_BUILD_DEPENDS := lua-cjson/host PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) @@ -38,6 +38,7 @@ endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) + mkdir -p $(PKG_BUILD_DIR)/domains endef define Build/Configure @@ -45,12 +46,16 @@ endef define Build/Compile GLUON_SITEDIR='$(call qstrip,$(CONFIG_GLUON_SITEDIR))' lua -e 'print(require("cjson").encode(assert(dofile("../../scripts/site_config.lua"))))' > $(PKG_BUILD_DIR)/site.json + ls $(call qstrip,$(CONFIG_GLUON_SITEDIR))/domains/*.conf > /dev/null # at least one domain cfg has to exist + for domain_cfg in `find $(call qstrip,$(CONFIG_GLUON_SITEDIR))/domains/ -iname \*.conf -printf "%f\n"`; do dc=$$$${domain_cfg%.conf}; GLUON_SITEDIR='$(call qstrip,$(CONFIG_GLUON_SITEDIR))' lua -e 'print(require("cjson").encode(assert(dofile("../../scripts/domain_config.lua")("'$$$${dc}'"))))' > $(PKG_BUILD_DIR)/domains/$$$${dc}.json; done $(call GluonBuildI18N,gluon-site,$(GLUON_SITEDIR)/i18n) endef define Package/gluon-site/install $(INSTALL_DIR) $(1)/lib/gluon $(INSTALL_DATA) $(PKG_BUILD_DIR)/site.json $(1)/lib/gluon/ + $(INSTALL_DIR) $(1)/lib/gluon/domains + $(CP) $(PKG_BUILD_DIR)/domains/*.json $(1)/lib/gluon/domains/ echo '$(GLUON_SITE_VERSION)' > $(1)/lib/gluon/site-version echo '$(call qstrip,$(CONFIG_GLUON_RELEASE))' > $(1)/lib/gluon/release diff --git a/package/gluon.mk b/package/gluon.mk index ab46dc22..e20d6bf9 100644 --- a/package/gluon.mk +++ b/package/gluon.mk @@ -11,7 +11,24 @@ local site_json = f:read('*a') f:close() site = require('cjson').decode(site_json) -$(shell cat '$(TOPDIR)/../scripts/check_site_lib.lua' '$(1)' | sed -ne '1h; 1!H; $$ {g; s/@/+@/g; s/\n/-@/g; p}') + +function check_domain(domain_code, domain) + $(shell cat '$(TOPDIR)/../scripts/check_site_lib.lua' '$(1)' | sed -ne '1h; 1!H; $$ {g; s/@/+@/g; s/\n/-@/g; p}') +end + +local dir = os.getenv('IPKG_INSTROOT') .. '/lib/gluon/domains/' +local pfile = io.popen('find '..dir..' -iname \\*.json') +for domain_path in pfile:lines() do + local domain_code = string.gmatch(domain_path, '([^/]+).json$$')() + local f = assert(io.open(domain_path)) + local domain_json = f:read('*a') + f:close() + + domain = require('cjson').decode(domain_json) + + check_domain(domain_code, domain) +end +pfile:close() END__GLUON__CHECK__SITE endef diff --git a/scripts/check_site_lib.lua b/scripts/check_site_lib.lua index 9e2bd135..a82e8352 100644 --- a/scripts/check_site_lib.lua +++ b/scripts/check_site_lib.lua @@ -1,9 +1,32 @@ local function loadvar(varname) - local ok, val = pcall(assert(loadstring('return site.' .. varname))) - if ok then - return val + local ok, val = pcall(assert(loadstring('return domain.' .. varname))) + if ok and val ~= nil then + return val, 'domains/'..domain_code..'.conf' + end + + ok, val = pcall(assert(loadstring('return site.' .. varname))) + if ok and val ~= nil then + return val, 'site.conf' else - return nil + return nil, 'site.conf or domains/'..domain_code..'.conf' + end +end + +local function loadvar_domain(varname) + local ok, val = pcall(assert(loadstring('return domain.' .. varname))) + if ok then + return val, 'domains/'..domain_code..'.conf' + else + return nil, 'domains/'..domain_code..'.conf' + end +end + +local function loadvar_site(varname) + ok, val = pcall(assert(loadstring('return site.' .. varname))) + if ok then + return val, 'site.conf' + else + return nil, 'site.conf' end end @@ -32,68 +55,87 @@ local function assert_type(var, t, msg) assert(type(var) == t, msg) end +-- returns an unique keys in keys of returned table +function keys_merged(a, b) + keys_table = {} + for k, _ in pairs(a or {}) do + keys_table[k] = 1 + end + for k, _ in pairs(b or {}) do + keys_table[k] = 1 + end + return keys_table +end -function assert_uci_name(var) +function forbid_in_domain(varname) + local ok, val = pcall(assert(loadstring('return domain.' .. varname))) + assert(not ok or val == nil, "domains/"..domain_code..".conf error: `"..varname.."` is not allowed in domain specific config.") +end + +function forbid_in_site(varname) + local ok, val = pcall(assert(loadstring('return site.' .. varname))) + assert(not ok or val == nil, "site.conf error: `"..varname.."` is not allowed in site config.") +end + +function assert_uci_name(var, conf_name) -- We don't use character classes like %w here to be independent of the locale - assert(var:match('^[0-9a-zA-Z_]+$'), "site.conf error: `" .. var .. "' is not a valid config section name (only alphanumeric characters and the underscore are allowed)") + assert(var:match('^[0-9a-zA-Z_]+$'), conf_name.." error: `" .. var .. "' is not a valid config section name (only alphanumeric characters and the underscore are allowed)") end function need_string(varname, required) - local var = loadvar(varname) + local var, conf_name = loadvar(varname) if required == false and var == nil then - return nil + return nil, conf_name end - assert_type(var, 'string', "site.conf error: expected `" .. varname .. "' to be a string") - return var + assert_type(var, 'string', conf_name .. " error: expected `" .. varname .. "' to be a string") + return var, conf_name end function need_string_match(varname, pat, required) - local var = need_string(varname, required) + local var, conf_name = need_string(varname, required) if not var then return nil end - assert(var:match(pat), "site.conf error: expected `" .. varname .. "' to match pattern `" .. pat .. "'") + assert(var:match(pat), conf_name.." error: expected `" .. varname .. "' to match pattern `" .. pat .. "'") return var end function need_number(varname, required) - local var = loadvar(varname) + local var, conf_name = loadvar(varname) if required == false and var == nil then return nil end - assert_type(var, 'number', "site.conf error: expected `" .. varname .. "' to be a number") + assert_type(var, 'number', conf_name.." error: expected `" .. varname .. "' to be a number") return var end function need_boolean(varname, required) - local var = loadvar(varname) + local var, conf_name = loadvar(varname) if required == false and var == nil then return nil end - assert_type(var, 'boolean', "site.conf error: expected `" .. varname .. "' to be a boolean") + assert_type(var, 'boolean', conf_name.." error: expected `" .. varname .. "' to be a boolean") return var end -function need_array(varname, subcheck, required) - local var = loadvar(varname) - +local function __need_array_from_var(var, varname, subcheck, required, conf_name) if required == false and var == nil then return nil end - assert_type(var, 'table', "site.conf error: expected `" .. varname .. "' to be an array") + assert_type(var, 'table', conf_name.." error: expected `" .. varname .. "' to be an array") for _, e in ipairs(var) do subcheck(e) @@ -102,18 +144,27 @@ function need_array(varname, subcheck, required) return var end +function need_array(varname, subcheck, required) + local var, conf_name = loadvar(varname) + return __need_array_from_var(var, varname, subcheck, required, conf_name) +end + + function need_table(varname, subcheck, required) - local var = loadvar(varname) + local var, conf_name = loadvar(varname) if required == false and var == nil then return nil end - assert_type(var, 'table', "site.conf error: expected `" .. varname .. "' to be a table") + assert_type(var, 'table', conf_name.." error: expected `" .. varname .. "' to be a table") + + local dvar = loadvar_domain(varname) + local svar = loadvar_site(varname) if subcheck then - for k, v in pairs(var) do - subcheck(k, v) + for k, _ in pairs(keys_merged(dvar, svar)) do + subcheck(k, conf_name) end end @@ -121,31 +172,44 @@ function need_table(varname, subcheck, required) end function need_one_of(varname, array, required) - local var = loadvar(varname) + local var, conf_name = loadvar(varname) if required == false and var == nil then return nil end - assert_one_of(var, array, "site.conf error: expected `" .. varname .. "' to be one of given array: " .. array_to_string(array)) + assert_one_of(var, array, conf_name.." error: expected `" .. varname .. "' to be one of given array: " .. array_to_string(array)) return var end function need_string_array(varname, required) - local ok, var = pcall(need_array, varname, function(e) assert_type(e, 'string') end, required) - assert(ok, "site.conf error: expected `" .. varname .. "' to be a string array") + local var, conf_name = loadvar(varname) + local ok, var = pcall(__need_array_from_var, var, varname, function(e) assert_type(e, 'string') end, required, conf_name) + assert(ok, conf_name.." error: expected `" .. varname .. "' to be a string array") return var end function need_string_array_match(varname, pat, required) - local ok, var = pcall(need_array, varname, function(e) assert(e:match(pat)) end, required) - assert(ok, "site.conf error: expected `" .. varname .. "' to be a string array matching pattern `" .. pat .. "'") + local var, conf_name = loadvar(varname) + local ok, var = pcall(__need_array_from_var, var, varname, function(e) assert(e:match(pat)) end, required, conf_name) + assert(ok, conf_name.." error: expected `" .. varname .. "' to be a string array matching pattern `" .. pat .. "'") return var end function need_array_of(varname, array, required) - local ok, var = pcall(need_array, varname, function(e) assert_one_of(e, array) end,required) - assert(ok, "site.conf error: expected `" .. varname .. "' to be a subset of given array: " .. array_to_string(array)) + local var, conf_name = loadvar(varname) + local ok, var = pcall(__need_array_from_var, var, varname, function(e) assert_one_of(e, array) end, required, conf_name) + assert(ok, conf_name.." error: expected `" .. varname .. "' to be a subset of given array: " .. array_to_string(array)) + return var +end + +function in_domain(var) + forbid_in_site(var) + return var +end + +function in_site(var) + forbid_in_domain(var) return var end diff --git a/scripts/domain_config.lua b/scripts/domain_config.lua new file mode 100644 index 00000000..1e166f66 --- /dev/null +++ b/scripts/domain_config.lua @@ -0,0 +1,13 @@ +local function load_domain(domain_code) + local config = os.getenv('GLUON_SITEDIR') + + local function loader() + coroutine.yield('return ') + coroutine.yield(io.open(config .. '/domains/' .. domain_code .. '.conf'):read('*a')) + end + + -- setfenv doesn't work with Lua 5.2 anymore, but we're using 5.1 + return setfenv(assert(load(coroutine.wrap(loader), 'domains/' .. domain_code .. '.conf')), {})() +end + +return load_domain