This commit is contained in:
fenris 2025-04-25 10:47:04 +02:00
parent 1a59e3763c
commit 27336159db
9 changed files with 7367 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/build/
/temp/

1661
libs/plankton/plankton.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

5067
libs/plankton/plankton.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,3 +2,11 @@
Führt auf Grundlage eines Datenblatts bestimmte Befehle aus, die häufig für die Entwicklung von Programmen verwendet werden Führt auf Grundlage eines Datenblatts bestimmte Befehle aus, die häufig für die Entwicklung von Programmen verwendet werden
## Nutzung
- `ivaldi fetch`
- `ivaldi clear`
- `ivaldi build`
- `ivaldi deploy`

498
source/main.ts Normal file
View file

@ -0,0 +1,498 @@
/*
This file is part of »munin«.
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
»munin« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»munin« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »munin«. If not, see <http://www.gnu.org/licenses/>.
*/
namespace _munin
{
/**
* @todo outsource
*/
function execute(
command : string,
{
"log_only": log_only = false,
} : {
log_only ?: boolean;
} = {
}
) : Promise<
{
code : int;
stdout : string;
stderr : string;
}
>
{
const nm_child_process = require("child_process");
return (
new Promise(
(resolve, reject) => {
lib_plankton.log._info(
"execute",
{
"details": {
"command": command,
}
}
);
if (log_only) {
resolve(
{
"code": 0,
"stdout": "",
"stderr": "",
}
);
}
else {
nm_child_process.exec(
command,
{
},
(error, stdout, stderr) => {
if (error) {
reject(error);
}
else {
resolve(
{
/**
* @todo assign correct value
*/
"code": 0,
"stdout": stdout,
"stderr": stderr,
}
);
}
}
);
}
}
)
);
}
/**
*/
export async function main(
args_raw : Array<string>
) : Promise<void>
{
// args
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
{
"action": lib_plankton.args.class_argument.positional({
"index": 0,
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "help",
"info": "what to do : fetch | clear | build | deploy",
"name": "action",
}),
"data_path": lib_plankton.args.class_argument.volatile({
"indicators_long": ["data-path"],
"indicators_short": ["d"],
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "ivaldi.json",
"info": "path to data file",
"name": "data-path",
}),
"verbosity": lib_plankton.args.class_argument.volatile({
"indicators_long": ["verbosity"],
"indicators_short": ["v"],
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "notice",
"info": "error | warning | notice | info | debug",
"name": "verbosity",
}),
"help": lib_plankton.args.class_argument.volatile({
"indicators_long": ["help"],
"indicators_short": ["h"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": "alias for action 'help'",
"name": "help",
}),
}
);
const args : Record<string, any> = arg_handler.read(
lib_plankton.args.enum_environment.cli,
args_raw.join(" ")
);
// init
lib_plankton.log.set_main_logger(
[
{
"kind": "filtered",
"data": {
"core": {
"kind": "std",
"data": {
"target": "stdout",
"format": {
"kind": "human_readable",
"data": {
}
}
}
},
"predicate": [
[
{
"item": {
"kind": "level",
"data": {
"threshold": args.verbosity,
}
},
}
]
],
}
},
]
);
// exec
if (args.help) {
process.stdout.write(
arg_handler.generate_help(
{
"programname": "lixer-event-reminder",
"description": "a telegram bot, which sends reminders about upcoming events",
"executable": "node build/event-reminder",
}
)
);
}
else {
const content : string = await lib_plankton.file.read(args.data_path);
const data_raw : any = lib_plankton.json.decode(content);
const data : _munin.type_data = {
"version": data_raw["version"],
"name": data_raw["name"],
"libs": (data_raw["libs"] ?? {}),
"sources": data_raw["sources"],
};
/**
* @todo outsource
*/
const conf = {
"directories": {
"source": "source",
"libs": "libs",
"temp": "temp",
"build": "build",
},
"command_tsc": "tsc",
"makefile_path": "/tmp/ivaldi-makefile",
};
switch (args.action) {
default: {
return Promise.reject<void>((new Error("unhandled action: " + args.action)));
break;
}
case "fetch": {
for (const lib of data.libs) {
switch (lib.kind) {
case "plankton": {
/**
* @todo outsource
*/
const conf = {
"directory": "libs/plankton",
};
const commands : Array<string> = [
lib_plankton.string.coin(
"mkdir -p {{directory}}",
{
"directory": conf.directory,
}
),
lib_plankton.string.coin(
"cd {{directory}}",
{
"directory": conf.directory,
}
),
lib_plankton.string.coin(
"ptk bundle node {{modules}}",
{
"modules": lib.data.modules.join(" "),
}
),
];
for (const command of commands) {
await execute(command);
}
break;
}
case "node": {
/**
* @todo
*/
throw (new Error("unhanled lib kind: " + "node"));
break;
}
default: {
throw (new Error("unhanled lib kind: " + lib["kind"]));
break;
}
}
}
return Promise.resolve<void>(undefined);
break;
}
case "clear": {
const commands : Array<string> = [
lib_plankton.string.coin(
"rm -r -f {{directory}}",
{
"directory": conf.directories.temp,
}
),
lib_plankton.string.coin(
"rm -r -f {{directory}}",
{
"directory": conf.directories.build,
}
),
];
for (const command of commands) {
await execute(command);
}
return Promise.resolve<void>(undefined);
break;
}
case "build": {
const has_plankton : boolean = data.libs.some(lib => (lib.kind === "plankton"));
const path_plankton_declaration : string = lib_plankton.string.coin(
"{{directory_libs}}/plankton/plankton.d.ts",
{
"directory_libs": conf.directories.libs,
}
);
const path_plankton_implementation : string = lib_plankton.string.coin(
"{{directory_libs}}/plankton/plankton.js",
{
"directory_libs": conf.directories.libs,
}
);
const paths_sources : Array<string> = (
data.sources
.map(
source => lib_plankton.string.coin(
"{{directory}}/{{name}}",
{
"directory": conf.directories.source,
"name": source,
}
)
)
);
const path_unlinked : string = lib_plankton.string.coin(
"{{directory_temp}}/{{name}}-unlinked.js",
{
"directory_temp": conf.directories.temp,
"name": data.name,
}
);
const path_head : string = lib_plankton.string.coin(
"{{directory_temp}}/head.js",
{
"directory_temp": conf.directories.temp,
}
);
const path_result : string = lib_plankton.string.coin(
"{{directory_build}}/{{name}}",
{
"directory_build": conf.directories.build,
"name": data.name,
}
);
const dependencies_compilation : Array<string> = (
[]
.concat(has_plankton ? [path_plankton_declaration] : [])
.concat(paths_sources)
);
const gnu_make_sheet : lib_plankton.gnu_make.type_sheet = {
"rules": [
// root
{
"kind": "meta",
"data": {
"phony": true,
"name": "_root",
"dependencies": [
path_result,
],
}
},
// compile
{
"kind": "concrete",
"data": {
"targets": [
path_unlinked,
],
"dependencies": dependencies_compilation,
"actions": [
// log
lib_plankton.string.coin(
"echo '-- {{message}}'",
{
"message": "compiling …",
}
),
// mkdir
lib_plankton.string.coin(
"mkdir -p $(dir $@)",
{
}
),
// command
lib_plankton.string.coin(
"{{command}} $^ --lib es2020,dom --target es6 --outFile $@",
{
"command": conf.command_tsc,
}
),
],
}
},
// head
{
"kind": "concrete",
"data": {
"targets": [
path_head,
],
"dependencies": [
],
"actions": [
// log
lib_plankton.string.coin(
"echo '-- {{message}}'",
{
"message": "creating head …",
}
),
// mkdir
lib_plankton.string.coin(
"mkdir -p $(dir $@)",
{
}
),
// create
lib_plankton.string.coin(
"echo '#!/usr/bin/env node' > {{path}}",
{
"path": path_head,
}
),
]
}
},
// link
{
"kind": "concrete",
"data": {
"targets": [
path_result,
],
"dependencies": (
[]
.concat([path_head])
.concat(has_plankton ? [path_plankton_implementation] : [])
.concat([path_unlinked])
),
"actions": [
// log
lib_plankton.string.coin(
"echo '-- {{message}}'",
{
"message": "linking …",
}
),
// mkdir
lib_plankton.string.coin(
"mkdir -p $(dir $@)",
{
}
),
// command
lib_plankton.string.coin(
"cat $^ > $@",
{
}
),
// make executable
lib_plankton.string.coin(
"chmod +x {{path}}",
{
"path": path_result,
}
),
],
},
},
],
};
const makefile : string = lib_plankton.gnu_make.render_sheet(
gnu_make_sheet,
{
"break_dependencies": true,
"silent_actions": true,
}
);
await lib_plankton.file.write(
conf.makefile_path,
makefile
);
const command : string = lib_plankton.string.coin(
"make -f {{path}}",
{
"path": conf.makefile_path,
}
);
await execute(command);
return Promise.resolve<void>(undefined);
break;
}
case "deploy": {
return Promise.reject<void>(new Error("not yet implemented"));
break;
}
}
}
}
}
_munin.main(process.argv.slice(2))
.then(() => {})
.catch((reason) => {process.stderr.write(String(reason) + "\n");})
;

