Skip to content

Instantly share code, notes, and snippets.

@jow-
Last active March 7, 2022 18:52
Show Gist options
  • Save jow-/1ea62b00cad4172fc59d6efcef32569b to your computer and use it in GitHub Desktop.
Save jow-/1ea62b00cad4172fc59d6efcef32569b to your computer and use it in GitHub Desktop.
Dependency specs
"depends": {
/* fs: filesystem dependencies
* Either an array of dictionaries (each item being an ORed alternative)
* or single dictionary.
*/
"fs": [
/* Satisfied if either a non-empty directory /sys/class/ieee80211 exists... */
{ "directory": "/sys/class/ieee80211" },
/* ... or an executable file /usr/bin/whatever... */
{ "executable": "/usr/bin/whatever" },
/* ... or a regular file /etc/config/blub */
{ "file": "/etc/config/blub" }
],
/* uci: uci dependencies
* Either an array of dictionaries (each item being an ORed alternative)
* or single dictionary.
*/
"uci": [
/* Satisfied if non-empty "foo" uci config exists ... */
{ "foo": true },
/* Satisfied if at least one typed, non-empty section "bar" in config "foo" exists */
{ "foo": { "@bar": true } },
/* Satisfied if at least one typed section "bar" in config "foo" with option "baz" exists */
{ "foo": { "@bar": { "baz": true } } },
/* Satisfied if at least one typed section "bar" in config "foo" with option "baz" equal to "qrx" exists */
{ "foo": { "@bar": { "baz": "qrx" } } },
/* Satisfied if a named, non-empty section "abc" in config "foo" exists */
{ "foo": { "abc": true } },
/* Satisfied if a named section "abc" in config "foo" with option "baz" exists */
{ "foo": { "abc": { "baz": true } } },
/* Satisfied if a named section "abc" in config "foo" with option "baz" equal to "qrx" exists */
{ "foo": { "abc": { "baz": "qrx" } } },
]
}
// If there's only one alternative, the array container may be omitted:
"depends": {
"fs": { "file": "/etc/config/blub" },
"uci": { "wireless": { "@wifi-device": true } }
}
// Multiple fields within a dictionary are AND-ed
"depends": {
"fs": {
"executable": "/sbin/fw4",
"file": "/etc/config/firewall"
}
}
function check_fs_depends(spec) {
for (let path, kind in spec) {
if (kind == 'directory') {
if (!length(fs.lsdir(path)))
return false;
}
else if (kind == 'executable') {
let stat = fs.stat(path);
if (stat?.type != 'file' || stat?.user_exec == false)
return false;
}
else if (kind == 'file') {
let stat = fs.stat(path);
if (stat?.type != 'file')
return false;
}
}
return true;
}
function check_uci_depends_options(conf, s, opts) {
if (type(opts) == 'string') {
return (s['.type'] == opts);
}
else if (opts === true) {
for (let option, value in s)
if (ord(option) != 46)
return true;
}
else if (type(opts) == 'object') {
for (let option, value in opts) {
let sval = s[option];
if (type(sval) == 'array') {
if (!(value in sval))
return false;
}
else if (value === true) {
if (sval == null)
return false;
}
else {
if (sval != value)
return false;
}
}
}
return true;
}
function check_uci_depends_section(conf, sect) {
for (let section, options in sect) {
let stype = match(section, /^@([A-Za-z0-9_-]+)$/);
if (stype) {
let found = false;
uci.load(conf);
uci.foreach(conf, stype[1], (s) => {
if (check_uci_depends_options(conf, s, options)) {
found = true;
return false;
}
});
if (!found)
return false;
}
else {
let s = uci.get_all(conf, section);
if (!s || !check_uci_depends_options(conf, s, options))
return false;
}
}
return true;
}
function check_uci_depends(conf) {
for (let config, values in conf) {
if (values == true) {
let found = false;
uci.load(config);
uci.foreach(config, null, () => { found = true });
if (!found)
return false;
}
else if (type(values) == 'object') {
if (!check_uci_depends_section(config, values))
return false;
}
}
return true;
}
function check_depends(spec) {
if (type(spec?.depends?.fs) in ['array', 'object']) {
let satisfied = false;
let alternatives = (type(spec.depends.fs) == 'array') ? spec.depends.fs : [ spec.depends.fs ];
for (let alternative in alternatives) {
if (check_fs_depends(alternative)) {
satisfied = true;
break;
}
}
if (!satisfied)
return false;
}
if (type(spec?.depends?.uci) in ['array', 'object']) {
let satisfied = false;
let alternatives = (type(spec.depends.uci) == 'array') ? spec.depends.uci : [ spec.depends.uci ];
for (let alternative in alternatives) {
if (check_uci_depends(alternative)) {
satisfied = true;
break;
}
}
if (!satisfied)
return false;
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment