From 66ddcbb71735f07faac5ccf25aa8c4e480041851 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Fri, 18 Sep 2026 09:53:28 +0200 Subject: [PATCH] [int] --- source/helpers.ts | 73 +++ source/main.ts | 1235 ++++++++++++++++++++++++--------------------- source/types.ts | 5 +- tools/build | 14 +- tools/install | 31 ++ tools/makefile | 33 +- 6 files changed, 795 insertions(+), 596 deletions(-) create mode 100755 tools/install diff --git a/source/helpers.ts b/source/helpers.ts index a696aef..a13dd97 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -185,4 +185,77 @@ namespace _ivaldi ) } + + /** + * @todo outsource + */ + export function execute( + command : string, + { + "log_only": log_only = false, + "working_directory": working_directory = null, + } : { + log_only ?: boolean; + working_directory ?: (null | string); + } = { + } + ) : 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, + { + "cwd": ((working_directory === null) ? undefined : working_directory), + }, + (error, stdout, stderr) => { + if (error) { + reject(error); + } + else { + resolve( + { + /** + * @todo assign correct value + */ + "code": 0, + "stdout": stdout, + "stderr": stderr, + } + ); + } + } + ); + } + } + ) + ); + } + } diff --git a/source/main.ts b/source/main.ts index efb64c3..0afe72a 100644 --- a/source/main.ts +++ b/source/main.ts @@ -21,91 +21,606 @@ namespace _ivaldi { /** - * @todo outsource */ - function execute( - command : string, - { - "log_only": log_only = false, - "working_directory": working_directory = null, - } : { - log_only ?: boolean; - working_directory ?: (null | string); - } = { - } - ) : Promise< - { - code : int; - stdout : string; - stderr : string; - } - > + function refine_definition( + definition_raw : any + ) : _ivaldi.type_definition { - const nm_child_process = require("child_process"); - return ( - new Promise( - (resolve, reject) => { - lib_plankton.log._info( - "execute", - { - "details": { - "command": command, - } + return { + "version": definition_raw["version"], + "name": definition_raw["name"], + "target": ( + definition_raw["target"] + ?? + "node" + ), + "settings": { + "typescript": { + "command": (((definition_raw["settings"] ?? {})["typescript"] ?? {})["command"] ?? "tsc"), + "libs": (((definition_raw["settings"] ?? {})["typescript"] ?? {})["libs"] ?? ["es2020"]), + }, + }, + "directories": { + "lib": ( + (definition_raw["misc"] ?? {})["lib"] + ?? + "lib" + ), + "source": ( + (definition_raw["misc"] ?? {})["source"] + ?? + "source" + ), + "misc": ( + (definition_raw["misc"] ?? {})["misc"] + ?? + "misc" + ), + }, + "libs": (definition_raw["libs"] ?? {}), + "core": definition_raw["core"], + "apps": ( + definition_raw["apps"].map( + (app_raw : Record) => ( + { + "name": app_raw["name"], + "sources": app_raw["sources"], + "additional_dependencies": (app_raw["additional_dependencies"] ?? []), + "destination": (app_raw["destination"] ?? "{{project}}-{{app}}"), + "head": (app_raw["head"] ?? null), + "executable": (app_raw["executable"] ?? false), } - ); - if (log_only) { - resolve( - { - "code": 0, - "stdout": "", - "stderr": "", - } - ); - } - else { - nm_child_process.exec( - command, - { - "cwd": ((working_directory === null) ? undefined : working_directory), - }, - (error, stdout, stderr) => { - if (error) { - reject(error); - } - else { - resolve( - { - /** - * @todo assign correct value - */ - "code": 0, - "stdout": stdout, - "stderr": stderr, - } - ); - } - } - ); - } - } - ) + ) + ) + ), + "custom_rules": ( + (definition_raw["custom_rules"] ?? []).map( + (custom_rule_raw : Record) => ( + { + "targets": custom_rule_raw["targets"], + "dependencies": custom_rule_raw["dependencies"], + "actions": custom_rule_raw["actions"], + "info": (custom_rule_raw["info"] ?? null), + } + ) + ) + ), + }; + } + + + /** + */ + function get_target_name( + app_name : string + ) : string + { + return lib_plankton.string.coin( + "app-{{name}}", + { + "name": app_name, + } ); } /** */ - function get_app_facade_name( - app : type_app + function get_temp_directory( + definition : _ivaldi.type_definition, + pattern : string ) : string { return lib_plankton.string.coin( - "app-{{name}}", + pattern, { - "name": app.name, + "project": definition.name, } ); } + + + /** + */ + function get_build_directory( + definition : _ivaldi.type_definition, + pattern : string + ) : string + { + return lib_plankton.string.coin( + pattern, + { + "project": definition.name, + } + ); + } + + + /** + */ + async function action_fetch( + definition : _ivaldi.type_definition + ) : Promise + { + // plankton + { + if (definition.libs.plankton === null) + { + // do nothing + } + else + { + const directory : string = lib_plankton.string.coin( + "{{directory}}/plankton", + { + "directory": definition.directories.lib, + } + ); + /** + * @todo do not use "_ivaldi.execute" for that + */ + await _ivaldi.execute( + _ivaldi.command_mkdir(directory), + ); + await _ivaldi.execute( + _ivaldi.command_ptk_bundle(definition.target, definition.libs.plankton), + { + "working_directory": directory, + } + ); + } + } + // node + { + if (definition.libs.node === null) + { + // do nothing + } + else + { + const directory : string = lib_plankton.string.coin( + "{{directory}}/node", + { + "directory": definition.directories.lib, + } + ); + /** + * @todo do not use "_ivaldi.execute" for that + */ + await _ivaldi.execute( + _ivaldi.command_mkdir(directory) + ); + await _ivaldi.execute( + _ivaldi.command_npm_install(definition.libs.node), + { + "working_directory": directory, + } + ); + } + } + } + + + /** + */ + async function action_clear( + definition : _ivaldi.type_definition, + temp_directory_pattern : string, + build_directory_pattern : string + ) : Promise + { + const commands : Array = [ + _ivaldi.command_delete(get_temp_directory(definition, temp_directory_pattern)), + _ivaldi.command_delete(get_build_directory(definition, build_directory_pattern)), + ]; + /** + * @todo do not use "_ivaldi.execute" for that + */ + for (const command of commands) + { + await _ivaldi.execute(command); + } + } + + + /** + */ + async function action_build( + definition : _ivaldi.type_definition, + assets : Array<{from : string; to : string;}>, + temp_directory_pattern : string, + build_directory_pattern : string, + makefile_path_pattern : string, + targets : (null | Array), + { + "show_actions": show_actions = true, + } + : + { + show_actions ?: boolean + } + = + { + } + ) : Promise + { + const temp_directory : string = get_build_directory(definition, temp_directory_pattern); + const build_directory : string = get_build_directory(definition, build_directory_pattern); + + // makefile stuff + { + const has_plankton : boolean = ((definition.libs.plankton !== null) && (definition.libs.plankton.length > 0)); + const has_node : boolean = ((definition.libs.node !== null) && (definition.libs.node.length > 0)); + + const path_plankton_declaration : string = lib_plankton.string.coin( + "{{directory_libs}}/plankton/plankton.d.ts", + { + "directory_libs": definition.directories.lib, + } + ); + const path_plankton_implementation : string = lib_plankton.string.coin( + "{{directory_libs}}/plankton/plankton.js", + { + "directory_libs": definition.directories.lib, + } + ); + const path_core_declaration : string = lib_plankton.string.coin( + "{{directory_temp}}/core-unlinked.d.ts", + { + "directory_temp": temp_directory, + } + ); + const path_core_implementation : string = lib_plankton.string.coin( + "{{directory_temp}}/core-unlinked.js", + { + "directory_temp": temp_directory, + } + ); + + const gnu_make_sheet : lib_plankton.gnu_make.type_sheet = { + "rules": ( + (new Array>) + // root + .concat( + [ + { + "kind": "meta", + "data": { + "phony": true, + "name": "_root", + "dependencies": definition.apps.map((app : _ivaldi.type_app) => get_target_name(app.name)), + } + }, + ] + ) + // node modules + .concat( + has_node + ? + [ + { + "kind": "concrete", + "data": { + "targets": [ + "node_modules" + ], + "dependencies": [], + "actions": [ + _ivaldi.command_log("placing node modules …"), + _ivaldi.command_mkdir( + lib_plankton.string.coin("{{directory}}/node_modules", {"directory": build_directory}) + ), + _ivaldi.command_copy( + lib_plankton.string.coin("{{directory}}/node/node_modules/*", {"directory": definition.directories.lib}), + lib_plankton.string.coin("{{directory}}/node_modules/", {"directory": build_directory}) + ) + ] + } + }, + ] + : + [] + ) + // custom rules + .concat( + [ + definition.custom_rules + .map( + custom_rule => ({ + "kind": "concrete", + "data": { + "targets": ( + custom_rule.targets + .map( + target => lib_plankton.string.coin( + target, + { + "dir_build": build_directory, + } + ) + ) + ), + "dependencies": ( + custom_rule.dependencies.map( + dependency => lib_plankton.string.coin( + dependency, + { + "dir_source": definition.directories.source, + "dir_misc": definition.directories.misc, + } + ), + ) + ), + "actions": ( + (new Array()) + .concat( + (custom_rule.info === null) + ? + [] + : + [ + _ivaldi.command_log( + lib_plankton.string.coin( + "{{info}} …", + { + "info": custom_rule.info, + } + ), + ) + ] + ) + .concat( + /** + * @todo coin? + */ + custom_rule.actions + ) + ), + } + }) + ) + ] + ) + // core + .concat( + [ + [ + { + "kind": "concrete", + "data": { + "targets": [ + path_core_declaration, + path_core_implementation, + ], + "dependencies": ( + (new Array()) + .concat(has_plankton ? [path_plankton_declaration] : []) + .concat( + definition.core.map( + path => lib_plankton.string.coin( + "{{directory}}/{{path}}", + { + "directory": definition.directories.source, + "path": path, + } + ) + ) + ) + ), + "actions": [ + // log + _ivaldi.command_log("core | compiling …"), + // mkdir + _ivaldi.command_mkdir("$(dir $@)"), + // command + _ivaldi.command_tsc( + ["$^"], + path_core_implementation, + { + "declaration": true, + "head": definition.settings.typescript.command, + "libs": definition.settings.typescript.libs, + } + ), + ] + } + }, + ] + ] + ) + // apps + .concat( + definition.apps + .map( + app => { + const paths_sources : Array = ( + app.sources + .map( + source => lib_plankton.string.coin( + "{{directory}}/{{name}}", + { + "directory": definition.directories.source, + "name": source, + } + ) + ) + ); + const path_app_unlinked : string = lib_plankton.string.coin( + "{{directory_temp}}/app-{{name}}-unlinked.js", + { + "directory_temp": temp_directory, + "name": app.name, + } + ); + const path_app_complete : string = lib_plankton.string.coin( + "{{directory_build}}/{{destination}}", + { + "directory_build": build_directory, + "destination": lib_plankton.string.coin( + app.destination, + { + "project": definition.name, + "app": app.name, + } + ), + } + ); + return [ + // compile + { + "kind": "concrete", + "data": { + "targets": [ + path_app_unlinked, + ], + "dependencies": ( + (new Array()) + .concat(has_plankton ? [path_plankton_declaration] : []) + .concat([path_core_declaration]) + .concat(paths_sources) + ), + "actions": [ + _ivaldi.command_log(lib_plankton.string.coin("app:{{name}} | compiling …", {"name": app.name})), + _ivaldi.command_mkdir("$(dir $@)"), + _ivaldi.command_tsc( + ["$^"], + "$@", + { + "head": definition.settings.typescript.command, + "libs": definition.settings.typescript.libs, + } + ), + ] + } + }, + // link + { + "kind": "concrete", + "data": { + "targets": [ + path_app_complete, + ], + "dependencies": ( + (new Array()) + .concat(has_plankton ? [path_plankton_implementation] : []) + .concat([path_core_implementation]) + .concat([path_app_unlinked]) + ), + "actions": ( + (new Array()) + .concat( + [ + _ivaldi.command_log(lib_plankton.string.coin("app:{{name}} | linking …", {"name": app.name})), + _ivaldi.command_mkdir("$(dir $@)"), + lib_plankton.string.coin("echo '{{head}}' > {{path}}", {"head": (app.head ?? ""), "path": path_app_complete}), + _ivaldi.command_cat(["$^"], "$@", {"append": true}), + ] + ) + // make executable + .concat( + ( + app.executable + ? + [ + /** + * @todo _ivaldi.command_ + */ + "chmod +x $@", + ] + : + [ + ] + ) + ) + ) + }, + }, + // facade + { + "kind": "meta", + "data": { + "phony": true, + "name": get_target_name(app.name), + "dependencies": ( + (new Array()) + .concat(has_node ? ["node_modules"] : []) + .concat([path_app_complete]) + // additional dependencies + .concat( + app.additional_dependencies + .map( + dependency => lib_plankton.string.coin( + dependency, + { + "dir_source": definition.directories.source, + "dir_misc": definition.directories.misc, + "dir_temp": temp_directory, + "dir_build": build_directory, + } + ) + ) + ) + ), + }, + }, + ]; + } + ) + ) + .reduce( + (x, y) => x.concat(y), + [] + ) + ), + }; + const makefile_content : string = lib_plankton.gnu_make.render_sheet( + gnu_make_sheet, + { + "break_dependencies": true, + "silent_actions": (! show_actions), + } + ); + const makefile_path : string = lib_plankton.string.coin( + makefile_path_pattern, + { + "project": definition.name, + } + ); + await lib_plankton.file.write( + makefile_path, + makefile_content + ); + const command : string = lib_plankton.string.coin( + "make --file={{path}} {{targets}}", + { + "path": makefile_path, + "targets": ( + (targets === null) + ? + "" + : + targets.map(target => get_target_name(target)).join(" ") + ), + } + ); + const result = await _ivaldi.execute(command); + process.stdout.write(result.stdout + "\n"); + process.stderr.write(result.stderr + "\n"); + } + // assets + { + const commands : Array = assets.map( + asset => _ivaldi.command_copy( + asset.from, + lib_plankton.string.coin("{{directory}}/{{path}}", {"directory": build_directory, "path": asset.to}) + ) + ); + for (const command of commands) + { + await _ivaldi.execute(command); + } + } + } /** @@ -125,14 +640,59 @@ namespace _ivaldi "info": "what to do : fetch | clear | build | deploy", "name": "action", }), - "data_path": lib_plankton.args.class_argument.volatile({ - "indicators_long": ["data-path"], + "definition_path": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["definition-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", + "info": "path to definition file", + "name": "definition-path", + }), + "assets": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["asset"], + "indicators_short": ["a"], + "type": lib_plankton.args.enum_type.string, + "mode": lib_plankton.args.enum_mode.accumulate, + "default": [], + "info": ":", + "name": "assets", + }), + "targets": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["targets"], + "indicators_short": ["t"], + "type": lib_plankton.args.enum_type.string, + "mode": lib_plankton.args.enum_mode.accumulate, + "default": [], + "info": "list of targets to build", + "name": "targets", + }), + "temp_directory_pattern": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["temp-directory-pattern"], + "indicators_short": ["T"], + "type": lib_plankton.args.enum_type.string, + "mode": lib_plankton.args.enum_mode.replace, + "default": "/tmp/{{project}}-temp", + "info": "pattern for temp directory", + "name": "temp-directory-pattern", + }), + "build_directory_pattern": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["build-directory-pattern"], + "indicators_short": ["B"], + "type": lib_plankton.args.enum_type.string, + "mode": lib_plankton.args.enum_mode.replace, + "default": "/tmp/{{project}}", + "info": "pattern for build directory", + "name": "build-directory-pattern", + }), + "makefile_path_pattern": lib_plankton.args.class_argument.volatile({ + "indicators_long": ["makefile-path-pattern"], + "indicators_short": ["M"], + "type": lib_plankton.args.enum_type.string, + "mode": lib_plankton.args.enum_mode.replace, + "default": "/tmp/{{project}}-makefile", + "info": "pattern for makefile path", + "name": "makefile-path-pattern", }), "verbosity": lib_plankton.args.class_argument.volatile({ "indicators_long": ["verbosity"], @@ -200,91 +760,18 @@ namespace _ivaldi arg_handler.generate_help( { "programname": "ivaldi", - "description": "a collection of tools for building and deploying a software project", + "description": "a collection of tools for building and deploying a software project on basis of typescript and node", "executable": "ivaldi", } ) ); } else - { - const content : string = await lib_plankton.file.read(args.data_path); + { + const content : string = await lib_plankton.file.read(args.definition_path as string); const data_raw : any = lib_plankton.json.decode(content); - const data : _ivaldi.type_data = { - "version": data_raw["version"], - "name": data_raw["name"], - "target": ( - data_raw["target"] - ?? - "node" - ), - "settings": { - "typescript": { - "command": (((data_raw["settings"] ?? {})["typescript"] ?? {})["command"] ?? "tsc"), - "libs": (((data_raw["settings"] ?? {})["typescript"] ?? {})["libs"] ?? ["es2020"]), - }, - }, - "directories": { - "lib": ( - (data_raw["misc"] ?? {})["lib"] - ?? - "lib" - ), - "source": ( - (data_raw["misc"] ?? {})["source"] - ?? - "source" - ), - "misc": ( - (data_raw["misc"] ?? {})["misc"] - ?? - "misc" - ), - "temp": ( - (data_raw["misc"] ?? {})["temp"] - ?? - lib_plankton.string.coin("/tmp/_{{name}}", {"name": data_raw["name"]}) - ), - "build": ( - (data_raw["misc"] ?? {})["build"] - ?? - lib_plankton.string.coin("/tmp/{{name}}", {"name": data_raw["name"]}) - ), - "makefile": ( - (data_raw["misc"] ?? {})["makefile"] - ?? - lib_plankton.string.coin("/tmp/", {}) - ), - }, - "libs": (data_raw["libs"] ?? {}), - "core": data_raw["core"], - "apps": ( - data_raw["apps"].map( - (app_raw : Record) => ( - { - "name": app_raw["name"], - "sources": app_raw["sources"], - "additional_dependencies": (app_raw["additional_dependencies"] ?? []), - "destination": (app_raw["destination"] ?? "{{project}}-{{app}}"), - "head": (app_raw["head"] ?? null), - "executable": (app_raw["executable"] ?? false), - } - ) - ) - ), - "custom_rules": ( - (data_raw["custom_rules"] ?? []).map( - (custom_rule_raw : Record) => ( - { - "targets": custom_rule_raw["targets"], - "dependencies": custom_rule_raw["dependencies"], - "actions": custom_rule_raw["actions"], - "info": (custom_rule_raw["info"] ?? null), - } - ) - ) - ), - }; + const definition : _ivaldi.type_definition = refine_definition(data_raw); + switch (args.action) { default: @@ -294,444 +781,38 @@ namespace _ivaldi } case "fetch": { - // plankton - { - if (data.libs.plankton === null) - { - // do nothing - } - else - { - const directory : string = lib_plankton.string.coin( - "{{directory}}/plankton", - { - "directory": data.directories.lib, - } - ); - /** - * @todo do not use "execute" for that - */ - await execute( - _ivaldi.command_mkdir(directory), - ); - await execute( - _ivaldi.command_ptk_bundle(data.target, data.libs.plankton), - { - "working_directory": directory, - } - ); - } - } - // node - { - if (data.libs.node === null) - { - // do nothing - } - else - { - const directory : string = lib_plankton.string.coin( - "{{directory}}/node", - { - "directory": data.directories.lib, - } - ); - /** - * @todo do not use "execute" for that - */ - await execute( - _ivaldi.command_mkdir(directory) - ); - await execute( - _ivaldi.command_npm_install(data.libs.node), - { - "working_directory": directory, - } - ); - } - } - return Promise.resolve(undefined); + await action_fetch( + definition + ); break; } case "clear": { - const commands : Array = [ - _ivaldi.command_delete(data.directories.temp), - _ivaldi.command_delete(data.directories.build), - ]; - /** - * @todo do not use "execute" for that - */ - for (const command of commands) - { - await execute(command); - } - return Promise.resolve(undefined); + await action_clear( + definition, + args.temp_directory_pattern, + args.build_directory_pattern + ); break; } case "build": { - const has_plankton : boolean = ((data.libs.plankton !== null) && (data.libs.plankton.length > 0)); - const path_plankton_declaration : string = lib_plankton.string.coin( - "{{directory_libs}}/plankton/plankton.d.ts", - { - "directory_libs": data.directories.lib, - } - ); - const path_plankton_implementation : string = lib_plankton.string.coin( - "{{directory_libs}}/plankton/plankton.js", - { - "directory_libs": data.directories.lib, - } - ); - const path_core_declaration : string = lib_plankton.string.coin( - "{{directory_temp}}/core-unlinked.d.ts", - { - "directory_temp": data.directories.temp, - } - ); - const path_core_implementation : string = lib_plankton.string.coin( - "{{directory_temp}}/core-unlinked.js", - { - "directory_temp": data.directories.temp, - } - ); - const gnu_make_sheet : lib_plankton.gnu_make.type_sheet = { - "rules": ( - (new Array>) - // root - .concat( - [ - { - "kind": "meta", - "data": { - "phony": true, - "name": "_root", - "dependencies": data.apps.map(app => get_app_facade_name(app)), - } - }, - ] - ) - // node modules - .concat( - [ - { - "kind": "concrete", - "data": { - "targets": [ - "node_modules" - ], - "dependencies": [], - "actions": [ - _ivaldi.command_log("placing node modules …"), - _ivaldi.command_mkdir( - lib_plankton.string.coin("{{directory}}/node_modules", {"directory": data.directories.build}) - ), - _ivaldi.command_copy( - lib_plankton.string.coin("{{directory}}/node/node_modules/*", {"directory": data.directories.lib}), - lib_plankton.string.coin("{{directory}}/node_modules/", {"directory": data.directories.build}) - ) - ] - } - }, - ] - ) - // custom rules - .concat( - [ - data.custom_rules - .map( - data_custom_rule => ({ - "kind": "concrete", - "data": { - "targets": ( - data_custom_rule.targets - .map( - target => lib_plankton.string.coin( - target, - { - "dir_build": data.directories.build, - } - ) - ) - ), - "dependencies": ( - data_custom_rule.dependencies.map( - dependency => lib_plankton.string.coin( - dependency, - { - "dir_source": data.directories.source, - "dir_misc": data.directories.misc, - } - ), - ) - ), - "actions": ( - (new Array()) - .concat( - (data_custom_rule.info === null) - ? - [] - : - [ - _ivaldi.command_log( - lib_plankton.string.coin( - "{{info}} …", - { - "info": data_custom_rule.info, - } - ), - ) - ] - ) - .concat( - /** - * @todo coin? - */ - data_custom_rule.actions - ) - ), - } - }) - ) - ] - ) - // core - .concat( - [ - [ - { - "kind": "concrete", - "data": { - "targets": [ - path_core_declaration, - path_core_implementation, - ], - "dependencies": ( - (new Array()) - .concat(has_plankton ? [path_plankton_declaration] : []) - .concat( - data.core.map( - path => lib_plankton.string.coin( - "{{directory}}/{{path}}", - { - "directory": data.directories.source, - "path": path, - } - ) - ) - ) - ), - "actions": [ - // log - _ivaldi.command_log("core | compiling …"), - // mkdir - _ivaldi.command_mkdir("$(dir $@)"), - // command - _ivaldi.command_tsc( - ["$^"], - path_core_implementation, - { - "declaration": true, - "head": data.settings.typescript.command, - "libs": data.settings.typescript.libs, - } - ), - ] - } - }, - ] - ] - ) - // apps - .concat( - data.apps - .map( - app => { - const paths_sources : Array = ( - app.sources - .map( - source => lib_plankton.string.coin( - "{{directory}}/{{name}}", - { - "directory": data.directories.source, - "name": source, - } - ) - ) - ); - const path_unlinked : string = lib_plankton.string.coin( - "{{directory_temp}}/app-{{name}}-unlinked.js", - { - "directory_temp": data.directories.temp, - "name": app.name, - } - ); - /* - const path_head : string = lib_plankton.string.coin( - "{{directory_temp}}/head.js", - { - "directory_temp": data.directories.temp, - } - ); - */ - - const path_result : string = lib_plankton.string.coin( - "{{directory_build}}/{{destination}}", - { - "directory_build": data.directories.build, - "destination": lib_plankton.string.coin( - app.destination, - { - "project": data.name, - "app": app.name, - } - ), - } - ); - return [ - // compile - { - "kind": "concrete", - "data": { - "targets": [ - path_unlinked, - ], - "dependencies": ( - (new Array()) - .concat(has_plankton ? [path_plankton_declaration] : []) - .concat([path_core_declaration]) - .concat(paths_sources) - ), - "actions": [ - _ivaldi.command_log(lib_plankton.string.coin("app:{{name}} | compiling …", {"name": app.name})), - _ivaldi.command_mkdir("$(dir $@)"), - _ivaldi.command_tsc( - ["$^"], - "$@", - { - "head": data.settings.typescript.command, - "libs": data.settings.typescript.libs, - } - ), - ] - } - }, - // link - { - "kind": "concrete", - "data": { - "targets": [ - path_result, - ], - "dependencies": ( - (new Array()) - // .concat([path_head]) - .concat(has_plankton ? [path_plankton_implementation] : []) - .concat([path_unlinked]) - ), - "actions": ( - (new Array()) - .concat( - [ - _ivaldi.command_log(lib_plankton.string.coin("app:{{name}} | linking …", {"name": app.name})), - _ivaldi.command_mkdir("$(dir $@)"), - lib_plankton.string.coin("echo '{{head}}' > {{path}}", {"head": (app.head ?? ""), "path": path_result}), - _ivaldi.command_cat(["$^"], "$@", {"append": true}), - ] - ) - // make executable - .concat( - ( - app.executable - ? - [ - /** - * @todo _ivaldi.command_ - */ - "chmod +x $@", - ] - : - [ - ] - ) - ) - ) - }, - }, - // facade - { - "kind": "meta", - "data": { - "phony": true, - "name": get_app_facade_name(app), - "dependencies": ( - (new Array()) - .concat( - [ - /** - * @todo variable - */ - "node_modules", - path_result, - ] - ) - // additional dependencies - .concat( - app.additional_dependencies - .map( - dependency => lib_plankton.string.coin( - dependency, - { - "dir_source": data.directories.source, - "dir_misc": data.directories.misc, - "dir_temp": data.directories.temp, - "dir_build": data.directories.build, - } - ) - ) - ) - ), - }, - }, - ]; - } - ) - ) - .reduce( - (x, y) => x.concat(y), - [] - ) + await action_build( + definition, + args.assets.map( + (asset_raw : string) => { + const parts : Array = asset_raw.split(":", 2); + return {"from": parts[0], "to": parts[1]}; + } ), - }; - const makefile : string = lib_plankton.gnu_make.render_sheet( - gnu_make_sheet, + args.temp_directory_pattern, + args.build_directory_pattern, + args.makefile_path_pattern, + ((args.targets.length <= 0) ? null : args.targets), { - "break_dependencies": true, - "silent_actions": true, + "show_actions": ["debug"].includes(args.verbosity), } ); - const makefile_path : string = lib_plankton.string.coin( - "{{directory}}/ivaldi-makefile-{{name}}", - { - "directory": data.directories.makefile, - "name": data.name, - } - ); - await lib_plankton.file.write( - makefile_path, - makefile - ); - const command : string = lib_plankton.string.coin( - "make -f {{path}}", - { - "path": makefile_path, - } - ); - const result = await execute(command); - process.stdout.write(result.stdout + "\n"); - process.stderr.write(result.stderr + "\n"); - return Promise.resolve(undefined); break; } case "deploy": diff --git a/source/types.ts b/source/types.ts index d34bf86..1964c95 100644 --- a/source/types.ts +++ b/source/types.ts @@ -53,7 +53,7 @@ namespace _ivaldi /** */ - export type type_data = { + export type type_definition = { version : string; name : string; target : ("node" | "web"); @@ -67,9 +67,6 @@ namespace _ivaldi lib : string; source : string; misc : string; - temp : string; - build : string; - makefile : string; }; libs : { plankton : (null | Array); diff --git a/tools/build b/tools/build index 91e9a7b..5ccff90 100755 --- a/tools/build +++ b/tools/build @@ -7,10 +7,22 @@ import argparse as _argparse def main(): argument_parser = _argparse.ArgumentParser( ) + argument_parser.add_argument( + "-o", + "--output-directory", + type = str, + default = "/tmp/ivaldi", + metavar = "", + ) args = argument_parser.parse_args() if True: - _os.system("make -f tools/makefile") + _os.system( + "make dir_build=%s --file=tools/makefile" + % ( + args.output_directory + ) + ) main() diff --git a/tools/install b/tools/install new file mode 100755 index 0000000..8c77b38 --- /dev/null +++ b/tools/install @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import os as _os +import argparse as _argparse + + +def main(): + argument_parser = _argparse.ArgumentParser( + ) + argument_parser.add_argument( + "-b", + "--build-directory", + type = str, + default = "/tmp/ivaldi", + metavar = "", + ) + argument_parser.add_argument( + "-t", + "--target-directory", + type = str, + default = "~/.local/bin", + metavar = "", + ) + args = argument_parser.parse_args() + + _os.system("mkdir -p %s" % (args.target_directory, )) + _os.system("cp %s/ivaldi %s/ivaldi" % (args.build_directory, args.target_directory, )) + + +main() + diff --git a/tools/makefile b/tools/makefile index 60b1c0c..9e8e900 100644 --- a/tools/makefile +++ b/tools/makefile @@ -9,30 +9,35 @@ cmd_echo := echo cmd_chmod := chmod +## args + +dir_lib := libs +dir_source := source +dir_temp := temp +dir_build := build + + ## rules .PHONY: _default _default: _root -temp/ivaldi-unlinked.js: \ - libs/plankton/plankton.d.ts \ - source/types.ts \ - source/helpers.ts \ - source/main.ts +${dir_temp}/ivaldi-unlinked.js: \ + ${dir_lib}/plankton/plankton.d.ts \ + ${dir_source}/types.ts \ + ${dir_source}/helpers.ts \ + ${dir_source}/main.ts @ ${cmd_log} "compiling …" - @ ${cmd_mkdir} temp + @ ${cmd_mkdir} $(dir $@) @ ${cmd_tsc} $^ --lib es2020,dom --target es6 --outFile $@ -build/ivaldi: libs/plankton/plankton.js temp/ivaldi-unlinked.js +${dir_build}/ivaldi: ${dir_lib}/plankton/plankton.js ${dir_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_mkdir} $(dir $@) + @ ${cmd_echo} "#!/usr/bin/env node" > $@ + @ ${cmd_cat} $^ >> $@ @ ${cmd_chmod} +x $@ -.PHONY: sources -sources: build/ivaldi - .PHONY: _root -_root: sources +_root: ${dir_build}/ivaldi