52
source/types.ts Normal file
View file

@ -0,0 +1,52 @@
/*
This file is part of »munin«.
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
»munin« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»munin« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »munin«. If not, see <http://www.gnu.org/licenses/>.
*/
namespace _munin
{
/**
*/
type type_lib = (
{
kind : "node";
data : {
modules : Array<string>;
};
}
|
{
kind : "plankton";
data : {
modules : Array<string>;
};
}
);
/**
*/
export type type_data = {
version : string;
name : string;
libs : Array<type_lib>;
sources : Array<string>;
};
}

17
tools/build Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env python3
import os as _os
import argparse as _argparse
def main():
argument_parser = _argparse.ArgumentParser(
)
args = argument_parser.parse_args()
if True:
_os.system("make -f tools/makefile")
main()

37
tools/makefile Normal file
View file

@ -0,0 +1,37 @@
## commands
cmd_mkdir := mkdir -p
cmd_cp := cp -r -u
cmd_tsc := tsc
cmd_log := echo "--"
cmd_cat := cat
cmd_echo := echo
cmd_chmod := chmod
## rules
.PHONY: _default
_default: _root
temp/ivaldi-unlinked.js: \
libs/plankton/plankton.d.ts \
source/types.ts \
source/main.ts
@ ${cmd_log} "compiling …"
@ ${cmd_mkdir} temp
@ ${cmd_tsc} $^ --lib es2020,dom --target es6 --outFile $@
build/ivaldi: libs/plankton/plankton.js temp/ivaldi-unlinked.js
@ ${cmd_log} "linking …"
@ ${cmd_echo} "#!/usr/bin/env node" > temp/head.js
@ ${cmd_mkdir} build
@ ${cmd_cat} temp/head.js $^ > $@
@ ${cmd_chmod} +x $@
.PHONY: sources
sources: build/ivaldi
.PHONY: _root
_root: sources

25
tools/update-plankton Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env sh
## consts
dir="libs/plankton"
## vars
modules=""
modules="${modules} base"
modules="${modules} string"
modules="${modules} log"
modules="${modules} json"
modules="${modules} gnu_make"
modules="${modules} file"
modules="${modules} args"
## exec
mkdir -p ${dir}
cd ${dir}
ptk bundle node ${modules}