[int]
This commit is contained in:
parent
d13b3776e2
commit
4dbb7474e7
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
.geany
|
.geany
|
||||||
source/__pycache__/
|
source/__pycache__/
|
||||||
|
temp/
|
||||||
build/
|
build/
|
||||||
|
|
||||||
|
|
|
||||||
1775
lib/plankton/plankton.d.ts
vendored
Normal file
1775
lib/plankton/plankton.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
5427
lib/plankton/plankton.js
Normal file
5427
lib/plankton/plankton.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@
|
||||||
"help.args.send_ok_notifications": "ob '{{condition_name}}'-Zustände gemeldet werden sollen",
|
"help.args.send_ok_notifications": "ob '{{condition_name}}'-Zustände gemeldet werden sollen",
|
||||||
"help.args.language": "welche Sprache verwendet werden soll (statt der in den Umgebungs-Variablen gesetzten)",
|
"help.args.language": "welche Sprache verwendet werden soll (statt der in den Umgebungs-Variablen gesetzten)",
|
||||||
"help.args.erase_state": "ob der Zustand bei Start gelöscht werden soll; das hat zur Folge, dass alle Prüfungen unmittelbar durchgeführt werden",
|
"help.args.erase_state": "ob der Zustand bei Start gelöscht werden soll; das hat zur Folge, dass alle Prüfungen unmittelbar durchgeführt werden",
|
||||||
|
"help.args.show_help": "nur die Hilfe zur Standard-Ausgabe schreiben und beenden",
|
||||||
"help.args.show_schema": "nur das hmdl-JSON-Schema zur Standard-Ausgabe schreiben und beenden",
|
"help.args.show_schema": "nur das hmdl-JSON-Schema zur Standard-Ausgabe schreiben und beenden",
|
||||||
"help.args.expose_full_order": "nur den Pfad zur Datenbank-Datei zur Standard-Ausgabe schreiben und beenden (nützlich für Fehlersuche)",
|
"help.args.expose_full_order": "nur den Pfad zur Datenbank-Datei zur Standard-Ausgabe schreiben und beenden (nützlich für Fehlersuche)",
|
||||||
"help.args.show_version": "nur die Version zur Standard-Ausgabe schreiben und beenden",
|
"help.args.show_version": "nur die Version zur Standard-Ausgabe schreiben und beenden",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"help.args.send_ok_notifications": "whether an '{{condition_name}}' condition shall be reported",
|
"help.args.send_ok_notifications": "whether an '{{condition_name}}' condition shall be reported",
|
||||||
"help.args.language": "language to use (instead of the language, set in the environment variables)",
|
"help.args.language": "language to use (instead of the language, set in the environment variables)",
|
||||||
"help.args.erase_state": "whether the state shall be deleted on start; this will cause that all checks are executed immediatly",
|
"help.args.erase_state": "whether the state shall be deleted on start; this will cause that all checks are executed immediatly",
|
||||||
|
"help.args.show_schema": "print help to stdout and exit",
|
||||||
"help.args.show_schema": "print the hmdl JSON schema to stdout and exit",
|
"help.args.show_schema": "print the hmdl JSON schema to stdout and exit",
|
||||||
"help.args.expose_full_order": "only print the extended order to stdout and exit (useful for debugging)",
|
"help.args.expose_full_order": "only print the extended order to stdout and exit (useful for debugging)",
|
||||||
"help.args.show_version": "only print the version to stdout and exit",
|
"help.args.show_version": "only print the version to stdout and exit",
|
||||||
|
|
|
||||||
12
source/logic/channels/_type.ts
Normal file
12
source/logic/channels/_type.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace _heimdall.channels
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_channel = {
|
||||||
|
parameters_schema : (() => _heimdall.helpers.json_schema.type_schema);
|
||||||
|
normalize_order_node : ((node : any) => any);
|
||||||
|
notify : (parameters, name, data, state, info) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
12
source/logic/checks/_type.ts
Normal file
12
source/logic/checks/_type.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace _heimdall.checks
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_check = {
|
||||||
|
parameters_schema : (() => _heimdall.helpers.json_schema.type_schema);
|
||||||
|
normalize_order_node : ((node : any) => any);
|
||||||
|
run : (parameters) => Promise<{condition : _heimdall.enum_condition; info : any;}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
13
source/logic/condition.ts
Normal file
13
source/logic/condition.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace _heimdall
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export enum enum_condition {
|
||||||
|
unknown = 0,
|
||||||
|
ok = 1,
|
||||||
|
concerning = 2,
|
||||||
|
critical = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
47
source/logic/helpers/json_schema.ts
Normal file
47
source/logic/helpers/json_schema.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
namespace _heimdall.helpers.json_schema
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
type type_type = (
|
||||||
|
"null"
|
||||||
|
|
|
||||||
|
"boolean"
|
||||||
|
|
|
||||||
|
"integer"
|
||||||
|
|
|
||||||
|
"float"
|
||||||
|
|
|
||||||
|
"string"
|
||||||
|
|
|
||||||
|
"array"
|
||||||
|
|
|
||||||
|
"object"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type type_schema = {
|
||||||
|
type ?: (
|
||||||
|
type_type
|
||||||
|
|
|
||||||
|
Array<type_type>
|
||||||
|
);
|
||||||
|
additionalProperties ?: (
|
||||||
|
false
|
||||||
|
|
|
||||||
|
type_schema
|
||||||
|
);
|
||||||
|
properties ?: Record<string, type_schema>;
|
||||||
|
required ?: Array<string>;
|
||||||
|
description ?: string;
|
||||||
|
default ?: any;
|
||||||
|
minimum ?: int;
|
||||||
|
maximum ?: int;
|
||||||
|
enum ?: Array<any>;
|
||||||
|
items ?: type_schema;
|
||||||
|
anyOf ?: Array<type_schema>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
237
source/logic/main.ts
Normal file
237
source/logic/main.ts
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
async function main(
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
// consts
|
||||||
|
const version : string = "0.8";
|
||||||
|
|
||||||
|
// init
|
||||||
|
await lib_plankton.translate.initialize_promise(
|
||||||
|
{
|
||||||
|
"verbosity": 1,
|
||||||
|
"order": ["de", "en"],
|
||||||
|
"packages": await Promise.all(
|
||||||
|
[
|
||||||
|
{"identifier": "de", "path": "localization/de.json"},
|
||||||
|
{"identifier": "en", "path": "localization/en.json"},
|
||||||
|
]
|
||||||
|
.map(
|
||||||
|
(entry) => (
|
||||||
|
lib_plankton.file.read(entry.path)
|
||||||
|
.then(content => Promise.resolve(JSON.parse(content)))
|
||||||
|
.then(tree => Promise.resolve({"meta": {"identifier": entry.identifier}, "tree": tree}))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// args
|
||||||
|
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
|
||||||
|
{
|
||||||
|
"order_path": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "order_path",
|
||||||
|
"type": lib_plankton.args.enum_type.string,
|
||||||
|
"kind": lib_plankton.args.enum_kind.positional,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": "monitoring.hmdl.json",
|
||||||
|
"parameters": {
|
||||||
|
"index": 0,
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.order_path"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"show_help": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "help",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["help"],
|
||||||
|
"indicators_short": ["h"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.show_help"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"show_version": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["version"],
|
||||||
|
"indicators_short": ["v"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.show_version"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"show_schema": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "schema",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["schema"],
|
||||||
|
"indicators_short": ["s"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.show_schema"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"expose_full_order": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "expose_full_order",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["expose-full-order"],
|
||||||
|
"indicators_short": ["e"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.expose_full_order"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"erase_state": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "erase_state",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["erase-state"],
|
||||||
|
"indicators_short": ["x"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.erase_state"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"database_path": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "database_path",
|
||||||
|
"type": lib_plankton.args.enum_type.string,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["database-path"],
|
||||||
|
"indicators_short": ["d"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.database_path"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"mutex_path": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "mutex_path",
|
||||||
|
"type": lib_plankton.args.enum_type.string,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["mutex-path"],
|
||||||
|
"indicators_short": ["m"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.mutex_path"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"send_ok_notifications": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "send_ok_notifications",
|
||||||
|
"type": lib_plankton.args.enum_type.boolean,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["send-ok-notifications"],
|
||||||
|
"indicators_short": ["y"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.send_ok_notifications"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"language": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "language",
|
||||||
|
"type": lib_plankton.args.enum_type.string,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": false,
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["language"],
|
||||||
|
"indicators_short": ["l"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.language"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"time_to_live": new lib_plankton.args.class_argument(
|
||||||
|
{
|
||||||
|
"name": "time_to_live",
|
||||||
|
"type": lib_plankton.args.enum_type.float,
|
||||||
|
"kind": lib_plankton.args.enum_kind.volatile,
|
||||||
|
"mode": lib_plankton.args.enum_mode.replace,
|
||||||
|
"default": (60 * 60 * 24 * 7),
|
||||||
|
"parameters": {
|
||||||
|
"indicators_long": ["time-to-live"],
|
||||||
|
"indicators_short": ["t"],
|
||||||
|
},
|
||||||
|
"info": lib_plankton.translate.get("help.args.time_to_live"),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const args : Record<string, any> = arg_handler.read(
|
||||||
|
lib_plankton.args.enum_environment.cli,
|
||||||
|
process.argv.slice(2).join(" ")
|
||||||
|
);
|
||||||
|
|
||||||
|
// exec
|
||||||
|
if (args.show_help) {
|
||||||
|
process.stdout.write(
|
||||||
|
arg_handler.generate_help(
|
||||||
|
{
|
||||||
|
"programname": "heimdall",
|
||||||
|
"description": lib_plankton.translate.get("help.title"),
|
||||||
|
"executable": "heimdall",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (args.show_version) {
|
||||||
|
process.stdout.write(version + "\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (args.show_version) {
|
||||||
|
process.stdout.write(version + "\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const check_kind_implementations : Record<string, _heimdall.checks.type_check> = {
|
||||||
|
};
|
||||||
|
const channel_kind_implementations : Record<string, _heimdall.channels.type_channel> = {
|
||||||
|
};
|
||||||
|
if (args.show_schema) {
|
||||||
|
process.stdout.write(
|
||||||
|
lib_plankton.json.encode(
|
||||||
|
_heimdall.order.schema_root(
|
||||||
|
check_kind_implementations,
|
||||||
|
channel_kind_implementations
|
||||||
|
),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
+
|
||||||
|
"\n"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
process.stdout.write(JSON.stringify(args, undefined, "\t") + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
546
source/logic/order.ts
Normal file
546
source/logic/order.ts
Normal file
|
|
@ -0,0 +1,546 @@
|
||||||
|
namespace _heimdall.order
|
||||||
|
{
|
||||||
|
|
||||||
|
function schema_active(
|
||||||
|
) : _heimdall.helpers.json_schema.type_schema
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"description": "whether the check shall be executed",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function schema_threshold(
|
||||||
|
) : _heimdall.helpers.json_schema.type_schema
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"description": "how often a condition has to occur in order to be reported",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"default": 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function schema_annoy(
|
||||||
|
) : _heimdall.helpers.json_schema.type_schema
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"description": "whether notifications about non-ok states shall be kept sending after the threshold has been surpassed",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function schema_interval(
|
||||||
|
allow_null,
|
||||||
|
default_
|
||||||
|
) : _heimdall.helpers.json_schema.type_schema
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"description": "in seconds",
|
||||||
|
"type": (allow_null ? "integer" : ["null", "integer"]),
|
||||||
|
"exclusiveMinimum": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "as text",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"minute",
|
||||||
|
"hour",
|
||||||
|
"day",
|
||||||
|
"week",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"default": default_,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function schema_schedule(
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"regular_interval": schema_interval(false, (60 * 60)),
|
||||||
|
"attentive_interval": schema_interval(false, (60 * 2)),
|
||||||
|
"reminding_interval": schema_interval(true, (60 * 60 * 24)),
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function schema_notifications(
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"anyOf": (
|
||||||
|
Object.entries(channel_implementations)
|
||||||
|
.map(
|
||||||
|
([key, value]) => ({
|
||||||
|
"title": ("notification channel '" + key + "'"),
|
||||||
|
"type": "object",
|
||||||
|
"unevaluatedProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [key]
|
||||||
|
},
|
||||||
|
"parameters": value.parameters_schema(),
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
"default": [
|
||||||
|
{
|
||||||
|
"kind": "console",
|
||||||
|
"parameters": {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function schema_root(
|
||||||
|
check_kind_implementations : Record<string, _heimdall.checks.type_check>,
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"defaults": {
|
||||||
|
"description": "default values for checks",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"active": schema_active(),
|
||||||
|
"threshold": schema_threshold(),
|
||||||
|
"annoy": schema_annoy(),
|
||||||
|
"schedule": schema_schedule(),
|
||||||
|
"notifications": schema_notifications(channel_implementations),
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"includes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": [],
|
||||||
|
"description": "list of relative or absolute paths to other hmdl files on the local machine, which shall be subsumed in the overall monitoring task"
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"description": "should represent a specific check",
|
||||||
|
"type": "object",
|
||||||
|
"unevaluatedProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"active": schema_active(),
|
||||||
|
"threshold": schema_threshold(),
|
||||||
|
"annoy": schema_annoy(),
|
||||||
|
"schedule": schema_schedule(),
|
||||||
|
"notifications": schema_notifications(channel_implementations),
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anyOf": (
|
||||||
|
Object.entries(check_kind_implementations)
|
||||||
|
.map(
|
||||||
|
([key, value]) => ({
|
||||||
|
"title": ("check '" + key + "'"),
|
||||||
|
"type": "object",
|
||||||
|
"unevaluatedProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [key]
|
||||||
|
},
|
||||||
|
"parameters": value.parameters_schema(),
|
||||||
|
"custom": {
|
||||||
|
"description": "custom data, which shall be attached to notifications",
|
||||||
|
"default": null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters",
|
||||||
|
]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_interval(
|
||||||
|
interval_raw
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (interval_raw === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (typeof(interval_raw) === "number") {
|
||||||
|
return interval_raw;
|
||||||
|
}
|
||||||
|
else if (typeof(interval_raw) === "string") {
|
||||||
|
const map_ = {
|
||||||
|
"minute": (60),
|
||||||
|
"hour": (60 * 60),
|
||||||
|
"day": (60 * 60 * 24),
|
||||||
|
"week": (60 * 60 * 24 * 7),
|
||||||
|
};
|
||||||
|
if (! (interval_raw in map_)) {
|
||||||
|
throw new Error("invalid string interval value: " + interval_raw);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return map_[interval_raw];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("invalid type for interval value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_schedule(
|
||||||
|
node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const node_ = Object.assign(
|
||||||
|
{
|
||||||
|
"regular_interval": (60 * 60),
|
||||||
|
"attentive_interval": (60 * 2),
|
||||||
|
"reminding_interval": (60 * 60 * 24),
|
||||||
|
},
|
||||||
|
node
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
"regular_interval": normalize_interval(node_["regular_interval"]),
|
||||||
|
"attentive_interval": normalize_interval(node_["attentive_interval"]),
|
||||||
|
"reminding_interval": normalize_interval(node_["reminding_interval"]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_notification(
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (! (node["kind"] in channel_implementations)) {
|
||||||
|
throw new Error("invalid notification kind: " + node["kind"]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
"kind": node["kind"],
|
||||||
|
"parameters": channel_implementations[node["kind"]].normalize_order_node(node["parameters"]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_defaults(
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const node_ = Object.assign(
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"threshold": 3,
|
||||||
|
"annoy": false,
|
||||||
|
"schedule": {
|
||||||
|
"regular_interval": (60 * 60),
|
||||||
|
"attentive_interval": (60 * 2),
|
||||||
|
"reminding_interval": (60 * 60 * 24),
|
||||||
|
},
|
||||||
|
"notifications": [
|
||||||
|
],
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"active": node_["active"],
|
||||||
|
"threshold": node_["threshold"],
|
||||||
|
"annoy": node_["annoy"],
|
||||||
|
"schedule": node_["schedule"],
|
||||||
|
"notifications": (
|
||||||
|
node_["notifications"]
|
||||||
|
.map(x => normalize_notification(channel_implementations, x))
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_check(
|
||||||
|
check_kind_implementations : Record<string, _heimdall.checks.type_check>,
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
defaults,
|
||||||
|
node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (! ("name" in node)) {
|
||||||
|
throw new Error("missing mandatory field in 'check' node: 'name'");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (! ("kind" in node)) {
|
||||||
|
throw new Error("missing mandatory field in 'check' node: 'kind'");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (! (node["kind"] in check_kind_implementations)) {
|
||||||
|
throw new Error("invalid check kind: " + node["kind"]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const node_ = Object.assign(
|
||||||
|
Object.assign(
|
||||||
|
defaults,
|
||||||
|
{
|
||||||
|
"title": node["name"],
|
||||||
|
"parameters": {},
|
||||||
|
"custom": null,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
node
|
||||||
|
);
|
||||||
|
let node__ = {};
|
||||||
|
if (true) {
|
||||||
|
node__["name"] = node_["name"];
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
node__["title"] = node_["title"];
|
||||||
|
}
|
||||||
|
if ("active" in node_) {
|
||||||
|
node__["active"] = node_["active"];
|
||||||
|
}
|
||||||
|
if ("threshold" in node_) {
|
||||||
|
node__["threshold"] = node_["threshold"];
|
||||||
|
}
|
||||||
|
if ("annoy" in node_) {
|
||||||
|
node__["annoy"] = node_["annoy"];
|
||||||
|
}
|
||||||
|
if ("schedule" in node_) {
|
||||||
|
node__["schedule"] = normalize_schedule(node_["schedule"]);
|
||||||
|
}
|
||||||
|
if ("notifications" in node_) {
|
||||||
|
node__["notifications"] = (
|
||||||
|
node_["notifications"]
|
||||||
|
.map(
|
||||||
|
x => normalize_notification(channel_implementations, x),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ("kind" in node_) {
|
||||||
|
node__["kind"] = node_["kind"];
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
node__["parameters"] = check_kind_implementations[node_["kind"]].normalize_order_node(node_["parameters"]);
|
||||||
|
}
|
||||||
|
if ("custom" in node_) {
|
||||||
|
node__["custom"] = node_["custom"];
|
||||||
|
}
|
||||||
|
return node__;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normalize_root(
|
||||||
|
check_kind_implementations : Record<string, _heimdall.checks.type_check>,
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
node,
|
||||||
|
options = {}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"use_implicit_default_values": true,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
)
|
||||||
|
let counts = {};
|
||||||
|
let checks_raw = (
|
||||||
|
("checks" in node)
|
||||||
|
? node["checks"]
|
||||||
|
: []
|
||||||
|
);
|
||||||
|
checks_raw.forEach(
|
||||||
|
node_ => {
|
||||||
|
if (! (node_["name"] in counts)) {
|
||||||
|
counts[node_["name"]] = 0;
|
||||||
|
}
|
||||||
|
counts[node_["name"]] += 1;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let fails : Array<[string, int]> = (
|
||||||
|
Object.entries(counts)
|
||||||
|
.filter(
|
||||||
|
([key, value]) => (value > 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (fails.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"ambiguous check names: {{names}}",
|
||||||
|
{
|
||||||
|
"names": fails.map(([key, value]) => key).join(","),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let defaults_raw = (
|
||||||
|
("defaults" in node)
|
||||||
|
? node["defaults"]
|
||||||
|
: {}
|
||||||
|
)
|
||||||
|
let defaults = (
|
||||||
|
options["use_implicit_default_values"]
|
||||||
|
? normalize_defaults(
|
||||||
|
channel_implementations,
|
||||||
|
defaults_raw
|
||||||
|
)
|
||||||
|
: defaults_raw
|
||||||
|
)
|
||||||
|
let includes = (
|
||||||
|
("includes" in node)
|
||||||
|
? node["includes"]
|
||||||
|
: []
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"defaults": defaults,
|
||||||
|
"includes": includes,
|
||||||
|
"checks": (
|
||||||
|
checks_raw
|
||||||
|
.map(
|
||||||
|
node_ => normalize_check(
|
||||||
|
check_kind_implementations,
|
||||||
|
channel_implementations,
|
||||||
|
defaults,
|
||||||
|
node_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function load(
|
||||||
|
check_kind_implementations : Record<string, _heimdall.checks.type_check>,
|
||||||
|
channel_implementations : Record<string, _heimdall.channels.type_channel>,
|
||||||
|
path : string,
|
||||||
|
options = {}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"already_included": new Set([]),
|
||||||
|
},
|
||||||
|
options
|
||||||
|
)
|
||||||
|
if (path in options["already_included"]) {
|
||||||
|
throw new Error("circular dependency detected")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const order_raw = lib_plankton.json.decode(await lib_plankton.file.read(path));
|
||||||
|
let includes : Array<string> = (
|
||||||
|
("includes" in order_raw)
|
||||||
|
? order_raw["includes"]
|
||||||
|
: []
|
||||||
|
);
|
||||||
|
for (let index = 0; index < includes.length; index += 1) {
|
||||||
|
let path_ = includes[index];
|
||||||
|
let sub_order = load(
|
||||||
|
check_kind_implementations,
|
||||||
|
channel_implementations,
|
||||||
|
(
|
||||||
|
_os.path.isabs(path_)
|
||||||
|
? path_
|
||||||
|
: _os.path.join(_os.path.dirname(path), path_)
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"root": false,
|
||||||
|
// TODO set union
|
||||||
|
"already_included": (options["already_included"] | {path})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (! ("checks" in order_raw)) {
|
||||||
|
order_raw["checks"] = [];
|
||||||
|
}
|
||||||
|
order_raw["checks"].extend(
|
||||||
|
sub_order["checks"]
|
||||||
|
.map(
|
||||||
|
check => Object.assign(
|
||||||
|
check,
|
||||||
|
{
|
||||||
|
"name": lib_plankton.string.coin(
|
||||||
|
"{{prefix}}.{{original_name}}",
|
||||||
|
{
|
||||||
|
"prefix": _os.path.basename(path_).split(".")[0],
|
||||||
|
"original_name": check["name"],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
sub_order["checks"]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
order_raw["includes"] = [];
|
||||||
|
}
|
||||||
|
return normalize_root(
|
||||||
|
check_kind_implementations,
|
||||||
|
channel_implementations,
|
||||||
|
order_raw,
|
||||||
|
{
|
||||||
|
"use_implicit_default_values": options["root"],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1
source/misc/head.js
Normal file
1
source/misc/head.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
141
tools/build
141
tools/build
|
|
@ -1,136 +1,13 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
import sys as _sys
|
## vars
|
||||||
import os as _os
|
|
||||||
import json as _json
|
path_prj_from=tools/heimdall.prj.json
|
||||||
import stat as _stat
|
path_prj_to=heimdall.prj.json
|
||||||
import argparse as _argparse
|
|
||||||
|
|
||||||
|
|
||||||
def file_read(path):
|
## exec
|
||||||
handle = open(path, "r")
|
|
||||||
content = handle.read()
|
|
||||||
handle.close()
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def file_write(path, content):
|
cp ${path_prj_from} ${path_prj_to}
|
||||||
handle = open(path, "w")
|
koralle --execute ${path_prj_to}
|
||||||
handle.write(content)
|
rm ${path_prj_to}
|
||||||
handle.close()
|
|
||||||
|
|
||||||
|
|
||||||
def string_coin(template, arguments):
|
|
||||||
result = template
|
|
||||||
for (key, value, ) in arguments.items():
|
|
||||||
result = result.replace("{{%s}}" % key, value)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def python_data_encode(data):
|
|
||||||
return _json.dumps(data, indent = "\t")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
## consts
|
|
||||||
dir_source = "source"
|
|
||||||
dir_build = "build"
|
|
||||||
sources_common = [
|
|
||||||
_os.path.join(dir_source, "logic", "packages.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "lib.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "localization.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "condition.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "order.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "_interface.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "script.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "file_state.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "tls_certificate.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "http_request.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "checks", "generic_remote.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "channels", "_interface.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "channels", "console.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "channels", "email.py"),
|
|
||||||
_os.path.join(dir_source, "logic", "channels", "libnotify.py"),
|
|
||||||
]
|
|
||||||
targets = {
|
|
||||||
"app": {
|
|
||||||
"sources": (
|
|
||||||
sources_common
|
|
||||||
+
|
|
||||||
[
|
|
||||||
_os.path.join(dir_source, "logic", "main.py"),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
"build": _os.path.join(dir_build, "heimdall"),
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"sources": (
|
|
||||||
sources_common
|
|
||||||
+
|
|
||||||
[
|
|
||||||
_os.path.join(dir_source, "test", "test.py"),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
"build": _os.path.join(dir_build, "heimdall-test"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
## args
|
|
||||||
argument_parser = _argparse.ArgumentParser(
|
|
||||||
)
|
|
||||||
argument_parser.add_argument(
|
|
||||||
"-t",
|
|
||||||
"--target",
|
|
||||||
type = str,
|
|
||||||
choices = ["app", "test"],
|
|
||||||
default = "app",
|
|
||||||
dest = "target_name",
|
|
||||||
help = "which target to build",
|
|
||||||
)
|
|
||||||
args = argument_parser.parse_args()
|
|
||||||
|
|
||||||
## exec
|
|
||||||
if (not _os.path.exists(dir_build)):
|
|
||||||
_os.mkdir(dir_build)
|
|
||||||
|
|
||||||
compilation = ""
|
|
||||||
compilation += "#!/usr/bin/env python3\n\n"
|
|
||||||
|
|
||||||
### localization
|
|
||||||
if True:
|
|
||||||
localization_data = dict(
|
|
||||||
map(
|
|
||||||
lambda entry: (
|
|
||||||
entry.name.split(".")[0],
|
|
||||||
_json.loads(file_read(entry.path)),
|
|
||||||
),
|
|
||||||
filter(
|
|
||||||
lambda entry: (entry.is_file() and entry.name.endswith(".json")),
|
|
||||||
_os.scandir(_os.path.join(dir_source, "localization"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
compilation += string_coin(
|
|
||||||
"localization_data = {{data}}\n\n",
|
|
||||||
{
|
|
||||||
"data": python_data_encode(localization_data),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
### logic
|
|
||||||
for path in targets[args.target_name]["sources"]:
|
|
||||||
compilation += (file_read(path) + "\n")
|
|
||||||
|
|
||||||
### write to file
|
|
||||||
if _os.path.exists(targets[args.target_name]["build"]):
|
|
||||||
_os.remove(targets[args.target_name]["build"])
|
|
||||||
file_write(targets[args.target_name]["build"], compilation)
|
|
||||||
|
|
||||||
### postproess
|
|
||||||
_os.chmod(
|
|
||||||
targets[args.target_name]["build"],
|
|
||||||
(_stat.S_IRWXU | _stat.S_IXGRP | _stat.S_IXOTH)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
|
||||||
68
tools/heimdall.prj.json
Normal file
68
tools/heimdall.prj.json
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"name": "heimdall",
|
||||||
|
"version": "0.8",
|
||||||
|
"dependencies": [
|
||||||
|
],
|
||||||
|
"roottask": {
|
||||||
|
"name": "logic",
|
||||||
|
"type": "group",
|
||||||
|
"sub": [
|
||||||
|
{
|
||||||
|
"name": "postprocess",
|
||||||
|
"sub": [
|
||||||
|
{
|
||||||
|
"name": "link",
|
||||||
|
"sub": [
|
||||||
|
{
|
||||||
|
"name": "compile",
|
||||||
|
"type": "typescript",
|
||||||
|
"parameters": {
|
||||||
|
"inputs": [
|
||||||
|
"lib/plankton/plankton.d.ts",
|
||||||
|
"source/logic/condition.ts",
|
||||||
|
"source/logic/helpers/json_schema.ts",
|
||||||
|
"source/logic/checks/_type.ts",
|
||||||
|
"source/logic/channels/_type.ts",
|
||||||
|
"source/logic/order.ts",
|
||||||
|
"source/logic/main.ts"
|
||||||
|
],
|
||||||
|
"target": "es2020",
|
||||||
|
"output": "temp/heimdall-unlinked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "concat",
|
||||||
|
"parameters": {
|
||||||
|
"inputs": [
|
||||||
|
"source/misc/head.js",
|
||||||
|
"lib/plankton/plankton.js",
|
||||||
|
"temp/heimdall-unlinked"
|
||||||
|
],
|
||||||
|
"output": "temp/heimdall-raw"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "script",
|
||||||
|
"parameters": {
|
||||||
|
"path": "tools/postprocess",
|
||||||
|
"interpreter": null,
|
||||||
|
"inputs": [
|
||||||
|
"temp/heimdall-raw"
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
"build/heimdall"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "localization",
|
||||||
|
"type": "copy",
|
||||||
|
"parameters": {
|
||||||
|
"folder": true,
|
||||||
|
"input": "source/localization/",
|
||||||
|
"output": "build/localization/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
14
tools/makefile
Normal file
14
tools/makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
## consts
|
||||||
|
|
||||||
|
dir_lib := lib
|
||||||
|
dir_source := source
|
||||||
|
dir_build := build
|
||||||
|
|
||||||
|
cmd_mkdir := mkdir -p
|
||||||
|
cmd_tsc := tsc
|
||||||
|
cmd_chmod := chmod
|
||||||
|
|
||||||
|
|
||||||
|
## rules
|
||||||
|
|
||||||
|
${dir_build}
|
||||||
7
tools/postprocess
Executable file
7
tools/postprocess
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
path_input=$1
|
||||||
|
path_output=$2
|
||||||
|
|
||||||
|
cp ${path_input} ${path_output}
|
||||||
|
chmod +x ${path_output}
|
||||||
23
tools/update-plankton
Executable file
23
tools/update-plankton
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
## consts
|
||||||
|
|
||||||
|
dir_lib=lib
|
||||||
|
dir_plankton=${dir_lib}/plankton
|
||||||
|
|
||||||
|
|
||||||
|
## vars
|
||||||
|
|
||||||
|
modules=""
|
||||||
|
modules="${modules} string"
|
||||||
|
modules="${modules} json"
|
||||||
|
modules="${modules} file"
|
||||||
|
modules="${modules} translate"
|
||||||
|
modules="${modules} args"
|
||||||
|
|
||||||
|
|
||||||
|
## exec
|
||||||
|
|
||||||
|
mkdir -p ${dir_plankton}
|
||||||
|
cd ${dir_plankton}
|
||||||
|
ptk bundle node ${modules}
|
||||||
Loading…
Reference in a new issue