From 766272ae737b43762a4f0f14d513f3f7121db6df Mon Sep 17 00:00:00 2001 From: David Worms Date: Tue, 3 Sep 2024 10:38:55 +0200 Subject: [PATCH] build: eslint 9 activation --- .gitignore | 3 +- .prettierrc.yml | 1 + commitlint.config.js | 32 +- eslint.config.js | 16 + package.json | 12 +- packages/core/.eslintrc | 12 - packages/core/env/chown/index.js | 55 +- packages/core/env/ssh/index.js | 67 ++- packages/core/lib/actions/assert/index.js | 50 +- packages/core/lib/actions/call/index.js | 39 +- .../core/lib/actions/execute/assert/index.js | 90 ++- packages/core/lib/actions/execute/index.js | 74 +-- .../core/lib/actions/execute/wait/index.js | 46 +- packages/core/lib/actions/fs/assert/index.js | 560 +++++++++++------- .../core/lib/actions/fs/base/chmod/index.js | 22 +- .../core/lib/actions/fs/base/chown/index.js | 10 +- .../core/lib/actions/fs/base/copy/index.js | 43 +- .../core/lib/actions/fs/base/mkdir/index.js | 17 +- packages/core/lib/actions/fs/chmod/index.js | 13 +- packages/core/lib/actions/fs/chown/index.js | 20 +- packages/core/lib/actions/fs/copy/index.js | 27 +- .../lib/actions/fs/createReadStream/index.js | 217 ++++--- .../lib/actions/fs/createWriteStream/index.js | 150 ++--- packages/core/lib/actions/fs/exists/index.js | 25 +- packages/core/lib/actions/fs/glob/index.js | 25 +- packages/core/lib/actions/fs/hash/index.js | 29 +- packages/core/lib/actions/fs/link/index.js | 15 +- packages/core/lib/actions/fs/lstat/index.js | 19 +- packages/core/lib/actions/fs/mkdir/index.js | 64 +- packages/core/lib/actions/fs/move/index.js | 10 +- .../core/lib/actions/fs/readFile/index.js | 31 +- packages/core/lib/actions/fs/readdir/index.js | 135 +++-- .../core/lib/actions/fs/readlink/index.js | 23 +- packages/core/lib/actions/fs/remove/index.js | 13 +- packages/core/lib/actions/fs/rename/index.js | 19 +- packages/core/lib/actions/fs/rmdir/index.js | 70 ++- packages/core/lib/actions/fs/stat/index.js | 47 +- packages/core/lib/actions/fs/symlink/index.js | 18 +- packages/core/lib/actions/fs/unlink/index.js | 42 +- packages/core/lib/actions/fs/wait/index.js | 8 +- .../core/lib/actions/fs/writeFile/index.js | 60 +- .../lib/actions/registry/register/index.js | 8 +- .../lib/actions/registry/registered/index.js | 4 +- .../lib/actions/registry/unregister/index.js | 4 +- packages/core/lib/actions/ssh/close/index.js | 37 +- packages/core/lib/actions/ssh/open/index.js | 44 +- packages/core/lib/actions/ssh/root/index.js | 49 +- packages/core/lib/actions/wait/index.js | 23 +- packages/core/lib/plugins/assertions.js | 69 ++- .../core/lib/plugins/assertions/exists.js | 90 +-- packages/core/lib/plugins/conditions.js | 82 +-- .../core/lib/plugins/conditions/execute.js | 109 ++-- .../core/lib/plugins/conditions/exists.js | 71 +-- packages/core/lib/plugins/conditions/os.js | 385 ++++++------ .../plugins/metadata/argument_to_config.js | 42 +- packages/core/lib/plugins/metadata/audit.js | 142 ++--- packages/core/lib/plugins/metadata/debug.js | 139 ++--- .../core/lib/plugins/metadata/disabled.js | 19 +- packages/core/lib/plugins/metadata/execute.js | 23 +- packages/core/lib/plugins/metadata/header.js | 34 +- .../core/lib/plugins/metadata/position.js | 91 +-- packages/core/lib/plugins/metadata/raw.js | 19 +- .../core/lib/plugins/metadata/register.js | 25 +- packages/core/lib/plugins/metadata/retry.js | 49 +- packages/core/lib/plugins/metadata/schema.js | 44 +- packages/core/lib/plugins/metadata/tmpdir.js | 44 +- packages/core/lib/plugins/metadata/uuid.js | 15 +- packages/core/lib/plugins/output/logs.js | 42 +- packages/core/lib/plugins/output/status.js | 66 ++- .../core/lib/plugins/pubsub/engines/memory.js | 15 +- packages/core/lib/plugins/pubsub/index.js | 21 +- packages/core/lib/plugins/templated.js | 2 +- packages/core/lib/plugins/tools/dig.js | 6 +- packages/core/lib/plugins/tools/events.js | 7 +- packages/core/lib/plugins/tools/find.js | 37 +- packages/core/lib/plugins/tools/log.js | 78 +-- packages/core/lib/plugins/tools/path.js | 7 +- packages/core/lib/plugins/tools/schema.js | 132 ++--- .../plugins/tools/schema.keyword.coercion.js | 30 +- packages/core/lib/registry.js | 121 ++-- packages/core/lib/schedulers/index.js | 121 ++-- packages/core/lib/session.js | 213 ++++--- packages/core/lib/session/contextualize.js | 4 +- packages/core/lib/utils/index.js | 3 +- packages/core/package.json | 9 +- packages/core/test/loaders/all.js | 7 +- packages/core/test/loaders/coffee.js | 6 +- .../test/plugins/metadata/register.coffee | 22 +- packages/db/lib/database/exists/index.js | 32 +- packages/db/lib/database/index.js | 121 ++-- packages/db/lib/database/remove/index.js | 17 +- packages/db/lib/database/wait/index.js | 55 +- packages/db/lib/query/index.js | 14 +- packages/db/lib/register.js | 31 +- packages/db/lib/schema/exists/index.js | 7 +- packages/db/lib/schema/index.js | 11 +- packages/db/lib/schema/list/index.js | 7 +- packages/db/lib/schema/remove/index.js | 7 +- packages/db/lib/user/exists/index.js | 7 +- packages/db/lib/user/index.js | 91 +-- packages/db/lib/user/remove/index.js | 19 +- packages/db/lib/utils/db.js | 30 +- packages/docker/lib/build/index.js | 71 +-- packages/docker/lib/compose/index.js | 13 +- packages/docker/lib/cp/index.js | 7 +- packages/docker/lib/exec/index.js | 19 +- packages/docker/lib/images/index.js | 48 +- packages/docker/lib/inspect/index.js | 8 +- packages/docker/lib/kill/index.js | 21 +- packages/docker/lib/load/index.js | 16 +- packages/docker/lib/login/index.js | 7 +- packages/docker/lib/logout/index.js | 25 +- packages/docker/lib/pause/index.js | 19 +- packages/docker/lib/ps/index.js | 50 +- packages/docker/lib/pull/index.js | 10 +- packages/docker/lib/register.js | 59 +- packages/docker/lib/restart/index.js | 23 +- packages/docker/lib/rm/index.js | 46 +- packages/docker/lib/rmi/index.js | 10 +- packages/docker/lib/run/index.js | 9 +- packages/docker/lib/save/index.js | 35 +- packages/docker/lib/start/index.js | 24 +- packages/docker/lib/stop/index.js | 18 +- packages/docker/lib/tools/checksum/index.js | 34 +- packages/docker/lib/tools/execute/index.js | 26 +- packages/docker/lib/tools/service/index.js | 13 +- packages/docker/lib/tools/status/index.js | 9 +- packages/docker/lib/unpause/index.js | 19 +- packages/docker/lib/utils/docker.js | 2 +- packages/docker/lib/utils/index.js | 2 +- packages/docker/lib/volume_create/index.js | 29 +- packages/docker/lib/volume_rm/index.js | 19 +- packages/docker/lib/wait/index.js | 17 +- packages/file/lib/cache/index.js | 88 ++- packages/file/lib/cson/index.js | 31 +- packages/file/lib/download/index.js | 82 +-- packages/file/lib/index.js | 25 +- packages/file/lib/ini/index.js | 27 +- packages/file/lib/ini/read/index.js | 23 +- packages/file/lib/json/index.js | 35 +- packages/file/lib/properties/index.js | 37 +- packages/file/lib/properties/read/index.js | 29 +- packages/file/lib/register.js | 55 +- packages/file/lib/render/index.js | 18 +- packages/file/lib/touch/index.js | 18 +- packages/file/lib/types/ceph_conf/index.js | 17 +- packages/file/lib/types/hfile/index.js | 13 +- packages/file/lib/types/krb5_conf/index.js | 24 +- packages/file/lib/types/locale_gen/index.js | 35 +- packages/file/lib/types/my_cnf/index.js | 22 +- packages/file/lib/types/pacman_conf/index.js | 24 +- .../lib/types/ssh_authorized_keys/index.js | 29 +- .../file/lib/types/systemd/resolved/index.js | 11 +- .../file/lib/types/systemd/timesyncd/index.js | 23 +- .../file/lib/types/wireguard_conf/index.js | 17 +- packages/file/lib/types/yum_repo/index.js | 7 +- packages/file/lib/upload/index.js | 41 +- packages/file/lib/utils/diff.js | 20 +- packages/file/lib/utils/hfile.js | 47 +- packages/file/lib/utils/index.js | 9 +- packages/file/lib/utils/ini.js | 35 +- packages/file/lib/utils/partial.js | 93 ++- packages/file/lib/yaml/index.js | 21 +- packages/file/package.json | 2 - packages/incus/lib/cluster/cli/start/index.js | 102 ++-- packages/incus/lib/cluster/cli/stop/index.js | 36 +- packages/incus/lib/cluster/delete/index.js | 28 +- packages/incus/lib/cluster/index.js | 290 ++++----- .../incus/lib/cluster/samples/three_nodes.js | 7 +- packages/incus/lib/cluster/stop/index.js | 26 +- .../incus/lib/config/device/delete/index.js | 37 +- .../incus/lib/config/device/exists/index.js | 22 +- packages/incus/lib/config/device/index.js | 28 +- .../incus/lib/config/device/show/index.js | 22 +- packages/incus/lib/config/set/index.js | 7 +- packages/incus/lib/delete/index.js | 23 +- packages/incus/lib/exec/index.js | 31 +- packages/incus/lib/exists/index.js | 8 +- packages/incus/lib/file/exists/index.js | 20 +- packages/incus/lib/file/pull/index.js | 13 +- packages/incus/lib/file/push/index.js | 23 +- packages/incus/lib/file/read/index.js | 22 +- packages/incus/lib/goodies/prlimit/index.js | 35 +- packages/incus/lib/info/index.js | 8 +- packages/incus/lib/init/index.js | 29 +- packages/incus/lib/list/index.js | 23 +- packages/incus/lib/network/attach/index.js | 19 +- packages/incus/lib/network/delete/index.js | 20 +- packages/incus/lib/network/detach/index.js | 21 +- packages/incus/lib/network/index.js | 33 +- packages/incus/lib/network/list/index.js | 10 +- packages/incus/lib/query/index.js | 30 +- packages/incus/lib/register.js | 93 ++- packages/incus/lib/resources/index.js | 20 +- packages/incus/lib/running/index.js | 18 +- packages/incus/lib/start/index.js | 22 +- packages/incus/lib/state/index.js | 22 +- packages/incus/lib/stop/index.js | 22 +- packages/incus/lib/storage/delete/index.js | 19 +- packages/incus/lib/storage/exists/index.js | 22 +- packages/incus/lib/storage/index.js | 32 +- packages/incus/lib/storage/list/index.js | 18 +- .../incus/lib/storage/volume/attach/index.js | 56 +- .../incus/lib/storage/volume/delete/index.js | 22 +- .../incus/lib/storage/volume/get/index.js | 20 +- packages/incus/lib/storage/volume/index.js | 24 +- .../incus/lib/storage/volume/list/index.js | 24 +- packages/incus/lib/utils/index.js | 4 +- .../lib/utils/stderr_to_error_message.js | 6 +- packages/incus/lib/wait/ready/index.js | 9 +- packages/ipa/env/ipa/index.js | 105 ++-- packages/ipa/lib/group/add_member/index.js | 28 +- packages/ipa/lib/group/del/index.js | 28 +- packages/ipa/lib/group/exists/index.js | 27 +- packages/ipa/lib/group/index.js | 36 +- packages/ipa/lib/group/show/index.js | 28 +- packages/ipa/lib/register.js | 43 +- packages/ipa/lib/service/del/index.js | 28 +- packages/ipa/lib/service/exists/index.js | 27 +- packages/ipa/lib/service/index.js | 31 +- packages/ipa/lib/service/show/index.js | 30 +- packages/ipa/lib/user/del/index.js | 32 +- packages/ipa/lib/user/disable/index.js | 32 +- packages/ipa/lib/user/enable/index.js | 28 +- packages/ipa/lib/user/exists/index.js | 31 +- packages/ipa/lib/user/find/index.js | 30 +- packages/ipa/lib/user/index.js | 52 +- packages/ipa/lib/user/show/index.js | 34 +- packages/ipa/lib/user/status/index.js | 34 +- packages/java/lib/keystore/add/index.js | 29 +- packages/java/lib/keystore/exists/index.js | 7 +- packages/java/lib/keystore/remove/index.js | 18 +- packages/krb5/lib/addprinc/index.js | 35 +- packages/krb5/lib/delprinc/index.js | 26 +- packages/krb5/lib/execute/index.js | 39 +- packages/krb5/lib/ktadd/index.js | 93 +-- packages/krb5/lib/ktutil/add/index.js | 39 +- packages/krb5/lib/register.js | 19 +- packages/krb5/lib/ticket/index.js | 26 +- packages/krb5/lib/utils/index.js | 5 +- packages/ldap/lib/acl/index.js | 16 +- packages/ldap/lib/add/index.js | 25 +- packages/ldap/lib/delete/index.js | 30 +- packages/ldap/lib/index/index.js | 10 +- packages/ldap/lib/modify/index.js | 55 +- packages/ldap/lib/schema/index.js | 12 +- packages/ldap/lib/search/index.js | 35 +- packages/ldap/lib/tools/database/index.js | 25 +- packages/ldap/lib/tools/databases/index.js | 9 +- packages/ldap/lib/user/index.js | 24 +- packages/ldap/lib/utils/index.js | 5 +- packages/ldap/lib/utils/ldap.js | 34 +- packages/log/lib/cli/index.js | 108 ++-- packages/log/lib/csv/index.js | 25 +- packages/log/lib/fs/index.js | 48 +- packages/log/lib/md/index.js | 91 +-- packages/log/lib/stream/index.js | 29 +- packages/log/package.json | 2 - packages/network/lib/http/index.js | 49 +- packages/network/lib/http/wait/index.js | 20 +- packages/network/lib/register.js | 17 +- packages/network/lib/tcp/assert/index.js | 13 +- packages/network/lib/tcp/wait/index.js | 9 +- packages/network/lib/utils/curl.js | 163 +++-- packages/nikita/test/index.js | 4 +- packages/service/env/systemctl/index.js | 9 +- packages/service/lib/assert/index.js | 39 +- packages/service/lib/discover/index.js | 19 +- packages/service/lib/index.js | 45 +- packages/service/lib/init/index.js | 12 +- packages/service/lib/install/index.js | 31 +- packages/service/lib/installed/index.js | 32 +- packages/service/lib/outdated/index.js | 31 +- packages/service/lib/register.js | 31 +- packages/service/lib/remove/index.js | 37 +- packages/service/lib/restart/index.js | 8 +- packages/service/lib/start/index.js | 7 +- packages/service/lib/startup/index.js | 285 +++++---- packages/service/lib/status/index.js | 20 +- packages/service/lib/stop/index.js | 22 +- packages/system/env/cgroups/index.js | 5 +- packages/system/lib/cgroups/index.js | 139 ++--- packages/system/lib/group/index.js | 42 +- packages/system/lib/group/read/index.js | 16 +- packages/system/lib/group/remove/index.js | 19 +- packages/system/lib/info/disks/index.js | 7 +- packages/system/lib/info/os/index.js | 7 +- packages/system/lib/limits/index.js | 33 +- packages/system/lib/mod/index.js | 34 +- packages/system/lib/register.js | 39 +- packages/system/lib/running/index.js | 76 +-- packages/system/lib/tmpfs/index.js | 16 +- packages/system/lib/uid_gid/index.js | 8 +- packages/system/lib/user/index.js | 97 +-- packages/system/lib/user/read/index.js | 13 +- packages/system/lib/user/remove/index.js | 17 +- packages/system/lib/utils/cgconfig.js | 116 ++-- packages/system/lib/utils/tmpfs.js | 9 +- packages/tools/env/iptables/index.js | 54 +- packages/tools/env/npm/index.js | 55 +- packages/tools/env/rubygems/index.js | 59 +- packages/tools/env/run.sh | 1 + packages/tools/lib/backup/index.js | 8 +- packages/tools/lib/compress/index.js | 67 +-- packages/tools/lib/cron/add/index.js | 25 +- packages/tools/lib/cron/list/index.js | 20 +- packages/tools/lib/cron/remove/index.js | 36 +- packages/tools/lib/cron/reset/index.js | 10 +- packages/tools/lib/dconf/index.js | 18 +- packages/tools/lib/extract/index.js | 79 +-- packages/tools/lib/git/index.js | 45 +- packages/tools/lib/gsettings/index.js | 22 +- packages/tools/lib/iptables/index.js | 7 +- packages/tools/lib/npm/index.js | 10 +- packages/tools/lib/npm/list/index.js | 24 +- packages/tools/lib/npm/outdated/index.js | 28 +- packages/tools/lib/npm/uninstall/index.js | 8 +- packages/tools/lib/npm/upgrade/index.js | 8 +- packages/tools/lib/register.js | 57 +- packages/tools/lib/repo/index.js | 18 +- packages/tools/lib/rubygems/fetch/index.js | 32 +- packages/tools/lib/rubygems/install/index.js | 21 +- packages/tools/lib/rubygems/remove/index.js | 22 +- packages/tools/lib/ssh/keygen/index.js | 27 +- packages/tools/lib/sysctl/file/index.js | 40 +- packages/tools/lib/sysctl/file/read/index.js | 9 +- packages/tools/lib/utils/index.js | 7 +- packages/tools/lib/utils/iptables.js | 27 +- packages/tools/test/repo.coffee | 20 +- packages/utils/lib/array.js | 3 +- packages/utils/lib/buffer.js | 9 +- packages/utils/lib/error.js | 9 +- packages/utils/lib/mode.js | 2 +- packages/utils/lib/object.js | 14 +- packages/utils/lib/os.js | 2 +- packages/utils/lib/promise.js | 16 +- packages/utils/lib/regexp.js | 9 +- packages/utils/lib/string.js | 2 +- packages/utils/lib/tilde.js | 2 +- packages/utils/package.json | 3 - packages/utils/test.sample.coffee | 3 +- packages/utils/test/loaders/all.js | 7 +- packages/utils/test/loaders/coffee.js | 6 +- packages/utils/test/promise.coffee | 12 + 344 files changed, 7082 insertions(+), 5460 deletions(-) create mode 100644 .prettierrc.yml create mode 100644 eslint.config.js delete mode 100644 packages/core/.eslintrc diff --git a/.gitignore b/.gitignore index a53df1b95..89367fb68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ .* /playground node_modules -!.eslintrc -!.travis.yml +!.prettierrc.yml !.gitignore !.github !.gitattributes diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 000000000..73901116b --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1 @@ +experimentalTernaries: true diff --git a/commitlint.config.js b/commitlint.config.js index 6d6016135..2e08bab98 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,17 +1,33 @@ -import scopes from "@commitlint/config-lerna-scopes"; +import fs from "node:fs/promises"; +import { glob } from "glob"; +const pkg = await fs + .readFile("./package.json", { encoding: "utf8" }) + .then((data) => JSON.parse(data)); + +console.log(pkg.workspaces); + +const packages = await glob( + pkg.workspaces.map((pattern) => `${pattern}/package.json`), +).then((files) => + Promise.all( + files.map((file) => + fs + .readFile(file, { encoding: "utf8" }) + .then((data) => JSON.parse(data)) + .then((pkg) => pkg.name.replace("@nikitajs/", "")), + ), + ), +); export default { - extends: [ - "@commitlint/config-conventional", - "@commitlint/config-lerna-scopes", - ], + extends: ["@commitlint/config-conventional"], rules: { - "scope-enum": async (ctx) => [ + "scope-enum": async () => [ 2, "always", [ - ...(await scopes.utils.getPackages(ctx)), - // Insert custom scopes below: + ...packages, + // Custom scopes "release", ], ], diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..6f938ba78 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,16 @@ +import globals from "globals"; +import js from "@eslint/js"; +import mocha from "eslint-plugin-mocha"; +import prettier from "eslint-plugin-prettier/recommended"; + +export default [ + { + ignores: ["**/node_modules/", "docs/**", "extra/**"], + }, + { + languageOptions: { globals: { ...globals.node } }, + }, + js.configs.recommended, + mocha.configs.flat.recommended, + prettier, +]; diff --git a/package.json b/package.json index 5903f4021..8dad8d207 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,16 @@ "devDependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", - "@commitlint/config-lerna-scopes": "^19.0.0", + "@eslint/js": "^9.9.1", "cz-conventional-changelog": "^3.3.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-prettier": "^5.2.1", + "glob": "^11.0.0", "husky": "^9.1.1", - "lerna": "^8.1.6" + "lerna": "^8.1.6", + "prettier": "^3.3.3" }, "scripts": { "compile": "lerna run compile", @@ -14,6 +20,8 @@ "docs:clean": "cd docs/website && yarn clean", "docs:develop": "cd docs/website && yarn develop", "lint": "lerna run lint", + "lint:check": "eslint", + "lint:fix": "eslint --fix", "test": "lerna run test", "test:local": "lerna run test:local", "goodies:incus:macos": "./packages/incus/assets/multipass.sh", diff --git a/packages/core/.eslintrc b/packages/core/.eslintrc deleted file mode 100644 index 1ea63efde..000000000 --- a/packages/core/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": [ - "plugin:coffee/eslint-recommended" - ], - "parser": "eslint-plugin-coffee", - "plugins": ["coffee"], - "rules": { - "coffee/implicit-arrow-linebreak": "off", - "coffee/comma-style": "off", - "coffee/jsx-wrap-multilines": "off" - } -} diff --git a/packages/core/env/chown/index.js b/packages/core/env/chown/index.js index 2b4b1ef24..e377f0e5e 100644 --- a/packages/core/env/chown/index.js +++ b/packages/core/env/chown/index.js @@ -1,35 +1,40 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const __dirname = new URL( '.', import.meta.url).pathname +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const __dirname = new URL(".", import.meta.url).pathname; runner({ - cwd: '/nikita/packages/core', - container: 'nikita-core-chown', - logdir: path.resolve(__dirname, './logs'), + cwd: "/nikita/packages/core", + container: "nikita-core-chown", + logdir: path.resolve(__dirname, "./logs"), cluster: { containers: { - 'nikita-core-chown': { - image: 'images:almalinux/8', + "nikita-core-chown": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/core/env/chown/test.coffee', - 'raw.idmap': parseInt(process.env['NIKITA_INCUS_IN_VAGRANT']) ? 'both 1000 0' : `uid ${process.getuid()} 0\ngid ${process.getgid()} 0` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/core/env/chown/test.coffee", + "raw.idmap": + parseInt(process.env["NIKITA_INCUS_IN_VAGRANT"]) ? "both 1000 0" : ( + `uid ${process.getuid()} 0\ngid ${process.getgid()} 0` + ), }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(__dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || + path.join(__dirname, "../../../../"), + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", container: config.container, command: dedent` if command -v node ; then exit 42; fi @@ -39,10 +44,10 @@ runner({ nvm install 22 `, trap: true, - code: [0, 42] + code: [0, 42], }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", container: config.container, command: dedent` mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -51,8 +56,8 @@ runner({ cat /root/.ssh/id_ed25519.pub > /root/.ssh/authorized_keys fi `, - trap: true + trap: true, }); - } - } + }, + }, }); diff --git a/packages/core/env/ssh/index.js b/packages/core/env/ssh/index.js index c1529ef00..ab3870101 100644 --- a/packages/core/env/ssh/index.js +++ b/packages/core/env/ssh/index.js @@ -1,45 +1,50 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const __dirname = new URL( '.', import.meta.url).pathname +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const __dirname = new URL(".", import.meta.url).pathname; runner({ - cwd: '/nikita/packages/core', - container: 'nikita-core-ssh', - logdir: path.resolve(__dirname, './logs'), + cwd: "/nikita/packages/core", + container: "nikita-core-ssh", + logdir: path.resolve(__dirname, "./logs"), test_user: 1234, cluster: { containers: { - 'nikita-core-ssh': { - image: 'images:almalinux/8', + "nikita-core-ssh": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/core/env/ssh/test.coffee', - 'environment.HOME': '/home/source', // Fix, Incus doesnt set HOME with --user - 'raw.idmap': process.env['NIKITA_INCUS_IN_VAGRANT'] ? 'both 1000 1234' : `both ${process.getuid()} 1234` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/core/env/ssh/test.coffee", + "environment.HOME": "/home/source", // Fix, Incus doesnt set HOME with --user + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 1234" + : `both ${process.getuid()} 1234`, }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(__dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || + path.join(__dirname, "../../../../"), + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Dependencies', + $header: "Dependencies", container: config.container, command: dedent` # nvm require the tar commands yum install -y tar - ` + `, }); await this.incus.exec({ - $header: 'User `source`', + $header: "User `source`", container: config.container, command: dedent` if ! id -u 1234 ; then @@ -51,10 +56,10 @@ runner({ fi chown -R source /home/source/ `, - trap: true + trap: true, }); await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", container: config.container, command: dedent` if command -v node ; then exit 42; fi @@ -63,12 +68,12 @@ runner({ nvm install 22 `, user: 1234, - shell: 'bash', + shell: "bash", trap: true, - code: [0, 42] + code: [0, 42], }); await this.incus.exec({ - $header: 'User `target`', + $header: "User `target`", container: config.container, command: dedent` if ! id -u 1235; then @@ -81,8 +86,8 @@ runner({ fi chown -R target /home/target/ `, - trap: true + trap: true, }); - } - } + }, + }, }); diff --git a/packages/core/lib/actions/assert/index.js b/packages/core/lib/actions/assert/index.js index b64a2bc96..4bb4db99b 100644 --- a/packages/core/lib/actions/assert/index.js +++ b/packages/core/lib/actions/assert/index.js @@ -1,33 +1,37 @@ - // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { hooks: { - on_action: function(action) { + on_action: function (action) { action.handler = ((handler) => - async function({config}) { + async function ({ config }) { let result = await this.call({ $raw_output: true, - $handler: handler + $handler: handler, }); if (!Array.isArray(result)) { result = [result]; } if (!config.strict) { - result = result.map(function(res) { + result = result.map(function (res) { switch (typeof res) { - case 'undefined': + case "undefined": return false; - case 'boolean': + case "boolean": return !!res; - case 'number': + case "number": return !!res; - case 'string': + case "string": return !!res.length; - case 'object': + case "object": if (Buffer.isBuffer(res)) { return !!res.length; } else if (res === null) { @@ -35,22 +39,26 @@ export default { } else { return !!Object.keys(res).length; } - case 'function': - throw utils.error('NIKITA_ASSERT_INVALID_OUTPUT', ['assertion does not accept functions']); + case "function": + throw utils.error("NIKITA_ASSERT_INVALID_OUTPUT", [ + "assertion does not accept functions", + ]); } }); } result = !result.some((res) => - !config.not ? res !== true : res === true + !config.not ? res !== true : res === true, ); if (result !== true) { - throw utils.error('NIKITA_ASSERT_UNTRUE', ['assertion did not validate,', `got ${JSON.stringify(result)}`]); + throw utils.error("NIKITA_ASSERT_UNTRUE", [ + "assertion did not validate,", + `got ${JSON.stringify(result)}`, + ]); } - } - )(action.handler); - } + })(action.handler); + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/call/index.js b/packages/core/lib/actions/call/index.js index 883ce0338..ff28dfd15 100644 --- a/packages/core/lib/actions/call/index.js +++ b/packages/core/lib/actions/call/index.js @@ -1,21 +1,20 @@ - // Dependencies -import path from 'node:path'; -import {mutate} from 'mixme'; -import utils from '@nikitajs/core/utils' +import path from "node:path"; +import { mutate } from "mixme"; +import utils from "@nikitajs/core/utils"; // Action export default { hooks: { - on_action: async function(action) { - if (typeof action.metadata.argument !== 'string') { + on_action: async function (action) { + if (typeof action.metadata.argument !== "string") { return; } const arg = action.metadata.argument; let mod = arg; // When metadata.argument is a string, consider it as the module name to load. - if (typeof mod === 'string') { - if (mod.startsWith('.')) { + if (typeof mod === "string") { + if (mod.startsWith(".")) { mod = path.resolve(process.cwd(), mod); } mod = (await import(mod)).default; @@ -26,28 +25,28 @@ export default { action.metadata.module = arg; action.metadata.argument = undefined; } - const on_action = mod.hooks?.on_action - if (typeof mod === 'function') { + const on_action = mod.hooks?.on_action; + if (typeof mod === "function") { mod = { - handler: mod + handler: mod, }; } mutate(action, mod, { metadata: { - module: action.metadata.argument - } + module: action.metadata.argument, + }, }); - if (typeof arg === 'string' && typeof action.handler !== 'function'){ - throw utils.error('NIKITA_CALL_UNDEFINED_HANDLER', [ - 'Action `nikita.call` failed to load', + if (typeof arg === "string" && typeof action.handler !== "function") { + throw utils.error("NIKITA_CALL_UNDEFINED_HANDLER", [ + "Action `nikita.call` failed to load", `module "${arg}"`, - 'because it does not define a handler.', - ]) + "because it does not define a handler.", + ]); } if (on_action) { action = on_action.call(null, action); } return action; - } - } + }, + }, }; diff --git a/packages/core/lib/actions/execute/assert/index.js b/packages/core/lib/actions/execute/assert/index.js index da23ef39d..0ffcc2fe7 100644 --- a/packages/core/lib/actions/execute/assert/index.js +++ b/packages/core/lib/actions/execute/assert/index.js @@ -1,79 +1,119 @@ - - // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const configForExecute = utils.object.filter(config, ['code', 'content', 'not', 'trim']); + handler: async function ({ config }) { + const configForExecute = utils.object.filter(config, [ + "code", + "content", + "not", + "trim", + ]); // Command exit code const res = await this.execute({ ...configForExecute, - $relax: true + $relax: true, }); - const code = res.error ? res.error.exit_code : res.code - const expectedCodes = utils.array.flatten(config.code.true, config.code.false); + const code = res.error ? res.error.exit_code : res.code; + const expectedCodes = utils.array.flatten( + config.code.true, + config.code.false, + ); if (!config.not) { if (!expectedCodes.includes(code)) { - throw utils.error('NIKITA_EXECUTE_ASSERT_EXIT_CODE', ['an unexpected exit code was encountered,', `got ${JSON.stringify(code)}`, expectedCodes.length === 1 ? `while expecting ${expectedCodes}.` : `while expecting one of ${JSON.stringify(expectedCodes)}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_EXIT_CODE", [ + "an unexpected exit code was encountered,", + `got ${JSON.stringify(code)}`, + expectedCodes.length === 1 ? + `while expecting ${expectedCodes}.` + : `while expecting one of ${JSON.stringify(expectedCodes)}.`, + ]); } } else { if (expectedCodes.includes(code)) { - throw utils.error('NIKITA_EXECUTE_ASSERT_NOT_EXIT_CODE', ['an unexpected exit code was encountered,', `got ${JSON.stringify(code)}`, expectedCodes.length === 1 ? `while expecting anything but ${expectedCodes}.` : `while expecting anything but one of ${JSON.stringify(expectedCodes)}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_NOT_EXIT_CODE", [ + "an unexpected exit code was encountered,", + `got ${JSON.stringify(code)}`, + expectedCodes.length === 1 ? + `while expecting anything but ${expectedCodes}.` + : `while expecting anything but one of ${JSON.stringify(expectedCodes)}.`, + ]); } } // Content is a string or a buffer - for(let content of (config.content || [])) { - if (typeof content === 'string' && config.trim) { + for (let content of config.content || []) { + if (typeof content === "string" && config.trim) { content = content.trim(); } if (Buffer.isBuffer(content)) { content = content.toString(); } - if(typeof content === 'string'){ - let {stdout} = await this.execute(configForExecute); + if (typeof content === "string") { + let { stdout } = await this.execute(configForExecute); if (config.trim) { stdout = stdout.trim(); } if (!config.not) { if (stdout !== content) { - throw utils.error('NIKITA_EXECUTE_ASSERT_CONTENT', ['the command output is not matching the content,', `got ${JSON.stringify(stdout)}`, `while expecting to match ${JSON.stringify(content)}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_CONTENT", [ + "the command output is not matching the content,", + `got ${JSON.stringify(stdout)}`, + `while expecting to match ${JSON.stringify(content)}.`, + ]); } } else { if (stdout === content) { - throw utils.error('NIKITA_EXECUTE_ASSERT_NOT_CONTENT', ['the command output is unfortunately matching the content,', `got ${JSON.stringify(stdout)}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_NOT_CONTENT", [ + "the command output is unfortunately matching the content,", + `got ${JSON.stringify(stdout)}.`, + ]); } } } // Content is a regexp if (utils.regexp.is(content)) { - let {stdout} = await this.execute(configForExecute); + let { stdout } = await this.execute(configForExecute); if (config.trim) { stdout = stdout.trim(); } if (!config.not) { if (!content.test(stdout)) { - throw utils.error('NIKITA_EXECUTE_ASSERT_CONTENT_REGEX', ['the command output is not matching the content regexp,', `got ${JSON.stringify(stdout)}`, `while expecting to match ${content.toString()}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_CONTENT_REGEX", [ + "the command output is not matching the content regexp,", + `got ${JSON.stringify(stdout)}`, + `while expecting to match ${content.toString()}.`, + ]); } } else { if (content.test(stdout)) { - throw utils.error('NIKITA_EXECUTE_ASSERT_NOT_CONTENT_REGEX', ['the command output is unfortunately matching the content regexp,', `got ${JSON.stringify(stdout)}`, `matching ${content.toString()}.`]); + throw utils.error("NIKITA_EXECUTE_ASSERT_NOT_CONTENT_REGEX", [ + "the command output is unfortunately matching the content regexp,", + `got ${JSON.stringify(stdout)}`, + `matching ${content.toString()}.`, + ]); } } } } }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (!config.content) { - return config.code != null ? config.code : config.code = {true: [0]}; + return config.code != null ? + config.code + : (config.code = { true: [0] }); } - } + }, }, metadata: { // Schema definitions - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/execute/index.js b/packages/core/lib/actions/execute/index.js index 4fa7ec6e3..89449dd41 100644 --- a/packages/core/lib/actions/execute/index.js +++ b/packages/core/lib/actions/execute/index.js @@ -1,30 +1,36 @@ - // Dependencies -import exec from 'ssh2-exec'; -import execPromise from 'ssh2-exec/promises'; -import utils from '@nikitajs/core/utils'; +import exec from "ssh2-exec"; +import execPromise from "ssh2-exec/promises"; +import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_EXECUTE_ARCH_CHROOT_ROOTDIR_NOT_EXIST: function({err, config}) { - return utils.error('NIKITA_EXECUTE_ARCH_CHROOT_ROOTDIR_NOT_EXIST', ['directory defined by `config.arch_chroot_rootdir` must exist,', `location is ${JSON.stringify(config.arch_chroot_rootdir)}.`], { - exit_code: err.code, - stdout: err.stdout, - stderr: err.stderr - }); - } + NIKITA_EXECUTE_ARCH_CHROOT_ROOTDIR_NOT_EXIST: function ({ err, config }) { + return utils.error( + "NIKITA_EXECUTE_ARCH_CHROOT_ROOTDIR_NOT_EXIST", + [ + "directory defined by `config.arch_chroot_rootdir` must exist,", + `location is ${JSON.stringify(config.arch_chroot_rootdir)}.`, + ], + { + exit_code: err.code, + stdout: err.stdout, + stderr: err.stderr, + }, + ); + }, }; // Action export default { - handler: async function ({ - config, - metadata, - tools: { log, path }, - ssh, - }) { + handler: async function ({ config, metadata, tools: { log, path }, ssh }) { // Validate parameters config.mode ??= 0o500; if (typeof config.command === "function") { @@ -80,7 +86,7 @@ export default { { [`awk -v val=${config.uid} -F `]: " '$3==val{print $1}' /etc/passwd`", }, - function () {} + function () {}, ); config.uid = stdout.trim(); if (!(config.bash || config.arch_chroot)) { @@ -108,7 +114,7 @@ export default { const command = config.command; const target_in = path.join( config.arch_chroot_tmpdir, - `execute-arch_chroot-${utils.string.hash(config.command)}` + `execute-arch_chroot-${utils.string.hash(config.command)}`, ); const target = path.join(config.arch_chroot_rootdir, target_in); // target = "#{metadata.tmpdir}/#{utils.string.hash config.command}" if typeof config.target isnt 'string' @@ -128,7 +134,7 @@ export default { const command = config.command; const target = path.join( metadata.tmpdir, - `execute-bash-${utils.string.hash(config.command)}` + `execute-bash-${utils.string.hash(config.command)}`, ); log(`Writing bash script to ${JSON.stringify(target)}`); let cmd = `${config.bash} ${target}`; @@ -219,7 +225,7 @@ export default { `got ${JSON.stringify(data.toString())},`, "this is embarassing and we never found how to catch this bug,", "we would really enjoy some help to replicate or fix this one.", - ].join(" ") + ].join(" "), ); } } @@ -249,7 +255,7 @@ export default { `got ${JSON.stringify(data.toString())},`, "this is embarassing and we never found how to catch this bug,", "we would really enjoy some help to replicate or fix this one.", - ].join(" ") + ].join(" "), ); } } @@ -324,7 +330,7 @@ export default { "An unexpected exit code was encountered,", metadata.relax ? "using relax mode," : void 0, `command is ${JSON.stringify( - utils.string.max(config.command_original, 50) + utils.string.max(config.command_original, 50), )},`, `got ${JSON.stringify(result.code)}`, `instead of ${JSON.stringify(config.code)}.`, @@ -342,7 +348,7 @@ export default { "an unexpected exit code was encountered,", metadata.relax ? "using relax mode," : void 0, `command is ${JSON.stringify( - utils.string.max(config.command_original, 50) + utils.string.max(config.command_original, 50), )},`, `got ${JSON.stringify(result.code)}`, `instead of ${JSON.stringify(config.code)}.`, @@ -350,8 +356,8 @@ export default { { ...result, exit_code: code, - } - ) + }, + ), ); } if (config.code.false.indexOf(code) === -1) { @@ -383,15 +389,15 @@ export default { config.env_export != null ? config.env_export : !!ssh; // Create the tmpdir if arch_chroot is activated if (config.arch_chroot && config.arch_chroot_rootdir) { - return metadata.tmpdir != null - ? metadata.tmpdir - : (metadata.tmpdir = async function ({ os_tmpdir, tmpdir }) { + return metadata.tmpdir != null ? + metadata.tmpdir + : (metadata.tmpdir = async function ({ tmpdir }) { // Note, Arch mount `/tmp` with tmpfs in memory // placing a file in the host fs will not expose it inside of chroot config.arch_chroot_tmpdir = path.join("/opt", tmpdir); tmpdir = path.join( config.arch_chroot_rootdir, - config.arch_chroot_tmpdir + config.arch_chroot_tmpdir, ); const sudo = function (command) { if (utils.os.whoami({ ssh }) === "root") { @@ -408,7 +414,7 @@ export default { sudo(`[ -w ${config.arch_chroot_rootdir} ] || exit 2;`), sudo(`mkdir -p ${tmpdir};`), sudo(`chmod 700 ${tmpdir};`), - ].join("\n") + ].join("\n"), ); } catch (error) { if (error.code === 2) { @@ -428,8 +434,8 @@ export default { config.bash || (env_export && Object.keys(config.env).length) ) { - return metadata.tmpdir != null - ? metadata.tmpdir + return metadata.tmpdir != null ? + metadata.tmpdir : (metadata.tmpdir = true); } }, diff --git a/packages/core/lib/actions/execute/wait/index.js b/packages/core/lib/actions/execute/wait/index.js index 10eda272d..c4f69a7bc 100644 --- a/packages/core/lib/actions/execute/wait/index.js +++ b/packages/core/lib/actions/execute/wait/index.js @@ -1,33 +1,45 @@ - // ## Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { let attempts = 0; - const wait = (timeout) => timeout && new Promise( (resolve) => setTimeout(resolve, timeout) ); + const wait = (timeout) => + timeout && new Promise((resolve) => setTimeout(resolve, timeout)); let commands = config.command; while (attempts !== config.retry) { attempts++; log("DEBUG", `Start attempt #${attempts}`); - commands = await utils.promise.array_filter(commands, config.concurrency, async (command) => { - const { $status: success } = await this.execute({ - command: command, - code: config.code, - stdin_log: config.stdin_log, - stdout_log: config.stdout_log, - stderr_log: config.stderr_log, - $relax: config.code.false.length === 0, - }); - return !success; - }); - log("INFO", `Attempt #${attempts}, expect ${ + commands = await utils.promise.array_filter( + commands, + config.concurrency, + async (command) => { + const { $status: success } = await this.execute({ + command: command, + code: config.code, + stdin_log: config.stdin_log, + stdout_log: config.stdout_log, + stderr_log: config.stderr_log, + $relax: config.code.false.length === 0, + }); + return !success; + }, + ); + log( + "INFO", + `Attempt #${attempts}, expect ${ config.quorum } success to reach the quorum, got ${ config.command.length - commands.length - }`); + }`, + ); if (commands.length <= config.command.length - config.quorum) { return { attempts: attempts, diff --git a/packages/core/lib/actions/fs/assert/index.js b/packages/core/lib/actions/fs/assert/index.js index 10a487c44..092ffd6b6 100644 --- a/packages/core/lib/actions/fs/assert/index.js +++ b/packages/core/lib/actions/fs/assert/index.js @@ -1,219 +1,310 @@ // Dependencies -import pad from 'pad'; -import fs from 'fs'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import pad from "pad"; +import fs from "fs"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_ASSERT_FILE_MISSING: function({config}) { - return utils.error('NIKITA_FS_ASSERT_FILE_MISSING', ['file does not exists,', `location is ${JSON.stringify(config.target)}.`], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_FILE_MISSING: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_FILE_MISSING", + [ + "file does not exists,", + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_FILE_EXISTS: function({config}) { - return utils.error('NIKITA_FS_ASSERT_FILE_EXISTS', ['file exists,', `location is ${JSON.stringify(config.target)}.`], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_FILE_EXISTS: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_FILE_EXISTS", + ["file exists,", `location is ${JSON.stringify(config.target)}.`], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_FILETYPE_INVALID: function({config, expect, stats}) { - return utils.error('NIKITA_FS_ASSERT_FILETYPE_INVALID', ['filetype is invalid,', `expect ${JSON.stringify(expect)} type,`, `got ${JSON.stringify(utils.stats.type(stats.mode))} type,`, `location is ${JSON.stringify(config.target)}.`], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_FILETYPE_INVALID: function ({ config, expect, stats }) { + return utils.error( + "NIKITA_FS_ASSERT_FILETYPE_INVALID", + [ + "filetype is invalid,", + `expect ${JSON.stringify(expect)} type,`, + `got ${JSON.stringify(utils.stats.type(stats.mode))} type,`, + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_CONTENT_UNEQUAL: function({config, expect}) { - return utils.error('NIKITA_FS_ASSERT_CONTENT_UNEQUAL', ['content does not equal the expected value,', `expect ${JSON.stringify(expect.toString())}`, `to equal ${JSON.stringify(config.content.toString())},`, `location is ${JSON.stringify(config.target)}.`], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_CONTENT_UNEQUAL: function ({ config, expect }) { + return utils.error( + "NIKITA_FS_ASSERT_CONTENT_UNEQUAL", + [ + "content does not equal the expected value,", + `expect ${JSON.stringify(expect.toString())}`, + `to equal ${JSON.stringify(config.content.toString())},`, + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_CONTENT_EQUAL: function({config, expect}) { - return utils.error('NIKITA_FS_ASSERT_CONTENT_EQUAL', ['content is matching,', `not expecting to equal ${JSON.stringify(expect.toString())},`, `location is ${JSON.stringify(config.target)}.`], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_CONTENT_EQUAL: function ({ config, expect }) { + return utils.error( + "NIKITA_FS_ASSERT_CONTENT_EQUAL", + [ + "content is matching,", + `not expecting to equal ${JSON.stringify(expect.toString())},`, + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_CONTENT_UNMATCH: function({config, expect}) { - return utils.error('NIKITA_FS_ASSERT_CONTENT_UNMATCH', [ - 'content does not match the provided regexp,', - `expect ${JSON.stringify(expect.toString())}`, - `to match ${config.content.toString()},`, - `location is ${JSON.stringify(config.target)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_CONTENT_UNMATCH: function ({ config, expect }) { + return utils.error( + "NIKITA_FS_ASSERT_CONTENT_UNMATCH", + [ + "content does not match the provided regexp,", + `expect ${JSON.stringify(expect.toString())}`, + `to match ${config.content.toString()},`, + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_CONTENT_MATCH: function({config, expect}) { - return utils.error('NIKITA_FS_ASSERT_CONTENT_MATCH', [ - 'content is matching the provided regexp,', - `got ${JSON.stringify(expect.toString())}`, - `to match ${config.content.toString()},`, - `location is ${JSON.stringify(config.target)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_CONTENT_MATCH: function ({ config, expect }) { + return utils.error( + "NIKITA_FS_ASSERT_CONTENT_MATCH", + [ + "content is matching the provided regexp,", + `got ${JSON.stringify(expect.toString())}`, + `to match ${config.content.toString()},`, + `location is ${JSON.stringify(config.target)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE: function({config}) { - return utils.error('NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE', [ - 'provided filetype is not supported,', - `got ${JSON.stringify(config.filetype)}.` - ], { - target: config.target, - }); + NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE", + [ + "provided filetype is not supported,", + `got ${JSON.stringify(config.filetype)}.`, + ], + { + target: config.target, + }, + ); }, - NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE: function({config}) { - return utils.error('NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE', [ - 'filetype must be a string or a number,', - `got ${JSON.stringify(config.filetype)}.` - ], { - target: config.target, - }); + NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE", + [ + "filetype must be a string or a number,", + `got ${JSON.stringify(config.filetype)}.`, + ], + { + target: config.target, + }, + ); }, - NIKITA_FS_ASSERT_HASH_UNMATCH: function({config, algo, hash}) { - return utils.error('NIKITA_FS_ASSERT_HASH_UNMATCH', [ - `an invalid ${algo} signature was computed,`, - `expect ${JSON.stringify(hash.expected)},`, - `got ${JSON.stringify(hash.actual)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_HASH_UNMATCH: function ({ config, algo, hash }) { + return utils.error( + "NIKITA_FS_ASSERT_HASH_UNMATCH", + [ + `an invalid ${algo} signature was computed,`, + `expect ${JSON.stringify(hash.expected)},`, + `got ${JSON.stringify(hash.actual)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_HASH_MATCH: function({config, algo, hash}) { - return utils.error('NIKITA_FS_ASSERT_HASH_MATCH', [ - `the ${algo} signatures are matching,`, - `not expecting to equal ${JSON.stringify(hash)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_HASH_MATCH: function ({ config, algo, hash }) { + return utils.error( + "NIKITA_FS_ASSERT_HASH_MATCH", + [ + `the ${algo} signatures are matching,`, + `not expecting to equal ${JSON.stringify(hash)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_MODE_UNMATCH: function({config, mode}) { - const expect = config.mode.map(function(mode) { - return pad(4, utils.mode.stringify(mode), '0'); - }); - return utils.error("NIKITA_FS_ASSERT_MODE_UNMATCH", [ - 'content permission don\'t match the provided mode,', - `expect ${expect},`, - `got ${utils.mode.stringify(mode).slice(-4)}.` - ], { - target: config.target, - message: config.error + NIKITA_FS_ASSERT_MODE_UNMATCH: function ({ config, mode }) { + const expect = config.mode.map(function (mode) { + return pad(4, utils.mode.stringify(mode), "0"); }); + return utils.error( + "NIKITA_FS_ASSERT_MODE_UNMATCH", + [ + "content permission don't match the provided mode,", + `expect ${expect},`, + `got ${utils.mode.stringify(mode).slice(-4)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_MODE_MATCH: function({config}) { - const expect = config.mode.map(function(mode) { - return pad(4, utils.mode.stringify(mode), '0'); - }); - return utils.error("NIKITA_FS_ASSERT_MODE_MATCH", [ - 'the content permission match the provided mode,', - `not expecting to equal ${expect}.` - ], { - target: config.target, - message: config.error + NIKITA_FS_ASSERT_MODE_MATCH: function ({ config }) { + const expect = config.mode.map(function (mode) { + return pad(4, utils.mode.stringify(mode), "0"); }); + return utils.error( + "NIKITA_FS_ASSERT_MODE_MATCH", + [ + "the content permission match the provided mode,", + `not expecting to equal ${expect}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_UID_UNMATCH: function({config, actual}) { - return utils.error('NIKITA_FS_ASSERT_UID_UNMATCH', [ - 'the uid of the target does not match the expected value,', - `expected ${JSON.stringify(config.uid)},`, `got ${JSON.stringify(actual)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_UID_UNMATCH: function ({ config, actual }) { + return utils.error( + "NIKITA_FS_ASSERT_UID_UNMATCH", + [ + "the uid of the target does not match the expected value,", + `expected ${JSON.stringify(config.uid)},`, + `got ${JSON.stringify(actual)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_UID_MATCH: function({config}) { - return utils.error('NIKITA_FS_ASSERT_UID_MATCH', [ - 'the uid of the target match the provided value,', - `not expecting to equal ${JSON.stringify(config.uid)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_UID_MATCH: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_UID_MATCH", + [ + "the uid of the target match the provided value,", + `not expecting to equal ${JSON.stringify(config.uid)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_GID_UNMATCH: function({config, actual}) { - return utils.error('NIKITA_FS_ASSERT_GID_UNMATCH', [ - 'the gid of the target does not match the expected value,', - `expected ${JSON.stringify(config.uid)},`, - `got ${JSON.stringify(actual)}.` - ], { - target: config.target, - message: config.error - }); + NIKITA_FS_ASSERT_GID_UNMATCH: function ({ config, actual }) { + return utils.error( + "NIKITA_FS_ASSERT_GID_UNMATCH", + [ + "the gid of the target does not match the expected value,", + `expected ${JSON.stringify(config.uid)},`, + `got ${JSON.stringify(actual)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); + }, + NIKITA_FS_ASSERT_GID_MATCH: function ({ config }) { + return utils.error( + "NIKITA_FS_ASSERT_GID_MATCH", + [ + "the gid of the target match the provided value,", + `not expecting to equal ${JSON.stringify(config.uid)}.`, + ], + { + target: config.target, + message: config.error, + }, + ); }, - NIKITA_FS_ASSERT_GID_MATCH: function({config}) { - return utils.error('NIKITA_FS_ASSERT_GID_MATCH', [ - 'the gid of the target match the provided value,', - `not expecting to equal ${JSON.stringify(config.uid)}.` - ], { - target: config.target, - message: config.error - }); - } }; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Cached version of `nikita.fs.lstat` - const cache = {} + const cache = {}; const lstat = async (location) => { if (cache[location] != null) return cache[location]; - return cache[location] = await this.fs.lstat(config.target) - } - config.filetype = (function() { + return (cache[location] = await this.fs.lstat(config.target)); + }; + config.filetype = (function () { const results = []; - for(const filetype of config.filetype ?? []) { + for (const filetype of config.filetype ?? []) { if (!filetype) { continue; } - if (typeof filetype === 'string') { + if (typeof filetype === "string") { switch (filetype.toLowerCase()) { - case 'ifreg': - case 'file': + case "ifreg": + case "file": results.push(fs.constants.S_IFREG); break; - case 'ifdir': - case 'directory': + case "ifdir": + case "directory": results.push(fs.constants.S_IFDIR); break; - case 'ifchr': - case 'chardevice': + case "ifchr": + case "chardevice": results.push(fs.constants.S_IFCHR); break; - case 'iffblk': - case 'blockdevice': + case "iffblk": + case "blockdevice": results.push(fs.constants.S_IFBLK); break; - case 'ififo': - case 'fifo': + case "ififo": + case "fifo": results.push(fs.constants.S_IFIFO); break; - case 'iflink': - case 'symlink': + case "iflink": + case "symlink": results.push(fs.constants.S_IFLNK); break; - case 'ifsock': - case 'socket': + case "ifsock": + case "socket": results.push(fs.constants.S_IFSOCK); break; default: - throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE({config}); + throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID_VALUE({ config }); } - } else if (typeof filetype === 'number') { + } else if (typeof filetype === "number") { results.push(filetype); } else { - throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE({config}); + throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID_TYPE({ config }); } } return results; })(); // Asset content string and buffer - if (typeof config.content === 'string') { + if (typeof config.content === "string") { if (config.trim) { config.content = config.content.trim(); } @@ -226,83 +317,110 @@ export default { // Assert file exists // if content is not defined and there is no hash nor mode // hash and mode verification are done later, whether the file was updated or not - if ((config.content == null && !(config.md5 || config.sha1 || config.sha256 || config.mode?.length))) { - const {exists} = (await this.fs.exists(config.target.toString())); + if ( + config.content == null && + !(config.md5 || config.sha1 || config.sha256 || config.mode?.length) + ) { + const { exists } = await this.fs.exists(config.target.toString()); if (!config.not) { if (!exists) { throw errors.NIKITA_FS_ASSERT_FILE_MISSING({ - config: config + config: config, }); } } else { if (exists) { throw errors.NIKITA_FS_ASSERT_FILE_EXISTS({ - config: config + config: config, }); } } } // Assert file filetype if (config.filetype?.length) { - const {stats} = await lstat(config.target); - if (config.filetype.includes(fs.constants.S_IFREG) && ! utils.stats.isFile(stats.mode)) { + const { stats } = await lstat(config.target); + if ( + config.filetype.includes(fs.constants.S_IFREG) && + !utils.stats.isFile(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'File', - stats: stats + expect: "File", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFDIR) && !utils.stats.isDirectory(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFDIR) && + !utils.stats.isDirectory(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'Directory', - stats: stats + expect: "Directory", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFCHR) && !utils.stats.isCharacterDevice(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFCHR) && + !utils.stats.isCharacterDevice(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'Character Device', - stats: stats + expect: "Character Device", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFBLK) && !utils.stats.isBlockDevice(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFBLK) && + !utils.stats.isBlockDevice(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'Block Device', - stats: stats + expect: "Block Device", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFIFO) && !utils.stats.isFIFO(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFIFO) && + !utils.stats.isFIFO(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'FIFO', - stats: stats + expect: "FIFO", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFLNK) && !utils.stats.isSymbolicLink(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFLNK) && + !utils.stats.isSymbolicLink(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'Symbolic Link', - stats: stats + expect: "Symbolic Link", + stats: stats, }); } - if (config.filetype.includes(fs.constants.S_IFSOCK) && !utils.stats.isSocket(stats.mode)) { + if ( + config.filetype.includes(fs.constants.S_IFSOCK) && + !utils.stats.isSocket(stats.mode) + ) { throw errors.NIKITA_FS_ASSERT_FILETYPE_INVALID({ config: config, - expect: 'Socket', - stats: stats + expect: "Socket", + stats: stats, }); } } // Assert content equal - if ((config.content != null) && (typeof config.content === 'string' || Buffer.isBuffer(config.content))) { - let {data} = (await this.fs.readFile(config.target)); + if ( + config.content != null && + (typeof config.content === "string" || Buffer.isBuffer(config.content)) + ) { + let { data } = await this.fs.readFile(config.target); for (const filter of config.filter) { - data = filter[Symbol.replace](data, ''); + data = filter[Symbol.replace](data, ""); } // RegExp returns string - if (typeof data === 'string') { + if (typeof data === "string") { data = Buffer.from(data); } if (config.trim) { @@ -312,23 +430,23 @@ export default { if (!data.equals(config.content)) { throw errors.NIKITA_FS_ASSERT_CONTENT_UNEQUAL({ config: config, - expect: data + expect: data, }); } } else { if (data.equals(config.content)) { throw errors.NIKITA_FS_ASSERT_CONTENT_EQUAL({ config: config, - expect: data + expect: data, }); } } } // Assert content match if (config.content != null && config.content instanceof RegExp) { - let {data} = (await this.fs.readFile(config.target)); - for (const filter of config.filter) { - data = filter[Symbol.replace](data, ''); + let { data } = await this.fs.readFile(config.target); + for (const filter of config.filter) { + data = filter[Symbol.replace](data, ""); } if (config.trim) { data = utils.buffer.trim(data, config.encoding); @@ -337,14 +455,14 @@ export default { if (!config.content.test(data)) { throw errors.NIKITA_FS_ASSERT_CONTENT_UNMATCH({ config: config, - expect: data + expect: data, }); } } else { if (config.content.test(data)) { throw errors.NIKITA_FS_ASSERT_CONTENT_MATCH({ config: config, - expect: data + expect: data, }); } } @@ -353,18 +471,18 @@ export default { if (config.md5) { // Assert hash match // todo, also support config.algo and config.hash - (algo = 'md5', hashExpected = config.md5); + (algo = "md5"), (hashExpected = config.md5); } if (config.sha1) { - (algo = 'sha1', hashExpected = config.sha1); + (algo = "sha1"), (hashExpected = config.sha1); } if (config.sha256) { - (algo = 'sha256', hashExpected = config.sha256); + (algo = "sha256"), (hashExpected = config.sha256); } if (algo) { - const {hash} = (await this.fs.hash(config.target, { - algo: algo - })); + const { hash } = await this.fs.hash(config.target, { + algo: algo, + }); if (!config.not) { if (hashExpected !== hash) { throw errors.NIKITA_FS_ASSERT_HASH_UNMATCH({ @@ -372,8 +490,8 @@ export default { algo: algo, hash: { expected: hashExpected, - actual: hash - } + actual: hash, + }, }); } } else { @@ -381,75 +499,75 @@ export default { throw errors.NIKITA_FS_ASSERT_HASH_MATCH({ config: config, algo: algo, - hash: hash + hash: hash, }); } } } // Assert uid ownerships if (config.uid != null) { - const {stats} = await lstat(config.target); + const { stats } = await lstat(config.target); if (!config.not) { if (`${stats.uid}` !== `${config.uid}`) { throw errors.NIKITA_FS_ASSERT_UID_UNMATCH({ config: config, - actual: stats.uid + actual: stats.uid, }); } } else { if (`${stats.uid}` === `${config.uid}`) { throw errors.NIKITA_FS_ASSERT_UID_MATCH({ - config: config + config: config, }); } } } // Assert gid ownerships if (config.gid != null) { - const {stats} = await lstat(config.target); + const { stats } = await lstat(config.target); if (!config.not) { if (`${stats.gid}` !== `${config.gid}`) { throw errors.NIKITA_FS_ASSERT_GID_UNMATCH({ config: config, - actual: stats.gid + actual: stats.gid, }); } } else { if (`${stats.gid}` === `${config.gid}`) { throw errors.NIKITA_FS_ASSERT_GID_MATCH({ - config: config + config: config, }); } } } // Assert file permissions if (config.mode?.length) { - const {stats} = (await lstat(config.target)); + const { stats } = await lstat(config.target); if (!config.not) { if (!utils.mode.compare(config.mode, stats.mode)) { throw errors.NIKITA_FS_ASSERT_MODE_UNMATCH({ config: config, - mode: stats.mode + mode: stats.mode, }); } } else { if (utils.mode.compare(config.mode, stats.mode)) { throw errors.NIKITA_FS_ASSERT_MODE_MATCH({ - config: config + config: config, }); } } } }, hooks: { - on_action: function({config, metadata}) { + on_action: function ({ config }) { if (config.filter instanceof RegExp) { - return config.filter = [config.filter]; + return (config.filter = [config.filter]); } - } + }, }, metadata: { - argument_to_config: 'target', - definitions: definitions - } + argument_to_config: "target", + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/base/chmod/index.js b/packages/core/lib/actions/fs/base/chmod/index.js index b776e297d..bc1801148 100644 --- a/packages/core/lib/actions/fs/base/chmod/index.js +++ b/packages/core/lib/actions/fs/base/chmod/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const mode = typeof config.mode === 'number' - ? config.mode.toString(8).slice(-4) + handler: async function ({ config }) { + const mode = + typeof config.mode === "number" ? + config.mode.toString(8).slice(-4) : config.mode; await this.execute(`chmod ${mode} ${config.target}`); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/base/chown/index.js b/packages/core/lib/actions/fs/base/chown/index.js index 4266cff68..0aed71a95 100644 --- a/packages/core/lib/actions/fs/base/chown/index.js +++ b/packages/core/lib/actions/fs/base/chown/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -19,7 +23,7 @@ export default { [ config.uid != null ? `chown ${config.uid} ${config.target}` : void 0, config.gid != null ? `chgrp ${config.gid} ${config.target}` : void 0, - ].join("\n") + ].join("\n"), ); }, hooks: { diff --git a/packages/core/lib/actions/fs/base/copy/index.js b/packages/core/lib/actions/fs/base/copy/index.js index 114a13d67..786b98728 100644 --- a/packages/core/lib/actions/fs/base/copy/index.js +++ b/packages/core/lib/actions/fs/base/copy/index.js @@ -1,22 +1,33 @@ - // Dependencies -import dedent from 'dedent'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import dedent from "dedent"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_COPY_TARGET_ENOENT: ({config, error}) => - utils.error('NIKITA_FS_COPY_TARGET_ENOENT', ['target parent directory does not exists or is not a directory,', `got ${JSON.stringify(config.target)}`], { - exit_code: error.exit_code, - errno: -2, - syscall: 'open', - path: config.target - }) + NIKITA_FS_COPY_TARGET_ENOENT: ({ config, error }) => + utils.error( + "NIKITA_FS_COPY_TARGET_ENOENT", + [ + "target parent directory does not exists or is not a directory,", + `got ${JSON.stringify(config.target)}`, + ], + { + exit_code: error.exit_code, + errno: -2, + syscall: "open", + path: config.target, + }, + ), }; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { try { return await this.execute(dedent` [ ! -d \`dirname "${config.target}"\` ] && exit 2 @@ -26,16 +37,16 @@ export default { if (error.exit_code === 2) { throw errors.NIKITA_FS_COPY_TARGET_ENOENT({ config: config, - error: error + error: error, }); } throw error; } }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/base/mkdir/index.js b/packages/core/lib/actions/fs/base/mkdir/index.js index 1c46e8380..f15be05b9 100644 --- a/packages/core/lib/actions/fs/base/mkdir/index.js +++ b/packages/core/lib/actions/fs/base/mkdir/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { NIKITA_FS_MKDIR_TARGET_EEXIST: ({ config }) => @@ -16,7 +21,7 @@ const errors = { errno: -17, path: config.target_tmp || config.target, // Native Node.js api doesn't provide path syscall: "mkdir", - } + }, ), }; @@ -37,12 +42,14 @@ export default { config.uid && `-o '${config.uid}'`, config.gid && `-g '${config.gid}'`, `-d '${config.target}'`, - ].filter(Boolean).join(" "), - ].join("\n") + ] + .filter(Boolean) + .join(" "), + ].join("\n"), ); } catch (error) { if (error.exit_code === 17) { - error = errors.NIKITA_FS_MKDIR_TARGET_EEXIST({ + throw errors.NIKITA_FS_MKDIR_TARGET_EEXIST({ config: config, }); } diff --git a/packages/core/lib/actions/fs/chmod/index.js b/packages/core/lib/actions/fs/chmod/index.js index c3af2df27..4d4a8057d 100644 --- a/packages/core/lib/actions/fs/chmod/index.js +++ b/packages/core/lib/actions/fs/chmod/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -12,9 +17,9 @@ export default { if (utils.mode.compare(stats.mode, config.mode)) { log( "INFO", - `Identical permissions \"${config.mode.toString(8)}\" on \"${ + `Identical permissions "${config.mode.toString(8)}" on "${ config.target - }\"` + }"`, ); return false; } @@ -30,7 +35,7 @@ export default { `from "${stats.mode.toString(8)}"`, `to "${config.mode.toString(8)}"`, `on "${config.target}"`, - ].join(" ") + ].join(" "), ); return true; }, diff --git a/packages/core/lib/actions/fs/chown/index.js b/packages/core/lib/actions/fs/chown/index.js index 38ec9bd49..61bff35a7 100644 --- a/packages/core/lib/actions/fs/chown/index.js +++ b/packages/core/lib/actions/fs/chown/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -7,11 +11,15 @@ export default { if (config.uid == null && config.gid == null) { throw Error("Missing one of uid or gid option"); } - if(typeof config.uid === 'string'){ - config.uid = await this.execute(`id -u '${config.uid}'`).then(({stdout}) => parseInt(stdout.trim())) + if (typeof config.uid === "string") { + config.uid = await this.execute(`id -u '${config.uid}'`).then( + ({ stdout }) => parseInt(stdout.trim()), + ); } - if(typeof config.gid === 'string'){ - config.gid = await this.execute(`id -g '${config.gid}'`).then(({stdout}) => parseInt(stdout.trim())) + if (typeof config.gid === "string") { + config.gid = await this.execute(`id -g '${config.gid}'`).then( + ({ stdout }) => parseInt(stdout.trim()), + ); } // Retrieve target stats if (config.stats) { diff --git a/packages/core/lib/actions/fs/copy/index.js b/packages/core/lib/actions/fs/copy/index.js index cd0d305b7..b308add64 100644 --- a/packages/core/lib/actions/fs/copy/index.js +++ b/packages/core/lib/actions/fs/copy/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -12,9 +17,11 @@ export default { return config.source_stats; } log("DEBUG", `Stats source file ${config.source}`); - return await this.fs.stat({ - target: config.source, - }).then( ({stats}) => stats); + return await this.fs + .stat({ + target: config.source, + }) + .then(({ stats }) => stats); })(); // Retrieve stat information about the traget unless provided through the "target_stats" option. const target_stats = await (async () => { @@ -57,7 +64,7 @@ export default { if (target_stats && !sourceEndWithSlash) { config.target = path.resolve( config.target, - path.basename(config.source) + path.basename(config.source), ); } log("Source is a directory"); @@ -67,7 +74,7 @@ export default { for (const source of files) { const target = path.resolve( config.target, - path.relative(config.source, source) + path.relative(config.source, source), ); const { stats } = await this.fs.stat({ target: source, @@ -118,7 +125,7 @@ export default { } else { log( "WARN", - `Hash dont match, source is '${hash_source}' and target is '${hash_target}'` + `Hash dont match, source is '${hash_source}' and target is '${hash_target}'`, ); await this.fs.base.copy({ source: config.source, @@ -142,9 +149,9 @@ export default { target: config.target, stats: target_stats, mode: - config.preserve && config.mode == null - ? source_stats.mode - : config.mode, + config.preserve && config.mode == null ? + source_stats.mode + : config.mode, }); return {}; }, diff --git a/packages/core/lib/actions/fs/createReadStream/index.js b/packages/core/lib/actions/fs/createReadStream/index.js index e2dc5f590..c58ed9882 100644 --- a/packages/core/lib/actions/fs/createReadStream/index.js +++ b/packages/core/lib/actions/fs/createReadStream/index.js @@ -1,48 +1,72 @@ - // Dependencies -import fs from 'ssh2-fs'; -import exec from 'ssh2-exec/promises'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import fs from "ssh2-fs"; +import exec from "ssh2-exec/promises"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { NIKITA_FS_CRS_NO_EVENT_HANDLER: () => - utils.error('NIKITA_FS_CRS_NO_EVENT_HANDLER', [ - 'unable to consume the readable stream,', + utils.error("NIKITA_FS_CRS_NO_EVENT_HANDLER", [ + "unable to consume the readable stream,", 'one of the "on_readable" or "stream"', - 'hooks must be provided']) - , - NIKITA_FS_CRS_TARGET_ENOENT: ({error, config}) => - utils.error('NIKITA_FS_CRS_TARGET_ENOENT', ['fail to read a file because it does not exist,', !config.target_tmp ? `location is ${JSON.stringify(config.target)}.` : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`], { - errno: error.errno, - syscall: error.syscall, - path: error.path - }) - , - NIKITA_FS_CRS_TARGET_EISDIR: ({error, config}) => - utils.error('NIKITA_FS_CRS_TARGET_EISDIR', ['fail to read a file because it is a directory,', !config.target_tmp ? `location is ${JSON.stringify(config.target)}.` : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`], { - errno: error.errno, - syscall: error.syscall, - path: config.target_tmp || config.target // Native Node.js api doesn't provide path - }) - , - NIKITA_FS_CRS_TARGET_EACCES: ({error, config}) => - utils.error('NIKITA_FS_CRS_TARGET_EACCES', ['fail to read a file because permission was denied,', !config.target_tmp ? `location is ${JSON.stringify(config.target)}.` : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`], { - errno: error.errno, - syscall: error.syscall, - path: config.target_tmp || config.target // Native Node.js api doesn't provide path - }) + "hooks must be provided", + ]), + NIKITA_FS_CRS_TARGET_ENOENT: ({ error, config }) => + utils.error( + "NIKITA_FS_CRS_TARGET_ENOENT", + [ + "fail to read a file because it does not exist,", + !config.target_tmp ? + `location is ${JSON.stringify(config.target)}.` + : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`, + ], + { + errno: error.errno, + syscall: error.syscall, + path: error.path, + }, + ), + NIKITA_FS_CRS_TARGET_EISDIR: ({ error, config }) => + utils.error( + "NIKITA_FS_CRS_TARGET_EISDIR", + [ + "fail to read a file because it is a directory,", + !config.target_tmp ? + `location is ${JSON.stringify(config.target)}.` + : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`, + ], + { + errno: error.errno, + syscall: error.syscall, + path: config.target_tmp || config.target, // Native Node.js api doesn't provide path + }, + ), + NIKITA_FS_CRS_TARGET_EACCES: ({ error, config }) => + utils.error( + "NIKITA_FS_CRS_TARGET_EACCES", + [ + "fail to read a file because permission was denied,", + !config.target_tmp ? + `location is ${JSON.stringify(config.target)}.` + : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`, + ], + { + errno: error.errno, + syscall: error.syscall, + path: config.target_tmp || config.target, // Native Node.js api doesn't provide path + }, + ), }; // ## Exports export default { - handler: async function({ - config, - metadata, - ssh, - tools: {path, log} - }) { - const sudo = function(cmd) { + handler: async function ({ config, metadata, ssh, tools: { path, log } }) { + const sudo = function (cmd) { if (config.sudo) { return `sudo ${cmd}`; } else { @@ -50,9 +74,14 @@ export default { } }; // Normalization - config.target = config.cwd ? path.resolve(config.cwd, config.target) : path.normalize(config.target); + config.target = + config.cwd ? + path.resolve(config.cwd, config.target) + : path.normalize(config.target); if (ssh && !path.isAbsolute(config.target)) { - throw Error(`Non Absolute Path: target is ${JSON.stringify(config.target)}, SSH requires absolute paths, you must provide an absolute path in the target or the cwd option`); + throw Error( + `Non Absolute Path: target is ${JSON.stringify(config.target)}, SSH requires absolute paths, you must provide an absolute path in the target or the cwd option`, + ); } if (!(config.on_readable || config.stream)) { throw errors.NIKITA_FS_CRS_NO_EVENT_HANDLER(); @@ -67,91 +96,85 @@ export default { } // Guess current username const whoami = utils.os.whoami({ - ssh: ssh + ssh: ssh, }); try { if (config.target_tmp) { - await exec(ssh, [sudo(`[ ! -f '${config.target}' ] && exit 0`), sudo(`cp '${config.target}' '${config.target_tmp}'`), sudo(`chown '${whoami}' '${config.target_tmp}'`)].join('\n')); - log({ - message: "Placing original file in temporary path before reading", - level: 'INFO' - }); + await exec( + ssh, + [ + sudo(`[ ! -f '${config.target}' ] && exit 0`), + sudo(`cp '${config.target}' '${config.target_tmp}'`), + sudo(`chown '${whoami}' '${config.target_tmp}'`), + ].join("\n"), + ); + log("INFO", "Placing original file in temporary path before reading"); } } catch (error) { - log({ - message: "Failed to place original file in temporary path", - level: 'ERROR' - }); + log("ERROR", "Failed to place original file in temporary path"); throw error; } // Read the stream - log({ - message: `Reading file ${config.target_tmp || config.target}`, - level: 'DEBUG' - }); - return new Promise(async function(resolve, reject) { - const buffers = []; - const rs = await fs.createReadStream(ssh, config.target_tmp || config.target); - if (config.on_readable) { - rs.on('readable', function() { - return config.on_readable(rs); + log("DEBUG", `Reading file ${config.target_tmp || config.target}`); + let { promise, resolve, reject } = utils.promise.withResolvers(); + const rs = await fs.createReadStream( + ssh, + config.target_tmp || config.target, + ); + if (config.on_readable) { + rs.on("readable", function () { + return config.on_readable(rs); + }); + } else { + config.stream(rs); + } + rs.on("error", function (error) { + if (error.code === "ENOENT") { + error = errors.NIKITA_FS_CRS_TARGET_ENOENT({ + config: config, + error: error, + }); + } else if (error.code === "EISDIR") { + error = errors.NIKITA_FS_CRS_TARGET_EISDIR({ + config: config, + error: error, + }); + } else if (error.code === "EACCES") { + error = errors.NIKITA_FS_CRS_TARGET_EACCES({ + config: config, + error: error, }); - } else { - config.stream(rs); } - rs.on('error', function(error) { - if (error.code === 'ENOENT') { - error = errors.NIKITA_FS_CRS_TARGET_ENOENT({ - config: config, - error: error - }); - } else if (error.code === 'EISDIR') { - error = errors.NIKITA_FS_CRS_TARGET_EISDIR({ - config: config, - error: error - }); - } else if (error.code === 'EACCES') { - error = errors.NIKITA_FS_CRS_TARGET_EACCES({ - config: config, - error: error - }); - } - reject(error); - }); - rs.on('end', resolve); + reject(error); }); + rs.on("end", resolve); + return promise; }, hooks: { on_action: { - after: [ - '@nikitajs/core/plugins/execute' - ], + after: ["@nikitajs/core/plugins/execute"], before: [ - '@nikitajs/core/plugins/metadata/schema', - '@nikitajs/core/plugins/metadata/tmpdir' + "@nikitajs/core/plugins/metadata/schema", + "@nikitajs/core/plugins/metadata/tmpdir", ], - handler: async function({ - config, - metadata, - tools: {find} - }) { + handler: async function ({ config, metadata, tools: { find } }) { if (config.sudo == null) { - config.sudo = await find(function({metadata: {sudo}}) { + config.sudo = await find(function ({ metadata: { sudo } }) { return sudo; }); } if (config.sudo) { metadata.tmpdir = { - sudo: false + sudo: false, }; } - } - } + }, + }, }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/createWriteStream/index.js b/packages/core/lib/actions/fs/createWriteStream/index.js index a6b5b68da..ed43d8c30 100644 --- a/packages/core/lib/actions/fs/createWriteStream/index.js +++ b/packages/core/lib/actions/fs/createWriteStream/index.js @@ -1,37 +1,39 @@ - // Dependencies -import fs from 'ssh2-fs'; -import exec from 'ssh2-exec/promises'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import fs from "ssh2-fs"; +import exec from "ssh2-exec/promises"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_FS_CWS_TARGET_ENOENT: ({config}) => - utils.error('NIKITA_FS_CWS_TARGET_ENOENT', [ - 'fail to write a file,', - !config.target_tmp - ? `location is ${JSON.stringify(config.target)}.` - : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).` - ], { - errno: -2, - path: config.target_tmp || config.target, // Native Node.js api doesn't provide path - syscall: 'open' - }) + NIKITA_FS_CWS_TARGET_ENOENT: ({ config }) => + utils.error( + "NIKITA_FS_CWS_TARGET_ENOENT", + [ + "fail to write a file,", + !config.target_tmp ? + `location is ${JSON.stringify(config.target)}.` + : `location is ${JSON.stringify(config.target_tmp)} (temporary file, target is ${JSON.stringify(config.target)}).`, + ], + { + errno: -2, + path: config.target_tmp || config.target, // Native Node.js api doesn't provide path + syscall: "open", + }, + ), }; // Action export default { - handler: async function({ - config, - metadata, - ssh, - tools: {log} - }) { - const sudo = (cmd) => - (config.sudo) ? `sudo ${cmd}` : `${cmd}`; + handler: async function ({ config, metadata, ssh, tools: { log } }) { + const sudo = (cmd) => (config.sudo ? `sudo ${cmd}` : `${cmd}`); // Normalize config - if (config.sudo || config.flags[0] === 'a') { + if (config.sudo || config.flags[0] === "a") { if (config.target_tmp == null) { config.target_tmp = `${metadata.tmpdir}/${utils.string.hash(config.target)}`; } @@ -39,81 +41,81 @@ export default { try { // config.mode ?= 0o644 # Node.js default to 0o666 // In append mode, we write to a copy of the target file located in a temporary location - if (config.flags[0] === 'a') { - const whoami = utils.os.whoami({ssh}); - await exec(ssh, [ - sudo(`[ ! -f '${config.target}' ] && exit`), - sudo(`cp '${config.target}' '${config.target_tmp}'`), - sudo(`chown ${whoami} '${config.target_tmp}'`)].join('\n') + if (config.flags[0] === "a") { + const whoami = utils.os.whoami({ ssh }); + await exec( + ssh, + [ + sudo(`[ ! -f '${config.target}' ] && exit`), + sudo(`cp '${config.target}' '${config.target_tmp}'`), + sudo(`chown ${whoami} '${config.target_tmp}'`), + ].join("\n"), + ); + log( + "INFO", + "Append prepared by placing a copy of the original file in a temporary path", ); - log('INFO', "Append prepared by placing a copy of the original file in a temporary path"); } } catch (error) { - log('ERROR', "Failed to place original file in temporary path"); + log("ERROR", "Failed to place original file in temporary path"); throw error; } // Start writing the content - log('DEBUG', 'Start writing bytes'); - await new Promise(async function(resolve, reject) { - const ws = await fs.createWriteStream( - ssh, - config.target_tmp || config.target, - { - flags: config.flags, - mode: config.mode, - } - ); - config.stream(ws); - ws.on('error', function(error) { - if (error.code === 'ENOENT') { - error = errors.NIKITA_FS_CWS_TARGET_ENOENT({ - config: config - }); - } - reject(error); - }); - ws.on('end', () => ws.destroy() ); - ws.on('close', () => resolve() ); + log("DEBUG", "Start writing bytes"); + let { promise, resolve, reject } = utils.promise.withResolvers(); + const ws = await fs.createWriteStream( + ssh, + config.target_tmp || config.target, + { + flags: config.flags, + mode: config.mode, + }, + ); + config.stream(ws); + ws.on("error", function (error) { + if (error.code === "ENOENT") { + error = errors.NIKITA_FS_CWS_TARGET_ENOENT({ + config: config, + }); + } + reject(error); }); + ws.on("end", () => ws.destroy()); + ws.on("close", () => resolve()); + await promise; // Replace the target file in append or sudo mode if (config.target_tmp) { await exec(ssh, { command: [ sudo(`mv '${config.target_tmp}' '${config.target}'`), - config.sudo ? sudo(`chown root:root '${config.target}'`) : undefined - ].join('\n') + config.sudo ? sudo(`chown root:root '${config.target}'`) : undefined, + ].join("\n"), }); } }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions + definitions: definitions, }, hooks: { on_action: { - after: [ - '@nikitajs/core/plugins/execute' - ], + after: ["@nikitajs/core/plugins/execute"], before: [ - '@nikitajs/core/plugins/metadata/schema', - '@nikitajs/core/plugins/metadata/tmpdir' + "@nikitajs/core/plugins/metadata/schema", + "@nikitajs/core/plugins/metadata/tmpdir", ], - handler: async function({ - config, - metadata, - tools: {find} - }) { + handler: async function ({ config, metadata, tools: { find } }) { if (config.sudo == null) { - config.sudo = await find( ({metadata: {sudo}}) => sudo ); + config.sudo = await find(({ metadata: { sudo } }) => sudo); } - if (config.sudo || config.flags?.[0] === 'a') { + if (config.sudo || config.flags?.[0] === "a") { metadata.tmpdir = { - sudo: false + sudo: false, }; } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/actions/fs/exists/index.js b/packages/core/lib/actions/fs/exists/index.js index 552793fee..9e26dd600 100644 --- a/packages/core/lib/actions/fs/exists/index.js +++ b/packages/core/lib/actions/fs/exists/index.js @@ -1,24 +1,27 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { try { await this.fs.stat({ target: config.target, - dereference: true + dereference: true, }); return { exists: true, - target: config.target + target: config.target, }; } catch (error) { - if (error.code === 'NIKITA_FS_STAT_TARGET_ENOENT') { + if (error.code === "NIKITA_FS_STAT_TARGET_ENOENT") { return { exists: false, - target: config.target + target: config.target, }; } else { throw error; @@ -26,9 +29,9 @@ export default { } }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/glob/index.js b/packages/core/lib/actions/fs/glob/index.js index fcfc438f1..21f0e272a 100644 --- a/packages/core/lib/actions/fs/glob/index.js +++ b/packages/core/lib/actions/fs/glob/index.js @@ -1,10 +1,15 @@ // Dependencies import { Minimatch } from "minimatch"; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Utility -const getprefix = function(pattern) { +const getprefix = function (pattern) { let prefix = null; let n = 0; while (typeof pattern[n] === "string") { @@ -15,7 +20,7 @@ const getprefix = function(pattern) { switch (n) { // if not, then this is rather simple case pattern.length: - prefix = pattern.join('/'); + prefix = pattern.join("/"); return prefix; case 0: // pattern *starts* with some non-trivial item. @@ -26,7 +31,7 @@ const getprefix = function(pattern) { // whatever it starts with, whether that's "absolute" like /foo/bar, // or "relative" like "../baz" prefix = pattern.slice(0, n); - prefix = prefix.join('/'); + prefix = prefix.join("/"); return prefix; } }; @@ -46,11 +51,11 @@ export default { const minimatch = new Minimatch(config.target, config.minimatch); let { stdout } = await this.execute({ command: [ - 'find', - ...minimatch.set.map( getprefix ), + "find", + ...minimatch.set.map(getprefix), // trailing slash '-type d -exec sh -c \'printf "%s/\\n" "$0"\' {} \\; -or -print', - ].join(' '), + ].join(" "), $relax: true, trim: true, }); @@ -64,8 +69,8 @@ export default { }); // Remove the trailing slash introduced by the find command if (!config.trailing) { - files = files.map( (file) => - file.slice(-1) === "/" ? file.slice(0, -1):file + files = files.map((file) => + file.slice(-1) === "/" ? file.slice(0, -1) : file, ); } return { diff --git a/packages/core/lib/actions/fs/hash/index.js b/packages/core/lib/actions/fs/hash/index.js index c70e3eed3..46ce658ac 100644 --- a/packages/core/lib/actions/fs/hash/index.js +++ b/packages/core/lib/actions/fs/hash/index.js @@ -2,7 +2,12 @@ import crypto from "crypto"; import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { NIKITA_FS_HASH_FILETYPE_UNSUPPORTED: function ({ config, stats }) { @@ -15,7 +20,7 @@ const errors = { ], { target: config.target, - } + }, ); }, NIKITA_FS_HASH_MISSING_OPENSSL: function () { @@ -34,7 +39,7 @@ const errors = { ], { target: config.target, - } + }, ); }, }; @@ -42,9 +47,8 @@ const errors = { // Action export default { handler: async function ({ config }) { - const { stats } = config.stats - ? config.stats - : await this.fs.stat(config.target); + const { stats } = + config.stats ? config.stats : await this.fs.stat(config.target); if ( !utils.stats.isFile(stats.mode) && !utils.stats.isDirectory(stats.mode) @@ -65,7 +69,7 @@ export default { "command -v openssl >/dev/null || exit 2", ...files.map( (file) => - `[ -f ${file} ] && openssl dgst -${config.algo} ${file} | sed 's/^.* \\([a-z0-9]*\\)$/\\1/g'` + `[ -f ${file} ] && openssl dgst -${config.algo} ${file} | sed 's/^.* \\([a-z0-9]*\\)$/\\1/g'`, ), "exit 0", ].join("\n"), @@ -80,11 +84,12 @@ export default { .lines(stdout) .filter((line) => /\w+/.test(line)) .sort(); - return hashs.length === 0 - ? crypto.createHash(config.algo).update("").digest("hex") - : hashs.length === 1 - ? hashs[0] - : crypto.createHash(config.algo).update(hashs.join("")).digest("hex"); + return ( + hashs.length === 0 ? + crypto.createHash(config.algo).update("").digest("hex") + : hashs.length === 1 ? hashs[0] + : crypto.createHash(config.algo).update(hashs.join("")).digest("hex") + ); // Target is a file } else if (utils.stats.isFile(stats.mode)) { const { stdout: hash } = await this.execute({ diff --git a/packages/core/lib/actions/fs/link/index.js b/packages/core/lib/actions/fs/link/index.js index 5f3ec7e85..2718f378b 100644 --- a/packages/core/lib/actions/fs/link/index.js +++ b/packages/core/lib/actions/fs/link/index.js @@ -1,6 +1,11 @@ // Dependencies -import dedent from 'dedent'; -import definitions from "./schema.json" with { type: "json" }; +import dedent from "dedent"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -31,7 +36,7 @@ export default { }); const exec_command = /exec (.*) \$@/.exec(data)[1]; return exec_command && exec_command === config.source; - } + }, ); if (exists) { return; @@ -64,10 +69,10 @@ export default { target: config.target, }); return false; - } catch (error) { + } catch { return false; } - } + }, ); if (exists) { return; diff --git a/packages/core/lib/actions/fs/lstat/index.js b/packages/core/lib/actions/fs/lstat/index.js index 88f62872d..78f16a9a3 100644 --- a/packages/core/lib/actions/fs/lstat/index.js +++ b/packages/core/lib/actions/fs/lstat/index.js @@ -1,19 +1,22 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { return await this.fs.stat({ target: config.target, - dereference: false + dereference: false, }); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/mkdir/index.js b/packages/core/lib/actions/fs/mkdir/index.js index 62b1ed060..3bdab617e 100644 --- a/packages/core/lib/actions/fs/mkdir/index.js +++ b/packages/core/lib/actions/fs/mkdir/index.js @@ -1,19 +1,40 @@ // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_MKDIR_TARGET_RELATIVE: function({config}) { - return utils.error('NIKITA_MKDIR_TARGET_RELATIVE', ['only absolute path are supported over SSH,', 'target is relative and config `cwd` is not provided,', `got ${JSON.stringify(config.target)}`], { - target: config.target - }); + NIKITA_MKDIR_TARGET_RELATIVE: function ({ config }) { + return utils.error( + "NIKITA_MKDIR_TARGET_RELATIVE", + [ + "only absolute path are supported over SSH,", + "target is relative and config `cwd` is not provided,", + `got ${JSON.stringify(config.target)}`, + ], + { + target: config.target, + }, + ); + }, + NIKITA_MKDIR_TARGET_INVALID_TYPE: function ({ stats, target }) { + return utils.error( + "NIKITA_MKDIR_TARGET_INVALID_TYPE", + [ + "target exists but it is not a directory,", + `got ${JSON.stringify(utils.stats.type(stats.mode))} type`, + `for ${JSON.stringify(target)}`, + ], + { + target: target, + }, + ); }, - NIKITA_MKDIR_TARGET_INVALID_TYPE: function({stats, target}) { - return utils.error('NIKITA_MKDIR_TARGET_INVALID_TYPE', ['target exists but it is not a directory,', `got ${JSON.stringify(utils.stats.type(stats.mode))} type`, `for ${JSON.stringify(target)}`], { - target: target - }); - } }; // Action @@ -26,8 +47,9 @@ export default { if (config.parent === true) { config.parent = {}; } - config.target = config.cwd - ? path.resolve(config.cwd, config.target) + config.target = + config.cwd ? + path.resolve(config.cwd, config.target) : path.normalize(config.target); if (ssh && !path.isAbsolute(config.target)) { throw errors.NIKITA_MKDIR_TARGET_RELATIVE({ @@ -37,16 +59,16 @@ export default { // Retrieve every directories including parents let parents = config.target.split(path.sep); parents.shift(); // first element is empty with absolute path - if (parents[parents.length - 1] === '') { + if (parents[parents.length - 1] === "") { parents.pop(); } - parents = Array(parents.length).fill(null).map( (_, i) => - '/' + parents.slice(0, parents.length - i).join('/') - ) + parents = Array(parents.length) + .fill(null) + .map((_, i) => "/" + parents.slice(0, parents.length - i).join("/")); // Discovery of directories to create let creates = []; - let stats - for(const target of parents) { + let stats; + for (const target of parents) { try { ({ stats } = await this.fs.stat(target)); if (utils.stats.isDirectory(stats.mode)) { @@ -74,7 +96,7 @@ export default { } } const opts = {}; - const attributes = ['mode', 'uid', 'gid', 'size', 'atime', 'mtime']; + const attributes = ["mode", "uid", "gid", "size", "atime", "mtime"]; for (const attr of attributes) { const val = i === creates.length - 1 ? config[attr] : config.parent?.[attr]; @@ -112,7 +134,7 @@ export default { return {}; }, hooks: { - on_action: function ({ config, metadata }) { + on_action: function ({ config }) { if (config.parent == null) { config.parent = {}; } diff --git a/packages/core/lib/actions/fs/move/index.js b/packages/core/lib/actions/fs/move/index.js index 01928b99f..880c545a0 100644 --- a/packages/core/lib/actions/fs/move/index.js +++ b/packages/core/lib/actions/fs/move/index.js @@ -1,9 +1,13 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function ({ config, tools: { log, path } }) { + handler: async function ({ config, tools: { log } }) { const { exists } = await this.fs.exists(config.target); if (!exists) { log("WARN", `Rename ${config.source} to ${config.target}`); diff --git a/packages/core/lib/actions/fs/readFile/index.js b/packages/core/lib/actions/fs/readFile/index.js index c3bc931c0..dd3a850b3 100644 --- a/packages/core/lib/actions/fs/readFile/index.js +++ b/packages/core/lib/actions/fs/readFile/index.js @@ -1,41 +1,46 @@ - // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Normalize options const buffers = []; await this.fs.createReadStream({ target: config.target, - on_readable: function(rs) { + on_readable: function (rs) { const results = []; - let buffer; while (buffer = rs.read()) { + let buffer; + while ((buffer = rs.read())) { results.push(buffers.push(buffer)); } return results; - } + }, }); let data = Buffer.concat(buffers); if (config.encoding) { data = data.toString(config.encoding); } - if (config.trim && typeof data === 'string') { + if (config.trim && typeof data === "string") { data = data.trim(); } if (config.format) { - data = await utils.string.format(data, config.format) + data = await utils.string.format(data, config.format); } return { - data: data + data: data, }; }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/readdir/index.js b/packages/core/lib/actions/fs/readdir/index.js index 75bbc40c2..f9c47867e 100644 --- a/packages/core/lib/actions/fs/readdir/index.js +++ b/packages/core/lib/actions/fs/readdir/index.js @@ -1,90 +1,105 @@ - // Dependencies -import {Dirent, constants} from 'fs'; -import dedent from 'dedent'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import { Dirent, constants } from "fs"; +import dedent from "dedent"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_READDIR_TARGET_ENOENT: ({config, error}) => - utils.error('NIKITA_FS_READDIR_TARGET_ENOENT', ['fail to read a directory, target is not a directory,', `got ${JSON.stringify(config.target)}`], { - exit_code: error.exit_code, - errno: -2, - syscall: 'rmdir', - path: config.target - }) -} + NIKITA_FS_READDIR_TARGET_ENOENT: ({ config, error }) => + utils.error( + "NIKITA_FS_READDIR_TARGET_ENOENT", + [ + "fail to read a directory, target is not a directory,", + `got ${JSON.stringify(config.target)}`, + ], + { + exit_code: error.exit_code, + errno: -2, + syscall: "rmdir", + path: config.target, + }, + ), +}; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Note: -w work on macos, not on linux, it force raw printing of // non-printable characters. This is the default when output is not to a // terminal. const opts = [ - '1', // (The numeric digit ``one''.) Force output to be one entry per line. This is the default when output is not to a terminal. - 'a', // Include directory entries whose names begin with a dot (.) - config.extended ? 'n' : void 0, // Display user and group IDs numerically, rather than converting to a user or group name in a long (-l) output. This option turns on the -l option. - config.extended ? 'l' : void 0 - ].join(''); + "1", // (The numeric digit ``one''.) Force output to be one entry per line. This is the default when output is not to a terminal. + "a", // Include directory entries whose names begin with a dot (.) + config.extended ? "n" : void 0, // Display user and group IDs numerically, rather than converting to a user or group name in a long (-l) output. This option turns on the -l option. + config.extended ? "l" : void 0, + ].join(""); try { // List the directory - const {stdout} = await this.execute({ + const { stdout } = await this.execute({ command: dedent` [ ! -d '${config.target}' ] && exit 2 ls -${opts} ${config.target} - ` + `, }); return { // Convert the output into a `files` array files: utils.string .lines(stdout) - .filter( (line, i) => - !config.extended || i !== 0 // First line in extended mode - ).filter( (line) => - line !== '' // Empty lines - ).map(function(line, i) { + .filter( + (line, i) => !config.extended || i !== 0, // First line in extended mode + ) + .filter( + (line) => line !== "", // Empty lines + ) + .map(function (line) { if (!config.extended) { return { - name: line + name: line, }; } else { - const [, perm, , name] = /^(.+?)\s+.*?(\d+:\d+)\s+(.+)$/.exec(line); + const [, perm, , name] = /^(.+?)\s+.*?(\d+:\d+)\s+(.+)$/.exec( + line, + ); return { name: name, type: - perm[0] === 'b' && constants.UV_DIRENT_BLOCK || // Block special file - perm[0] === 'c' && constants.UV_DIRENT_CHAR || // Character special file - perm[0] === 'd' && constants.UV_DIRENT_DIR || // Directory - perm[0] === 'l' && constants.UV_DIRENT_LINK || // Symbolic link - perm[0] === 's' && constants.UV_DIRENT_SOCKET || // Socket link - perm[0] === 'p' && constants.UV_DIRENT_FIFO || // FIFO - constants.UV_DIRENT_FILE // Regular file + (perm[0] === "b" && constants.UV_DIRENT_BLOCK) || // Block special file + (perm[0] === "c" && constants.UV_DIRENT_CHAR) || // Character special file + (perm[0] === "d" && constants.UV_DIRENT_DIR) || // Directory + (perm[0] === "l" && constants.UV_DIRENT_LINK) || // Symbolic link + (perm[0] === "s" && constants.UV_DIRENT_SOCKET) || // Socket link + (perm[0] === "p" && constants.UV_DIRENT_FIFO) || // FIFO + constants.UV_DIRENT_FILE, // Regular file }; } - }).filter( ({name}) => - name !== '' && name !== '.' && name !== '..' - ).map((file) => - config.extended - // 20230527, Node.js 20 introduce a `path` property with the parent dir, - // We might do sth about it such as: - // ? (function () { - // // Return a new DirEnt object - // const dirent = new Dirent(file.name, file.type); - // if (!dirent.path) { - // dirent.path = config.target; - // } - // return dirent; - // })() - ? new Dirent(file.name, file.type) - : file.name - ) + }) + .filter(({ name }) => name !== "" && name !== "." && name !== "..") + .map((file) => + config.extended ? + // 20230527, Node.js 20 introduce a `path` property with the parent dir, + // We might do sth about it such as: + // ? (function () { + // // Return a new DirEnt object + // const dirent = new Dirent(file.name, file.type); + // if (!dirent.path) { + // dirent.path = config.target; + // } + // return dirent; + // })() + new Dirent(file.name, file.type) + : file.name, + ), }; } catch (error) { if (error.exit_code === 2) { throw errors.NIKITA_FS_READDIR_TARGET_ENOENT({ config: config, - error: error + error: error, }); } else { throw error; @@ -92,16 +107,18 @@ export default { } }, hooks: { - on_action: function({config, metadata}) { + on_action: function ({ config }) { if (config.withFileTypes != null) { - return config.extended != null ? config.extended : config.extended = config.withFileTypes; + return config.extended != null ? + config.extended + : (config.extended = config.withFileTypes); } - } + }, }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/readlink/index.js b/packages/core/lib/actions/fs/readlink/index.js index 020e7324e..25c917aa7 100644 --- a/packages/core/lib/actions/fs/readlink/index.js +++ b/packages/core/lib/actions/fs/readlink/index.js @@ -1,21 +1,24 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {stdout} = await this.execute({ - command: `readlink ${config.target}` + handler: async function ({ config }) { + const { stdout } = await this.execute({ + command: `readlink ${config.target}`, }); return { - target: stdout.trim() + target: stdout.trim(), }; }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/remove/index.js b/packages/core/lib/actions/fs/remove/index.js index 87e021aa2..41dc057c1 100644 --- a/packages/core/lib/actions/fs/remove/index.js +++ b/packages/core/lib/actions/fs/remove/index.js @@ -1,6 +1,11 @@ // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const esa = utils.string.escapeshellarg; // Action @@ -16,7 +21,9 @@ export default { "-d", // Attempt to remove directories as well as other types of files. config.recursive && "-r", esa(file), - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), }); if (status) { log("WARN", `File ${esa(file)} removed.`); diff --git a/packages/core/lib/actions/fs/rename/index.js b/packages/core/lib/actions/fs/rename/index.js index baac1c4cd..03e8c8a2d 100644 --- a/packages/core/lib/actions/fs/rename/index.js +++ b/packages/core/lib/actions/fs/rename/index.js @@ -1,19 +1,22 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { return await this.execute({ command: `mv ${config.source} ${config.target}`, - trim: true + trim: true, }); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/rmdir/index.js b/packages/core/lib/actions/fs/rmdir/index.js index 25af44406..d328e1276 100644 --- a/packages/core/lib/actions/fs/rmdir/index.js +++ b/packages/core/lib/actions/fs/rmdir/index.js @@ -1,48 +1,56 @@ - // Dependencies -import utils from '@nikitajs/core/utils'; +import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_RMDIR_TARGET_ENOENT: ({config, error}) => - utils.error('NIKITA_FS_RMDIR_TARGET_ENOENT', ['fail to remove a directory, target is not a directory,', `got ${JSON.stringify(config.target)}`], { - exit_code: error.exit_code, - errno: -2, - syscall: 'rmdir', - path: config.target - }) + NIKITA_FS_RMDIR_TARGET_ENOENT: ({ config, error }) => + utils.error( + "NIKITA_FS_RMDIR_TARGET_ENOENT", + [ + "fail to remove a directory, target is not a directory,", + `got ${JSON.stringify(config.target)}`, + ], + { + exit_code: error.exit_code, + errno: -2, + syscall: "rmdir", + path: config.target, + }, + ), }; // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { await this.execute({ command: [ `[ ! -d ${esa(config.target)} ] && exit 2`, - !config.recursive - ? `rmdir ${esa(config.target)}` - : `rm -R ${esa(config.target)}`, + !config.recursive ? + `rmdir ${esa(config.target)}` + : `rm -R ${esa(config.target)}`, ].join("\n"), - }).then(() => - log("INFO", "Directory successfully removed") - ).catch((error) => { - if (error.exit_code === 2) { - error = errors.NIKITA_FS_RMDIR_TARGET_ENOENT({ - config: config, - error: error - }); - } - throw error; - }); + }) + .then(() => log("INFO", "Directory successfully removed")) + .catch((error) => { + if (error.exit_code === 2) { + error = errors.NIKITA_FS_RMDIR_TARGET_ENOENT({ + config: config, + error: error, + }); + } + throw error; + }); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/stat/index.js b/packages/core/lib/actions/fs/stat/index.js index d4b31df2f..8f2939c7a 100644 --- a/packages/core/lib/actions/fs/stat/index.js +++ b/packages/core/lib/actions/fs/stat/index.js @@ -1,27 +1,38 @@ - // Dependencies -import dedent from 'dedent'; -import utils from '@nikitajs/core/utils'; +import dedent from "dedent"; +import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_STAT_TARGET_ENOENT: ({config, error}) => - utils.error('NIKITA_FS_STAT_TARGET_ENOENT', ['failed to stat the target, no file exists for target,', `got ${JSON.stringify(config.target)}`], { - exit_code: error.exit_code, - errno: -2, - syscall: 'rmdir', - path: config.target - }) + NIKITA_FS_STAT_TARGET_ENOENT: ({ config, error }) => + utils.error( + "NIKITA_FS_STAT_TARGET_ENOENT", + [ + "failed to stat the target, no file exists for target,", + `got ${JSON.stringify(config.target)}`, + ], + { + exit_code: error.exit_code, + errno: -2, + syscall: "rmdir", + path: config.target, + }, + ), }; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Normalize configuration // config.dereference ??= true; const dereference = config.dereference ? "-L" : ""; - const {stdout} = await this.execute({ + const { stdout } = await this.execute({ command: dedent` [ ! -e ${config.target} ] && exit 3 if [ -d /private ]; then @@ -30,12 +41,12 @@ export default { stat ${dereference} -c '%f|%u|%g|%s|%X|%Y' ${esa(config.target)} # Linux fi `, - trim: true - }).catch( error => { + trim: true, + }).catch((error) => { if (error.exit_code === 3) { throw errors.NIKITA_FS_STAT_TARGET_ENOENT({ config: config, - error: error + error: error, }); } throw error; @@ -53,9 +64,9 @@ export default { }; }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions + definitions: definitions, }, }; diff --git a/packages/core/lib/actions/fs/symlink/index.js b/packages/core/lib/actions/fs/symlink/index.js index 3a334dc00..e7a801b7b 100644 --- a/packages/core/lib/actions/fs/symlink/index.js +++ b/packages/core/lib/actions/fs/symlink/index.js @@ -1,19 +1,23 @@ - // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.execute({ - command: `ln -sf ${esa(config.source)} ${esa(config.target)}` + command: `ln -sf ${esa(config.source)} ${esa(config.target)}`, }); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/unlink/index.js b/packages/core/lib/actions/fs/unlink/index.js index 512ba2625..7e8108bb5 100644 --- a/packages/core/lib/actions/fs/unlink/index.js +++ b/packages/core/lib/actions/fs/unlink/index.js @@ -1,27 +1,31 @@ - // ## Dependencies -import dedent from 'dedent'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import dedent from "dedent"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_UNLINK_ENOENT: function({config}) { - return utils.error('NIKITA_FS_UNLINK_ENOENT', [ - 'the file to remove does not exists,', - `got ${JSON.stringify(config.target)}` + NIKITA_FS_UNLINK_ENOENT: function ({ config }) { + return utils.error("NIKITA_FS_UNLINK_ENOENT", [ + "the file to remove does not exists,", + `got ${JSON.stringify(config.target)}`, ]); }, - NIKITA_FS_UNLINK_EPERM: function({config}) { - return utils.error('NIKITA_FS_UNLINK_EPERM', [ - 'you do not have the permission to remove the file,', - `got ${JSON.stringify(config.target)}` + NIKITA_FS_UNLINK_EPERM: function ({ config }) { + return utils.error("NIKITA_FS_UNLINK_EPERM", [ + "you do not have the permission to remove the file,", + `got ${JSON.stringify(config.target)}`, ]); - } + }, }; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { try { // `! -e`: file does not exist // `! -L && -d`: file is not a symlink and is a directory, @@ -36,20 +40,20 @@ export default { switch (error.exit_code) { case 2: throw errors.NIKITA_FS_UNLINK_ENOENT({ - config: config + config: config, }); case 3: throw errors.NIKITA_FS_UNLINK_EPERM({ - config: config + config: config, }); } throw error; } }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/fs/wait/index.js b/packages/core/lib/actions/fs/wait/index.js index 2e3630055..007671d98 100644 --- a/packages/core/lib/actions/fs/wait/index.js +++ b/packages/core/lib/actions/fs/wait/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/core/lib/actions/fs/writeFile/index.js b/packages/core/lib/actions/fs/writeFile/index.js index cd9c03359..8711f165b 100644 --- a/packages/core/lib/actions/fs/writeFile/index.js +++ b/packages/core/lib/actions/fs/writeFile/index.js @@ -1,36 +1,42 @@ - // Dependencies -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { - NIKITA_FS_TARGET_INVALID: ({config, err}) => - utils.error('NIKITA_FS_TARGET_INVALID', [ - 'the target location is absolute', - 'but this is not suported in SSH mode,', - 'you must provide an absolute path or the cwd option,', - `got ${JSON.stringify(config.target)}` - ], { - exit_code: err.exit_code, - errno: -2, - syscall: 'rmdir', - path: config.target - }) + NIKITA_FS_TARGET_INVALID: ({ config, err }) => + utils.error( + "NIKITA_FS_TARGET_INVALID", + [ + "the target location is absolute", + "but this is not suported in SSH mode,", + "you must provide an absolute path or the cwd option,", + `got ${JSON.stringify(config.target)}`, + ], + { + exit_code: err.exit_code, + errno: -2, + syscall: "rmdir", + path: config.target, + }, + ), }; // Action export default { - handler: async function({ - config, - tools: {path}, - ssh - }) { + handler: async function ({ config, tools: { path }, ssh }) { // Normalization - config.target = config.cwd ? path.resolve(config.cwd, config.target) : path.normalize(config.target); + config.target = + config.cwd ? + path.resolve(config.cwd, config.target) + : path.normalize(config.target); if (ssh && !path.isAbsolute(config.target)) { throw errors.NIKITA_FS_TARGET_INVALID({ config: config, - err: err }); } // Real work @@ -38,16 +44,16 @@ export default { target: config.target, flags: config.flags, mode: config.mode, - stream: function(ws) { + stream: function (ws) { ws.write(config.content); ws.end(); - } + }, }); }, metadata: { - argument_to_config: 'target', + argument_to_config: "target", log: false, raw_output: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/registry/register/index.js b/packages/core/lib/actions/registry/register/index.js index de820e8c3..b060e80b0 100644 --- a/packages/core/lib/actions/registry/register/index.js +++ b/packages/core/lib/actions/registry/register/index.js @@ -1,14 +1,14 @@ // Action export default { - handler: async function({config, parent}) { - if(config.actions){ + handler: async function ({ config, parent }) { + if (config.actions) { await parent.registry.register(config.actions); } - if(config.namespace) { + if (config.namespace) { await parent.registry.register(config.namespace, config.action); } }, metadata: { - raw_output: true + raw_output: true, }, }; diff --git a/packages/core/lib/actions/registry/registered/index.js b/packages/core/lib/actions/registry/registered/index.js index be2c679fd..8d0096b6b 100644 --- a/packages/core/lib/actions/registry/registered/index.js +++ b/packages/core/lib/actions/registry/registered/index.js @@ -1,9 +1,9 @@ // Action export default { - handler: function({config, parent}) { + handler: function ({ config, parent }) { return parent.registry.registered(config.namespace); }, metadata: { - raw_output: true + raw_output: true, }, }; diff --git a/packages/core/lib/actions/registry/unregister/index.js b/packages/core/lib/actions/registry/unregister/index.js index c886012f1..83a864d6c 100644 --- a/packages/core/lib/actions/registry/unregister/index.js +++ b/packages/core/lib/actions/registry/unregister/index.js @@ -1,9 +1,9 @@ // Action export default { - handler: function({config, parent}) { + handler: function ({ config, parent }) { parent.registry.unregister(config.namespace); }, metadata: { - raw_output: true + raw_output: true, }, }; diff --git a/packages/core/lib/actions/ssh/close/index.js b/packages/core/lib/actions/ssh/close/index.js index b7253f3ce..bb4034dd8 100644 --- a/packages/core/lib/actions/ssh/close/index.js +++ b/packages/core/lib/actions/ssh/close/index.js @@ -1,35 +1,42 @@ // Dependencies -import connect from 'ssh2-connect'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import connect from "ssh2-connect"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: function({config, siblings}) { + handler: function ({ config, siblings }) { if (config.ssh == null) { - config.ssh = siblings.map( ({output}) => - output?.ssh - ).find((ssh) => - !!ssh - ); + config.ssh = siblings + .map(({ output }) => output?.ssh) + .find((ssh) => !!ssh); } if (!config.ssh) { - throw utils.error('NIKITA_SSH_CLOSE_NO_CONN', ['There is no connection to close,', 'either pass the connection in the `ssh` configuation', 'or ensure a connection was open in a sibling action']); + throw utils.error("NIKITA_SSH_CLOSE_NO_CONN", [ + "There is no connection to close,", + "either pass the connection in the `ssh` configuation", + "or ensure a connection was open in a sibling action", + ]); } if (connect.closed(config.ssh)) { // Exit if the connection is already close return false; } // Terminate the connection - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { config.ssh.end(); - config.ssh.on('error', reject); - return config.ssh.on('end', function() { + config.ssh.on("error", reject); + return config.ssh.on("end", function () { return resolve(true); }); }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/core/lib/actions/ssh/open/index.js b/packages/core/lib/actions/ssh/open/index.js index bf8069cd0..1a98f1fdf 100644 --- a/packages/core/lib/actions/ssh/open/index.js +++ b/packages/core/lib/actions/ssh/open/index.js @@ -2,7 +2,12 @@ import connect from "ssh2-connect"; import fs from "node:fs/promises"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -17,10 +22,7 @@ export default { } // Read private key if option is a path if (!config.private_key && !config.password) { - log({ - message: `Read Private Key from: ${config.private_key_path}`, - level: "DEBUG", - }); + log("DEBUG", `Read Private Key from: ${config.private_key_path}`); const location = await utils.tilde.normalize(config.private_key_path); try { ({ data: config.private_key } = await fs.readFile(location, "ascii")); @@ -33,37 +35,25 @@ export default { } try { // Establish connection - log({ - message: `Read Private Key: ${JSON.stringify(config.private_key_path)}`, - level: "DEBUG", - }); + log( + "DEBUG", + `Read Private Key: ${JSON.stringify(config.private_key_path)}`, + ); const conn = await connect(config); - log({ - message: "Connection is established", - level: "INFO", - }); + log("INFO", "Connection is established"); return { ssh: conn, }; - } catch (error) { - log({ - message: "Connection failed", - level: "WARN", - }); + } catch { + log("WARN", "Connection failed"); // Continue to bootstrap root access } // Enable root access if (config.root.username) { - log({ - message: "Bootstrap Root Access", - level: "INFO", - }); + log("INFO", "Bootstrap Root Access"); await this.ssh.root(config.root); } - log({ - message: "Establish Connection: attempt after enabling root access", - level: "DEBUG", - }); + log("DEBUG", "Establish Connection: attempt after enabling root access"); return await this.call( { $retry: 3, @@ -72,7 +62,7 @@ export default { return { ssh: await connect(config), }; - } + }, ); }, hooks: { diff --git a/packages/core/lib/actions/ssh/root/index.js b/packages/core/lib/actions/ssh/root/index.js index dfa23fc08..06072de7d 100644 --- a/packages/core/lib/actions/ssh/root/index.js +++ b/packages/core/lib/actions/ssh/root/index.js @@ -4,7 +4,12 @@ import dedent from "dedent"; import connect from "ssh2-connect"; import exec from "ssh2-exec"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -32,7 +37,7 @@ export default { config.selinux !== "disabled" ) { // Validation - throw Error(`Invalid option \"selinux\": ${config.selinux}`); + throw Error(`Invalid option "selinux": ${config.selinux}`); } let rebooting = false; // Read public key if option is a path @@ -49,10 +54,10 @@ export default { } // Read private key if option is a path if (config.private_key_path && !config.private_key) { - log({ - message: `Read Private Key: ${JSON.stringify(config.private_key_path)}`, - level: "DEBUG", - }); + log( + "DEBUG", + `Read Private Key: ${JSON.stringify(config.private_key_path)}`, + ); const location = await utils.tilde.normalize(config.private_key_path); try { ({ data: config.private_key } = await fs.readFile(location, "ascii")); @@ -69,7 +74,7 @@ export default { log("INFO", "Connection establish"); let command = []; command.push( - `sed -i.back 's/.*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config;` + `sed -i.back 's/.*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config;`, ); if (config.public_key) { command.push(dedent` @@ -100,20 +105,14 @@ export default { config.command += `-u ${config.user} `; } if (config.password) { - config.command = `echo -e \"${config.password}\\n\" | ${config.command} -S `; + config.command = `echo -e "${config.password}\\n" | ${config.command} -S `; } - config.command += `-- sh -c \"${command}\"`; + config.command += `-- sh -c "${command}"`; command = config.command; } } - log({ - message: "Enable Root Access", - level: "DEBUG", - }); - log({ - message: command, - type: "stdin", - }); + log("DEBUG", "Enable Root Access"); + log("stdin", command); if (!metadata.dry) { const child = exec( { @@ -127,20 +126,16 @@ export default { } else { throw error; } - } + }, ); child.stdout.on("data", (data) => - log({ message: data, type: "stdout" }) - ); - child.stdout.on("end", () => - log({ message: null, type: "stdout" }) + log({ message: data, type: "stdout" }), ); + child.stdout.on("end", () => log({ message: null, type: "stdout" })); child.stderr.on("data", (data) => - log({ message: data, type: "stderr" }) - ); - child.stderr.on("end", () => - log({ message: null, type: "stderr" }) + log({ message: data, type: "stderr" }), ); + child.stderr.on("end", () => log({ message: null, type: "stderr" })); } }); await this.call( @@ -151,7 +146,7 @@ export default { }, async function () { (await connect(config)).end(); - } + }, ); }, metadata: { diff --git a/packages/core/lib/actions/wait/index.js b/packages/core/lib/actions/wait/index.js index ef0e8fdb7..09aecea91 100644 --- a/packages/core/lib/actions/wait/index.js +++ b/packages/core/lib/actions/wait/index.js @@ -1,6 +1,11 @@ // Dependencies -import definitions from "./schema.json" with { type: "json" }; import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -10,16 +15,17 @@ export default { hooks: { on_action: function (action) { const { args, handler, config } = action; - if(!args.some((arg) => typeof arg === 'function')){ + if (!args.some((arg) => typeof arg === "function")) { // Fallback to default handler - return action + return action; } // Use handler wraper - action.config = {} - action.metadata.argument_to_config = undefined + action.config = {}; + action.metadata.argument_to_config = undefined; action.handler = async function ({ context, tools: { log } }) { let attempts = 0; - const wait = (timeout) => timeout && new Promise( (resolve) => setTimeout(resolve, timeout) ); + const wait = (timeout) => + timeout && new Promise((resolve) => setTimeout(resolve, timeout)); while (attempts !== config.retry) { attempts++; log("DEBUG", `Start attempt #${attempts}`); @@ -34,7 +40,10 @@ export default { $status: attempts > 1, }; } catch (err) { - log("WARN", `Attempt #${attempts} failed with message: ${err.message}`); + log( + "WARN", + `Attempt #${attempts} failed with message: ${err.message}`, + ); await wait(config.interval); } } diff --git a/packages/core/lib/plugins/assertions.js b/packages/core/lib/plugins/assertions.js index 10d453d8c..32cf2a21f 100644 --- a/packages/core/lib/plugins/assertions.js +++ b/packages/core/lib/plugins/assertions.js @@ -1,27 +1,30 @@ - -import session from '@nikitajs/core/session'; -import utils from '@nikitajs/core/utils'; +import session from "@nikitajs/core/session"; +import utils from "@nikitajs/core/utils"; const handlers = { - assert: async function(action, error, output) { + assert: async function (action, error, output) { let final_run = true; for (const assertion of action.assertions.assert) { let run; - if (typeof assertion === 'function') { + if (typeof assertion === "function") { run = await session({ $: false, handler: assertion, metadata: { bastard: true, - raw_output: true + raw_output: true, }, parent: action, config: action.config, error: error, - output: output + output: output, }); - if (typeof run !== 'boolean') { - throw utils.error('NIKITA_ASSERTION_INVALID_OUTPUT', ['invalid assertion output,', 'expect a boolean value,', `got ${JSON.stringify(run)}.`]); + if (typeof run !== "boolean") { + throw utils.error("NIKITA_ASSERTION_INVALID_OUTPUT", [ + "invalid assertion output,", + "expect a boolean value,", + `got ${JSON.stringify(run)}.`, + ]); } } else { run = utils.object.match(output, assertion); @@ -32,11 +35,11 @@ const handlers = { } return final_run; }, - unassert: async function(action, error, output) { + unassert: async function (action, error, output) { let final_run = true; for (const assertion of action.assertions.unassert) { let run; - if (typeof assertion === 'function') { + if (typeof assertion === "function") { run = await session({ $: false, handler: assertion, @@ -49,8 +52,12 @@ const handlers = { error: error, output: output, }); - if (typeof run !== 'boolean') { - throw utils.error('NIKITA_ASSERTION_INVALID_OUTPUT', ['invalid assertion output,', 'expect a boolean value,', `got ${JSON.stringify(run)}.`]); + if (typeof run !== "boolean") { + throw utils.error("NIKITA_ASSERTION_INVALID_OUTPUT", [ + "invalid assertion output,", + "expect a boolean value,", + `got ${JSON.stringify(run)}.`, + ]); } } else { run = utils.object.match(output, assertion); @@ -60,24 +67,27 @@ const handlers = { } } return final_run; - } + }, }; export default { - name: '@nikitajs/core/plugins/assertions', + name: "@nikitajs/core/plugins/assertions", require: [ - '@nikitajs/core/plugins/metadata/raw', - '@nikitajs/core/plugins/metadata/disabled' + "@nikitajs/core/plugins/metadata/raw", + "@nikitajs/core/plugins/metadata/disabled", ], hooks: { - 'nikita:normalize': function(action, handler) { + "nikita:normalize": function (action, handler) { // Ventilate assertions properties defined at root const assertions = {}; for (const property in action.metadata) { let value = action.metadata[property]; if (/^(un)?assert$/.test(property)) { if (assertions[property]) { - throw Error('ASSERTION_DUPLICATED_DECLARATION', [`Property ${property} is defined multiple times,`, 'at the root of the action and inside assertions']); + throw Error("ASSERTION_DUPLICATED_DECLARATION", [ + `Property ${property} is defined multiple times,`, + "at the root of the action and inside assertions", + ]); } if (!Array.isArray(value)) { value = [value]; @@ -86,26 +96,33 @@ export default { delete action.metadata[property]; } } - return async function() { - action = (await handler.call(null, ...arguments)); + return async function () { + action = await handler.call(null, ...arguments); action.assertions = assertions; return action; }; }, - 'nikita:result': async function({action, error, output}) { + "nikita:result": async function ({ action, error, output }) { let final_run = true; for (const assertion in action.assertions) { if (handlers[assertion] == null) { continue; } - const local_run = await handlers[assertion].call(null, action, error, output); + const local_run = await handlers[assertion].call( + null, + action, + error, + output, + ); if (local_run === false) { final_run = false; } } if (!final_run) { - throw utils.error('NIKITA_INVALID_ASSERTION', ['action did not validate the assertion']); + throw utils.error("NIKITA_INVALID_ASSERTION", [ + "action did not validate the assertion", + ]); } - } - } + }, + }, }; diff --git a/packages/core/lib/plugins/assertions/exists.js b/packages/core/lib/plugins/assertions/exists.js index e6270b10f..5bb1d27b4 100644 --- a/packages/core/lib/plugins/assertions/exists.js +++ b/packages/core/lib/plugins/assertions/exists.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/assertions/exists` @@ -7,71 +6,80 @@ Assert that a file exist. The plugin register two action properties, `$assert_exists` and `$unassert_exists`. */ -import session from '@nikitajs/core/session'; -import utils from '@nikitajs/core/utils'; -import {mutate} from 'mixme'; +import session from "@nikitajs/core/session"; +import utils from "@nikitajs/core/utils"; +import { mutate } from "mixme"; const handlers = { - assert_exists: async function(action) { + assert_exists: async function (action) { let final_run = true; for (const assertion of action.assertions.assert_exists) { - const run = await session({ - $bastard: true, - $parent: action, - $raw_output: true - }, async function({parent}) { - const {exists} = await this.fs.exists({ - target: assertion - }); - return exists; - }); + const run = await session( + { + $bastard: true, + $parent: action, + $raw_output: true, + }, + async function () { + const { exists } = await this.fs.exists({ + target: assertion, + }); + return exists; + }, + ); if (run === false) { final_run = false; } } return final_run; }, - unassert_exists: async function(action) { + unassert_exists: async function (action) { let final_run = true; for (const assertion of action.assertions.unassert_exists) { - const run = await session({ - $bastard: true, - $parent: action, - $raw_output: true - }, async function() { - const {exists} = await this.fs.exists({ - target: assertion - }); - return exists; - }); + const run = await session( + { + $bastard: true, + $parent: action, + $raw_output: true, + }, + async function () { + const { exists } = await this.fs.exists({ + target: assertion, + }); + return exists; + }, + ); if (run === true) { final_run = false; } } return final_run; - } + }, }; export default { - name: '@nikitajs/core/plugins/assertions/exists', + name: "@nikitajs/core/plugins/assertions/exists", require: [ - '@nikitajs/core/plugins/metadata/raw', - '@nikitajs/core/plugins/metadata/disabled' + "@nikitajs/core/plugins/metadata/raw", + "@nikitajs/core/plugins/metadata/disabled", ], hooks: { - 'nikita:normalize': { + "nikita:normalize": { // This is hanging, no time for investigation // after: [ // '@nikitajs/core/plugins/assertions' // ] - handler: function(action, handler) { + handler: function (action, handler) { // Ventilate assertions properties defined at root const assertions = {}; for (const property in action.metadata) { let value = action.metadata[property]; if (/^(un)?assert_exists$/.test(property)) { if (assertions[property]) { - throw Error('ASSERTION_DUPLICATED_DECLARATION', [`Property ${property} is defined multiple times,`, 'at the root of the action and inside assertions']); + throw Error("ASSERTION_DUPLICATED_DECLARATION", [ + `Property ${property} is defined multiple times,`, + "at the root of the action and inside assertions", + ]); } if (!Array.isArray(value)) { value = [value]; @@ -80,14 +88,14 @@ export default { delete action.metadata[property]; } } - return async function() { - action = (await handler.call(null, ...arguments)); + return async function () { + action = await handler.call(null, ...arguments); mutate(action.assertions, assertions); return action; }; - } + }, }, - 'nikita:result': async function({action, error, output}) { + "nikita:result": async function ({ action }) { let final_run = true; for (const assertion in action.assertions) { if (handlers[assertion] == null) { @@ -99,8 +107,10 @@ export default { } } if (!final_run) { - throw utils.error('NIKITA_INVALID_ASSERTION', ['action did not validate the assertion']); + throw utils.error("NIKITA_INVALID_ASSERTION", [ + "action did not validate the assertion", + ]); } - } - } + }, + }, }; diff --git a/packages/core/lib/plugins/conditions.js b/packages/core/lib/plugins/conditions.js index 6672beaf2..a87c88cce 100644 --- a/packages/core/lib/plugins/conditions.js +++ b/packages/core/lib/plugins/conditions.js @@ -1,29 +1,28 @@ - -import session from '@nikitajs/core/session'; +import session from "@nikitajs/core/session"; const handlers = { - if: async function(action) { + if: async function (action) { for (let condition of action.conditions.if) { - if (typeof condition === 'function') { + if (typeof condition === "function") { condition = await session({ $bastard: true, $handler: condition, $parent: action, $raw_output: true, - ...action.config + ...action.config, }); } - const run = (function() { + const run = (function () { switch (typeof condition) { - case 'undefined': + case "undefined": return false; - case 'boolean': + case "boolean": return condition; - case 'number': + case "number": return !!condition; - case 'string': + case "string": return !!condition.length; - case 'object': + case "object": if (Buffer.isBuffer(condition)) { return !!condition.length; } else if (condition === null) { @@ -31,39 +30,38 @@ const handlers = { } else { return !!Object.keys(condition).length; } - break; default: - throw Error('Value type is not handled'); + throw Error("Value type is not handled"); } })(); if (run === false) { - return false + return false; } } return true; }, - unless: async function(action) { + unless: async function (action) { for (let condition of action.conditions.unless) { - if (typeof condition === 'function') { + if (typeof condition === "function") { condition = await session({ $bastard: true, $handler: condition, $parent: action, $raw_output: true, - ...action.config + ...action.config, }); } - const run = (function() { + const run = (function () { switch (typeof condition) { - case 'undefined': + case "undefined": return true; - case 'boolean': + case "boolean": return !condition; - case 'number': + case "number": return !condition; - case 'string': + case "string": return !condition.length; - case 'object': + case "object": if (Buffer.isBuffer(condition)) { return !condition.length; } else if (condition === null) { @@ -71,9 +69,8 @@ const handlers = { } else { return !Object.keys(condition).length; } - break; default: - throw Error('Value type is not handled'); + throw Error("Value type is not handled"); } })(); if (run === false) { @@ -81,15 +78,18 @@ const handlers = { } } return true; - } + }, }; export default { - name: '@nikitajs/core/plugins/conditions', - require: ['@nikitajs/core/plugins/metadata/raw', '@nikitajs/core/plugins/metadata/disabled'], + name: "@nikitajs/core/plugins/conditions", + require: [ + "@nikitajs/core/plugins/metadata/raw", + "@nikitajs/core/plugins/metadata/disabled", + ], hooks: { - 'nikita:normalize': { - handler: function(action, handler) { + "nikita:normalize": { + handler: function (action, handler) { // Ventilate conditions properties defined at root const conditions = {}; for (const property in action.metadata) { @@ -108,27 +108,27 @@ export default { delete action.metadata[property]; } } - return async function() { - action = (await handler.call(null, ...arguments)); + return async function () { + action = await handler.call(null, ...arguments); action.conditions = conditions; return action; }; - } + }, }, - 'nikita:action': { - before: '@nikitajs/core/plugins/metadata/disabled', - after: '@nikitajs/core/plugins/templated', - handler: async function(action) { + "nikita:action": { + before: "@nikitajs/core/plugins/metadata/disabled", + after: "@nikitajs/core/plugins/templated", + handler: async function (action) { for (const condition in action.conditions) { if (handlers[condition] == null) { continue; } - if (await handlers[condition].call(null, action) === false) { + if ((await handlers[condition].call(null, action)) === false) { action.metadata.disabled = true; break; } } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/conditions/execute.js b/packages/core/lib/plugins/conditions/execute.js index f74a4f0ac..50b31a0da 100644 --- a/packages/core/lib/plugins/conditions/execute.js +++ b/packages/core/lib/plugins/conditions/execute.js @@ -1,31 +1,37 @@ - -import session from '@nikitajs/core/session'; -import { is_object_literal } from 'mixme'; +import session from "@nikitajs/core/session"; +import { is_object_literal } from "mixme"; const handlers = { - if_execute: async function(action) { + if_execute: async function (action) { for (const condition of action.conditions.if_execute) { try { - const {$status} = await session({ - $bastard: true, - $namespace: ['execute'], - $parent: action, - ...(is_object_literal(condition) ? condition : {}), - }, is_object_literal(condition) ? null : condition); + const { $status } = await session( + { + $bastard: true, + $namespace: ["execute"], + $parent: action, + ...(is_object_literal(condition) ? condition : {}), + }, + is_object_literal(condition) ? null : condition, + ); if (!$status) { return false; } } catch (error) { - const {code} = await session({ - $bastard: true, - $namespace: ['execute'], - $parent: action, - ...(is_object_literal(condition) ? condition : {}), - }, is_object_literal(condition) ? null : condition, function({config}) { - return { - code: config.code - }; - }); + const { code } = await session( + { + $bastard: true, + $namespace: ["execute"], + $parent: action, + ...(is_object_literal(condition) ? condition : {}), + }, + is_object_literal(condition) ? null : condition, + function ({ config }) { + return { + code: config.code, + }; + }, + ); if (code.false.length && !code.false.includes(error.exit_code)) { // If `code.false` is present, // use it instead of error to disabled the action @@ -36,29 +42,36 @@ const handlers = { } return true; }, - unless_execute: async function(action) { + unless_execute: async function (action) { for (const condition of action.conditions.unless_execute) { try { - const {$status} = await session({ - $bastard: true, - $namespace: ['execute'], - $parent: action, - ...(is_object_literal(condition) ? condition : {}), - }, is_object_literal(condition) ? null : condition); + const { $status } = await session( + { + $bastard: true, + $namespace: ["execute"], + $parent: action, + ...(is_object_literal(condition) ? condition : {}), + }, + is_object_literal(condition) ? null : condition, + ); if ($status) { return false; } } catch (error) { - const {code} = await session({ - $bastard: true, - $namespace: ['execute'], - $parent: action, - ...(is_object_literal(condition) ? condition : {}), - }, is_object_literal(condition) ? null : condition, function({config}) { - return { - code: config.code - }; - }); + const { code } = await session( + { + $bastard: true, + $namespace: ["execute"], + $parent: action, + ...(is_object_literal(condition) ? condition : {}), + }, + is_object_literal(condition) ? null : condition, + function ({ config }) { + return { + code: config.code, + }; + }, + ); if (code.false.length && !code.false.includes(error.exit_code)) { // If `code.false` is present, // use it instead of error to to disabled the action @@ -67,26 +80,26 @@ const handlers = { } } return true; - } + }, }; export default { - name: '@nikitajs/core/plugins/conditions/execute', - require: ['@nikitajs/core/plugins/conditions'], + name: "@nikitajs/core/plugins/conditions/execute", + require: ["@nikitajs/core/plugins/conditions"], hooks: { - 'nikita:action': { - after: '@nikitajs/core/plugins/conditions', - before: '@nikitajs/core/plugins/metadata/disabled', - handler: async function(action) { + "nikita:action": { + after: "@nikitajs/core/plugins/conditions", + before: "@nikitajs/core/plugins/metadata/disabled", + handler: async function (action) { for (const condition in action.conditions) { if (handlers[condition] == null) { continue; } - if (await handlers[condition].call(null, action) === false) { + if ((await handlers[condition].call(null, action)) === false) { action.metadata.disabled = true; } } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/conditions/exists.js b/packages/core/lib/plugins/conditions/exists.js index 5f56211ab..85e4b083f 100644 --- a/packages/core/lib/plugins/conditions/exists.js +++ b/packages/core/lib/plugins/conditions/exists.js @@ -1,20 +1,22 @@ - -import session from '@nikitajs/core/session'; +import session from "@nikitajs/core/session"; const handlers = { - if_exists: async function(action, value) { + if_exists: async function (action) { for (const condition of action.conditions.if_exists) { try { - await session({ - $bastard: true, - $parent: action - }, async function() { - return await this.fs.stat({ - target: condition - }); - }); + await session( + { + $bastard: true, + $parent: action, + }, + async function () { + return await this.fs.stat({ + target: condition, + }); + }, + ); } catch (error) { - if (error.code === 'NIKITA_FS_STAT_TARGET_ENOENT') { + if (error.code === "NIKITA_FS_STAT_TARGET_ENOENT") { return false; } else { throw error; @@ -23,45 +25,48 @@ const handlers = { } return true; }, - unless_exists: async function(action) { + unless_exists: async function (action) { for (const condition of action.conditions.unless_exists) { try { - await session({ - $bastard: true, - $parent: action - }, async function() { - return await this.fs.stat({ - target: condition - }); - }); + await session( + { + $bastard: true, + $parent: action, + }, + async function () { + return await this.fs.stat({ + target: condition, + }); + }, + ); return false; } catch (error) { - if (error.code !== 'NIKITA_FS_STAT_TARGET_ENOENT') { + if (error.code !== "NIKITA_FS_STAT_TARGET_ENOENT") { throw error; } } } return true; - } + }, }; export default { - name: '@nikitajs/core/plugins/conditions/exists', - require: ['@nikitajs/core/plugins/conditions'], + name: "@nikitajs/core/plugins/conditions/exists", + require: ["@nikitajs/core/plugins/conditions"], hooks: { - 'nikita:action': { - after: '@nikitajs/core/plugins/conditions', - before: '@nikitajs/core/plugins/metadata/disabled', - handler: async function(action) { + "nikita:action": { + after: "@nikitajs/core/plugins/conditions", + before: "@nikitajs/core/plugins/metadata/disabled", + handler: async function (action) { for (const condition in action.conditions) { if (handlers[condition] == null) { continue; } - if (await handlers[condition].call(null, action) === false) { + if ((await handlers[condition].call(null, action)) === false) { action.metadata.disabled = true; } } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/conditions/os.js b/packages/core/lib/plugins/conditions/os.js index 215a75919..e8765525a 100644 --- a/packages/core/lib/plugins/conditions/os.js +++ b/packages/core/lib/plugins/conditions/os.js @@ -1,182 +1,220 @@ - -import session from '@nikitajs/core/session'; -import utils from '@nikitajs/core/utils'; +import session from "@nikitajs/core/session"; +import utils from "@nikitajs/core/utils"; const handlers = { - if_os: async function(action) { - return await session({ - $bastard: true, - $parent: action - }, async function() { - const { $status, stdout } = await this.execute(utils.os.command).catch( - (error) => { - if (error.exit_code === 2) { - throw utils.error("NIKITA_PLUGIN_OS_UNSUPPORTED_DISTRIB", [ - "your current distribution is not yet listed,", - "please report to us,", - `it name is ${JSON.stringify(error.stdout)}`, - ]); - } - throw error; + if_os: async function (action) { + return await session( + { + $bastard: true, + $parent: action, + }, + async function () { + const { $status, stdout } = await this.execute(utils.os.command).catch( + (error) => { + if (error.exit_code === 2) { + throw utils.error("NIKITA_PLUGIN_OS_UNSUPPORTED_DISTRIB", [ + "your current distribution is not yet listed,", + "please report to us,", + `it name is ${JSON.stringify(error.stdout)}`, + ]); + } + throw error; + }, + ); + if (!$status) { + return false; } - ); - if (!$status) { - return false; - } - let [arch, distribution, version, linux_version] = stdout.split('|'); - let match; - if (match = /^(\d+)\.(\d+)\.(\d+)/.exec(version)) { - // Note, CentOS 7 version currently return version "7.9.2009", transforming it to "5.19" - // means that the check runs agains "5.19.0" later on and may fail - // Remove patch version (eg. 7.8.12 -> 7.8) - // Instead, remove any information after the patch value - version = `${match[0]}`; - } - if (match = /^(\d+)\.(\d+)\.(\d+)/.exec(linux_version)) { - // Note, arch linux currently return the linux version "5.15.49", transforming it to "5.19" - // means that the check runs agains "5.19.0" later on and may fail - // linux_version = "#{match[0]}" if match = /^(\d+)\.(\d+)/.exec linux_version - // Instead, remove any information after the patch value - linux_version = `${match[0]}`; - } - match = action.conditions.if_os.some(function(condition) { - const a = !condition.arch.length || condition.arch.some(function(value) { - if (typeof value === 'string' && value === arch) { - // Uses `uname -m` internally. - // Node.js values: 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64' - // `uname` values: see https://en.wikipedia.org/wiki/Uname#Examples - return true; - } - if (value instanceof RegExp && value.test(arch)) { - return true; - } - }); - const n = !condition.distribution.length || condition.distribution.some(function(value) { - if (typeof value === 'string' && value === distribution) { - return true; - } - if (value instanceof RegExp && value.test(distribution)) { - return true; - } - }); - // Arch Linux has only linux_version - const v = !version.length || !condition.version.length || condition.version.some(function(value) { - version = utils.semver.sanitize(version, '0'); - if (typeof value === 'string' && utils.semver.satisfies(version, value)) { - return true; - } - if (value instanceof RegExp && value.test(version)) { - return true; - } - }); - const lv = !condition.linux_version.length || condition.linux_version.some(function(value) { - linux_version = utils.semver.sanitize(linux_version, '0'); - if (typeof value === 'string' && utils.semver.satisfies(linux_version, value)) { - return true; - } - if (value instanceof RegExp && value.test(linux_version)) { - return true; - } + let [arch, distribution, version, linux_version] = stdout.split("|"); + let match; + if ((match = /^(\d+)\.(\d+)\.(\d+)/.exec(version))) { + // Note, CentOS 7 version currently return version "7.9.2009", transforming it to "5.19" + // means that the check runs agains "5.19.0" later on and may fail + // Remove patch version (eg. 7.8.12 -> 7.8) + // Instead, remove any information after the patch value + version = `${match[0]}`; + } + if ((match = /^(\d+)\.(\d+)\.(\d+)/.exec(linux_version))) { + // Note, arch linux currently return the linux version "5.15.49", transforming it to "5.19" + // means that the check runs agains "5.19.0" later on and may fail + // linux_version = "#{match[0]}" if match = /^(\d+)\.(\d+)/.exec linux_version + // Instead, remove any information after the patch value + linux_version = `${match[0]}`; + } + match = action.conditions.if_os.some(function (condition) { + const a = + !condition.arch.length || + condition.arch.some(function (value) { + if (typeof value === "string" && value === arch) { + // Uses `uname -m` internally. + // Node.js values: 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64' + // `uname` values: see https://en.wikipedia.org/wiki/Uname#Examples + return true; + } + if (value instanceof RegExp && value.test(arch)) { + return true; + } + }); + const n = + !condition.distribution.length || + condition.distribution.some(function (value) { + if (typeof value === "string" && value === distribution) { + return true; + } + if (value instanceof RegExp && value.test(distribution)) { + return true; + } + }); + // Arch Linux has only linux_version + const v = + !version.length || + !condition.version.length || + condition.version.some(function (value) { + version = utils.semver.sanitize(version, "0"); + if ( + typeof value === "string" && + utils.semver.satisfies(version, value) + ) { + return true; + } + if (value instanceof RegExp && value.test(version)) { + return true; + } + }); + const lv = + !condition.linux_version.length || + condition.linux_version.some(function (value) { + linux_version = utils.semver.sanitize(linux_version, "0"); + if ( + typeof value === "string" && + utils.semver.satisfies(linux_version, value) + ) { + return true; + } + if (value instanceof RegExp && value.test(linux_version)) { + return true; + } + }); + return a && n && v && lv; }); - return a && n && v && lv; - }); - if (!match) { - return false; - } - }).then( ({$status}) => $status); + if (!match) { + return false; + } + }, + ).then(({ $status }) => $status); }, - unless_os: async function(action) { - return await session({ - $bastard: true, - $parent: action - }, async function() { - const { $status, stdout } = await this.execute(utils.os.command).catch( - (error) => { - if (error.exit_code === 2) { - throw utils.error("NIKITA_PLUGIN_OS_UNSUPPORTED_DISTRIB", [ - "your current distribution is not yet listed,", - "please report to us,", - `it name is ${JSON.stringify(error.stdout)}`, - ]); - } - throw error; + unless_os: async function (action) { + return await session( + { + $bastard: true, + $parent: action, + }, + async function () { + const { $status, stdout } = await this.execute(utils.os.command).catch( + (error) => { + if (error.exit_code === 2) { + throw utils.error("NIKITA_PLUGIN_OS_UNSUPPORTED_DISTRIB", [ + "your current distribution is not yet listed,", + "please report to us,", + `it name is ${JSON.stringify(error.stdout)}`, + ]); + } + throw error; + }, + ); + if (!$status) { + return false; + } + let match; + let [arch, distribution, version, linux_version] = stdout.split("|"); + if ((match = /^(\d+)\.(\d+)\.(\d+)/.exec(version))) { + // Note, CentOS 7 version currently return version "7.9.2009", transforming it to "5.19" + // means that the check runs agains "5.19.0" later on and may fail + // Remove patch version (eg. 7.8.12 -> 7.8) + // Instead, remove any information after the patch value + version = `${match[0]}`; } - ); - if (!$status) { - return false; - } - let match; - let [arch, distribution, version, linux_version] = stdout.split('|'); - if (match = /^(\d+)\.(\d+)\.(\d+)/.exec(version)) { - // Note, CentOS 7 version currently return version "7.9.2009", transforming it to "5.19" + // Note, arch linux currently return the linux version "5.15.49", transforming it to "5.19" // means that the check runs agains "5.19.0" later on and may fail - // Remove patch version (eg. 7.8.12 -> 7.8) + // linux_version = "#{match[0]}" if match = /^(\d+)\.(\d+)/.exec linux_version // Instead, remove any information after the patch value - version = `${match[0]}`; - } - // Note, arch linux currently return the linux version "5.15.49", transforming it to "5.19" - // means that the check runs agains "5.19.0" later on and may fail - // linux_version = "#{match[0]}" if match = /^(\d+)\.(\d+)/.exec linux_version - // Instead, remove any information after the patch value - match = action.conditions.unless_os.some(function(condition) { - const a = !condition.arch.length || condition.arch.some(function(value) { - if (typeof value === 'string' && value === arch) { - return true; - } - if (value instanceof RegExp && value.test(arch)) { - return true; - } - }); - const n = !condition.distribution.length || condition.distribution.some(function(value) { - if (typeof value === 'string' && value === distribution) { - return true; - } - if (value instanceof RegExp && value.test(distribution)) { - return true; - } - }); - // Arch Linux has only linux_version - const v = !version.length || !condition.version.length || condition.version.some(function(value) { - version = utils.semver.sanitize(version, '0'); - if (typeof value === 'string' && utils.semver.satisfies(version, value)) { - return true; - } - if (value instanceof RegExp && value.test(version)) { - return true; - } - }); - const lv = !condition.linux_version.length || condition.linux_version.some(function(value) { - linux_version = utils.semver.sanitize(linux_version, '0'); - if (typeof value === 'string' && utils.semver.satisfies(linux_version, value)) { - return true; - } - if (value instanceof RegExp && value.test(linux_version)) { - return true; - } + match = action.conditions.unless_os.some(function (condition) { + const a = + !condition.arch.length || + condition.arch.some(function (value) { + if (typeof value === "string" && value === arch) { + return true; + } + if (value instanceof RegExp && value.test(arch)) { + return true; + } + }); + const n = + !condition.distribution.length || + condition.distribution.some(function (value) { + if (typeof value === "string" && value === distribution) { + return true; + } + if (value instanceof RegExp && value.test(distribution)) { + return true; + } + }); + // Arch Linux has only linux_version + const v = + !version.length || + !condition.version.length || + condition.version.some(function (value) { + version = utils.semver.sanitize(version, "0"); + if ( + typeof value === "string" && + utils.semver.satisfies(version, value) + ) { + return true; + } + if (value instanceof RegExp && value.test(version)) { + return true; + } + }); + const lv = + !condition.linux_version.length || + condition.linux_version.some(function (value) { + linux_version = utils.semver.sanitize(linux_version, "0"); + if ( + typeof value === "string" && + utils.semver.satisfies(linux_version, value) + ) { + return true; + } + if (value instanceof RegExp && value.test(linux_version)) { + return true; + } + }); + return a && n && v && lv; }); - return a && n && v && lv; - }); - if (match) { - return false; - } - }).then( ({$status}) => $status); - } + if (match) { + return false; + } + }, + ).then(({ $status }) => $status); + }, }; export default { - name: '@nikitajs/core/plugins/conditions/os', - require: ['@nikitajs/core/plugins/conditions'], + name: "@nikitajs/core/plugins/conditions/os", + require: ["@nikitajs/core/plugins/conditions"], hooks: { - 'nikita:normalize': { - after: '@nikitajs/core/plugins/conditions', - handler: function(action, handler) { - return async function() { + "nikita:normalize": { + after: "@nikitajs/core/plugins/conditions", + handler: function (action, handler) { + return async function () { action = await handler.call(null, action); if (!action.conditions) { return; } // Normalize conditions - for (const config of [action.conditions.if_os, action.conditions.unless_os]) { + for (const config of [ + action.conditions.if_os, + action.conditions.unless_os, + ]) { if (!config) { continue; } @@ -199,33 +237,36 @@ export default { if (!Array.isArray(condition.version)) { condition.version = [condition.version]; } - condition.version = utils.semver.sanitize(condition.version, 'x'); + condition.version = utils.semver.sanitize(condition.version, "x"); if (condition.linux_version == null) { condition.linux_version = []; } if (!Array.isArray(condition.linux_version)) { condition.linux_version = [condition.linux_version]; } - condition.linux_version = utils.semver.sanitize(condition.linux_version, 'x'); + condition.linux_version = utils.semver.sanitize( + condition.linux_version, + "x", + ); } } return action; }; - } + }, }, - 'nikita:action': { - after: '@nikitajs/core/plugins/conditions', - before: '@nikitajs/core/plugins/metadata/disabled', - handler: async function(action) { + "nikita:action": { + after: "@nikitajs/core/plugins/conditions", + before: "@nikitajs/core/plugins/metadata/disabled", + handler: async function (action) { for (const condition in action.conditions) { if (handlers[condition] == null) { continue; } - if (await handlers[condition].call(null, action) === false) { + if ((await handlers[condition].call(null, action)) === false) { action.metadata.disabled = true; } } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/argument_to_config.js b/packages/core/lib/plugins/metadata/argument_to_config.js index a6d4da479..4ac601549 100644 --- a/packages/core/lib/plugins/metadata/argument_to_config.js +++ b/packages/core/lib/plugins/metadata/argument_to_config.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/metadata/argument_to_config` @@ -6,27 +5,34 @@ The `argument` plugin map an argument which is not an object into a configuratio */ // Dependencies -import {mutate} from 'mixme'; +import { mutate } from "mixme"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/argument_to_config', + name: "@nikitajs/core/plugins/metadata/argument_to_config", hooks: { - 'nikita:schema': function({schema}) { - mutate(schema.definitions.metadata.properties, { - argument_to_config: { - type: 'string', - description: `Maps the argument passed to the action to a configuration property.` - } - }); + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + argument_to_config: { + type: "string", + description: `Maps the argument passed to the action to a configuration property.`, + }, + }); + }, }, - 'nikita:action': { - before: ['@nikitajs/core/plugins/metadata/schema'], - handler: function(action) { - if (action.metadata.argument_to_config && action.config[action.metadata.argument_to_config] === undefined) { - action.config[action.metadata.argument_to_config] = action.metadata.argument; + "nikita:action": { + before: "@nikitajs/core/plugins/metadata/schema", + handler: function (action) { + if ( + action.metadata.argument_to_config && + action.config[action.metadata.argument_to_config] === undefined + ) { + action.config[action.metadata.argument_to_config] = + action.metadata.argument; } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/audit.js b/packages/core/lib/plugins/metadata/audit.js index 0307b5159..8f731ae87 100644 --- a/packages/core/lib/plugins/metadata/audit.js +++ b/packages/core/lib/plugins/metadata/audit.js @@ -1,9 +1,9 @@ /** * # Plugin `@nikitajs/core/plugins/metadata/debug` - * + * * Print the time execution of the child actions as well as various information in * a hierarchical tree. - * + * */ // Dependencies @@ -12,7 +12,7 @@ import dedent from "dedent"; import pad from "pad"; import chalk from "chalk"; import { mutate } from "mixme"; -import { string } from "@nikitajs/core/utils" +import { string } from "@nikitajs/core/utils"; // Utils const chars = { @@ -30,46 +30,42 @@ const print_branches = (record) => { branches.push(`${chars.vertical} `); } } - return branches.join(''); -} + return branches.join(""); +}; const print_leaf = (record, i) => { if (record.position.length === 0) return ""; - if ( record.index === 0 && i === 0 ) { - return chars.upper_left + chars.horizontal + " " + if (record.index === 0 && i === 0) { + return chars.upper_left + chars.horizontal + " "; } else if (i === 0) { - return chars.vertical_right + chars.horizontal + " " + return chars.vertical_right + chars.horizontal + " "; } else { return chars.vertical + " "; } -} +}; const print = (ws, record) => { const branches = print_branches(record); - const messages = Array.isArray(record.message) ? record.message : [record.message]; - for( let i = 0; i < messages.length; i++) { - const prefix = i === 0 ? pad(`[${record.prefix}]`, 9) : ' '.repeat(9); + const messages = + Array.isArray(record.message) ? record.message : [record.message]; + for (let i = 0; i < messages.length; i++) { + const prefix = i === 0 ? pad(`[${record.prefix}]`, 9) : " ".repeat(9); const leaf = print_leaf(record, i); const message = messages[i]; - const side = ws.isTTY - ? pad( + const side = + ws.isTTY ? + pad( ws.columns - prefix.length - branches.length - leaf.length - message.length, - record.side || " " + record.side || " ", ) : record.side && " " + record.side; - const out_raw = [ - prefix, - branches, - leaf, - message, - side, - ].join(""); + const out_raw = [prefix, branches, leaf, message, side].join(""); const out_color = record.color(out_raw); - ws.write(`${out_color}\n`) + ws.write(`${out_color}\n`); } -} +}; // Plugin export default { @@ -80,26 +76,29 @@ export default { "@nikitajs/core/plugins/tools/log", ], hooks: { - "nikita:schema": function ({ schema }) { - mutate(schema.definitions.metadata.properties, { - audit: { - oneOf: [ - { - type: "string", - enum: ["stdout", "stderr"], - }, - { - type: "boolean", - }, - { - instanceof: "stream.Writable", - }, - ], - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + audit: { + oneOf: [ + { + type: "string", + enum: ["stdout", "stderr"], + }, + { + type: "boolean", + }, + { + instanceof: "stream.Writable", + }, + ], + description: dedent` Print the time execution of the child actions. `, - }, - }); + }, + }); + }, }, "nikita:normalize": { // after: '@nikitajs/core/plugins/history', @@ -136,13 +135,10 @@ export default { // Print child actions let audit = metadata.audit; const ws = - audit === "stdout" - ? process.stdout - : audit === "stderr" - ? process.stderr - : audit instanceof stream.Writable - ? audit - : process.stderr; + audit === "stdout" ? process.stdout + : audit === "stderr" ? process.stderr + : audit instanceof stream.Writable ? audit + : process.stderr; audit = metadata.audit = { colors: { error: (out) => (ws.isTTY ? chalk.magenta(out) : out), @@ -157,7 +153,10 @@ export default { action: function ({ action, error }) { // Prevent parent to be undefined when an error incurred in a previous hook if (!action.parent) return; - const message = action.metadata.namespace?.join(".") || action.metadata.module || "nikita"; + const message = + action.metadata.namespace?.join(".") || + action.metadata.module || + "nikita"; const color = error ? audit.colors.error : audit.colors.info; action.parent.state.audit.index++; print( @@ -169,22 +168,19 @@ export default { index: action.parent.state.audit.index, position: action.parent.state.audit.position, side: string.print_time( - action.metadata.time_end - action.metadata.time_start + action.metadata.time_end - action.metadata.time_start, ), error: !!error, }, - action + action, ); }, log: function (log, action) { let message = - typeof log.message === "string" - ? log.message.trim() - : typeof log.message === "number" - ? log.message - : log.message?.toString != null - ? log.message.toString().trim() - : JSON.stringify(log.message); + typeof log.message === "string" ? log.message.trim() + : typeof log.message === "number" ? log.message + : log.message?.toString != null ? log.message.toString().trim() + : JSON.stringify(log.message); const color = (function () { switch (log.type) { case "stdin": @@ -243,20 +239,32 @@ export default { { color: error ? audit.colors.error : audit.colors.info, prefix: "ACTION", - message: action.metadata.namespace?.join(".") || action.metadata.module || "nikita", + message: + action.metadata.namespace?.join(".") || + action.metadata.module || + "nikita", index: action.metadata.index, position: [], side: string.print_time( - action.metadata.time_end - action.metadata.time_start + action.metadata.time_end - action.metadata.time_start, ), }, - action + action, + ); + action.tools.events.removeListener( + "nikita:action:end", + audit.listeners.action, + ); + action.tools.events.removeListener("text", audit.listeners.log); + action.tools.events.removeListener("stdin", audit.listeners.log); + action.tools.events.removeListener( + "stdout_stream", + audit.listeners.log, + ); + action.tools.events.removeListener( + "stderr_stream", + audit.listeners.log, ); - action.tools.events.removeListener("nikita:action:end", audit.listeners.action); - action.tools.events.removeListener('text', audit.listeners.log); - action.tools.events.removeListener('stdin', audit.listeners.log); - action.tools.events.removeListener('stdout_stream', audit.listeners.log); - action.tools.events.removeListener('stderr_stream', audit.listeners.log); }, }, }, diff --git a/packages/core/lib/plugins/metadata/debug.js b/packages/core/lib/plugins/metadata/debug.js index 704dd4f1d..13f390f73 100644 --- a/packages/core/lib/plugins/metadata/debug.js +++ b/packages/core/lib/plugins/metadata/debug.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/metadata/debug` @@ -10,102 +9,110 @@ TODO: detect/force isTTY */ // Dependencies -import stream from 'node:stream'; -import dedent from 'dedent'; -import {mutate} from 'mixme'; +import stream from "node:stream"; +import dedent from "dedent"; +import { mutate } from "mixme"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/debug', - require: '@nikitajs/core/plugins/tools/log', + name: "@nikitajs/core/plugins/metadata/debug", + require: "@nikitajs/core/plugins/tools/log", hooks: { - 'nikita:schema': function({schema}) { - mutate(schema.definitions.metadata.properties, { - debug: { - oneOf: [ - { - type: 'string', - enum: ['stdout', 'stderr'] - }, - { - type: 'boolean' - }, - { - instanceof: 'stream.Writable' - } - ], - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + debug: { + oneOf: [ + { + type: "string", + enum: ["stdout", "stderr"], + }, + { + type: "boolean", + }, + { + instanceof: "stream.Writable", + }, + ], + description: dedent` Print detailed information of an action and its children. It provides a quick and convenient solution to understand the various actions called, what they do, and in which order. - ` - } - }); + `, + }, + }); + }, }, - 'nikita:action': { - after: ['@nikitajs/core/plugins/metadata/schema'], - handler: function(action) { + "nikita:action": { + after: ["@nikitajs/core/plugins/metadata/schema"], + handler: function (action) { if (!action.metadata.debug) { return; } let debug = action.metadata.debug; debug = action.metadata.debug = { ws: - debug === 'stdout' - ? process.stdout - : debug === 'stderr' - ? process.stderr - : debug instanceof stream.Writable - ? debug + debug === "stdout" ? process.stdout + : debug === "stderr" ? process.stderr + : debug instanceof stream.Writable ? debug : process.stderr, - listener: function(log) { - if(['stdout_stream', 'stderr_stream'].includes(log.type) && log.message == null){ - return + listener: function (log) { + if ( + ["stdout_stream", "stderr_stream"].includes(log.type) && + log.message == null + ) { + return; } let msg = - typeof log.message === 'string' - ? log.message.trim() - : typeof log.message === 'number' - ? log.message - : log.message?.toString != null - ? log.message.toString().trim() + typeof log.message === "string" ? log.message.trim() + : typeof log.message === "number" ? log.message + : log.message?.toString != null ? log.message.toString().trim() : JSON.stringify(log.message); - const type = log.type.split('_')[0]; - const position = log.position.map((i) => i + 1).join('.'); - const name = log.namespace?.join('.') || log.module; - msg = ['[', type, ' ', position + ' ' + log.level, name ? ' ' + name : void 0, '] ', msg].join(''); - msg = (function() { + const type = log.type.split("_")[0]; + const position = log.position.map((i) => i + 1).join("."); + const name = log.namespace?.join(".") || log.module; + msg = [ + "[", + type, + " ", + position + " " + log.level, + name ? " " + name : void 0, + "] ", + msg, + ].join(""); + msg = (function () { switch (log.type) { - case 'stdin': + case "stdin": return `\x1b[33m${msg}\x1b[39m`; - case 'stdout_stream': + case "stdout_stream": return `\x1b[36m${msg}\x1b[39m`; - case 'stderr_stream': + case "stderr_stream": return `\x1b[35m${msg}\x1b[39m`; default: return `\x1b[32m${msg}\x1b[39m`; } })(); debug.ws.write(`${msg}\n`); - } + }, }; - action.tools.events.addListener('text', debug.listener); - action.tools.events.addListener('stdin', debug.listener); - action.tools.events.addListener('stdout_stream', debug.listener); - action.tools.events.addListener('stderr_stream', debug.listener); - } + action.tools.events.addListener("text", debug.listener); + action.tools.events.addListener("stdin", debug.listener); + action.tools.events.addListener("stdout_stream", debug.listener); + action.tools.events.addListener("stderr_stream", debug.listener); + }, }, - 'nikita:result': { - handler: function({action}) { + "nikita:result": { + handler: function ({ action }) { const debug = action.metadata.debug; if (!(debug && debug.listener)) { return; } - action.tools.events.removeListener('text', debug.listener); - action.tools.events.removeListener('stdin', debug.listener); - action.tools.events.removeListener('stdout_stream', debug.listener); - action.tools.events.removeListener('stderr_stream', debug.listener); - } - } - } + action.tools.events.removeListener("text", debug.listener); + action.tools.events.removeListener("stdin", debug.listener); + action.tools.events.removeListener("stdout_stream", debug.listener); + action.tools.events.removeListener("stderr_stream", debug.listener); + }, + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/disabled.js b/packages/core/lib/plugins/metadata/disabled.js index ea44b9ab2..d85609c0d 100644 --- a/packages/core/lib/plugins/metadata/disabled.js +++ b/packages/core/lib/plugins/metadata/disabled.js @@ -17,17 +17,20 @@ import { mutate } from "mixme"; export default { name: "@nikitajs/core/plugins/metadata/disabled", hooks: { - "nikita:schema": function ({ schema }) { - mutate(schema.definitions.metadata.properties, { - disabled: { - type: "boolean", - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + disabled: { + type: "boolean", + description: dedent` Disable the execution of the current action and consequently the execution of its child actions. `, - default: false, - }, - }); + default: false, + }, + }); + }, }, "nikita:action": function (action, handler) { if (action.metadata.disabled == null) { diff --git a/packages/core/lib/plugins/metadata/execute.js b/packages/core/lib/plugins/metadata/execute.js index 8a7df634c..af5fa00e6 100644 --- a/packages/core/lib/plugins/metadata/execute.js +++ b/packages/core/lib/plugins/metadata/execute.js @@ -14,13 +14,16 @@ export default { "@nikitajs/core/plugins/tools/walk", ], hooks: { - "nikita:schema": function ({ schema }) { - mutate(schema.definitions.metadata.properties, { - sudo: { - type: "boolean", - description: `Run the action with as the superuser.`, - }, - }); + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + sudo: { + type: "boolean", + description: `Run the action with as the superuser.`, + }, + }); + }, }, "nikita:action": { handler: async function ({ config, metadata, tools: { find, walk } }) { @@ -29,12 +32,12 @@ export default { } if (config.arch_chroot == null) { config.arch_chroot = await find( - ({ metadata }) => metadata.arch_chroot + ({ metadata }) => metadata.arch_chroot, ); } if (config.arch_chroot_rootdir == null) { config.arch_chroot_rootdir = await find( - ({ metadata }) => metadata.arch_chroot_rootdir + ({ metadata }) => metadata.arch_chroot_rootdir, ); } if (config.bash == null) { @@ -45,7 +48,7 @@ export default { } const env = merge( config.env, - ...(await walk(({ metadata }) => metadata.env)) + ...(await walk(({ metadata }) => metadata.env)), ); if (Object.keys(env).length) { config.env = env; diff --git a/packages/core/lib/plugins/metadata/header.js b/packages/core/lib/plugins/metadata/header.js index 551526fe0..85fa248b8 100644 --- a/packages/core/lib/plugins/metadata/header.js +++ b/packages/core/lib/plugins/metadata/header.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/metadata/header` @@ -6,24 +5,27 @@ The `header` plugin validate the metadata `header` property against the schema. */ // Dependencies -import {mutate} from 'mixme'; +import { mutate } from "mixme"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/header', + name: "@nikitajs/core/plugins/metadata/header", hooks: { - 'nikita:schema': function({schema}) { - mutate(schema.definitions.metadata.properties, { - header: { - // type: ['array', 'string'], - type: 'array', - items: { - type: ['string'] + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + header: { + // type: ['array', 'string'], + type: "array", + items: { + type: ["string"], + }, + coercion: true, + description: `Associate a title with the current action, eg used by log actions.`, }, - coercion: true, - description: `Associate a title with the current action, eg used by log actions.` - } - }); - } - } + }); + }, + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/position.js b/packages/core/lib/plugins/metadata/position.js index bda1c8661..dd045f6ad 100644 --- a/packages/core/lib/plugins/metadata/position.js +++ b/packages/core/lib/plugins/metadata/position.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/metadata/position` @@ -6,64 +5,72 @@ Insert the metadata properties `depth`, `index` and `position` to each action. */ // Dependencies -import dedent from 'dedent'; -import {mutate} from 'mixme'; -import utils from '@nikitajs/core/utils'; +import dedent from "dedent"; +import { mutate } from "mixme"; +import utils from "@nikitajs/core/utils"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/position', - require: [ - '@nikitajs/core/plugins/history' - ], + name: "@nikitajs/core/plugins/metadata/position", + require: ["@nikitajs/core/plugins/history"], hooks: { - 'nikita:schema': function({schema}) { - mutate(schema.definitions.metadata.properties, { - depth: { - type: 'integer', - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + depth: { + type: "integer", + description: dedent` Indicates the level number of the action in the Nikita session tree. `, - default: 0, - readOnly: true - }, - index: { - type: 'integer', - description: dedent` + default: 0, + readOnly: true, + }, + index: { + type: "integer", + description: dedent` Indicates the index of an action relative to its sibling actions in the Nikita session tree. `, - default: 0, - readOnly: true - }, - position: { - type: 'array', - items: { - type: 'integer' + default: 0, + readOnly: true, }, - description: dedent` + position: { + type: "array", + items: { + type: "integer", + }, + description: dedent` Indicates the position of the action relative to its parent and sibling action. It is unique to each action. `, - default: [0], - readOnly: true - } - }); + default: [0], + readOnly: true, + }, + }); + }, }, - 'nikita:normalize': { - after: '@nikitajs/core/plugins/history', - handler: function(action) { - action.metadata.depth = action.parent ? action.parent.metadata.depth + 1 : 0; + "nikita:normalize": { + after: "@nikitajs/core/plugins/history", + handler: function (action) { + action.metadata.depth = + action.parent ? action.parent.metadata.depth + 1 : 0; // plugins are not activated in the root session with {depth: 0} action.metadata.index = action.siblings ? action.siblings.length : 0; - action.metadata.position = action.parent ? action.parent.metadata.position.concat([action.metadata.index]) : [0]; - } + action.metadata.position = + action.parent ? + action.parent.metadata.position.concat([action.metadata.index]) + : [0]; + }, }, - 'nikita:action': function(action) { - if (typeof action.metadata.depth !== 'number') { - throw utils.error('METADATA_DEPTH_INVALID_VALUE', ["configuration `depth` expect an integer value,", `got ${JSON.stringify(action.metadata.depth)}.`]); + "nikita:action": function (action) { + if (typeof action.metadata.depth !== "number") { + throw utils.error("METADATA_DEPTH_INVALID_VALUE", [ + "configuration `depth` expect an integer value,", + `got ${JSON.stringify(action.metadata.depth)}.`, + ]); } - } - } + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/raw.js b/packages/core/lib/plugins/metadata/raw.js index 65e4a2442..4bb3fda09 100644 --- a/packages/core/lib/plugins/metadata/raw.js +++ b/packages/core/lib/plugins/metadata/raw.js @@ -12,17 +12,20 @@ import { mutate } from "mixme"; export default { name: "@nikitajs/core/plugins/metadata/raw", hooks: { - "nikita:schema": function ({ schema }) { - mutate(schema.definitions.metadata.properties, { - raw_output: { - type: "boolean", - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + raw_output: { + type: "boolean", + description: dedent` Indicates the position of the action relative to its parent and sibling action. It is unique to each action. `, - readOnly: true, - }, - }); + readOnly: true, + }, + }); + }, }, }, }; diff --git a/packages/core/lib/plugins/metadata/register.js b/packages/core/lib/plugins/metadata/register.js index b5d835563..e60079f59 100644 --- a/packages/core/lib/plugins/metadata/register.js +++ b/packages/core/lib/plugins/metadata/register.js @@ -1,21 +1,26 @@ -import utils from "@nikitajs/core/utils"; +// Dependencies +import dedent from "dedent"; +import { mutate } from "mixme"; export default { name: "@nikitajs/core/plugins/metadata/register", - "nikita:schema": function ({ schema }) { - mutate(schema.definitions.metadata.properties, { - register: { - type: "object", - description: dedent` + hooks: { + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + register: { + type: "object", + description: dedent` Register one of multiple actions into the current action registry. `, + }, + }); }, - }); - }, - hooks: { + }, "nikita:action": async function (action, handler) { if (action.metadata.register != null) { - await action.registry.register(action.metadata.register) + await action.registry.register(action.metadata.register); } return handler; }, diff --git a/packages/core/lib/plugins/metadata/retry.js b/packages/core/lib/plugins/metadata/retry.js index a1b9808d7..f2672e166 100644 --- a/packages/core/lib/plugins/metadata/retry.js +++ b/packages/core/lib/plugins/metadata/retry.js @@ -1,17 +1,16 @@ - /* # @nikitajs/core/plugins/metadata/retry Reschedule the execution of an action on error. */ -import {merge} from 'mixme'; -import utils from '@nikitajs/core/utils'; +import { merge } from "mixme"; +import utils from "@nikitajs/core/utils"; export default { - name: '@nikitajs/core/plugins/metadata/retry', + name: "@nikitajs/core/plugins/metadata/retry", hooks: { - 'nikita:action': function(action, handler) { + "nikita:action": function (action, handler) { if (action.metadata.attempt == null) { action.metadata.attempt = 0; } @@ -21,26 +20,38 @@ export default { if (action.metadata.sleep == null) { action.metadata.sleep = 3000; } - ['attempt', 'sleep', 'retry'].map(property => { - if (typeof action.metadata[property] === 'number') { + ["attempt", "sleep", "retry"].map((property) => { + if (typeof action.metadata[property] === "number") { if (action.metadata[property] < 0) { - throw utils.error(`METADATA_${property.toUpperCase()}_INVALID_RANGE`, [`configuration \`${property}\` expect a number above or equal to 0,`, `got ${action.metadata[property]}.`]); + throw utils.error( + `METADATA_${property.toUpperCase()}_INVALID_RANGE`, + [ + `configuration \`${property}\` expect a number above or equal to 0,`, + `got ${action.metadata[property]}.`, + ], + ); } - } else if (typeof action.metadata[property] !== 'boolean') { - throw utils.error(`METADATA_${property.toUpperCase()}_INVALID_VALUE`, [`configuration \`${property}\` expect a number or a boolean value,`, `got ${JSON.stringify(action.metadata[property])}.`]); + } else if (typeof action.metadata[property] !== "boolean") { + throw utils.error( + `METADATA_${property.toUpperCase()}_INVALID_VALUE`, + [ + `configuration \`${property}\` expect a number or a boolean value,`, + `got ${JSON.stringify(action.metadata[property])}.`, + ], + ); } - }) - return function(action) { - const {retry} = action.metadata; + }); + return function (action) { + const { retry } = action.metadata; const config = merge({}, action.config); // Handle error - const failure = async function(error) { + const failure = async function (error) { if (retry !== true && action.metadata.attempt >= retry - 1) { throw error; } // Sleep if (action.metadata.sleep) { - await new Promise(function(resolve) { + await new Promise(function (resolve) { setTimeout(resolve, action.metadata.sleep); }); } @@ -50,15 +61,15 @@ export default { // Reschedule return run(); }; - const run = async function() { + const run = async function () { try { - return (await handler.call(null, action)); + return await handler.call(null, action); } catch (error) { return failure(error); } }; return run(); }; - } - } + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/schema.js b/packages/core/lib/plugins/metadata/schema.js index 6d88e0f59..3ff5db74a 100644 --- a/packages/core/lib/plugins/metadata/schema.js +++ b/packages/core/lib/plugins/metadata/schema.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/metadata/schema` @@ -8,33 +7,34 @@ object. */ // Dependencies -import dedent from 'dedent'; -import {mutate} from 'mixme'; +import dedent from "dedent"; +import { mutate } from "mixme"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/schema', - require: [ - '@nikitajs/core/plugins/tools/schema' - ], + name: "@nikitajs/core/plugins/metadata/schema", + require: ["@nikitajs/core/plugins/tools/schema"], hooks: { - 'nikita:schema': function({schema}) { - mutate(schema.definitions.metadata.properties, { - definitions: { - type: 'object', - description: dedent` + "nikita:schema": { + before: "@nikitajs/core/plugins/tools/schema", + handler: function ({ schema }) { + mutate(schema.definitions.metadata.properties, { + definitions: { + type: "object", + description: dedent` Schema definition or \`false\` to disable schema validation in the current action. - ` - } - }); + `, + }, + }); + }, }, - 'nikita:action': { + "nikita:action": { after: [ - '@nikitajs/core/plugins/global', - '@nikitajs/core/plugins/metadata/disabled', + "@nikitajs/core/plugins/global", + "@nikitajs/core/plugins/metadata/disabled", ], - handler: async function(action) { + handler: async function (action) { if (action.metadata.schema === false) { return; } @@ -42,7 +42,7 @@ export default { if (error) { throw error; } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/metadata/tmpdir.js b/packages/core/lib/plugins/metadata/tmpdir.js index be465488f..ee22f67eb 100644 --- a/packages/core/lib/plugins/metadata/tmpdir.js +++ b/packages/core/lib/plugins/metadata/tmpdir.js @@ -11,18 +11,20 @@ export default { "@nikitajs/core/plugins/tools/path", ], hooks: { - // 'nikita:schema': ({schema}) -> - // mutate schema.definitions.metadata.properties, - // tmpdir: - // oneOf: [ - // type: ['boolean', 'string'] - // , - // typeof: 'function' - // ] - // description: ''' - // Creates a temporary directory for the duration of the action - // execution. - // ''' + // 'nikita:schema': + // before: "@nikitajs/core/plugins/tools/schema", + // handler: ({schema}) -> + // mutate schema.definitions.metadata.properties, + // tmpdir: + // oneOf: [ + // type: ['boolean', 'string'] + // , + // typeof: 'function' + // ] + // description: ''' + // Creates a temporary directory for the duration of the action + // execution. + // ''' "nikita:action": { before: ["@nikitajs/core/plugins/templated"], after: [ @@ -37,7 +39,7 @@ export default { const { config, metadata, tools } = action; if ( !["boolean", "function", "string", "undefined"].includes( - typeof metadata.tmpdir + typeof metadata.tmpdir, ) && !is_object_literal(metadata.tmpdir) ) { @@ -53,9 +55,9 @@ export default { } // SSH connection extraction const ssh = - config.ssh === false - ? undefined - : await tools.find((action) => action.ssh); + config.ssh === false ? + undefined + : await tools.find((action) => action.ssh); // Sudo extraction const sudo = await tools.find(({ metadata }) => metadata.sudo); // Generate temporary location @@ -66,7 +68,7 @@ export default { ssh_hash: ssh_hash, sudo: sudo, uuid: metadata.uuid, - }) + }), ); const tmpdir_info = await (async function () { switch (typeof metadata.tmpdir) { @@ -156,16 +158,16 @@ export default { } // SSH connection extraction const ssh = - config.ssh === false - ? undefined - : await tools.find(action, (action) => action.ssh); + config.ssh === false ? + undefined + : await tools.find(action, (action) => action.ssh); // Temporary directory decommissioning await exec( ssh, [ metadata.tmpdir_info.sudo ? "sudo" : undefined, `rm -r '${metadata.tmpdir}'`, - ].join(" ") + ].join(" "), ); }, }, diff --git a/packages/core/lib/plugins/metadata/uuid.js b/packages/core/lib/plugins/metadata/uuid.js index 770239814..4cfc02e1c 100644 --- a/packages/core/lib/plugins/metadata/uuid.js +++ b/packages/core/lib/plugins/metadata/uuid.js @@ -1,4 +1,3 @@ - /* # Plugin '@nikitajs/core/plugins/metadata/uuid' @@ -6,20 +5,20 @@ Identify each action with a unique identifier. */ // Dependencies -import {v4 as uuid} from 'uuid'; +import { v4 as uuid } from "uuid"; // Plugin export default { - name: '@nikitajs/core/plugins/metadata/uuid', + name: "@nikitajs/core/plugins/metadata/uuid", hooks: { - 'nikita:action': { - handler: function(action) { + "nikita:action": { + handler: function (action) { if (action.metadata.depth === 0) { action.metadata.uuid = uuid(); } else { action.metadata.uuid = action.parent.metadata.uuid; } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/output/logs.js b/packages/core/lib/plugins/output/logs.js index 425301313..57fbc9ef7 100644 --- a/packages/core/lib/plugins/output/logs.js +++ b/packages/core/lib/plugins/output/logs.js @@ -4,24 +4,24 @@ Return events emitted inside the action. */ -import {is_object_literal} from 'mixme'; -import stackTrace from 'stack-trace'; -import path from 'node:path'; +import { is_object_literal } from "mixme"; +import stackTrace from "stack-trace"; +import path from "node:path"; export default { - name: '@nikitajs/core/plugins/output/logs', + name: "@nikitajs/core/plugins/output/logs", require: [ - '@nikitajs/core/plugins/tools/log', - '@nikitajs/core/plugins/output/status', - '@nikitajs/core/plugins/metadata/raw' + "@nikitajs/core/plugins/tools/log", + "@nikitajs/core/plugins/output/status", + "@nikitajs/core/plugins/metadata/raw", ], hooks: { - 'nikita:action': { - after: '@nikitajs/core/plugins/tools/log', - handler: function(action) { + "nikita:action": { + after: "@nikitajs/core/plugins/tools/log", + handler: function (action) { action.state.logs = []; - action.tools.log = (function(fn) { - return function(...info) { + action.tools.log = (function (fn) { + return function (...info) { const log = fn.call(null, ...info); if (!is_object_literal(log)) { // Note, log is undefined if `metadata.log` is `false` @@ -38,17 +38,17 @@ export default { return log; }; })(action.tools.log); - } + }, }, - 'nikita:result': { - after: '@nikitajs/core/plugins/output/status', - handler: function({action, output}, handler) { + "nikita:result": { + after: "@nikitajs/core/plugins/output/status", + handler: function ({ action, output }, handler) { if (action.metadata.raw_output) { return handler; } - return async function({action}) { + return async function ({ action }) { try { - output = (await handler.apply(null, arguments)); + output = await handler.apply(null, arguments); if (is_object_literal(output)) { output.$logs = action.state.logs; } @@ -58,7 +58,7 @@ export default { throw error; } }; - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/output/status.js b/packages/core/lib/plugins/output/status.js index 1970a54ce..983c7d272 100644 --- a/packages/core/lib/plugins/output/status.js +++ b/packages/core/lib/plugins/output/status.js @@ -1,24 +1,24 @@ - -import {is_object, is_object_literal} from 'mixme'; -import utils from '@nikitajs/core/utils'; +import { is_object, is_object_literal } from "mixme"; +import utils from "@nikitajs/core/utils"; export default { - name: '@nikitajs/core/plugins/output/status', - require: ['@nikitajs/core/plugins/history'], + name: "@nikitajs/core/plugins/output/status", + require: ["@nikitajs/core/plugins/history"], recommand: [ // Status is set to `false` when action is disabled - '@nikitajs/core/plugins/metadata/disabled', + "@nikitajs/core/plugins/metadata/disabled", // Honors raw_output if present - '@nikitajs/core/plugins/metadata/raw' + "@nikitajs/core/plugins/metadata/raw", ], hooks: { - 'nikita:normalize': function(action) { - action.tools ??= {} - action.tools.status = function(index) { + "nikita:normalize": function (action) { + action.tools ??= {}; + action.tools.status = function (index) { if (arguments.length === 0) { - return action.children.some((sibling) => - !sibling.metadata.shy && sibling.output?.$status === true - ) + return action.children.some( + (sibling) => + !sibling.metadata.shy && sibling.output?.$status === true, + ); } else { const l = action.children.length; const i = index < 0 ? l + index : index; @@ -30,22 +30,22 @@ export default { } }; }, - 'nikita:result': { - before: '@nikitajs/core/plugins/history', - handler: function({action, error, output}) { + "nikita:result": { + before: "@nikitajs/core/plugins/history", + handler: function ({ action, error, output }) { // Honors the disabled plugin, status is `false` // when the action is disabled if (action.metadata.disabled) { arguments[0].output = { - $status: false + $status: false, }; return; } - const inherit = function(output) { + const inherit = function (output) { if (output == null) { output = {}; } - output.$status = action.children.some(function(child) { + output.$status = action.children.some(function (child) { if (child.metadata.shy) { return false; } @@ -54,13 +54,13 @@ export default { return output; }; if (!error && !action.metadata.raw_output) { - return arguments[0].output = (function() { - if (typeof output === 'boolean') { + return (arguments[0].output = (function () { + if (typeof output === "boolean") { return { - $status: output + $status: output, }; } else if (is_object_literal(output)) { - if (output.hasOwnProperty('$status')) { + if (Object.prototype.hasOwnProperty.call(output, "$status")) { output.$status = !!output.$status; return output; } else { @@ -72,14 +72,22 @@ export default { return inherit(output); } else if (is_object(output)) { return output; - } else if (Array.isArray(output) || (typeof output === 'string' || typeof output === 'number')) { + } else if ( + Array.isArray(output) || + typeof output === "string" || + typeof output === "number" + ) { return output; } else { - throw utils.error('HANDLER_INVALID_OUTPUT', ['expect a boolean or an object or nothing', 'unless the `raw_output` configuration is activated,', `got ${JSON.stringify(output)}`]); + throw utils.error("HANDLER_INVALID_OUTPUT", [ + "expect a boolean or an object or nothing", + "unless the `raw_output` configuration is activated,", + `got ${JSON.stringify(output)}`, + ]); } - })(); + })()); } - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/pubsub/engines/memory.js b/packages/core/lib/plugins/pubsub/engines/memory.js index 89786abcb..a14ee5c95 100644 --- a/packages/core/lib/plugins/pubsub/engines/memory.js +++ b/packages/core/lib/plugins/pubsub/engines/memory.js @@ -3,10 +3,10 @@ Default in-memory engine implementation. */ // Plugin -export default function() { +export default function () { const store = {}; return { - set: function(key, value) { + set: function (key, value) { if (store[key] == null) { store[key] = {}; } @@ -14,12 +14,13 @@ export default function() { if (store[key].promises == null) { store[key].promises = []; } - let promise; while (promise = store[key].promises.shift()) { + let promise; + while ((promise = store[key].promises.shift())) { promise.call(null, store[key].value); } }, - get: function(key) { - return new Promise(function(resolve) { + get: function (key) { + return new Promise(function (resolve) { if (store[key]?.value) { resolve(store[key].value); } else { @@ -32,6 +33,6 @@ export default function() { store[key].promises.push(resolve); } }); - } + }, }; -}; +} diff --git a/packages/core/lib/plugins/pubsub/index.js b/packages/core/lib/plugins/pubsub/index.js index 300cbc19c..79d25b648 100644 --- a/packages/core/lib/plugins/pubsub/index.js +++ b/packages/core/lib/plugins/pubsub/index.js @@ -1,4 +1,3 @@ - /* Plugin `@nikitajs/core/plugins/pubsub` @@ -7,24 +6,22 @@ continuing their execution. */ export default { - name: '@nikitajs/core/plugins/pubsub', - require: '@nikitajs/core/plugins/tools/find', + name: "@nikitajs/core/plugins/pubsub", + require: "@nikitajs/core/plugins/tools/find", hooks: { - 'nikita:action': async function(action) { - const engine = await action.tools.find( - ({metadata}) => metadata.pubsub - ); + "nikita:action": async function (action) { + const engine = await action.tools.find(({ metadata }) => metadata.pubsub); if (!engine) { return action; } action.tools.pubsub = { - get: function(key) { + get: function (key) { return engine.get(key); }, - set: function(key, value) { + set: function (key, value) { return engine.set(key, value); - } + }, }; - } - } + }, + }, }; diff --git a/packages/core/lib/plugins/templated.js b/packages/core/lib/plugins/templated.js index 4384c1da6..a8107b1fb 100644 --- a/packages/core/lib/plugins/templated.js +++ b/packages/core/lib/plugins/templated.js @@ -15,7 +15,7 @@ export default { before: ["@nikitajs/core/plugins/metadata/schema"], handler: async function (action) { const templated = await action.tools.find( - (action) => action.metadata.templated + (action) => action.metadata.templated, ); if (templated !== true) { return; diff --git a/packages/core/lib/plugins/tools/dig.js b/packages/core/lib/plugins/tools/dig.js index eaab535b0..05d8a22f3 100644 --- a/packages/core/lib/plugins/tools/dig.js +++ b/packages/core/lib/plugins/tools/dig.js @@ -16,11 +16,11 @@ import utils from "@nikitajs/core/utils"; const dig_down = async function (action, digger) { const results = []; await each(action.children.reverse(), async (child) => - results.push(...(await dig_down(child, digger))) + results.push(...(await dig_down(child, digger))), ); if (action.siblings) { await each(action.siblings.reverse(), async (sibling) => - results.push(...(await dig_down(sibling, digger))) + results.push(...(await dig_down(sibling, digger))), ); } const precious = await digger(action); @@ -38,7 +38,7 @@ const dig_up = async function (action, digger) { } if (action.siblings) { await each(action.siblings.reverse(), async (sibling) => - results.push(...(await dig_down(sibling, digger))) + results.push(...(await dig_down(sibling, digger))), ); } if (action.parent) { diff --git a/packages/core/lib/plugins/tools/events.js b/packages/core/lib/plugins/tools/events.js index 351dabc9d..17e731fa7 100644 --- a/packages/core/lib/plugins/tools/events.js +++ b/packages/core/lib/plugins/tools/events.js @@ -13,9 +13,8 @@ export default { if (action.tools == null) { action.tools = {}; } - action.tools.events = action.parent - ? action.parent.tools.events - : new EventEmitter(); + action.tools.events = + action.parent ? action.parent.tools.events : new EventEmitter(); }, "nikita:action": function (action) { action.tools.events.emit("nikita:action:start", { @@ -59,7 +58,7 @@ export default { action.tools.events.emit("nikita:rejected", { action: action, error: error, - event: "nikita:rejected" + event: "nikita:rejected", }); }, }, diff --git a/packages/core/lib/plugins/tools/find.js b/packages/core/lib/plugins/tools/find.js index d91dcab40..058a7164b 100644 --- a/packages/core/lib/plugins/tools/find.js +++ b/packages/core/lib/plugins/tools/find.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/tools/find` @@ -7,9 +6,9 @@ stop if the user function return anything else than `undefined`, including `null` or `false`. */ -import utils from '@nikitajs/core/utils'; +import utils from "@nikitajs/core/utils"; -const find = async function(action, finder) { +const find = async function (action, finder) { const precious = await finder(action, finder); if (precious !== undefined) { return precious; @@ -20,7 +19,7 @@ const find = async function(action, finder) { return find(action.parent, finder); }; -const validate = function(action, args) { +const validate = function (action, args) { let finder; if (args.length === 1) { [finder] = args; @@ -28,40 +27,40 @@ const validate = function(action, args) { [action, finder] = args; } else { if (!action) { - throw utils.error('TOOLS_FIND_INVALID_ARGUMENT', [ - 'action signature is expected to be', - '`finder` or `action, finder`', - `got ${JSON.stringify(args)}` + throw utils.error("TOOLS_FIND_INVALID_ARGUMENT", [ + "action signature is expected to be", + "`finder` or `action, finder`", + `got ${JSON.stringify(args)}`, ]); } } if (!action) { - throw utils.error('TOOLS_FIND_ACTION_FINDER_REQUIRED', [ - 'argument `action` is missing and must be a valid action' + throw utils.error("TOOLS_FIND_ACTION_FINDER_REQUIRED", [ + "argument `action` is missing and must be a valid action", ]); } if (!finder) { - throw utils.error('TOOLS_FIND_FINDER_REQUIRED', [ - 'argument `finder` is missing and must be a function' + throw utils.error("TOOLS_FIND_FINDER_REQUIRED", [ + "argument `finder` is missing and must be a function", ]); } - if (typeof finder !== 'function') { - throw utils.error('TOOLS_FIND_FINDER_INVALID', [ - 'argument `finder` is missing and must be a function' + if (typeof finder !== "function") { + throw utils.error("TOOLS_FIND_FINDER_INVALID", [ + "argument `finder` is missing and must be a function", ]); } return [action, finder]; }; export default { - name: '@nikitajs/core/plugins/tools/find', + name: "@nikitajs/core/plugins/tools/find", hooks: { - 'nikita:normalize': function(action) { + "nikita:normalize": function (action) { action.tools ??= {}; - action.tools.find = async function() { + action.tools.find = async function () { const [act, finder] = validate(action, arguments); return await find(act, finder); }; }, - } + }, }; diff --git a/packages/core/lib/plugins/tools/log.js b/packages/core/lib/plugins/tools/log.js index 516ecc38a..18a776df7 100644 --- a/packages/core/lib/plugins/tools/log.js +++ b/packages/core/lib/plugins/tools/log.js @@ -1,4 +1,3 @@ - /* # Plugin `@nikitajs/core/plugins/tools/log` @@ -10,68 +9,71 @@ time the `log` function is called with the `log`, `config` and `metadata` argume */ -import path from 'node:path'; -import stackTrace from 'stack-trace'; -import {is_object_literal, mutate} from 'mixme'; -import utils from '@nikitajs/core/utils'; +import path from "node:path"; +import stackTrace from "stack-trace"; +import { is_object_literal, mutate } from "mixme"; +import utils from "@nikitajs/core/utils"; export default { - name: '@nikitajs/core/plugins/tools/log', + name: "@nikitajs/core/plugins/tools/log", require: [ - '@nikitajs/core/plugins/tools/events', - '@nikitajs/core/plugins/tools/find' + "@nikitajs/core/plugins/tools/events", + "@nikitajs/core/plugins/tools/find", ], hooks: { - 'nikita:normalize': function(action) { + "nikita:normalize": function (action) { if (action.metadata.log == null && action.parent?.metadata?.log != null) { action.metadata.log = action.parent.metadata.log; } }, - 'nikita:action': { - after: ['@nikitajs/core/plugins/tools/events', '@nikitajs/core/plugins/metadata/debug'], - handler: async function(action) { - const debug = await action.tools.find(function(action) { + "nikita:action": { + after: [ + "@nikitajs/core/plugins/tools/events", + "@nikitajs/core/plugins/metadata/debug", + ], + handler: async function (action) { + const debug = await action.tools.find(function (action) { return action.metadata.debug; }); - action.tools.log = function(...args) { - const log = {} + action.tools.log = function (...args) { + const log = {}; let indexMessage = -1; let indexLevel = -1; - for(const i in args) { + for (const i in args) { const arg = args[i]; if (is_object_literal(arg)) { - continue - } else if (typeof arg !== 'string') { - throw utils.error('TOOLS_LOGS_INVALID_ARGUMENT', [ - '`tools.log` accept string and object arguments,', + continue; + } else if (typeof arg !== "string") { + throw utils.error("TOOLS_LOGS_INVALID_ARGUMENT", [ + "`tools.log` accept string and object arguments,", `got ${JSON.stringify(arg)}.`, ]); } if (indexMessage === -1 && indexLevel === -1) { indexMessage = i; - args[i] = {message: arg} + args[i] = { message: arg }; } else if (indexMessage !== -1 && indexLevel === -1) { - log.level = log.message - log.message = arg - args[indexMessage] = {level: args[indexMessage].message} - args[i] = {message: arg} + log.level = log.message; + log.message = arg; + args[indexMessage] = { level: args[indexMessage].message }; + args[i] = { message: arg }; indexLevel = indexMessage; indexMessage = i; } else { - throw utils.error('TOOLS_LOGS_INVALID_STRING_ARGUMENT', [ - '`tools.log` accept only 2 strings, a level and a message,', - 'additionnal string arguments are not supported,', - `got ${JSON.stringify(arg)}.` + throw utils.error("TOOLS_LOGS_INVALID_STRING_ARGUMENT", [ + "`tools.log` accept only 2 strings, a level and a message,", + "additionnal string arguments are not supported,", + `got ${JSON.stringify(arg)}.`, ]); } } - mutate(log, ...args) - log.level ??= 'INFO'; + mutate(log, ...args); + log.level ??= "INFO"; log.time ??= Date.now(); log.index ??= action.metadata.index; log.module ??= action.metadata.module; log.namespace ??= action.metadata.namespace; - log.type ??= 'text'; + log.type ??= "text"; log.depth = action.metadata.depth; log.index = action.metadata.index; log.position = action.metadata.position; @@ -79,23 +81,23 @@ export default { log.filename = frame.getFileName(); log.file = path.basename(frame.getFileName()); log.line = frame.getLineNumber(); - if (typeof action.metadata.log === 'function') { + if (typeof action.metadata.log === "function") { if (action.metadata != null) { action.metadata.log({ log: log, config: action.config, - metadata: action.metadata + metadata: action.metadata, }); } } else { - if (!debug && action.metadata?.log === false) { + if (!debug && action.metadata?.log === false) { return; } } action.tools.events.emit(log.type, log, action); return log; }; - } - } - } + }, + }, + }, }; diff --git a/packages/core/lib/plugins/tools/path.js b/packages/core/lib/plugins/tools/path.js index fdd0f3b20..374e890b2 100644 --- a/packages/core/lib/plugins/tools/path.js +++ b/packages/core/lib/plugins/tools/path.js @@ -16,9 +16,10 @@ export default { action.tools ??= {}; // Path is alwaws posix over ssh // otherwise it is platform dependent - action.tools.path = !action.ssh - ? os.platform === "win32" - ? path.win32 + action.tools.path = + !action.ssh ? + os.platform === "win32" ? + path.win32 : path.posix : path.posix; // Local is agnostic of ssh diff --git a/packages/core/lib/plugins/tools/schema.js b/packages/core/lib/plugins/tools/schema.js index fd1344cc3..1b954c89b 100644 --- a/packages/core/lib/plugins/tools/schema.js +++ b/packages/core/lib/plugins/tools/schema.js @@ -12,9 +12,9 @@ import ajv_keywords from "ajv-keywords"; import ajv_formats from "ajv-formats"; import utils from "@nikitajs/core/utils"; import instanceofDef from "ajv-keywords/dist/definitions/instanceof.js"; -import cast_code from '@nikitajs/core/plugins/tools/schema.keyword.cast_code'; -import coercion from '@nikitajs/core/plugins/tools/schema.keyword.coercion'; -import filemode from '@nikitajs/core/plugins/tools/schema.keyword.filemode'; +import cast_code from "@nikitajs/core/plugins/tools/schema.keyword.cast_code"; +import coercion from "@nikitajs/core/plugins/tools/schema.keyword.coercion"; +import filemode from "@nikitajs/core/plugins/tools/schema.keyword.filemode"; instanceofDef.CONSTRUCTORS["Error"] = Error; instanceofDef.CONSTRUCTORS["stream.Writable"] = stream.Writable; @@ -56,58 +56,41 @@ export default { strict: true, strictRequired: false, // see https://github.com/ajv-validator/ajv/issues/1571 // coerceTypes: 'array', - loadSchema: (uri) => - new Promise(async function (accept, reject) { - let pathname, protocol; + loadSchema: async (uri) => { + const { protocol, pathname } = parse(uri); + if (protocol === "module:") { try { - ({ protocol, pathname } = parse(uri)); + const act = (await import(pathname)).default; + return { + definitions: act.metadata.definitions, + }; } catch (error) { - return reject(error); + throw utils.error("NIKITA_SCHEMA_INVALID_MODULE", [ + "the module location is not resolvable,", + `module name is ${JSON.stringify(pathname)},`, + `error message is ${JSON.stringify(error.message)}.`, + ]); } - switch (protocol) { - case "module:": - try { - const act = (await import(pathname)).default; - return accept({ - definitions: act.metadata.definitions, - }); - } catch (error) { - return reject( - utils.error("NIKITA_SCHEMA_INVALID_MODULE", [ - "the module location is not resolvable,", - `module name is ${JSON.stringify(pathname)},`, - `error message is ${JSON.stringify(error.message)}.`, - ]) - ); - } - break; - case "registry:": - const module = pathname.split("/"); - const act = await action.registry.get(module); - if (act) { - return accept({ - definitions: act.metadata.definitions, - }); - } else { - return reject( - utils.error("NIKITA_SCHEMA_UNREGISTERED_ACTION", [ - "the action is not registered inside the Nikita registry,", - `action namespace is ${JSON.stringify( - module.join(".") - )}.`, - ]) - ); - } - break; - default: - return reject( - utils.error("NIKITA_SCHEMA_UNSUPPORTED_PROTOCOL", [ - "the $ref instruction reference an unsupported protocol,", - `got ${JSON.stringify(protocol)}.`, - ]) - ); + } else if (protocol === "registry:") { + const module = pathname.split("/"); + const act = await action.registry.get(module); + if (act) { + return { + definitions: act.metadata.definitions, + }; + } else { + throw utils.error("NIKITA_SCHEMA_UNREGISTERED_ACTION", [ + "the action is not registered inside the Nikita registry,", + `action namespace is ${JSON.stringify(module.join("."))}.`, + ]); } - }), + } else { + throw utils.error("NIKITA_SCHEMA_UNSUPPORTED_PROTOCOL", [ + "the $ref instruction reference an unsupported protocol,", + `got ${JSON.stringify(protocol)}.`, + ]); + } + }, }); ajv_keywords(ajv); ajv_formats(ajv); @@ -148,8 +131,9 @@ export default { // definitions: {config: {}, ...definitions}, type: "object", properties: { - config: definitions?.config - ? { + config: + definitions?.config ? + { type: "object", // additionalProperties: false, unevaluatedProperties: false, @@ -168,16 +152,18 @@ export default { "NIKITA_SCHEMA_INVALID_DEFINITION", [ "schema failed to compile in ", - action.metadata.namespace.length - ? `action \`${action.metadata.namespace.join(".")}\`` - : "root action", - action.metadata.namespace.join(".") === "call" && - action.metadata.module !== "@nikitajs/core/actions/call" - ? ` in module ${action.metadata.module}` - : undefined, + action.metadata.namespace.length ? + `action \`${action.metadata.namespace.join(".")}\`` + : "root action", + ( + action.metadata.namespace.join(".") === "call" && + action.metadata.module !== "@nikitajs/core/actions/call" + ) ? + ` in module ${action.metadata.module}` + : undefined, ", ", error.message, - ].join("") + "." + ].join("") + ".", ); } else { return error; @@ -189,16 +175,18 @@ export default { return utils.error( "NIKITA_SCHEMA_VALIDATION_CONFIG", [ - validate.errors.length === 1 - ? "one error was found in the configuration of " - : "multiple errors were found in the configuration of ", - action.metadata.namespace.length - ? `action \`${action.metadata.namespace.join(".")}\`` - : "root action", - action.metadata.namespace.join(".") === "call" && - action.metadata.module !== "@nikitajs/core/actions/call" - ? ` in module ${action.metadata.module}` - : undefined, + validate.errors.length === 1 ? + "one error was found in the configuration of " + : "multiple errors were found in the configuration of ", + action.metadata.namespace.length ? + `action \`${action.metadata.namespace.join(".")}\`` + : "root action", + ( + action.metadata.namespace.join(".") === "call" && + action.metadata.module !== "@nikitajs/core/actions/call" + ) ? + ` in module ${action.metadata.module}` + : undefined, ":", validate.errors .map((err) => { @@ -215,7 +203,7 @@ export default { }) .sort() .join(";"), - ].join("") + "." + ].join("") + ".", ); }, }; diff --git a/packages/core/lib/plugins/tools/schema.keyword.coercion.js b/packages/core/lib/plugins/tools/schema.keyword.coercion.js index 2fdd56877..9ac2bb2e4 100644 --- a/packages/core/lib/plugins/tools/schema.keyword.coercion.js +++ b/packages/core/lib/plugins/tools/schema.keyword.coercion.js @@ -1,6 +1,5 @@ - -import codegen from 'ajv/dist/compile/codegen/index.js'; -import errors from 'ajv/dist/compile/errors.js'; +import codegen from "ajv/dist/compile/codegen/index.js"; +import errors from "ajv/dist/compile/errors.js"; export default { keyword: "coercion", @@ -9,16 +8,17 @@ export default { // @see codegen reference: https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts const assignParentData = function ( { gen, parentData, parentDataProperty }, - expr + expr, ) { gen.if(codegen._`${parentData} !== undefined`, () => - gen.assign(codegen._`${parentData}[${parentDataProperty}]`, expr) + gen.assign(codegen._`${parentData}[${parentDataProperty}]`, expr), ); }; const { data, gen, parentSchema, it } = cxt; const coerced = gen.let("coerced", codegen._`undefined`); - const types = Array.isArray(parentSchema.type) - ? parentSchema.type + const types = + Array.isArray(parentSchema.type) ? + parentSchema.type : [parentSchema.type]; switch (types[0]) { case "array": @@ -31,7 +31,7 @@ export default { codegen._`typeof ${data} === "string" || typeof ${data} === "number"`, () => { gen.assign(coerced, codegen._`${data} != ""`); - } + }, ); break; case "number": @@ -47,7 +47,7 @@ export default { }, () => { gen.assign(coerced, codegen._`+${data}`); - } + }, ); }); break; @@ -56,14 +56,14 @@ export default { // `{..., coercion: ["boolean_to_string"] }` // Or: // `{..., coercion: {boolean_to_string: true} }` - gen.block() + gen.block(); gen.if(codegen._`typeof ${data} === "boolean"`); - gen.assign(coerced, codegen._`${data} ? "1" : ""`) + gen.assign(coerced, codegen._`${data} ? "1" : ""`); gen.elseIf(codegen._`typeof ${data} === "number"`); - gen.assign(coerced, codegen._`"" +${data}`) - gen.else() - gen.assign(coerced, codegen._`${data}`) - gen.endBlock() + gen.assign(coerced, codegen._`"" +${data}`); + gen.else(); + gen.assign(coerced, codegen._`${data}`); + gen.endBlock(); break; } gen.if(codegen._`${coerced} !== undefined`, () => { diff --git a/packages/core/lib/registry.js b/packages/core/lib/registry.js index 48ade5bcd..d2f157990 100644 --- a/packages/core/lib/registry.js +++ b/packages/core/lib/registry.js @@ -6,13 +6,13 @@ Management facility to register and unregister actions. // Dependencies import path from "node:path"; -import {is_object, merge, mutate} from 'mixme'; +import { is_object, merge, mutate } from "mixme"; // Register all functions -const create = function({chain, on_register, parent, plugins} = {}) { +const create = function ({ chain, on_register, parent, plugins } = {}) { const store = {}; const obj = { - chain: chain + chain: chain, }; /* @@ -32,13 +32,16 @@ const create = function({chain, on_register, parent, plugins} = {}) { Parent registry. */ - obj.create = function(options = {}) { + obj.create = function (options = {}) { // Inherit options from parent - options = merge({ - chain: obj.chain, - on_register: on_register, - parent: parent - }, options); + options = merge( + { + chain: obj.chain, + on_register: on_register, + parent: parent, + }, + options, + ); // Create the child registry return create(options); }; @@ -49,17 +52,19 @@ const create = function({chain, on_register, parent, plugins} = {}) { Load an action from the module name. */ - obj.load = async function(module) { - if (typeof module !== 'string') { - throw Error(`Invalid Argument: module must be a string, got ${module.toString()}`); + obj.load = async function (module) { + if (typeof module !== "string") { + throw Error( + `Invalid Argument: module must be a string, got ${module.toString()}`, + ); } - if (module.startsWith('.')) { + if (module.startsWith(".")) { module = path.resolve(process.cwd(), module); } let action = (await import(module)).default; - if (typeof action === 'function') { + if (typeof action === "function") { action = { - handler: action + handler: action, }; } action.metadata ??= {}; @@ -85,7 +90,7 @@ const create = function({chain, on_register, parent, plugins} = {}) { Call the 'nikita:registry:normalize' hook. */ - obj.get = async function(namespace, options) { + obj.get = async function (namespace, options) { if (arguments.length === 1 && is_object(arguments[0])) { options = namespace; namespace = null; @@ -97,11 +102,11 @@ const create = function({chain, on_register, parent, plugins} = {}) { // Flatten result if (options.flatten) { const actions = []; - const walk = function(store, keys) { + const walk = function (store, keys) { const results = []; for (const k in store) { const v = store[k]; - if (k === '') { + if (k === "") { if (v.metadata?.deprecate && !options.deprecate) { continue; } @@ -121,12 +126,12 @@ const create = function({chain, on_register, parent, plugins} = {}) { } } else { // Tree result - const walk = function(store, keys) { + const walk = function (store, keys) { const res = {}; for (const k in store) { let v = store[k]; - if (k === '') { - if (v.metadata?.deprecate && !options.deprecate){ + if (k === "") { + if (v.metadata?.deprecate && !options.deprecate) { continue; } res[k] = merge(v); @@ -143,18 +148,18 @@ const create = function({chain, on_register, parent, plugins} = {}) { if (!parent) { return actions; } else { - return merge((await parent.get(options)), actions); + return merge(await parent.get(options), actions); } } } - if (typeof namespace === 'string') { + if (typeof namespace === "string") { // Return one action namespace = [namespace]; } let action = null; // Search for action in the current registry let child_store = store; - const namespaceTemp = namespace.concat(['']); + const namespaceTemp = namespace.concat([""]); for (let i = 0; i < namespaceTemp.length; i++) { const n = namespaceTemp[i]; if (!child_store[n]) { @@ -170,7 +175,7 @@ const create = function({chain, on_register, parent, plugins} = {}) { if (!action && parent) { action = await parent.get(namespace, { ...options, - normalize: false + normalize: false, }); } if (action == null) { @@ -184,9 +189,9 @@ const create = function({chain, on_register, parent, plugins} = {}) { if (plugins) { // Hook attented to modify an action returned by the registry return await plugins.call({ - name: 'nikita:registry:normalize', + name: "nikita:registry:normalize", args: action, - handler: (action) => action + handler: (action) => action, }); } else { return action; @@ -249,19 +254,19 @@ const create = function({chain, on_register, parent, plugins} = {}) { ``` */ - obj.register = async function(namespace, action) { - if (typeof namespace === 'string') { + obj.register = async function (namespace, action) { + if (typeof namespace === "string") { namespace = [namespace]; } if (Array.isArray(namespace)) { if (action === void 0) { return obj.chain || obj; } - if (typeof action === 'string') { + if (typeof action === "string") { action = await obj.load(action); - } else if (typeof action === 'function') { + } else if (typeof action === "function") { action = { - handler: action + handler: action, }; } let child_store = store; @@ -270,29 +275,38 @@ const create = function({chain, on_register, parent, plugins} = {}) { child_store[property] ??= {}; child_store = child_store[property]; } - child_store[''] = action; + child_store[""] = action; if (on_register) { await on_register(namespace, action); } } else { - const walk = async function(namespace, store) { + const walk = async function (namespace, store) { for (const k in store) { action = store[k]; - if (k !== '' && action && typeof action === 'object' && !Array.isArray(action) && !(action.handler || action.module)) { + if ( + k !== "" && + action && + typeof action === "object" && + !Array.isArray(action) && + !(action.handler || action.module) + ) { namespace.push(k); await walk(namespace, action); } else { - if (typeof action === 'string') { + if (typeof action === "string") { action = await obj.load(action); - } else if (typeof action === 'function') { + } else if (typeof action === "function") { action = { - handler: action + handler: action, }; } namespace.push(k); - store[k] = k === '' ? action : { - '': action - }; + store[k] = + k === "" ? action : ( + { + "": action, + } + ); if (on_register) { await on_register(namespace, action); } @@ -323,23 +337,23 @@ const create = function({chain, on_register, parent, plugins} = {}) { ``` */ - obj.deprecate = async function(old_name, new_name, action) { + obj.deprecate = async function (old_name, new_name, action) { let handler; if (arguments.length === 2) { handler = new_name; new_name = null; } - if (typeof action === 'string') { + if (typeof action === "string") { action = await obj.load(action); } - if (typeof handler === 'function') { + if (typeof handler === "function") { action = { - handler: handler + handler: handler, }; } action.metadata ??= {}; action.metadata.deprecate = new_name; - if (typeof action.module === 'string') { + if (typeof action.module === "string") { action.metadata.deprecate ??= action.module; } action.metadata.deprecate ??= true; @@ -360,8 +374,8 @@ const create = function({chain, on_register, parent, plugins} = {}) { Return true if name match a namespace and not a leaf action. */ - obj.registered = function(name, options = {}) { - if (typeof name === 'string') { + obj.registered = function (name, options = {}) { + if (typeof name === "string") { name = [name]; } if (!options.local && parent && parent.registered(name, options)) { @@ -370,13 +384,16 @@ const create = function({chain, on_register, parent, plugins} = {}) { let child_store = store; for (let i = 0; i < name.length; i++) { const n = name[i]; - if ((child_store[n] == null) || !child_store.propertyIsEnumerable(n)) { + if ( + child_store[n] == null || + !Object.prototype.propertyIsEnumerable.call(child_store, n) + ) { return false; } if (options.partial && child_store[n] && i === name.length - 1) { return true; } - if (child_store[n][''] && i === name.length - 1) { + if (child_store[n][""] && i === name.length - 1) { return true; } child_store = child_store[n]; @@ -390,8 +407,8 @@ const create = function({chain, on_register, parent, plugins} = {}) { Remove an action from registry. */ - obj.unregister = function(name) { - if (typeof name === 'string') { + obj.unregister = function (name) { + if (typeof name === "string") { name = [name]; } let child_store = store; diff --git a/packages/core/lib/schedulers/index.js b/packages/core/lib/schedulers/index.js index bfbe28405..07dfcddff 100644 --- a/packages/core/lib/schedulers/index.js +++ b/packages/core/lib/schedulers/index.js @@ -1,4 +1,3 @@ - /* Usage: schedule([handlers], [options]) @@ -11,18 +10,21 @@ Options: Prevent the execution of newly registered tasks, call resume to trigger the execution. */ -export default function(handlers, options) { +export default function (handlers, options) { var opts, promise, scheduler, stack, state; if (Array.isArray(handlers) || (handlers != null) === false) { if (options == null) { options = {}; } - } else if (typeof handlers === 'object' && (Array.isArray(options) || (options != null) === false)) { + } else if ( + typeof handlers === "object" && + (Array.isArray(options) || (options != null) === false) + ) { opts = options; options = handlers; handlers = opts; } else { - throw Error('Invalid arguments'); + throw Error("Invalid arguments"); } // Options normalisation if (options.strict == null) { @@ -38,22 +40,22 @@ export default function(handlers, options) { paused: options.paused, output: [], resolved: false, - running: false + running: false, }; - promise = new Promise(function(resolve, reject) { + promise = new Promise(function (resolve, reject) { scheduler = { - pause: function() { - return state.paused = true; + pause: function () { + return (state.paused = true); }, - resume: function() { + resume: function () { state.paused = false; return scheduler.pump(); }, - end: function(err, output) { + end: function (err, output) { var task; state.resolved = true; if (err) { - while (task = stack.shift()) { + while ((task = stack.shift())) { task.reject(err); } return reject(err); @@ -61,7 +63,7 @@ export default function(handlers, options) { return resolve(output); } }, - pump: function() { + pump: function () { var item; if (state.running) { return; @@ -76,11 +78,10 @@ export default function(handlers, options) { } state.running = true; item = stack.shift(); - item = item; - return setImmediate(async function() { + return setImmediate(async function () { var error, result; try { - result = (await item.handler.call()); + result = await item.handler.call(); state.running = false; item.resolve.call(null, result); if (item.options.output) { @@ -89,7 +90,7 @@ export default function(handlers, options) { // Use the push output option to include additionnal tasks state.output.push(result); } - return setImmediate(function() { + return setImmediate(function () { return scheduler.pump(); }); } catch (error1) { @@ -99,92 +100,98 @@ export default function(handlers, options) { if (options.strict) { return scheduler.end(error); } else { - return setImmediate(function() { + return setImmediate(function () { return scheduler.pump(); }); } } }); }, - unshift: function(handlers, options = {}) { + unshift: function (handlers, options = {}) { var isArray; if (options.pump == null) { options.pump = true; } isArray = Array.isArray(handlers); - if (!(isArray || typeof handlers === 'function')) { - throw Error('Invalid Argument'); + if (!(isArray || typeof handlers === "function")) { + throw Error("Invalid Argument"); } - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { var handler; if (!isArray) { stack.unshift({ handler: handlers, resolve: resolve, reject: reject, - options: options + options: options, }); if (!state.paused) { return scheduler.pump(); } } else { // Unshift from the last to the first element to preserve order - return Promise.all(((function() { - var i, len, ref, results; - ref = handlers.reverse(); - results = []; - for (i = 0, len = ref.length; i < len; i++) { - handler = ref[i]; - results.push(scheduler.unshift(handler, { - pump: false - })); - } - return results; - })()).reverse()).then(resolve, reject); + return Promise.all( + (function () { + var i, len, ref, results; + ref = handlers.reverse(); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + handler = ref[i]; + results.push( + scheduler.unshift(handler, { + pump: false, + }), + ); + } + return results; + })().reverse(), + ).then(resolve, reject); } }); }, - push: function(handlers, options = {}) { + push: function (handlers, options = {}) { var isArray, prom; isArray = Array.isArray(handlers); - if (!(isArray || typeof handlers === 'function')) { - throw Error('Invalid Argument'); + if (!(isArray || typeof handlers === "function")) { + throw Error("Invalid Argument"); } - prom = new Promise(function(resolve, reject) { + prom = new Promise(function (resolve, reject) { var handler; if (!isArray) { stack.push({ handler: handlers, resolve: resolve, reject: reject, - options: options + options: options, }); if (!state.paused) { return scheduler.pump(); } } else { - return Promise.all((function() { - var i, len, results; - results = []; - for (i = 0, len = handlers.length; i < len; i++) { - handler = handlers[i]; - results.push(scheduler.push(handler, options)); - } - return results; - })()).then(resolve, reject); + return Promise.all( + (function () { + var i, len, results; + results = []; + for (i = 0, len = handlers.length; i < len; i++) { + handler = handlers[i]; + results.push(scheduler.push(handler, options)); + } + return results; + })(), + ).then(resolve, reject); } }); - prom.catch((function() {})); // Handle strict unhandled rejections + prom.catch(function () {}); // Handle strict unhandled rejections return prom; }, - call: function(handlers, options = {}) { + call: function (handlers, options = {}) { return this.push(handlers, options); - } + }, }; if (handlers) { if (handlers.length) { scheduler.push(handlers, { - output: true + output: true, }); return scheduler.pump(); } else { @@ -192,11 +199,11 @@ export default function(handlers, options) { } } }); - promise.catch((function() {})); // Handle strict unhandled rejections + promise.catch(function () {}); // Handle strict unhandled rejections return new Proxy(promise, { - get: function(target, name) { + get: function (target, name) { if (target[name] != null) { - if (typeof target[name] === 'function') { + if (typeof target[name] === "function") { return target[name].bind(target); } else { return target[name]; @@ -204,6 +211,6 @@ export default function(handlers, options) { } else { return scheduler[name]; } - } + }, }); -}; +} diff --git a/packages/core/lib/session.js b/packages/core/lib/session.js index df87aca59..4f6c4d1b1 100644 --- a/packages/core/lib/session.js +++ b/packages/core/lib/session.js @@ -1,21 +1,23 @@ +import { merge } from "mixme"; +import each from "each"; +import { plugandplay } from "plug-and-play"; +import registry from "@nikitajs/core/registry"; +import contextualize from "@nikitajs/core/session/contextualize"; +import utils from "@nikitajs/core/utils"; -import {merge} from 'mixme'; -import each from 'each'; -import {plugandplay} from 'plug-and-play'; -import registry from '@nikitajs/core/registry'; -import contextualize from '@nikitajs/core/session/contextualize'; -import utils from '@nikitajs/core/utils'; - -const session = function(...args) { +const session = function (...args) { // Multiply arguments - if (args.some( (arg) => Array.isArray(arg) )) { - return each({ - flatten: true - }, utils.array.multiply(...args).map(function(args) { - return function() { - return session(...args); - }; - })); + if (args.some((arg) => Array.isArray(arg))) { + return each( + { + flatten: true, + }, + utils.array.multiply(...args).map(function (args) { + return function () { + return session(...args); + }; + }), + ); } // Local schedulers to execute children and be notified on finish const schedulers = { @@ -41,10 +43,10 @@ const session = function(...args) { hooks: {}, scheduler: schedulers.out, state: {}, - } + }, }); } catch (e) { - return Promise.reject(e) + return Promise.reject(e); } // Initialize the plugins manager action.plugins = plugandplay({ @@ -55,34 +57,36 @@ const session = function(...args) { action.registry ??= registry.create({ plugins: action.plugins, parent: action.parent?.registry ?? registry, - on_register: async function(name, act) { + on_register: async function (name, act) { await action.plugins.call({ - name: 'nikita:register', + name: "nikita:register", args: { name: name, - action: act - } + action: act, + }, }); - } + }, }); // Children namespace let namespace = []; // Catch method calls - const on_call = function(...args) { + const on_call = function (...args) { let nm; // Extract action namespace and reset its value [namespace, nm] = [[], namespace]; // Schedule the action and get the result as a promise - if(action.scheduler.state().closed) { - return Promise.reject(utils.error('NIKITA_SCHEDULER_CLOSED', [ - 'cannot schedule new items when closed.' - ])) + if (action.scheduler.state().closed) { + return Promise.reject( + utils.error("NIKITA_SCHEDULER_CLOSED", [ + "cannot schedule new items when closed.", + ]), + ); } - const prom = action.scheduler.call(async function() { + const prom = action.scheduler.call(async function () { args.push({ $namespace: nm, $parent: action, - }) + }); return session(...args); }); return new Proxy(prom, { @@ -91,10 +95,10 @@ const session = function(...args) { }); }; // Building the namespace before calling an action - const on_get = function(target, name, concurrency) { + const on_get = function (target, name, concurrency) { // Return static properties - if ((target[name] != null) && !action.registry.registered(name)) { - if (typeof target[name] === 'function') { + if (target[name] != null && !action.registry.registered(name)) { + if (typeof target[name] === "function") { return target[name].bind(target); } else { return target[name]; @@ -103,7 +107,7 @@ const session = function(...args) { // Return the plugins instance in the root session if (namespace.length === 0) { switch (name) { - case 'plugins': + case "plugins": return action.plugins; } } @@ -118,14 +122,15 @@ const session = function(...args) { get: (target, name) => on_get(target, name, -1), }); // Execute the action - const result = new Promise(async function(resolve, reject) { + const { promise: result, resolve, reject } = utils.promise.withResolvers(); + (async () => { try { // Hook intented to modify the current action being created action = await action.plugins.call({ name: "nikita:normalize", args: action, hooks: action.hooks?.on_normalize, // || action.hooks?.["nikita:normalize"] - handler: (action) => action + handler: (action) => action, }); } catch (error) { schedulers.out.end(error); @@ -133,17 +138,23 @@ const session = function(...args) { } // Load action from registry if (action.metadata.namespace) { - try{ - const action_from_registry = await action.registry.get(action.metadata.namespace); - if(!action_from_registry && action.metadata.namespace.length !== 0){ - return reject(utils.error('ACTION_UNREGISTERED_NAMESPACE', ['no action is registered under this namespace,', `got ${JSON.stringify(action.metadata.namespace)}.`])); + try { + const action_from_registry = await action.registry.get( + action.metadata.namespace, + ); + if (!action_from_registry && action.metadata.namespace.length !== 0) { + return reject( + utils.error("ACTION_UNREGISTERED_NAMESPACE", [ + "no action is registered under this namespace,", + `got ${JSON.stringify(action.metadata.namespace)}.`, + ]), + ); } // Merge the registry action with the user action properties for (const k in action_from_registry) { - const v = action_from_registry[k]; action[k] = merge(action_from_registry[k], action[k]); } - }catch(err){ + } catch (err) { return reject(err); } } @@ -151,70 +162,86 @@ const session = function(...args) { action.scheduler = schedulers.in; // Hook attended to alter the execution of an action handler const output = action.plugins.call({ - name: 'nikita:action', + name: "nikita:action", args: action, hooks: action.hooks.on_action, // || action.hooks.["nikita:action"] - handler: function(action) { + handler: function (action) { // Execution of an action handler return action.handler?.call(action.context, action); - } + }, }); // Ensure child actions are executed even after parent execution - const pump = output.catch(function(err) { - return schedulers.in.error(err); - }).then(function() { - return schedulers.in.end(); - }); + const pump = output + .catch(function (err) { + return schedulers.in.error(err); + }) + .then(function () { + return schedulers.in.end(); + }); // Make sure the promise is resolved after the scheduler and its children - Promise.all([output, pump]).then(async function([output]) { - await schedulers.out.resume(); - return output; - }).then(function(output) { - schedulers.out.end(); - return on_result(undefined, output); - }, function(err) { - schedulers.out.end(err); - return on_result(err); - }); + Promise.all([output, pump]) + .then(async function ([output]) { + await schedulers.out.resume(); + return output; + }) + .then( + function (output) { + schedulers.out.end(); + return on_result(undefined, output); + }, + function (err) { + schedulers.out.end(err); + return on_result(err); + }, + ); // Hook to catch error and format output once all children are executed - const on_result = function(error, output) { + const on_result = function (error, output) { + return action.plugins + .call({ + name: "nikita:result", + args: { + action: action, + error: error, + output: output, + }, + hooks: action.hooks.on_result, // || action.hooks.["nikita:result"] + handler: function ({ error, output }) { + if (error) { + throw error; + } else { + return output; + } + }, + }) + .then(resolve, reject); + }; + })(); + result.then( + function (output) { + if (action.parent !== undefined) { + return; + } return action.plugins.call({ - name: 'nikita:result', + name: "nikita:resolved", args: { action: action, - error: error, - output: output + output: output, }, - hooks: action.hooks.on_result, // || action.hooks.["nikita:result"] - handler: function({action, error, output}) { - if (error) { - throw error; - } else { - return output; - } - } - }).then(resolve, reject); - }; - }); - result.then(function(output) { - if (action.parent !== undefined) { return; } - return action.plugins.call({ - name: 'nikita:resolved', - args: { - action: action, - output: output - } - }); - }, function(err) { - if (action.parent !== undefined) { return; } - return action.plugins.call({ - name: 'nikita:rejected', - args: { - action: action, - error: err + }); + }, + function (err) { + if (action.parent !== undefined) { + return; } - }); - }); + return action.plugins.call({ + name: "nikita:rejected", + args: { + action: action, + error: err, + }, + }); + }, + ); // Returning a proxified promise: // - new actions can be registered to it as long as the promised has not fulfilled // - resolve when all registered actions are fulfilled diff --git a/packages/core/lib/session/contextualize.js b/packages/core/lib/session/contextualize.js index 188a89378..c5c812212 100644 --- a/packages/core/lib/session/contextualize.js +++ b/packages/core/lib/session/contextualize.js @@ -1,4 +1,4 @@ -import { clone, merge, mutate, is_object_literal } from "mixme"; +import { clone, mutate, is_object_literal } from "mixme"; import utils from "@nikitajs/core/utils"; const properties = [ @@ -82,7 +82,7 @@ export default function ({ action = {}, args }) { } } else { for (const k in arg) { - if (k === '$') continue; + if (k === "$") continue; const v = arg[k]; if (["config", "metadata"].includes(k)) { mutate(action[k], v); diff --git a/packages/core/lib/utils/index.js b/packages/core/lib/utils/index.js index ed5c84ff7..3ad54ab91 100644 --- a/packages/core/lib/utils/index.js +++ b/packages/core/lib/utils/index.js @@ -1,8 +1,7 @@ - import * as utils from "@nikitajs/utils"; export * from "@nikitajs/utils"; export default { - ...utils + ...utils, }; diff --git a/packages/core/package.json b/packages/core/package.json index c47861395..90be1d4b5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -56,7 +56,7 @@ "regexp-quote": "^0.0.0", "self-templated": "^0.2.3", "semver": "^7.6.3", - "ssh2-connect": "^3.4.3", + "ssh2-connect": "^3.5.0", "ssh2-exec": "^0.7.7", "ssh2-fs": "^1.1.3", "stack-trace": "^0.0.10", @@ -64,12 +64,9 @@ "uuid": "^10.0.0" }, "devDependencies": { - "@babel/core": "^7.24.9", - "@babel/preset-env": "^7.25.0", "@nikitajs/incus-runner": "^1.0.0-alpha.6", "coffeescript": "^2.7.0", - "eslint": "^9.8.0", - "mocha": "^10.7.0", + "mocha": "^10.7.3", "mocha-they": "^0.1.3", "should": "^13.2.3" }, @@ -107,8 +104,6 @@ "directory": "packages/core" }, "scripts": { - "lint": "eslint 'lib/**/*.coffee'", - "lint-fix": "eslint --fix 'lib/**/*.coffee'", "test": "npm run test:local && npm run test:env", "test:env": "env/run.sh", "test:local": "mocha --node-flags '--unhandled-rejections=strict' 'test/**/*.coffee'" diff --git a/packages/core/test/loaders/all.js b/packages/core/test/loaders/all.js index e83023aa7..5049b8304 100644 --- a/packages/core/test/loaders/all.js +++ b/packages/core/test/loaders/all.js @@ -1,13 +1,12 @@ - -import * as coffee from './coffee.js' +import * as coffee from "./coffee.js"; // import * as ts from 'ts-node/esm' const coffeeRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; -const tsRegex = /\.ts$/; +// const tsRegex = /\.ts$/; export function load(url, context, next) { if (coffeeRegex.test(url)) { - return coffee.load.apply(this, arguments) + return coffee.load.apply(this, arguments); } // if (tsRegex.test(url)) { // return ts.load.apply(this, arguments) diff --git a/packages/core/test/loaders/coffee.js b/packages/core/test/loaders/coffee.js index c7b277cb7..75b15abe0 100644 --- a/packages/core/test/loaders/coffee.js +++ b/packages/core/test/loaders/coffee.js @@ -1,11 +1,11 @@ -import CoffeeScript from 'coffeescript'; +import CoffeeScript from "coffeescript"; // See https://github.com/nodejs/node/issues/36396 const extensionsRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; export async function load(url, context, next) { if (extensionsRegex.test(url)) { - const format = 'module'; + const format = "module"; const { source: rawSource } = await next(url, { format }); const source = CoffeeScript.compile(rawSource.toString(), { bare: true, @@ -14,7 +14,7 @@ export async function load(url, context, next) { header: false, sourceMap: false, }); - return {format, source}; + return { format, source }; } return next(url, context); } diff --git a/packages/core/test/plugins/metadata/register.coffee b/packages/core/test/plugins/metadata/register.coffee index 2228aa696..dc11137e7 100644 --- a/packages/core/test/plugins/metadata/register.coffee +++ b/packages/core/test/plugins/metadata/register.coffee @@ -1,7 +1,8 @@ import registry from '@nikitajs/core/registry' import session from '@nikitajs/core/session' import metadataRegister from '@nikitajs/core/plugins/metadata/register' -import utils from '@nikitajs/utils' +import metadataSchema from '@nikitajs/core/plugins/metadata/schema' +import toolsSchema from '@nikitajs/core/plugins/tools/schema' import test from '../../test.coffee' # Note, register is imported on purpose # When the test is executed along other tests, @@ -12,6 +13,25 @@ import '@nikitajs/core/register' describe 'plugins.metadata.register', -> return unless test.tags.api + + it 'validate schema', -> + session + $register: false + $plugins: [ + metadataRegister, + metadataSchema, + toolsSchema + ] + $handler: (->) + .should.be.rejectedWith + code: 'NIKITA_SCHEMA_VALIDATION_CONFIG' + message: [ + 'NIKITA_SCHEMA_VALIDATION_CONFIG:' + 'one error was found in the configuration of root action:' + 'nikita#/definitions/metadata/properties/register/type' + 'metadata/register must be object,' + 'type is "object".' + ].join ' ' it 'in session', -> session diff --git a/packages/db/lib/database/exists/index.js b/packages/db/lib/database/exists/index.js index 3144ae035..14598a665 100644 --- a/packages/db/lib/database/exists/index.js +++ b/packages/db/lib/database/exists/index.js @@ -1,29 +1,35 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const cmd_list_tables = config.engine === 'postgresql' - ? `SELECT datname FROM pg_database WHERE datname = '${config.database}';` - : config.engine === 'mariadb' || config.engine === 'mysql' - ? `SHOW DATABASES;` + handler: async function ({ config }) { + const cmd_list_tables = + config.engine === "postgresql" ? + `SELECT datname FROM pg_database WHERE datname = '${config.database}';` + : config.engine === "mariadb" || config.engine === "mysql" ? + `SHOW DATABASES;` : undefined; - const {$status} = await this.db.query({ + const { $status } = await this.db.query({ ...db.connection_config(config), command: cmd_list_tables, database: null, - grep: config.database + grep: config.database, }); return { - exists: $status + exists: $status, }; }, metadata: { - argument_to_config: 'database', - global: 'db', + argument_to_config: "database", + global: "db", shy: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/db/lib/database/index.js b/packages/db/lib/database/index.js index 504852bfa..e337322cd 100644 --- a/packages/db/lib/database/index.js +++ b/packages/db/lib/database/index.js @@ -1,7 +1,12 @@ // Dependencies import dedent from "dedent"; import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -10,9 +15,9 @@ export default { config.engine = config.engine.toLowerCase(); log("DEBUG", `Database engine set to ${config.engine}`); const engine = - config.engine === "mysql" || config.engine === "mariadb" - ? "mysql" - : "postgresql"; + config.engine === "mysql" || config.engine === "mariadb" ? + "mysql" + : "postgresql"; if (engine === "mysql") { config.character_set ??= "latin1"; // MySQL default switch (config.character_set) { @@ -26,33 +31,33 @@ export default { // Create the database if it does not exists log("DEBUG", `Check if database ${config.database} exists`); const { exists } = await this.db.database.exists( - db.connection_config(config) + db.connection_config(config), ); if (!exists) { await this.execute({ command: - engine === "mysql" - ? db.command( - config, - { - database: null, - }, - [ - `CREATE DATABASE ${config.database}`, - `DEFAULT CHARACTER SET ${config.character_set}`, - config.collation - ? `DEFAULT COLLATE ${config.collation}` - : void 0, - ";", - ].join(" ") - ) - : db.command( - config, - { - database: null, - }, - `CREATE DATABASE ${config.database};` - ), + engine === "mysql" ? + db.command( + config, + { + database: null, + }, + [ + `CREATE DATABASE ${config.database}`, + `DEFAULT CHARACTER SET ${config.character_set}`, + config.collation ? + `DEFAULT COLLATE ${config.collation}` + : void 0, + ";", + ].join(" "), + ) + : db.command( + config, + { + database: null, + }, + `CREATE DATABASE ${config.database};`, + ), }); log("WARN", `Database created: ${JSON.stringify(config.database)}`); } @@ -60,7 +65,7 @@ export default { for (const user of config.user) { log( "DEBUG", - `Check if user ${user} has PRIVILEGES on ${config.database} ` + `Check if user ${user} has PRIVILEGES on ${config.database} `, ); const { exists } = await this.db.user.exists({ ...db.connection_config(config), @@ -70,37 +75,37 @@ export default { throw Error(`DB user does not exists: ${user}`); } const command_has_privileges = - engine === "mysql" - ? db.command( - config, - { - database: "mysql", - }, - `SELECT user FROM db WHERE db='${config.database}';` - ) + ` | grep '${user}'` - : db.command( - config, - { - database: config.database, - }, - "\\l" - ) + ` | egrep '^${user}='`; + engine === "mysql" ? + db.command( + config, + { + database: "mysql", + }, + `SELECT user FROM db WHERE db='${config.database}';`, + ) + ` | grep '${user}'` + : db.command( + config, + { + database: config.database, + }, + "\\l", + ) + ` | egrep '^${user}='`; const command_grant_privileges = - engine === "mysql" - ? db.command( - config, - { - database: null, - }, - `GRANT ALL PRIVILEGES ON ${config.database}.* TO '${user}' WITH GRANT OPTION;` - ) - : db.command( - config, - { - database: null, - }, - `GRANT ALL PRIVILEGES ON DATABASE ${config.database} TO ${user}` - ); + engine === "mysql" ? + db.command( + config, + { + database: null, + }, + `GRANT ALL PRIVILEGES ON ${config.database}.* TO '${user}' WITH GRANT OPTION;`, + ) + : db.command( + config, + { + database: null, + }, + `GRANT ALL PRIVILEGES ON DATABASE ${config.database} TO ${user}`, + ); const { $status } = await this.execute({ command: dedent` if ${command_has_privileges}; then diff --git a/packages/db/lib/database/remove/index.js b/packages/db/lib/database/remove/index.js index 7e1491bef..1ae68a4e9 100644 --- a/packages/db/lib/database/remove/index.js +++ b/packages/db/lib/database/remove/index.js @@ -1,10 +1,15 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Avoid errors when database argument is provided in the command: // - Postgres: "ERROR: cannot drop the currently open database" // - MariaDB: "ERROR 1049 (42000): Unknown database 'my_db'" @@ -16,8 +21,8 @@ export default { }); }, metadata: { - argument_to_config: 'database', - global: 'db', - definitions: definitions - } + argument_to_config: "database", + global: "db", + definitions: definitions, + }, }; diff --git a/packages/db/lib/database/wait/index.js b/packages/db/lib/database/wait/index.js index 887d9fede..016a966a6 100644 --- a/packages/db/lib/database/wait/index.js +++ b/packages/db/lib/database/wait/index.js @@ -1,34 +1,43 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const cmd_list_tables = config.engine === 'postgresql' - ? `SELECT datname FROM pg_database WHERE datname = '${config.database}';` - : config.engine === 'mariadb' || config.engine === 'mysql' - ? `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='${config.database}';` + handler: async function ({ config }) { + const cmd_list_tables = + config.engine === "postgresql" ? + `SELECT datname FROM pg_database WHERE datname = '${config.database}';` + : config.engine === "mariadb" || config.engine === "mysql" ? + `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='${config.database}';` : undefined; - const {$status} = await this.wait({ - retry: config.retry, - interval: config.interval, - }, async function() { - const { stdout } = await this.db.query({ - ...db.connection_config(config), - command: cmd_list_tables, - database: null, - grep: config.database, - }); - if(stdout.trim() === '') throw Error('NIKITA_DB_WAIT_NOT_READY') - }); + const { $status } = await this.wait( + { + retry: config.retry, + interval: config.interval, + }, + async function () { + const { stdout } = await this.db.query({ + ...db.connection_config(config), + command: cmd_list_tables, + database: null, + grep: config.database, + }); + if (stdout.trim() === "") throw Error("NIKITA_DB_WAIT_NOT_READY"); + }, + ); return { - exists: $status + exists: $status, }; }, metadata: { - argument_to_config: 'database', - global: 'db', - definitions: definitions - } + argument_to_config: "database", + global: "db", + definitions: definitions, + }, }; diff --git a/packages/db/lib/query/index.js b/packages/db/lib/query/index.js index fe8ed4106..ff1f695f7 100644 --- a/packages/db/lib/query/index.js +++ b/packages/db/lib/query/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -11,9 +16,10 @@ export default { trim: config.trim, }); return { - $status: config.grep - ? utils.regexp.is(config.grep) - ? stdout.split("\n").some((line) => config.grep.test(line)) + $status: + config.grep ? + utils.regexp.is(config.grep) ? + stdout.split("\n").some((line) => config.grep.test(line)) : stdout.split("\n").some((line) => line === config.grep) : $status, stdout: stdout, diff --git a/packages/db/lib/register.js b/packages/db/lib/register.js index 46f4b864f..1847ed9ae 100644 --- a/packages/db/lib/register.js +++ b/packages/db/lib/register.js @@ -1,4 +1,3 @@ - // Dependencies import registry from "@nikitajs/core/registry"; @@ -6,24 +5,24 @@ import registry from "@nikitajs/core/registry"; const actions = { db: { database: { - '': '@nikitajs/db/database', - exists: '@nikitajs/db/database/exists', - remove: '@nikitajs/db/database/remove', - wait: '@nikitajs/db/database/wait' + "": "@nikitajs/db/database", + exists: "@nikitajs/db/database/exists", + remove: "@nikitajs/db/database/remove", + wait: "@nikitajs/db/database/wait", }, - query: '@nikitajs/db/query', + query: "@nikitajs/db/query", schema: { - '': '@nikitajs/db/schema', - exists: '@nikitajs/db/schema/exists', - list: '@nikitajs/db/schema/list', - remove: '@nikitajs/db/schema/remove' + "": "@nikitajs/db/schema", + exists: "@nikitajs/db/schema/exists", + list: "@nikitajs/db/schema/list", + remove: "@nikitajs/db/schema/remove", }, user: { - '': '@nikitajs/db/user', - exists: '@nikitajs/db/user/exists', - remove: '@nikitajs/db/user/remove' - } - } + "": "@nikitajs/db/user", + exists: "@nikitajs/db/user/exists", + remove: "@nikitajs/db/user/remove", + }, + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/db/lib/schema/exists/index.js b/packages/db/lib/schema/exists/index.js index e3f821367..918486c5a 100644 --- a/packages/db/lib/schema/exists/index.js +++ b/packages/db/lib/schema/exists/index.js @@ -1,6 +1,11 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/db/lib/schema/index.js b/packages/db/lib/schema/index.js index 83a1bced4..0e824024b 100644 --- a/packages/db/lib/schema/index.js +++ b/packages/db/lib/schema/index.js @@ -1,6 +1,11 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -19,7 +24,7 @@ export default { $unless_execute: db.command( config, - `SELECT 1 FROM pg_namespace WHERE nspname = '${config.schema}';` + `SELECT 1 FROM pg_namespace WHERE nspname = '${config.schema}';`, ) + " | grep 1", }); // Check if owner is the good one @@ -30,7 +35,7 @@ export default { ` | grep '${config.schema}|${config.owner}'`, command: db.command( config, - `ALTER SCHEMA ${config.schema} OWNER TO ${config.owner};` + `ALTER SCHEMA ${config.schema} OWNER TO ${config.owner};`, ), code: [0, 1], }); diff --git a/packages/db/lib/schema/list/index.js b/packages/db/lib/schema/list/index.js index e6e09f46b..614700615 100644 --- a/packages/db/lib/schema/list/index.js +++ b/packages/db/lib/schema/list/index.js @@ -1,7 +1,12 @@ // Dependencies import utils from "@nikitajs/core/utils"; import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { diff --git a/packages/db/lib/schema/remove/index.js b/packages/db/lib/schema/remove/index.js index 459863a2b..bd1386317 100644 --- a/packages/db/lib/schema/remove/index.js +++ b/packages/db/lib/schema/remove/index.js @@ -1,6 +1,11 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/db/lib/user/exists/index.js b/packages/db/lib/user/exists/index.js index f22ddfe44..ea8dab9f7 100644 --- a/packages/db/lib/user/exists/index.js +++ b/packages/db/lib/user/exists/index.js @@ -1,6 +1,11 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/db/lib/user/index.js b/packages/db/lib/user/index.js index 97858cb41..c3eebc805 100644 --- a/packages/db/lib/user/index.js +++ b/packages/db/lib/user/index.js @@ -1,68 +1,77 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; import utils from "@nikitajs/db/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config }) { // Commands - const engine = config.engine === 'mysql' || config.engine === 'mariadb' - ? "mysql" - : "postgresql" - const command_user_exists = engine === "mysql" - ? utils.db.command( + const engine = + config.engine === "mysql" || config.engine === "mariadb" ? + "mysql" + : "postgresql"; + const command_user_exists = + engine === "mysql" ? + utils.db.command( config, - `SELECT User FROM mysql.user WHERE User='${config.username}'` + `SELECT User FROM mysql.user WHERE User='${config.username}'`, ) + ` | grep ${config.username}` : utils.db.command( config, - `SELECT 1 FROM pg_roles WHERE rolname='${config.username}'` + `SELECT 1 FROM pg_roles WHERE rolname='${config.username}'`, ) + " | grep 1"; - const command_user_create = engine === "mysql" - ? utils.db.command( + const command_user_create = + engine === "mysql" ? + utils.db.command( config, - `CREATE USER ${config.username} IDENTIFIED BY '${config.password}';` + `CREATE USER ${config.username} IDENTIFIED BY '${config.password}';`, ) : utils.db.command( - config, - `CREATE USER ${config.username} WITH PASSWORD '${config.password}';` - ); - const command_password_is_invalid = engine === "mysql" - ? utils.db.command( + config, + `CREATE USER ${config.username} WITH PASSWORD '${config.password}';`, + ); + const command_password_is_invalid = + engine === "mysql" ? + utils.db.command( config, { admin_username: config.username, admin_password: config.password, }, - "\\dt" + "\\dt", ) + " 2>&1 >/dev/null | grep -e '^ERROR 1045.*'" : utils.db.command( - config, - { - admin_username: config.username, - admin_password: config.password, - }, - "\\dt" - ) + - " 2>&1 >/dev/null | grep -e '^.*\\sFATAL.*password\\sauthentication\\sfailed\\sfor\\suser.*'"; + config, + { + admin_username: config.username, + admin_password: config.password, + }, + "\\dt", + ) + + " 2>&1 >/dev/null | grep -e '^.*\\sFATAL.*password\\sauthentication\\sfailed\\sfor\\suser.*'"; const command_password_change = - engine === "mysql" - ? utils.db.command( - config, - // Old mysql version for MySQL 5.7.5 and earlier or MariaDB 10.1.20 and earlier - // `SET PASSWORD FOR ${config.username} = PASSWORD ('${config.password}');` - `ALTER USER ${config.username} IDENTIFIED BY '${config.password}';` - ) - : engine === "mariadb" - ? utils.db.command( - config, - `ALTER USER ${config.username} IDENTIFIED BY '${config.password}';` - ) - : utils.db.command( - config, - `ALTER USER ${config.username} WITH PASSWORD '${config.password}';` - ); + engine === "mysql" ? + utils.db.command( + config, + // Old mysql version for MySQL 5.7.5 and earlier or MariaDB 10.1.20 and earlier + // `SET PASSWORD FOR ${config.username} = PASSWORD ('${config.password}');` + `ALTER USER ${config.username} IDENTIFIED BY '${config.password}';`, + ) + : engine === "mariadb" ? + utils.db.command( + config, + `ALTER USER ${config.username} IDENTIFIED BY '${config.password}';`, + ) + : utils.db.command( + config, + `ALTER USER ${config.username} WITH PASSWORD '${config.password}';`, + ); return await this.execute({ command: dedent` signal=3 diff --git a/packages/db/lib/user/remove/index.js b/packages/db/lib/user/remove/index.js index 55db6f8bb..06b5051b4 100644 --- a/packages/db/lib/user/remove/index.js +++ b/packages/db/lib/user/remove/index.js @@ -1,18 +1,23 @@ // Dependencies import { db } from "@nikitajs/db/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.db.query({ ...db.connection_config(config), - command: `DROP USER IF EXISTS ${config.username};` + command: `DROP USER IF EXISTS ${config.username};`, }); }, metadata: { - argument_to_config: 'username', - global: 'db', - definitions: definitions - } + argument_to_config: "username", + global: "db", + definitions: definitions, + }, }; diff --git a/packages/db/lib/utils/db.js b/packages/db/lib/utils/db.js index 8a95f60c8..61d7c3a57 100644 --- a/packages/db/lib/utils/db.js +++ b/packages/db/lib/utils/db.js @@ -54,7 +54,7 @@ const command = function (...opts) { // -s, --silent Be more silent. Print results with a tab as separator, each row on new line. // -r, --raw Write fields without conversion. Used with --batch. config.silent ? "-N -s -r" : void 0, - config.command ? `-e \"${escape(config.command)}\"` : void 0, + config.command ? `-e "${escape(config.command)}"` : void 0, ] .filter(Boolean) .join(" "); @@ -77,7 +77,7 @@ const command = function (...opts) { // -A, --no-align Unaligned table output mode // -q, --quiet Run quietly (no messages, only query output) "-tAq", - config.command ? `-c \"${config.command}\"` : void 0, + config.command ? `-c "${config.command}"` : void 0, ] .filter(Boolean) .join(" "); @@ -104,7 +104,7 @@ parse 'jdbc:mysql://host1:3306,host2:3306/hive?createDatabaseIfNotExist=true' */ const jdbc = function (jdbc) { if (/^jdbc:mysql:/.test(jdbc)) { - let [_, __, addresses, database] = + let [, , addresses, database] = /^jdbc:(.*?):\/+(.*?)\/(.*?)(\?(.*)|$)/.exec(jdbc); return { engine: "mysql", @@ -118,7 +118,7 @@ const jdbc = function (jdbc) { database: database, }; } else if (/^jdbc:postgresql:/.test(jdbc)) { - let [_, __, addresses, database] = + let [, , addresses, database] = /^jdbc:(.*?):\/+(.*?)\/(.*?)(\?(.*)|$)/.exec(jdbc); return { engine: "postgresql", @@ -138,15 +138,19 @@ const jdbc = function (jdbc) { // Filter connection properties const connection_config = function (opts) { - return utils.object.filter(opts, [], [ - "admin_username", - "admin_password", - "database", - "engine", - "host", - "port", - "silent", - ]); + return utils.object.filter( + opts, + [], + [ + "admin_username", + "admin_password", + "database", + "engine", + "host", + "port", + "silent", + ], + ); }; export { escape, command, jdbc, connection_config }; diff --git a/packages/docker/lib/build/index.js b/packages/docker/lib/build/index.js index ce75fa1a1..d8aa042b8 100644 --- a/packages/docker/lib/build/index.js +++ b/packages/docker/lib/build/index.js @@ -2,7 +2,12 @@ import path from "node:path"; import utils from "@nikitajs/docker/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); const errors = { NIKITA_DOCKER_BUILD_CONTENT_FILE_REQUIRED: function () { @@ -26,9 +31,9 @@ export default { // Retrieve previous image const { images: oldImages } = await this.docker.images({ filters: { - reference: config.tag ? `${config.image}:${config.tag}` : config.image - } - }) + reference: config.tag ? `${config.image}:${config.tag}` : config.image, + }, + }); const oldID = oldImages.length === 1 ? oldImages[0].ID : null; // Make sure the Dockerfile exists if (!config.content) { @@ -47,51 +52,49 @@ export default { ["build_arg"] .filter((opt) => !!config[opt]) .map((opt) => - (Array.isArray(values) ? config[opt] : [config[opt]]).map( - (value) => `--${opt.replace("_", "-")} ${esa(value)}` - ) - ) + (Array.isArray(config[opt]) ? config[opt] : [config[opt]]).map( + (value) => `--${opt.replace("_", "-")} ${esa(value)}`, + ), + ), ), // arguments is a boolean string "--rm=" + (config.rm ? "true" : "false"), "-t " + esa(config.image + (config.tag ? `:${config.tag}` : "")), - config.content != null - ? (log({ - message: - "Building from text: Docker won't have a context. ADD/COPY not working", - level: "WARN", - }), - config.content != null - ? `- < { - const value = config.filters[property]; - if (typeof value === 'string') { - return '--filter ' + esa(property) + "=" + esa(value) - }else if(typeof value === 'boolean'){ - return '--filter ' + esa(property) + "=" + esa(value ? 'true' : 'false') - }else { - throw utils.error('NIKITA_DOCKER_IMAGES_FILTER', [ - 'Unsupported filter value type,', - 'expect a string or a boolean value,', - "got ${JSON.stringify(property)}." - ]) - } + ...Object.keys(config.filters || []).map((property) => { + const value = config.filters[property]; + if (typeof value === "string") { + return "--filter " + esa(property) + "=" + esa(value); + } else if (typeof value === "boolean") { + return ( + "--filter " + + esa(property) + + "=" + + esa(value ? "true" : "false") + ); + } else { + throw utils.error("NIKITA_DOCKER_IMAGES_FILTER", [ + "Unsupported filter value type,", + "expect a string or a boolean value,", + "got ${JSON.stringify(property)}.", + ]); } - ), - ].filter(Boolean).join(' '), + }), + ] + .filter(Boolean) + .join(" "), }) .then(({ data }) => data); return { @@ -38,6 +48,6 @@ export default { }, metadata: { shy: true, - definitions: definitions + definitions: definitions, }, }; diff --git a/packages/docker/lib/inspect/index.js b/packages/docker/lib/inspect/index.js index b4b0fbae9..9212995ae 100644 --- a/packages/docker/lib/inspect/index.js +++ b/packages/docker/lib/inspect/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/docker/lib/kill/index.js b/packages/docker/lib/kill/index.js index 9d7c8059b..47e0379d4 100644 --- a/packages/docker/lib/kill/index.js +++ b/packages/docker/lib/kill/index.js @@ -1,13 +1,16 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status} = await this.docker.tools.execute({ + handler: async function ({ config }) { + const { $status } = await this.docker.tools.execute({ command: `ps | egrep ' ${config.container}$' | grep 'Up'`, - code: [0, 1] + code: [0, 1], }); await this.docker.tools.execute({ $if: $status, @@ -21,7 +24,7 @@ export default { }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/load/index.js b/packages/docker/lib/load/index.js index e62260a9a..8e0437a27 100644 --- a/packages/docker/lib/load/index.js +++ b/packages/docker/lib/load/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -29,17 +33,17 @@ export default { .images({ filters: { dangling: false }, }) - .then(({images}) => + .then(({ images }) => images.map((image) => { if (image.ID === config.checksum) { log( "INFO", - `Image already exist checksum :${config.checksum}, repo:tag \"${image.Repository}:${image.Tag}\"` + `Image already exist checksum :${config.checksum}, repo:tag "${image.Repository}:${image.Tag}"`, ); checksumExists = true; } return `${image.Repository}:${image.Tag}#${image.ID}`; - }) + }), ); // Stop here if matching ID is found if (checksumExists) { @@ -56,7 +60,7 @@ export default { format: "json", }); let status = !images.includes( - `${imageInfo.Repository}:${imageInfo.Tag}#${imageInfo.ID}` + `${imageInfo.Repository}:${imageInfo.Tag}#${imageInfo.ID}`, ); return { $status: status, diff --git a/packages/docker/lib/login/index.js b/packages/docker/lib/login/index.js index 7c2744f07..74f05fe30 100644 --- a/packages/docker/lib/login/index.js +++ b/packages/docker/lib/login/index.js @@ -1,6 +1,11 @@ // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/docker/lib/logout/index.js b/packages/docker/lib/logout/index.js index 2ee0315ab..42b5582c0 100644 --- a/packages/docker/lib/logout/index.js +++ b/packages/docker/lib/logout/index.js @@ -1,21 +1,24 @@ - // Dependencies -import definitions from "./schema.json" with { type: "json" }; import { escapeshellarg as esa } from "@nikitajs/utils/string"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const command = [ - 'logout', - config.registry && esa(config.registry) - ].filter(Boolean).map(' '); + handler: async function ({ config }) { + const command = ["logout", config.registry && esa(config.registry)] + .filter(Boolean) + .map(" "); await this.docker.tools.execute({ - command: command + command: command, }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/pause/index.js b/packages/docker/lib/pause/index.js index f2e3d5298..96b43812d 100644 --- a/packages/docker/lib/pause/index.js +++ b/packages/docker/lib/pause/index.js @@ -1,16 +1,19 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.docker.tools.execute({ - command: `pause ${config.container}` + command: `pause ${config.container}`, }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/ps/index.js b/packages/docker/lib/ps/index.js index 96e500a88..5ff200519 100644 --- a/packages/docker/lib/ps/index.js +++ b/packages/docker/lib/ps/index.js @@ -1,7 +1,12 @@ // Dependencies -import utils from '@nikitajs/core/utils' +import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -12,24 +17,29 @@ export default { command: [ "ps", "--format '{{json .}}'", - config.all && '--all', - ...Object.keys(config.filters || []).map( - (property) => { - const value = config.filters[property]; - if (typeof value === 'string') { - return '--filter ' + esa(property) + "=" + esa(value) - }else if(typeof value === 'boolean'){ - return '--filter ' + esa(property) + "=" + esa(value ? 'true' : 'false') - }else { - throw utils.error('NIKITA_DOCKER_CONTAINERS_FILTER', [ - 'Unsupported filter value type,', - 'expect a string or a boolean value,', - "got ${JSON.stringify(property)}." - ]) - } + config.all && "--all", + ...Object.keys(config.filters || []).map((property) => { + const value = config.filters[property]; + if (typeof value === "string") { + return "--filter " + esa(property) + "=" + esa(value); + } else if (typeof value === "boolean") { + return ( + "--filter " + + esa(property) + + "=" + + esa(value ? "true" : "false") + ); + } else { + throw utils.error("NIKITA_DOCKER_CONTAINERS_FILTER", [ + "Unsupported filter value type,", + "expect a string or a boolean value,", + "got ${JSON.stringify(property)}.", + ]); } - ), - ].filter(Boolean).join(' '), + }), + ] + .filter(Boolean) + .join(" "), }) .then(({ data }) => data); return { @@ -40,6 +50,6 @@ export default { }, metadata: { shy: true, - definitions: definitions + definitions: definitions, }, }; diff --git a/packages/docker/lib/pull/index.js b/packages/docker/lib/pull/index.js index 3eacd2ce7..94fd172b9 100644 --- a/packages/docker/lib/pull/index.js +++ b/packages/docker/lib/pull/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -10,7 +14,7 @@ export default { if (tag && config.tag) { // it can be later changed to give a preference instead of error throw Error( - "Tag must be specified either in the image or in the tag config" + "Tag must be specified either in the image or in the tag config", ); } if (config.tag == null) { diff --git a/packages/docker/lib/register.js b/packages/docker/lib/register.js index 61949e659..c666b8548 100644 --- a/packages/docker/lib/register.js +++ b/packages/docker/lib/register.js @@ -1,43 +1,42 @@ - // Dependencies -import '@nikitajs/file/register'; +import "@nikitajs/file/register"; import registry from "@nikitajs/core/registry"; // Action registration const actions = { docker: { - build: '@nikitajs/docker/build', + build: "@nikitajs/docker/build", compose: { - '': '@nikitajs/docker/compose', - up: '@nikitajs/docker/compose' + "": "@nikitajs/docker/compose", + up: "@nikitajs/docker/compose", }, - cp: '@nikitajs/docker/cp', - exec: '@nikitajs/docker/exec', - images: '@nikitajs/docker/images', - inspect: '@nikitajs/docker/inspect', - kill: '@nikitajs/docker/kill', - load: '@nikitajs/docker/load', - pause: '@nikitajs/docker/pause', - ps: '@nikitajs/docker/ps', - pull: '@nikitajs/docker/pull', - restart: '@nikitajs/docker/restart', - rm: '@nikitajs/docker/rm', - rmi: '@nikitajs/docker/rmi', - run: '@nikitajs/docker/run', - save: '@nikitajs/docker/save', - start: '@nikitajs/docker/start', - stop: '@nikitajs/docker/stop', + cp: "@nikitajs/docker/cp", + exec: "@nikitajs/docker/exec", + images: "@nikitajs/docker/images", + inspect: "@nikitajs/docker/inspect", + kill: "@nikitajs/docker/kill", + load: "@nikitajs/docker/load", + pause: "@nikitajs/docker/pause", + ps: "@nikitajs/docker/ps", + pull: "@nikitajs/docker/pull", + restart: "@nikitajs/docker/restart", + rm: "@nikitajs/docker/rm", + rmi: "@nikitajs/docker/rmi", + run: "@nikitajs/docker/run", + save: "@nikitajs/docker/save", + start: "@nikitajs/docker/start", + stop: "@nikitajs/docker/stop", tools: { - checksum: '@nikitajs/docker/tools/checksum', - execute: '@nikitajs/docker/tools/execute', - service: '@nikitajs/docker/tools/service', - status: '@nikitajs/docker/tools/status' + checksum: "@nikitajs/docker/tools/checksum", + execute: "@nikitajs/docker/tools/execute", + service: "@nikitajs/docker/tools/service", + status: "@nikitajs/docker/tools/status", }, // unpause: '@nikitajs/docker/unpause' - volume_create: '@nikitajs/docker/volume_create', - volume_rm: '@nikitajs/docker/volume_rm', - wait: '@nikitajs/docker/wait' - } + volume_create: "@nikitajs/docker/volume_create", + volume_rm: "@nikitajs/docker/volume_rm", + wait: "@nikitajs/docker/wait", + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/docker/lib/restart/index.js b/packages/docker/lib/restart/index.js index 4840b02fd..269f365c3 100644 --- a/packages/docker/lib/restart/index.js +++ b/packages/docker/lib/restart/index.js @@ -1,16 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.docker.tools.execute({ - command: ['restart', config.timeout != null ? `-t ${config.timeout}` : void 0, `${config.container}`].join(' ') + command: [ + "restart", + config.timeout != null ? `-t ${config.timeout}` : void 0, + `${config.container}`, + ].join(" "), }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/rm/index.js b/packages/docker/lib/rm/index.js index 9ae4d2cc3..301ae0593 100644 --- a/packages/docker/lib/rm/index.js +++ b/packages/docker/lib/rm/index.js @@ -1,42 +1,42 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const { - $status: exists, - data: running - } = await this.docker.tools.execute({ + handler: async function ({ config }) { + const { $status: exists, data: running } = await this.docker.tools.execute({ $templated: false, command: `inspect ${config.container} --format '{{ json .State.Running }}'`, code: [0, 1], - format: 'json' + format: "json", }); if (!exists) { return false; } if (running && !config.force) { - throw Error('Container must be stopped to be removed without force'); + throw Error("Container must be stopped to be removed without force"); } await this.docker.tools.execute({ command: [ - 'rm', - ...(['link', - 'volumes', - 'force'].filter(function(opt) { - return config[opt]; - }).map(function(opt) { - return `-${opt.charAt(0)}`; - })), - config.container - ].join(' ') + "rm", + ...["link", "volumes", "force"] + .filter(function (opt) { + return config[opt]; + }) + .map(function (opt) { + return `-${opt.charAt(0)}`; + }), + config.container, + ].join(" "), }); }, metadata: { - argument_to_config: 'container', - global: 'docker', + argument_to_config: "container", + global: "docker", definitions: definitions, - } + }, }; diff --git a/packages/docker/lib/rmi/index.js b/packages/docker/lib/rmi/index.js index 546426467..907b77cc1 100644 --- a/packages/docker/lib/rmi/index.js +++ b/packages/docker/lib/rmi/index.js @@ -1,10 +1,14 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config }) { - const {$status} = await this.docker.tools.execute({ + const { $status } = await this.docker.tools.execute({ command: [ "images", `| grep '${config.image} '`, diff --git a/packages/docker/lib/run/index.js b/packages/docker/lib/run/index.js index e837b86a5..7943f3274 100644 --- a/packages/docker/lib/run/index.js +++ b/packages/docker/lib/run/index.js @@ -1,6 +1,11 @@ // Dependencies -import definitions from "./schema.json" with { type: "json" }; import utils from "@nikitajs/docker/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -85,7 +90,7 @@ export default { } else { throw utils.error("NIKITA_DOCKER_RUN_INVALID_VALUE", [ `${JSON.stringify( - opt + opt, )} array should only contains string or numberl`, ]); } diff --git a/packages/docker/lib/save/index.js b/packages/docker/lib/save/index.js index e10161944..e79db9d54 100644 --- a/packages/docker/lib/save/index.js +++ b/packages/docker/lib/save/index.js @@ -1,29 +1,34 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { // Saves image to local tmp path, than copy it log({ message: `Extracting image ${config.output} to file:${config.image}`, - level: 'INFO' + level: "INFO", }); await this.docker.tools.execute({ - command: [`save -o ${config.output} ${config.image}`, config.tag != null ? `:${config.tag}` : void 0].join('') + command: [ + `save -o ${config.output} ${config.image}`, + config.tag != null ? `:${config.tag}` : void 0, + ].join(""), }); }, hooks: { - on_action: function({config}) { - return config.output != null ? config.output : config.output = config.target; - } + on_action: function ({ config }) { + return config.output != null ? + config.output + : (config.output = config.target); + }, }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/start/index.js b/packages/docker/lib/start/index.js index d0ead206b..5d62f6d8d 100644 --- a/packages/docker/lib/start/index.js +++ b/packages/docker/lib/start/index.js @@ -1,16 +1,16 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { - const {$status} = await this.docker.tools.status({ + handler: async function ({ config, tools: { log } }) { + const { $status } = await this.docker.tools.status({ container: config.container, - $shy: true + $shy: true, }); if ($status) { log(`Container already started ${config.container} (Skipping)`); @@ -25,7 +25,7 @@ export default { }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/stop/index.js b/packages/docker/lib/stop/index.js index f95ea59f5..247c62f33 100644 --- a/packages/docker/lib/stop/index.js +++ b/packages/docker/lib/stop/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -9,15 +13,9 @@ export default { $shy: true, }); if ($status) { - log({ - message: `Stopping container ${config.container}`, - level: "INFO", - }); + log("INFO", `Stopping container ${config.container}`); } else { - log({ - message: `Container already stopped ${config.container} (Skipping)`, - level: "INFO", - }); + log("INFO", `Container already stopped ${config.container} (Skipping)`); } await this.docker.tools.execute({ $if: $status, diff --git a/packages/docker/lib/tools/checksum/index.js b/packages/docker/lib/tools/checksum/index.js index 231ee3900..aaa879f19 100644 --- a/packages/docker/lib/tools/checksum/index.js +++ b/packages/docker/lib/tools/checksum/index.js @@ -1,38 +1,40 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { - log('DEBUG', `Getting image checksum :${config.image}`); + handler: async function ({ config, tools: { log } }) { + log("DEBUG", `Getting image checksum :${config.image}`); // Run `docker images` with the following config: // - `--no-trunc`: display full checksum // - `--quiet`: discard headers - const {$status, stdout} = await this.docker.tools.execute({ + const { $status, stdout } = await this.docker.tools.execute({ command: `images --no-trunc --quiet ${config.image}:${config.tag}`, }); - const checksum = stdout === '' ? undefined : stdout.toString().trim(); + const checksum = stdout === "" ? undefined : stdout.toString().trim(); if ($status) { - log('INFO', `Image checksum for ${config.image}: ${checksum}`); + log("INFO", `Image checksum for ${config.image}: ${checksum}`); } return { $status: $status, - checksum: checksum + checksum: checksum, }; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.repository) { - throw Error('Configuration `repository` is deprecated, use `image` instead'); + throw Error( + "Configuration `repository` is deprecated, use `image` instead", + ); } - } + }, }, metadata: { definitions: definitions, global: "docker", - } + }, }; diff --git a/packages/docker/lib/tools/execute/index.js b/packages/docker/lib/tools/execute/index.js index 9023dd9cd..d2e5020a1 100644 --- a/packages/docker/lib/tools/execute/index.js +++ b/packages/docker/lib/tools/execute/index.js @@ -1,13 +1,17 @@ - // Dependencies import dedent from "dedent"; import utils from "@nikitajs/docker/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function ({ config, tools: { find } }) { + handler: async function ({ config }) { // Build Docker config.opts = Object.keys(config.opts) .filter((opt) => config.opts[opt] != null) @@ -20,11 +24,11 @@ export default { val = "false"; } if (["tlsverify", "debug"].includes(opt)) { - if(val === "true"){ - return `${esa('--'+opt)}`; + if (val === "true") { + return `${esa("--" + opt)}`; } } else { - return `${esa('--'+opt)}=${esa(val)}`; + return `${esa("--" + opt)}=${esa(val)}`; } }) .join(" "); @@ -45,13 +49,13 @@ export default { fi eval "$(docker-machine env \${machine})" `, - config.compose - ? dedent` + config.compose ? + dedent` opts='${config.opts}' bin=\`command -v docker-compose >/dev/null 2>&1 && echo "docker-compose $opts" || echo "docker $opts compose"\` $bin ${config.command} ` - : `docker ${config.opts} ${config.command}`, + : `docker ${config.opts} ${config.command}`, ] .filter(Boolean) .join("\n"), @@ -62,10 +66,10 @@ export default { } if (/^Error response from daemon/.test(error.stderr)) { throw Error( - error.stderr.trim().replace("Error response from daemon: ", "") + error.stderr.trim().replace("Error response from daemon: ", ""), ); } - throw error + throw error; } }, metadata: { diff --git a/packages/docker/lib/tools/service/index.js b/packages/docker/lib/tools/service/index.js index 206df1648..f279ab0b8 100644 --- a/packages/docker/lib/tools/service/index.js +++ b/packages/docker/lib/tools/service/index.js @@ -1,6 +1,9 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -8,11 +11,11 @@ export default { await this.docker.run({ detach: true, rm: false, - ...config + ...config, }); }, metadata: { definitions: definitions, global: "docker", - } + }, }; diff --git a/packages/docker/lib/tools/status/index.js b/packages/docker/lib/tools/status/index.js index 09850caee..63766cc92 100644 --- a/packages/docker/lib/tools/status/index.js +++ b/packages/docker/lib/tools/status/index.js @@ -1,6 +1,9 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/docker/lib/unpause/index.js b/packages/docker/lib/unpause/index.js index ad4ba0bfa..e8b729173 100644 --- a/packages/docker/lib/unpause/index.js +++ b/packages/docker/lib/unpause/index.js @@ -1,16 +1,19 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: function({config}) { + handler: function ({ config }) { this.docker.tools.execute({ - command: `unpause ${config.container}` + command: `unpause ${config.container}`, }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/utils/docker.js b/packages/docker/lib/utils/docker.js index 19c44602e..fa59befb6 100644 --- a/packages/docker/lib/utils/docker.js +++ b/packages/docker/lib/utils/docker.js @@ -1,4 +1,4 @@ -import dedent from 'dedent'; +import dedent from "dedent"; const options = [ "api-cors-header", diff --git a/packages/docker/lib/utils/index.js b/packages/docker/lib/utils/index.js index ab5c376bd..a9544108e 100644 --- a/packages/docker/lib/utils/index.js +++ b/packages/docker/lib/utils/index.js @@ -1,5 +1,5 @@ import utils from "@nikitajs/core/utils"; -import * as docker from './docker.js'; +import * as docker from "./docker.js"; export default { ...utils, diff --git a/packages/docker/lib/volume_create/index.js b/packages/docker/lib/volume_create/index.js index 002d1eae8..6898026b9 100644 --- a/packages/docker/lib/volume_create/index.js +++ b/packages/docker/lib/volume_create/index.js @@ -1,23 +1,32 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status} = await this.docker.tools.execute({ + handler: async function ({ config }) { + const { $status } = await this.docker.tools.execute({ $if: config.name, $shy: true, command: `volume inspect ${config.name}`, - code: [1, 0] + code: [1, 0], }); await this.docker.tools.execute({ $if: !config.name || $status, - command: ["volume create", config.driver ? `--driver ${config.driver}` : void 0, config.label ? `--label ${config.label.join(',')}` : void 0, config.name ? `--name ${config.name}` : void 0, config.opt ? `--opt ${config.opt.join(',')}` : void 0].join(' ') + command: [ + "volume create", + config.driver ? `--driver ${config.driver}` : void 0, + config.label ? `--label ${config.label.join(",")}` : void 0, + config.name ? `--name ${config.name}` : void 0, + config.opt ? `--opt ${config.opt.join(",")}` : void 0, + ].join(" "), }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/volume_rm/index.js b/packages/docker/lib/volume_rm/index.js index b7e872e8b..4d5d0e851 100644 --- a/packages/docker/lib/volume_rm/index.js +++ b/packages/docker/lib/volume_rm/index.js @@ -1,17 +1,20 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.docker.tools.execute({ command: `volume rm ${config.name}`, - code: [0, 1] + code: [0, 1], }); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/docker/lib/wait/index.js b/packages/docker/lib/wait/index.js index efe7e4269..74966c2c3 100644 --- a/packages/docker/lib/wait/index.js +++ b/packages/docker/lib/wait/index.js @@ -1,15 +1,18 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Old implementation was `wait {container} | read r; return $r` await this.docker.tools.execute(`wait ${config.container}`); }, metadata: { - global: 'docker', - definitions: definitions - } + global: "docker", + definitions: definitions, + }, }; diff --git a/packages/file/lib/cache/index.js b/packages/file/lib/cache/index.js index 58b9bee9f..60259168a 100644 --- a/packages/file/lib/cache/index.js +++ b/packages/file/lib/cache/index.js @@ -1,18 +1,26 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import url from "node:url"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +import { escapeshellarg as esa } from "@nikitajs/utils/string"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_FILE_INVALID_TARGET_HASH: function({config, hash, _hash}) { - return utils.error('NIKITA_FILE_INVALID_TARGET_HASH', [`target ${JSON.stringify(config.target)} got ${JSON.stringify(hash)} instead of ${JSON.stringify(_hash)}.`]); - } + NIKITA_FILE_INVALID_TARGET_HASH: function ({ config, hash, _hash }) { + return utils.error("NIKITA_FILE_INVALID_TARGET_HASH", [ + `target ${JSON.stringify(config.target)} got ${JSON.stringify(hash)} instead of ${JSON.stringify(_hash)}.`, + ]); + }, }; -const protocols_http = ['http:', 'https:']; -const protocols_ftp = ['ftp:', 'ftps:']; +const protocols_http = ["http:", "https:"]; +const protocols_ftp = ["ftp:", "ftps:"]; export { protocols_http, protocols_ftp }; @@ -49,18 +57,17 @@ export default { } const u = url.parse(config.source); if (u.protocol !== null) { - log({ - message: "Bypass source hash computation for non-file protocols", - level: "WARN", - }); + log("WARN", "Bypass source hash computation for non-file protocols"); } else { if (_hash === true) { _hash = await this.fs.hash(config.source); - _hash = (_hash != null ? _hash.hash : void 0) ? _hash.hash : false; - log({ - message: `Computed hash value is '${_hash}'`, - level: "INFO", - }); + _hash = + ( + _hash != null ? _hash.hash : void 0 + ) ? + _hash.hash + : false; + log("INFO", `Computed hash value is '${_hash}'`); } } // Download the file if @@ -68,38 +75,23 @@ export default { // - option force is provided // - hash isnt true and doesnt match const { $status } = await this.call(async function () { - log({ - message: `Check if target (${config.target}) exists`, - level: "DEBUG", - }); + log("DEBUG", `Check if target (${config.target}) exists`); const { exists } = await this.fs.exists({ target: config.target, }); if (exists) { - log({ - message: "Target file exists", - level: "INFO", - }); + log("INFO", "Target file exists"); // If no checksum, we ignore MD5 check if (config.force) { - log({ - message: "Force mode, cache will be overwritten", - level: "DEBUG", - }); + log("DEBUG", "Force mode, cache will be overwritten"); return true; } else if (_hash && typeof _hash === "string") { // then we compute the checksum of the file - log({ - message: `Comparing ${algo} hash`, - level: "DEBUG", - }); + log("DEBUG", `Comparing ${algo} hash`); const { hash } = await this.fs.hash(config.target); // And compare with the checksum provided by the user if (_hash === hash) { - log({ - message: "Hashes match, skipping", - level: "DEBUG", - }); + log("DEBUG", "Hashes match, skipping"); return false; } log({ @@ -111,17 +103,11 @@ export default { }); return true; } else { - log({ - message: "Target file exists, check disabled, skipping", - level: "DEBUG", - }); + log("DEBUG", "Target file exists, check disabled, skipping"); return false; } } else { - log({ - message: "Target file does not exists", - level: "INFO", - }); + log("INFO", "Target file does not exists"); return true; } }); @@ -142,12 +128,14 @@ export default { config.fail ? "--fail" : void 0, u.protocol === "https:" && "--insecure", config.location && "--location", - ...config.http_headers.map(header => `--header ${esa(header)}`), - ...config.cookies.map(cookie => `--cookie ${esa(cookie)}`), + ...config.http_headers.map((header) => `--header ${esa(header)}`), + ...config.cookies.map((cookie) => `--cookie ${esa(cookie)}`), `-s ${config.source}`, `-o ${config.target}`, config.proxy ? `-x ${config.proxy}` : void 0, - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), }); } else { await this.fs.mkdir({ @@ -177,7 +165,7 @@ export default { return {}; }, metadata: { - argument_to_config: 'source', - definitions: definitions - } + argument_to_config: "source", + definitions: definitions, + }, }; diff --git a/packages/file/lib/cson/index.js b/packages/file/lib/cson/index.js index 2a2da9157..d0f23ef46 100644 --- a/packages/file/lib/cson/index.js +++ b/packages/file/lib/cson/index.js @@ -1,41 +1,34 @@ // ## Dependencies -import {merge} from 'mixme'; -import cson from 'cson'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +import cson from "cson"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { if (config.merge) { - log({ - message: "Get Target Content", - level: "DEBUG", - }); + log("DEBUG", "Get Target Content"); try { const { data } = await this.fs.readFile({ target: config.target, encoding: config.encoding, }); config.content = merge(cson.parse(data), config.content); - log({ - message: "Target Merged", - level: "DEBUG", - }); + log("DEBUG", "Target Merged"); } catch (error) { if (error.code !== "NIKITA_FS_CRS_TARGET_ENOENT") { throw error; } // File does not exists, this is ok, there is simply nothing to merge - log({ - message: "No Target To Merged", - level: "DEBUG", - }); + log("DEBUG", "No Target To Merged"); } } - log({ - message: "Serialize Content", - level: "DEBUG", - }); + log("DEBUG", "Serialize Content"); await this.file({ content: cson.stringify(config.content), target: config.target, diff --git a/packages/file/lib/download/index.js b/packages/file/lib/download/index.js index 5d7cd21c7..16b90c700 100644 --- a/packages/file/lib/download/index.js +++ b/packages/file/lib/download/index.js @@ -3,7 +3,12 @@ import fs from "node:fs"; import url from "node:url"; import utils from "@nikitajs/file/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -55,14 +60,15 @@ export default { config.cookies = []; } // Normalization - config.target = config.cwd - ? path.resolve(config.cwd, config.target) + config.target = + config.cwd ? + path.resolve(config.cwd, config.target) : path.normalize(config.target); if (ssh && !path.isAbsolute(config.target)) { throw Error( `Non Absolute Path: target is ${JSON.stringify( - config.target - )}, SSH requires absolute paths, you must provide an absolute path in the target or the cwd option` + config.target, + )}, SSH requires absolute paths, you must provide an absolute path in the target or the cwd option`, ); } // Shortcircuit accelerator: @@ -90,7 +96,7 @@ export default { shortcircuit: false, }; } - } + }, ); if (shortcircuit) { return true; @@ -134,7 +140,7 @@ export default { } } const stageDestination = `${config.target}.${Date.now()}${Math.round( - Math.random() * 1000 + Math.random() * 1000, )}`; if (protocols_http.includes(source_url.protocol) === true) { log("DEBUG", "HTTP download target url"); @@ -166,7 +172,7 @@ export default { // Hash validation // Probably not the best to check hash, it only applies to HTTP for now throw Error( - `Invalid downloaded checksum, found '${hash_source}' instead of '${source_hash}'` + `Invalid downloaded checksum, found '${hash_source}' instead of '${source_hash}'`, ); } const { exists } = await this.fs.exists({ @@ -179,12 +185,12 @@ export default { algo: algo, })); match = hash_source === hash_target; - match - ? log("INFO", `Hash matches as "${hash_source}".`) - : log( - "WARN", - `Hash dont match, source is "${hash_source}" and target is "${hash_target}".` - ); + match ? + log("INFO", `Hash matches as "${hash_source}".`) + : log( + "WARN", + `Hash dont match, source is "${hash_source}" and target is "${hash_target}".`, + ); if (match) { await this.fs.remove({ $shy: true, @@ -192,9 +198,12 @@ export default { }); } } else if (protocols_http.includes(source_url.protocol) === false && !ssh) { - log("DEBUG", `File download without ssh (cache ${ + log( + "DEBUG", + `File download without ssh (cache ${ config.cache ? "enabled" : "disabled" - })`); + })`, + ); const { hash: hash_source } = await this.fs.hash({ target: config.source, algo: algo, @@ -209,12 +218,12 @@ export default { algo: algo, })); match = hash_source === hash_target; - match - ? log("INFO", `Hash matches as "${hash_source}".`) - : log( - "WARN", - `Hash dont match, source is "${hash_source}" and target is "${hash_target}".` - ); + match ? + log("INFO", `Hash matches as "${hash_source}".`) + : log( + "WARN", + `Hash dont match, source is "${hash_source}" and target is "${hash_target}".`, + ); if (!match) { await this.fs.mkdir({ $shy: true, @@ -226,9 +235,12 @@ export default { }); } } else if (protocols_http.includes(source_url.protocol) === false && ssh) { - log("DEBUG", `File download with ssh (cache ${ + log( + "DEBUG", + `File download with ssh (cache ${ config.cache ? "enabled" : "disabled" - })`); + })`, + ); const { hash: hash_source } = await this.fs.hash({ $ssh: false, $sudo: false, @@ -245,12 +257,12 @@ export default { algo: algo, })); match = hash_source === hash_target; - match - ? log("INFO", `Hash matches as "${hash_source}".`) - : log( - "WARN", - `Hash dont match, source is "${hash_source}" and target is "${hash_target}".` - ); + match ? + log("INFO", `Hash matches as "${hash_source}".`) + : log( + "WARN", + `Hash dont match, source is "${hash_source}" and target is "${hash_target}".`, + ); if (!match) { await this.fs.mkdir({ $shy: true, @@ -266,15 +278,15 @@ export default { log( "INFO", `Downloaded local source ${JSON.stringify( - config.source - )} to remote target ${JSON.stringify(stageDestination)}.` + config.source, + )} to remote target ${JSON.stringify(stageDestination)}.`, ); } catch (error) { log( "ERROR", `Downloaded local source ${JSON.stringify( - config.source - )} to remote target ${JSON.stringify(stageDestination)} failed.` + config.source, + )} to remote target ${JSON.stringify(stageDestination)} failed.`, ); throw error; } @@ -305,7 +317,7 @@ export default { on_action: async function ({ config, tools: { find } }) { config.cache = await find(({ config: { cache } }) => cache); config.cache_file = await find( - ({ config: { cache_file } }) => cache_file + ({ config: { cache_file } }) => cache_file, ); config.cache_dir = await find(({ config: { cache_dir } }) => cache_dir); if (/^file:\/\//.test(config.source)) { diff --git a/packages/file/lib/index.js b/packages/file/lib/index.js index f6f1003ca..ca749973b 100644 --- a/packages/file/lib/index.js +++ b/packages/file/lib/index.js @@ -1,7 +1,12 @@ // Dependencies import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -70,7 +75,7 @@ export default { const source = config.source || config.target; log( "DEBUG", - `Force local source is \`${config.local ? "true" : "false"}\`.` + `Force local source is \`${config.local ? "true" : "false"}\`.`, ); const { exists } = await this.fs.exists({ $ssh: config.local ? false : undefined, @@ -80,7 +85,7 @@ export default { if (!exists) { if (config.source) { throw Error( - `Source does not exist: ${JSON.stringify(config.source)}` + `Source does not exist: ${JSON.stringify(config.source)}`, ); } config.content = ""; @@ -156,7 +161,7 @@ export default { } return null; } - } + }, ); if (config.transform) { // if the transform function returns null or undefined, the file is not written @@ -169,7 +174,7 @@ export default { log("DEBUG", "Remove empty lines."); config.content = config.content.replace( /(\r\n|[\n\r\u0085\u2028\u2029])\s*(\r\n|[\n\r\u0085\u2028\u2029])/g, - "$1" + "$1", ); } if (config.write.length) { @@ -194,7 +199,7 @@ export default { } log( "INFO", - `Option eof is true, guessing as ${JSON.stringify(config.eof)}.` + `Option eof is true, guessing as ${JSON.stringify(config.eof)}.`, ); } if (!utils.string.endsWith(config.content, config.eof)) { @@ -211,10 +216,10 @@ export default { targetContentHash = utils.string.hash(targetContent); } const contentChanged = - config.content != null - ? targetStats == null || - targetContentHash !== utils.string.hash(config.content) - : false; + config.content != null ? + targetStats == null || + targetContentHash !== utils.string.hash(config.content) + : false; if (contentChanged) { const { raw, text } = utils.diff(targetContent, config.content, config); if (typeof config.diff === "function") { diff --git a/packages/file/lib/ini/index.js b/packages/file/lib/ini/index.js index 76fe315a3..b27ceb1a3 100644 --- a/packages/file/lib/ini/index.js +++ b/packages/file/lib/ini/index.js @@ -1,12 +1,16 @@ // Dependencies import utils from "@nikitajs/file/utils"; -import {merge} from 'mixme'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { - let content; let org_props = {}; const parse = config.parse || utils.ini.parse; const stringify = config.stringify || utils.ini.stringify; @@ -32,7 +36,7 @@ export default { target: config.source, encoding: config.encoding, }); - content = utils.object.clean(config.content, true); + // content = utils.object.clean(config.content, true); config.content = merge(parse(data, config), config.content); } } catch (error) { @@ -43,22 +47,13 @@ export default { // Merge if (config.merge) { config.content = merge(org_props, config.content); - log({ - message: "Get content for merge", - level: "DEBUG", - }); + log("DEBUG", "Get content for merge"); } if (config.clean) { - log({ - message: "Clean content", - level: "INFO", - }); + log("Clean content"); utils.object.clean(config.content); } - log({ - message: "Serialize content", - level: "DEBUG", - }); + log("DEBUG", "Serialize content"); return await this.file({ target: config.target, content: stringify(config.content, config), diff --git a/packages/file/lib/ini/read/index.js b/packages/file/lib/ini/read/index.js index 12cb72289..0ea182260 100644 --- a/packages/file/lib/ini/read/index.js +++ b/packages/file/lib/ini/read/index.js @@ -1,21 +1,26 @@ // Dependencies -import {merge} from 'mixme'; +import { merge } from "mixme"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { const parse = config.parse || utils.ini.parse; - const {data} = (await this.fs.readFile({ + const { data } = await this.fs.readFile({ target: config.target, - encoding: config.encoding - })); + encoding: config.encoding, + }); return { - data: merge(parse(data, config)) + data: merge(parse(data, config)), }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/json/index.js b/packages/file/lib/json/index.js index 766e41345..a8f0e29c7 100644 --- a/packages/file/lib/json/index.js +++ b/packages/file/lib/json/index.js @@ -1,29 +1,34 @@ // Dependencies -import {merge} from 'mixme'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.merge) { try { - const {data} = await this.fs.readFile({ + const { data } = await this.fs.readFile({ target: config.target, - encoding: 'utf8' + encoding: "utf8", }); config.content = merge(JSON.parse(data), config.content); } catch (error) { - if (error.code !== 'NIKITA_FS_CRS_TARGET_ENOENT') { + if (error.code !== "NIKITA_FS_CRS_TARGET_ENOENT") { throw error; } } } if (config.source) { - const {data} = await this.fs.readFile({ + const { data } = await this.fs.readFile({ $ssh: config.local ? false : void 0, $sudo: config.local ? false : void 0, target: config.source, - encoding: 'utf8' + encoding: "utf8", }); config.content = merge(JSON.parse(data), config.content); } @@ -32,7 +37,7 @@ export default { } await this.file({ target: config.target, - content: function() { + content: function () { return JSON.stringify(config.content, null, config.pretty); }, backup: config.backup, @@ -40,18 +45,18 @@ export default { eof: config.eof, gid: config.gid, uid: config.uid, - mode: config.mode + mode: config.mode, }); return {}; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.pretty === true) { - return config.pretty = 2; + return (config.pretty = 2); } - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/properties/index.js b/packages/file/lib/properties/index.js index e49b6ba30..091b31c2f 100644 --- a/packages/file/lib/properties/index.js +++ b/packages/file/lib/properties/index.js @@ -1,18 +1,19 @@ // Dependencies import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { // Trim - let fnl_props = config.trim - ? utils.object.trim(config.content) - : config.content; - log({ - message: `Merging \"${config.merge ? "true" : "false"}\"`, - level: "DEBUG", - }); + let fnl_props = + config.trim ? utils.object.trim(config.content) : config.content; + log("DEBUG", `Merging "${config.merge ? "true" : "false"}"`); // Read Original const { exists } = await this.fs.exists({ target: config.target, @@ -38,10 +39,10 @@ export default { } for (const key of Object.keys(keys)) { if (`${org_props[key]}` !== `${fnl_props[key]}`) { - log({ - message: `Property '${key}' was '${org_props[key]}' and is now '${fnl_props[key]}'`, - level: "WARN", - }); + log( + "WARN", + `Property '${key}' was '${org_props[key]}' and is now '${fnl_props[key]}'`, + ); if (fnl_props[key] != null) { status = true; } @@ -52,19 +53,17 @@ export default { // Merge if (config.merge) { for (const k in fnl_props) { - const v = fnl_props[k]; org_props[k] = fnl_props[k]; } fnl_props = org_props; } // Write data - const keys = config.sort - ? Object.keys(fnl_props).sort() - : Object.keys(fnl_props); + const keys = + config.sort ? Object.keys(fnl_props).sort() : Object.keys(fnl_props); const data = keys.map((key) => - fnl_props[key] != null - ? `${key}${config.separator}${fnl_props[key]}` - : `${key}` + fnl_props[key] != null ? + `${key}${config.separator}${fnl_props[key]}` + : `${key}`, ); await this.file({ $shy: true, diff --git a/packages/file/lib/properties/read/index.js b/packages/file/lib/properties/read/index.js index ff4f00c6b..84ba1e077 100644 --- a/packages/file/lib/properties/read/index.js +++ b/packages/file/lib/properties/read/index.js @@ -1,28 +1,35 @@ // Dependencies import quote from "regexp-quote"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Actions export default { - handler: async function({config}) { - const {data} = (await this.fs.readFile({ + handler: async function ({ config }) { + const { data } = await this.fs.readFile({ target: config.target, - encoding: config.encoding - })); + encoding: config.encoding, + }); const properties = {}; // Parse const lines = data.split(/\r\n|[\n\r\u0085\u2028\u2029]/g); for (const line of lines) { - if (/^\s*$/.test(line)) { // Empty line + if (/^\s*$/.test(line)) { + // Empty line continue; } - if (/^#/.test(line)) { // Comment + if (/^#/.test(line)) { + // Comment if (config.comment) { properties[line] = null; } continue; } - let [_, k, v] = RegExp(`^(.*?)${quote(config.separator)}(.*)$`).exec(line); + let [, k, v] = RegExp(`^(.*?)${quote(config.separator)}(.*)$`).exec(line); if (config.trim) { k = k.trim(); } @@ -32,10 +39,10 @@ export default { properties[k] = v; } return { - properties: properties + properties: properties, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/register.js b/packages/file/lib/register.js index d61211142..2b0512f85 100644 --- a/packages/file/lib/register.js +++ b/packages/file/lib/register.js @@ -1,43 +1,42 @@ - // Dependencies import registry from "@nikitajs/core/registry"; // Action registration const actions = { file: { - '': '@nikitajs/file', - cache: '@nikitajs/file/cache', - cson: '@nikitajs/file/cson', - download: '@nikitajs/file/download', + "": "@nikitajs/file", + cache: "@nikitajs/file/cache", + cson: "@nikitajs/file/cson", + download: "@nikitajs/file/download", ini: { - '': '@nikitajs/file/ini', - 'read': '@nikitajs/file/ini/read' + "": "@nikitajs/file/ini", + read: "@nikitajs/file/ini/read", }, - json: '@nikitajs/file/json', + json: "@nikitajs/file/json", properties: { - '': '@nikitajs/file/properties', - read: '@nikitajs/file/properties/read' + "": "@nikitajs/file/properties", + read: "@nikitajs/file/properties/read", }, - render: '@nikitajs/file/render', - touch: '@nikitajs/file/touch', + render: "@nikitajs/file/render", + touch: "@nikitajs/file/touch", types: { - 'systemd': { - 'resolved': '@nikitajs/file/types/systemd/resolved', - 'timesyncd': '@nikitajs/file/types/systemd/timesyncd' + systemd: { + resolved: "@nikitajs/file/types/systemd/resolved", + timesyncd: "@nikitajs/file/types/systemd/timesyncd", }, - 'ceph_conf': '@nikitajs/file/types/ceph_conf', - 'hfile': '@nikitajs/file/types/hfile', - 'krb5_conf': '@nikitajs/file/types/krb5_conf', - 'locale_gen': '@nikitajs/file/types/locale_gen', - 'my_cnf': '@nikitajs/file/types/my_cnf', - 'pacman_conf': '@nikitajs/file/types/pacman_conf', - 'ssh_authorized_keys': '@nikitajs/file/types/ssh_authorized_keys', - 'wireguard_conf': '@nikitajs/file/types/wireguard_conf', - 'yum_repo': '@nikitajs/file/types/yum_repo' + ceph_conf: "@nikitajs/file/types/ceph_conf", + hfile: "@nikitajs/file/types/hfile", + krb5_conf: "@nikitajs/file/types/krb5_conf", + locale_gen: "@nikitajs/file/types/locale_gen", + my_cnf: "@nikitajs/file/types/my_cnf", + pacman_conf: "@nikitajs/file/types/pacman_conf", + ssh_authorized_keys: "@nikitajs/file/types/ssh_authorized_keys", + wireguard_conf: "@nikitajs/file/types/wireguard_conf", + yum_repo: "@nikitajs/file/types/yum_repo", }, - upload: '@nikitajs/file/upload', - yaml: '@nikitajs/file/yaml' - } + upload: "@nikitajs/file/upload", + yaml: "@nikitajs/file/yaml", + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/file/lib/render/index.js b/packages/file/lib/render/index.js index 3d30be36d..b75ffcdbe 100644 --- a/packages/file/lib/render/index.js +++ b/packages/file/lib/render/index.js @@ -1,7 +1,12 @@ // Dependencies -import path from 'node:path' -import handlebars from 'handlebars'; -import definitions from "./schema.json" with { type: "json" }; +import path from "node:path"; +import handlebars from "handlebars"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -19,10 +24,7 @@ export default { config.content = data; } } - log({ - message: `Rendering with ${config.engine}`, - level: "DEBUG", - }); + log("DEBUG", `Rendering with ${config.engine}`); config.transform = function ({ config }) { const template = handlebars.compile(config.content.toString()); return template(config.context); @@ -43,7 +45,7 @@ export default { return (config.engine = "handlebars"); default: throw Error( - `Invalid Option: extension '${extension}' is not supported` + `Invalid Option: extension '${extension}' is not supported`, ); } } diff --git a/packages/file/lib/touch/index.js b/packages/file/lib/touch/index.js index f825cf8b8..df4588475 100644 --- a/packages/file/lib/touch/index.js +++ b/packages/file/lib/touch/index.js @@ -1,22 +1,20 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { const { $status } = await this.call(async function () { - log({ - message: `Check if target exists \"${config.target}\"`, - level: "DEBUG", - }); + log("DEBUG", `Check if target exists "${config.target}"`); const { exists } = await this.fs.exists({ target: config.target, }); if (!exists) { - log({ - message: "Destination does not exists", - level: "INFO", - }); + log("Destination does not exists"); } return !exists; }); diff --git a/packages/file/lib/types/ceph_conf/index.js b/packages/file/lib/types/ceph_conf/index.js index c153ef291..9e20da331 100644 --- a/packages/file/lib/types/ceph_conf/index.js +++ b/packages/file/lib/types/ceph_conf/index.js @@ -1,11 +1,16 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.rootdir) { config.target = `${path.join(config.rootdir, config.target)}`; } @@ -15,10 +20,10 @@ export default { parse: utils.ini.parse_multi_brackets, escape: false, }, - config + config, ); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/hfile/index.js b/packages/file/lib/types/hfile/index.js index 645ea1e60..575603d76 100644 --- a/packages/file/lib/types/hfile/index.js +++ b/packages/file/lib/types/hfile/index.js @@ -1,6 +1,11 @@ // Dependencies -import definitions from "./schema.json" with { type: "json" }; import utils from "@nikitajs/file/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -55,7 +60,7 @@ export default { level: "DEBUG", }); for (const k in config.source) { - const v = config.source[k]; + let v = config.source[k]; if (typeof v === "number") { v = `${v}`; } @@ -70,7 +75,7 @@ export default { level: "DEBUG", }); for (const k in config.properties) { - const v = config.properties[k]; + let v = config.properties[k]; if (typeof v === "number") { v = `${v}`; } @@ -107,7 +112,7 @@ export default { level: "WARN", }); } - if(exists && Object.keys(keys).length === 0){ + if (exists && Object.keys(keys).length === 0) { log({ message: `No properties to write.`, level: "DEBUG", diff --git a/packages/file/lib/types/krb5_conf/index.js b/packages/file/lib/types/krb5_conf/index.js index 252c89882..d28e33baa 100644 --- a/packages/file/lib/types/krb5_conf/index.js +++ b/packages/file/lib/types/krb5_conf/index.js @@ -1,16 +1,24 @@ // Dependencies import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - return await this.file.ini({ - parse: utils.ini.parse_brackets_then_curly, - stringify: utils.ini.stringify_brackets_then_curly - }, config); + handler: async function ({ config }) { + return await this.file.ini( + { + parse: utils.ini.parse_brackets_then_curly, + stringify: utils.ini.stringify_brackets_then_curly, + }, + config, + ); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/locale_gen/index.js b/packages/file/lib/types/locale_gen/index.js index 498aa36e8..d662395a1 100644 --- a/packages/file/lib/types/locale_gen/index.js +++ b/packages/file/lib/types/locale_gen/index.js @@ -1,32 +1,37 @@ // Dependencies -import path from 'node:path' -import definitions from "./schema.json" with { type: "json" }; +import path from "node:path"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.rootdir) { config.target = `${path.join(config.rootdir, config.target)}`; } // Write configuration - const {data} = await this.fs.readFile({ + const { data } = await this.fs.readFile({ target: config.target, - encoding: 'ascii' + encoding: "ascii", }); let status = false; - const locales = data.split('\n'); + const locales = data.split("\n"); for (const i in locales) { - const locale = locales[i] + const locale = locales[i]; let match; - if (match = /^#([\w_\-\.]+)($| .+$)/.exec(locale)) { + if ((match = /^#([\w_\-.]+)($| .+$)/.exec(locale))) { if (config.locales.includes(match[1]) === true) { locales[i] = match[1] + match[2]; status = true; } } - if (match = /^([\w_\-\.]+)($| .+$)/.exec(locale)) { + if ((match = /^([\w_\-.]+)($| .+$)/.exec(locale))) { if (config.locales.includes(match[1]) === false) { - locales[i] = '#' + match[1] + match[2]; + locales[i] = "#" + match[1] + match[2]; status = true; } } @@ -34,20 +39,20 @@ export default { if (status) { await this.fs.writeFile({ target: config.target, - content: locales.join('\n') + content: locales.join("\n"), }); } // Reload configuration await this.execute({ $if: config.generate != null ? config.generate : status, rootdir: config.rootdir, - command: "locale-gen" + command: "locale-gen", }); return { - $status: status || config.generate + $status: status || config.generate, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/my_cnf/index.js b/packages/file/lib/types/my_cnf/index.js index 11bcbc78e..55f68cd6a 100644 --- a/packages/file/lib/types/my_cnf/index.js +++ b/packages/file/lib/types/my_cnf/index.js @@ -1,15 +1,23 @@ // Dependencies import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - return await this.file.ini({ - stringify: utils.ini.stringify_single_key - }, config); + handler: async function ({ config }) { + return await this.file.ini( + { + stringify: utils.ini.stringify_single_key, + }, + config, + ); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/pacman_conf/index.js b/packages/file/lib/types/pacman_conf/index.js index 48ba5e166..1bac22f2d 100644 --- a/packages/file/lib/types/pacman_conf/index.js +++ b/packages/file/lib/types/pacman_conf/index.js @@ -1,19 +1,27 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.rootdir) { config.target = `${path.join(config.rootdir, config.target)}`; } - return await this.file.ini({ - stringify: utils.ini.stringify_single_key - }, utils.object.filter(config, ['rootdir'])); + return await this.file.ini( + { + stringify: utils.ini.stringify_single_key, + }, + utils.object.filter(config, ["rootdir"]), + ); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/ssh_authorized_keys/index.js b/packages/file/lib/types/ssh_authorized_keys/index.js index d1ca5bd9a..a06bae842 100644 --- a/packages/file/lib/types/ssh_authorized_keys/index.js +++ b/packages/file/lib/types/ssh_authorized_keys/index.js @@ -1,39 +1,44 @@ // ## Dependencies -import path from 'node:path' +import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.fs.assert({ - target: path.dirname(config.target) + target: path.dirname(config.target), }); if (config.merge) { await this.file({ target: config.target, - write: config.keys.map(key => ({ - match: new RegExp(`.*${utils.regexp.escape(key)}.*`, 'mg'), + write: config.keys.map((key) => ({ + match: new RegExp(`.*${utils.regexp.escape(key)}.*`, "mg"), replace: key, - append: true + append: true, })), uid: config.uid, gid: config.gid, mode: config.mode, - eof: true + eof: true, }); } else { await this.file({ target: config.target, - content: config.keys.join('\n'), + content: config.keys.join("\n"), uid: config.uid, gid: config.gid, mode: config.mode, - eof: true + eof: true, }); } }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/systemd/resolved/index.js b/packages/file/lib/types/systemd/resolved/index.js index 09f63594b..cb24fd031 100644 --- a/packages/file/lib/types/systemd/resolved/index.js +++ b/packages/file/lib/types/systemd/resolved/index.js @@ -1,7 +1,12 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -29,7 +34,7 @@ export default { merge: config.merge, }); await this.execute({ - $if: config.reload != null ? config.reload : $status, + $if: config.reload != null ? config.reload : $status, sudo: true, command: dedent` systemctl daemon-reload diff --git a/packages/file/lib/types/systemd/timesyncd/index.js b/packages/file/lib/types/systemd/timesyncd/index.js index f5be9773b..524870e84 100644 --- a/packages/file/lib/types/systemd/timesyncd/index.js +++ b/packages/file/lib/types/systemd/timesyncd/index.js @@ -1,11 +1,16 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.rootdir) { config.target = `${path.join(config.rootdir, config.target)}`; } @@ -16,14 +21,14 @@ export default { config.content.FallbackNTP = config.content.FallbackNTP.join(" "); } // Write configuration - const {$status} = (await this.file.ini({ + const { $status } = await this.file.ini({ separator: "=", target: config.target, content: { - 'Time': config.content + Time: config.content, }, - merge: config.merge - })); + merge: config.merge, + }); await this.execute({ $if: config.reload != null ? config.reload : $status, sudo: true, @@ -35,6 +40,6 @@ export default { }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/wireguard_conf/index.js b/packages/file/lib/types/wireguard_conf/index.js index 031fccd70..33056bbb9 100644 --- a/packages/file/lib/types/wireguard_conf/index.js +++ b/packages/file/lib/types/wireguard_conf/index.js @@ -1,11 +1,16 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.target == null) { config.target = `/etc/wireguard/${config.interface}.conf`; } @@ -16,10 +21,10 @@ export default { parse: utils.ini.parse_multi_brackets, stringify: utils.ini.stringify_multi_brackets, indent: "", - ...utils.object.filter(config, ['interface', 'rootdir']), + ...utils.object.filter(config, ["interface", "rootdir"]), }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/file/lib/types/yum_repo/index.js b/packages/file/lib/types/yum_repo/index.js index 4a56bb110..25e2a058d 100644 --- a/packages/file/lib/types/yum_repo/index.js +++ b/packages/file/lib/types/yum_repo/index.js @@ -1,7 +1,12 @@ // Dependencies import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/file/lib/upload/index.js b/packages/file/lib/upload/index.js index 2f46607f3..6595fd2f0 100644 --- a/packages/file/lib/upload/index.js +++ b/packages/file/lib/upload/index.js @@ -1,17 +1,19 @@ // Dependencies -import fs from 'node:fs' -import path from 'node:path' +import fs from "node:fs"; +import path from "node:path"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { const algo = config.sha1 != null ? "sha1" : "md5"; - log({ - message: `Source is \"${config.source}\", target is \"${config.target}\"`, - level: "DEBUG", - }); + log("DEBUG", `Source is "${config.source}", target is "${config.target}"`); // Stat the target and redefine its path if a directory const stats = await this.call( { @@ -32,14 +34,14 @@ export default { // Target is invalid throw Error( `Invalid Target: expect a file, a symlink or a directory for ${JSON.stringify( - config.target - )}` + config.target, + )}`, ); } // Target is a directory config.target = path.resolve( config.target, - path.basename(config.source) + path.basename(config.source), ); try { const { stats } = await this.fs.stat({ @@ -63,11 +65,11 @@ export default { } throw error; } - } + }, ); // Now that we know the real name of the target, define a temporary file to write const stage_target = `${config.target}.${Date.now()}${Math.round( - Math.random() * 1000 + Math.random() * 1000, )}`; const { $status } = await this.call(async function () { if (!stats) { @@ -85,15 +87,12 @@ export default { }); const match = hash_source === hash_target; log( - match - ? { - message: `Hash matches as '${hash_source}'`, - level: "INFO", - } - : { - message: `Hash dont match, source is '${hash_source}' and target is '${hash_target}'`, - level: "WARN", - } + match ? + `Hash matches as '${hash_source}'` + : { + message: `Hash dont match, source is '${hash_source}' and target is '${hash_target}'`, + level: "WARN", + }, ); return !match; }); diff --git a/packages/file/lib/utils/diff.js b/packages/file/lib/utils/diff.js index 788266eb4..552ed766d 100644 --- a/packages/file/lib/utils/diff.js +++ b/packages/file/lib/utils/diff.js @@ -10,12 +10,12 @@ import { diffLines } from "diff"; import string from "@nikitajs/utils/string"; // Utils -export default function(oldStr, newStr) { +export default function (oldStr, newStr) { if (oldStr == null) { - oldStr = ''; + oldStr = ""; } if (newStr == null) { - newStr = ''; + newStr = ""; } const lines = diffLines(oldStr, newStr); let text = []; @@ -35,19 +35,21 @@ export default function(oldStr, newStr) { if (line.added) { for (const line of ls) { count_added++; - text.push(`${pad(padsize, '' + count_added)} + ${line}`); + text.push(`${pad(padsize, "" + count_added)} + ${line}`); } } else { for (const line of ls) { count_removed++; - text.push(`${pad(padsize, '' + count_removed)} - ${line}`); + text.push(`${pad(padsize, "" + count_removed)} - ${line}`); } } } return { raw: lines, - text: text.map(function(t) { - return `${t}\n`; - }).join('') + text: text + .map(function (t) { + return `${t}\n`; + }) + .join(""), }; -}; +} diff --git a/packages/file/lib/utils/hfile.js b/packages/file/lib/utils/hfile.js index ebb4aeb8f..91102047d 100644 --- a/packages/file/lib/utils/hfile.js +++ b/packages/file/lib/utils/hfile.js @@ -1,6 +1,5 @@ - -import xmldom from 'xmldom'; -import builder from 'xmlbuilder'; +import xmldom from "xmldom"; +import builder from "xmlbuilder"; export default { /* @@ -11,28 +10,28 @@ export default { Retrieve all properties: `properties = parse(xml)` Retrieve a single property: `value = parse(xml, property)` */ - parse: function(markup, property) { + parse: function (markup, property) { const properties = {}; const doc = new xmldom.DOMParser().parseFromString(markup); for (const i in doc.documentElement.childNodes) { - const propertyChild = doc.documentElement.childNodes[i] - if (propertyChild.tagName?.toUpperCase() !== 'PROPERTY') { + const propertyChild = doc.documentElement.childNodes[i]; + if (propertyChild.tagName?.toUpperCase() !== "PROPERTY") { continue; } let name, value; for (const j in propertyChild.childNodes) { const child = propertyChild.childNodes[j]; - if (child.tagName?.toUpperCase() === 'NAME') { + if (child.tagName?.toUpperCase() === "NAME") { name = child.childNodes[0].nodeValue; } - if (child.tagName?.toUpperCase() === 'VALUE') { - value = child.childNodes[0].nodeValue || ''; + if (child.tagName?.toUpperCase() === "VALUE") { + value = child.childNodes[0].nodeValue || ""; } } if (property && name === property && value != null) { return value; } - if (name && (value != null)) { + if (name && value != null) { properties[name] = value; } } @@ -60,30 +59,30 @@ export default { }]) ``` */ - stringify: function(properties) { - const markup = builder.create('configuration', { - version: '1.0', - encoding: 'UTF-8' + stringify: function (properties) { + const markup = builder.create("configuration", { + version: "1.0", + encoding: "UTF-8", }); if (Array.isArray(properties)) { - properties.sort(function(el1, el2) { + properties.sort(function (el1, el2) { return el1.name > el2.name; }); - for (const {name, value} of properties) { - const property = markup.ele('property'); - property.ele('name', name); - property.ele('value', value); + for (const { name, value } of properties) { + const property = markup.ele("property"); + property.ele("name", name); + property.ele("value", value); } } else { const ks = Object.keys(properties).sort(); for (const k of ks) { - const property = markup.ele('property'); - property.ele('name', k); - property.ele('value', properties[k]); + const property = markup.ele("property"); + property.ele("name", k); + property.ele("value", properties[k]); } } return markup.end({ - pretty: true + pretty: true, }); }, -} +}; diff --git a/packages/file/lib/utils/index.js b/packages/file/lib/utils/index.js index e9f5ba43f..3d97a4a82 100644 --- a/packages/file/lib/utils/index.js +++ b/packages/file/lib/utils/index.js @@ -1,9 +1,8 @@ - import utils from "@nikitajs/core/utils"; -import diff from '@nikitajs/file/utils/diff'; -import hfile from '@nikitajs/file/utils/hfile'; -import ini from '@nikitajs/file/utils/ini'; -import partial from '@nikitajs/file/utils/partial'; +import diff from "@nikitajs/file/utils/diff"; +import hfile from "@nikitajs/file/utils/hfile"; +import ini from "@nikitajs/file/utils/ini"; +import partial from "@nikitajs/file/utils/partial"; export { diff, hfile, ini, partial }; diff --git a/packages/file/lib/utils/ini.js b/packages/file/lib/utils/ini.js index c8e03acee..6c79e240e 100644 --- a/packages/file/lib/utils/ini.js +++ b/packages/file/lib/utils/ini.js @@ -151,7 +151,7 @@ const parse_multi_brackets_multi_lines = function (str, options = {}) { const comment = options.comment || ";"; let writing = false; let previous = {}; - utils.string.lines(str).forEach(function (line, _, __) { + utils.string.lines(str).forEach(function (line) { if (!line || line.match(/^\s*$/)) { return; } @@ -231,7 +231,6 @@ const stringify = function (obj, section, options = {}) { } else if (typeof val === "boolean") { if (val === true) { return (out += safe(k) + options.eol); - } else { } } else { // disregard false value @@ -247,7 +246,7 @@ const stringify = function (obj, section, options = {}) { const child = stringify( obj[k], (section ? section + "." : "") + nk, - options + options, ); if (out.length && child.length) { out += options.eol; @@ -277,17 +276,17 @@ const stringify_single_key = function (obj, section, options = {}) { if (val && Array.isArray(val)) { return val.forEach(function (item) { return (out += - val === "" || val === true - ? `${k}` + "\n" - : safe(`${k}[]`) + options.separator + safe(item) + "\n"); + val === "" || val === true ? + `${k}` + "\n" + : safe(`${k}[]`) + options.separator + safe(item) + "\n"); }); } else if (val && typeof val === "object") { return children.push(k); } else { return (out += - val === "" || val === true - ? `${k}` + options.eol - : safe(k) + options.separator + safe(val) + options.eol); + val === "" || val === true ? + `${k}` + options.eol + : safe(k) + options.separator + safe(val) + options.eol); } }); if (section && out.length) { @@ -298,7 +297,7 @@ const stringify_single_key = function (obj, section, options = {}) { const child = stringify_single_key( obj[k], (section ? section + "." : "") + nk, - options + options, ); if (out.length && child.length) { out += options.eol; @@ -311,7 +310,7 @@ const stringify_single_key = function (obj, section, options = {}) { const stringify_brackets_then_curly = function ( content, depth = 0, - options = {} + options = {}, ) { if (arguments.length === 2) { options = depth; @@ -336,19 +335,11 @@ const stringify_brackets_then_curly = function ( if (isObj) { if (depth === 0) { out += `${prefix}[${k}]${options.eol}`; - out += stringify_brackets_then_curly( - v, - depth + 1, - options - ); + out += stringify_brackets_then_curly(v, depth + 1, options); out += `${options.eol}`; } else { out += `${prefix}${k}${options.separator}{${options.eol}`; - out += stringify_brackets_then_curly( - v, - depth + 1, - options - ); + out += stringify_brackets_then_curly(v, depth + 1, options); out += `${prefix}}${options.eol}`; } } else { @@ -409,7 +400,7 @@ const stringify_multi_brackets = function (content, depth = 0, options = {}) { .map(function (vv) { if (typeof vv !== "string") { throw Error( - `Stringify Invalid Value: expect a string for key ${k}, got ${vv}` + `Stringify Invalid Value: expect a string for key ${k}, got ${vv}`, ); } return `${prefix}${k}${options.separator}${vv}`; diff --git a/packages/file/lib/utils/partial.js b/packages/file/lib/utils/partial.js index c6998f79b..b17e0a622 100644 --- a/packages/file/lib/utils/partial.js +++ b/packages/file/lib/utils/partial.js @@ -10,8 +10,8 @@ Replace partial elements in a text. import utils from "@nikitajs/core/utils"; // Utils -export default function(config, log) { - if(!config.write?.length > 0) return; +export default function (config, log) { + if (!config.write?.length > 0) return; log("DEBUG", "Replacing sections of the file"); // let orgContent; for (const opts of config.write) { @@ -19,24 +19,26 @@ export default function(config, log) { if (opts.match == null) { opts.match = opts.replace; } - if (typeof opts.match === 'string') { + if (typeof opts.match === "string") { log("DEBUG", "Convert match string to regexp"); } - if (typeof opts.match === 'string') { + if (typeof opts.match === "string") { opts.match = RegExp(`${utils.regexp.quote(opts.match)}`, "mg"); } if (!(opts.match instanceof RegExp)) { - throw utils.error('NIKITA_PARTIAL_INVALID_MATCH', [ + throw utils.error("NIKITA_PARTIAL_INVALID_MATCH", [ "Invalid match option,", - `got ${JSON.stringify(opts.match)} instead of a RegExp` + `got ${JSON.stringify(opts.match)} instead of a RegExp`, ]); } if (opts.match.test(config.content)) { config.content = config.content.replace(opts.match, opts.replace); log("INFO", "Match existing partial"); - } else if (opts.place_before && typeof opts.replace === 'string') { + } else if (opts.place_before && typeof opts.replace === "string") { if (typeof opts.place_before === "string") { - opts.place_before = new RegExp(RegExp(`^.*${utils.regexp.quote(opts.place_before)}.*$`, "mg")); + opts.place_before = new RegExp( + RegExp(`^.*${utils.regexp.quote(opts.place_before)}.*$`, "mg"), + ); } if (opts.place_before instanceof RegExp) { log("DEBUG", "Replace with match and place_before regexp"); @@ -46,7 +48,11 @@ export default function(config, log) { while ((res = opts.place_before.exec(orgContent)) !== null) { log("INFO", "Before regexp found a match"); const pos = posoffset + res.index; //+ res[0].length - config.content = config.content.slice(0, pos) + opts.replace + '\n' + config.content.slice(pos); + config.content = + config.content.slice(0, pos) + + opts.replace + + "\n" + + config.content.slice(pos); posoffset += opts.replace.length + 1; if (!opts.place_before.global) { break; @@ -54,13 +60,22 @@ export default function(config, log) { } } else { log("DEBUG", "Forgot how we could get there, test shall say it all"); - const linebreak = config.content.length === 0 || config.content.slice(config.content.length - 1) === '\n' ? '' : '\n'; + const linebreak = + ( + config.content.length === 0 || + config.content.slice(config.content.length - 1) === "\n" + ) ? + "" + : "\n"; config.content = opts.replace + linebreak + config.content; } - } else if (opts.append && typeof opts.replace === 'string') { + } else if (opts.append && typeof opts.replace === "string") { if (typeof opts.append === "string") { log("DEBUG", "Convert append string to regexp"); - opts.append = new RegExp(`^.*${utils.regexp.quote(opts.append)}.*$`, 'mg'); + opts.append = new RegExp( + `^.*${utils.regexp.quote(opts.append)}.*$`, + "mg", + ); } if (opts.append instanceof RegExp) { log("DEBUG", "Replace with match and append regexp"); @@ -70,14 +85,24 @@ export default function(config, log) { while ((res = opts.append.exec(orgContent)) !== null) { log("INFO", "Append regexp found a match"); const pos = posoffset + res.index + res[0].length; - config.content = config.content.slice(0, pos) + '\n' + opts.replace + config.content.slice(pos); + config.content = + config.content.slice(0, pos) + + "\n" + + opts.replace + + config.content.slice(pos); posoffset += opts.replace.length + 1; if (!opts.append.global) { break; } } } else { - const linebreak = config.content.length === 0 || config.content.slice(config.content.length - 1) === '\n' ? '' : '\n'; + const linebreak = + ( + config.content.length === 0 || + config.content.slice(config.content.length - 1) === "\n" + ) ? + "" + : "\n"; config.content = config.content + linebreak + opts.replace; } } else { @@ -87,36 +112,52 @@ export default function(config, log) { log("INFO", "Before is true, need to explain how we could get here"); } else if (opts.from || opts.to) { if (opts.from && opts.to) { - const from = RegExp(`(^${utils.regexp.quote(opts.from)}$)`, "m").exec(config.content); - const to = RegExp(`(^${utils.regexp.quote(opts.to)}$)`, "m").exec(config.content); - if ((from != null) && (to == null)) { + const from = RegExp(`(^${utils.regexp.quote(opts.from)}$)`, "m").exec( + config.content, + ); + const to = RegExp(`(^${utils.regexp.quote(opts.to)}$)`, "m").exec( + config.content, + ); + if (from != null && to == null) { log("WARN", "Found 'from' but missing 'to', skip writing"); - } else if ((from == null) && (to != null)) { + } else if (from == null && to != null) { log("WARN", "Missing 'from' but found 'to', skip writing"); - } else if ((from == null) && (to == null)) { + } else if (from == null && to == null) { if (opts.append) { - config.content += '\n' + opts.from + '\n' + opts.replace + '\n' + opts.to; + config.content += + "\n" + opts.from + "\n" + opts.replace + "\n" + opts.to; } else { log("WARN", "Missing 'from' and 'to' without append, skip writing"); } } else { - config.content = config.content.slice(0, from.index + from[1].length + 1) + opts.replace + '\n' + config.content.slice(to.index); + config.content = + config.content.slice(0, from.index + from[1].length + 1) + + opts.replace + + "\n" + + config.content.slice(to.index); } } else if (opts.from && !opts.to) { - const from = RegExp(`(^${utils.regexp.quote(opts.from)}$)`, "m").exec(config.content); + const from = RegExp(`(^${utils.regexp.quote(opts.from)}$)`, "m").exec( + config.content, + ); if (from != null) { - config.content = config.content.slice(0, from.index + from[1].length) + '\n' + opts.replace; // TODO: honors append + config.content = + config.content.slice(0, from.index + from[1].length) + + "\n" + + opts.replace; // TODO: honors append } else { log("WARN", "Missing 'from', skip writing"); } } else if (!opts.from && opts.to) { - const to = RegExp(`(^${utils.regexp.quote(opts.to)}$)`, "m").exec(config.content); + const to = RegExp(`(^${utils.regexp.quote(opts.to)}$)`, "m").exec( + config.content, + ); if (to != null) { - config.content = opts.replace + '\n' + config.content.slice(to.index); // TODO: honors append + config.content = opts.replace + "\n" + config.content.slice(to.index); // TODO: honors append } else { log("WARN", "Missing 'to', skip writing"); } } } } -}; +} diff --git a/packages/file/lib/yaml/index.js b/packages/file/lib/yaml/index.js index 702a1a924..2b3630d0a 100644 --- a/packages/file/lib/yaml/index.js +++ b/packages/file/lib/yaml/index.js @@ -2,7 +2,12 @@ import utils from "@nikitajs/file/utils"; import yaml from "js-yaml"; import { merge } from "mixme"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -21,22 +26,18 @@ export default { } } if (config.clean) { - log({ - message: "Cleaning content", - level: "INFO", - }); + log("Cleaning content"); utils.object.clean(config.content); } - log({ - message: "Serialize content", - level: "DEBUG", - }); + log("DEBUG", "Serialize content"); config.content = yaml.dump(config.content, { indent: config.indent, noRefs: true, lineWidth: config.line_width, }); - await this.file(utils.object.filter(config, ['clean', 'indent', 'line_width', 'merge'])); + await this.file( + utils.object.filter(config, ["clean", "indent", "line_width", "merge"]), + ); }, metadata: { definitions: definitions, diff --git a/packages/file/package.json b/packages/file/package.json index ce7a1df36..aa7a24c2c 100644 --- a/packages/file/package.json +++ b/packages/file/package.json @@ -46,8 +46,6 @@ "devDependencies": { "@nikitajs/log": "^2.0.0-alpha.6", "coffeescript": "^2.7.0", - "eslint": "^9.8.0", - "eslint-plugin-coffee": "^0.1.15", "mocha": "^10.7.0", "mocha-they": "^0.1.3", "should": "^13.2.3" diff --git a/packages/incus/lib/cluster/cli/start/index.js b/packages/incus/lib/cluster/cli/start/index.js index 506e08509..ab6d2a4c6 100644 --- a/packages/incus/lib/cluster/cli/start/index.js +++ b/packages/incus/lib/cluster/cli/start/index.js @@ -1,44 +1,50 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; -import nikita from '@nikitajs/core'; -import '@nikitajs/incus/register'; -import '@nikitajs/log/register'; +import nikita from "@nikitajs/core"; +import "@nikitajs/incus/register"; +import "@nikitajs/log/register"; const key = path.relative( process.cwd(), - `${__dirname}/../../../assets/.vagrant/machines/default/virtualbox/private_key` + `${__dirname}/../../../assets/.vagrant/machines/default/virtualbox/private_key`, ); -export default async function({params}) { +export default async function ({ params }) { await nikita({ - $debug: params.debug - }).log.cli({ - pad: { - host: 20, - header: 60 - } - }).log.md({ - basename: 'start', - basedir: params.log, - archive: false, - $if: params.log - }).execute({ - $header: 'Dependencies', - $unless_exec: 'vagrant plugin list | egrep \'^vagrant-vbguest \'', - command: `vagrant plugin install vagrant-vbguest` - }).execute({ - $header: 'Vagrant', - cwd: `${__dirname}/../../../assets`, - command: `vagrant up` - }).execute({ - $header: 'LXC remote', - command: dedent` + $debug: params.debug, + }) + .log.cli({ + pad: { + host: 20, + header: 60, + }, + }) + .log.md({ + basename: "start", + basedir: params.log, + archive: false, + $if: params.log, + }) + .execute({ + $header: "Dependencies", + $unless_exec: "vagrant plugin list | egrep '^vagrant-vbguest '", + command: `vagrant plugin install vagrant-vbguest`, + }) + .execute({ + $header: "Vagrant", + cwd: `${__dirname}/../../../assets`, + command: `vagrant up`, + }) + .execute({ + $header: "LXC remote", + command: dedent` incus remote add nikita 127.0.0.1:8443 --accept-certificate --password secret incus remote switch nikita - ` - }).execute({ - $header: 'LXC remote (update)', + `, + }) + .execute({ + $header: "LXC remote (update)", // todo: use condition for `incus ls` command: dedent`incus ls || { incus remote switch local @@ -46,19 +52,23 @@ export default async function({params}) { incus remote add nikita --accept-certificate --password secret 127.0.0.1:8443 incus remote switch nikita } - ` - }).call(function() { - return { - $disabled: true, - command: `ssh -i ${key} -qtt -p 2222 vagrant@127.0.0.1 -- "cd /nikita && bash"\n`, - stdin: process.stdin, - stderr: process.stderr, - stdout: process.stdout - }; - }).call(function() { - ({ - $header: 'Connection' + `, + }) + .call(function () { + return { + $disabled: true, + command: `ssh -i ${key} -qtt -p 2222 vagrant@127.0.0.1 -- "cd /nikita && bash"\n`, + stdin: process.stdin, + stderr: process.stderr, + stdout: process.stdout, + }; + }) + .call(function () { + ({ + $header: "Connection", + }); + return process.stdout.write( + `ssh -i ${key} -qtt -p 2222 vagrant@127.0.0.1 -- "cd /nikita && bash"\n`, + ); }); - return process.stdout.write(`ssh -i ${key} -qtt -p 2222 vagrant@127.0.0.1 -- "cd /nikita && bash"\n`); - }); -}; +} diff --git a/packages/incus/lib/cluster/cli/stop/index.js b/packages/incus/lib/cluster/cli/stop/index.js index 043b2c9e3..7263df110 100644 --- a/packages/incus/lib/cluster/cli/stop/index.js +++ b/packages/incus/lib/cluster/cli/stop/index.js @@ -1,5 +1,5 @@ // Dependencies -import nikita from '@nikitajs/core'; +import nikita from "@nikitajs/core"; import "@nikitajs/incus/register"; import "@nikitajs/log/register"; @@ -7,20 +7,20 @@ export default function ({ params }) { nikita({ $debug: params.debug, }) - .log.cli({ - pad: { - host: 20, - header: 60, - }, - }) - .log.md({ - basename: "start", - basedir: params.log, - archive: false, - $if: params.log, - }) - .execute({ - cwd: `${__dirname}/../../../assets`, - command: `vagrant halt`, - }); -}; + .log.cli({ + pad: { + host: 20, + header: 60, + }, + }) + .log.md({ + basename: "start", + basedir: params.log, + archive: false, + $if: params.log, + }) + .execute({ + cwd: `${__dirname}/../../../assets`, + command: `vagrant halt`, + }); +} diff --git a/packages/incus/lib/cluster/delete/index.js b/packages/incus/lib/cluster/delete/index.js index f7ca1fa38..4525636b5 100644 --- a/packages/incus/lib/cluster/delete/index.js +++ b/packages/incus/lib/cluster/delete/index.js @@ -1,11 +1,15 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Pre hook - if (!!config.pre_delete) { + if (config.pre_delete) { await this.call(config, config.pre_delete); } // Containers removal @@ -13,29 +17,29 @@ export default { await this.incus.delete({ $header: `Container ${name} : delete`, container: name, - force: config.force + force: config.force, }); } // Networks removal for (const name in config.networks) { await this.incus.network.delete({ $header: `Network ${name} : delete`, - network: name + network: name, }); } return {}; }, hooks: { on_action: { - before: ['@nikitajs/core/src/plugins/metadata/schema'], - handler: function({config}) { + before: ["@nikitajs/core/src/plugins/metadata/schema"], + handler: function ({ config }) { for (const name in config.containers) { config.containers[name].container = name; } - } - } + }, + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/cluster/index.js b/packages/incus/lib/cluster/index.js index 42b246770..8a4818b13 100644 --- a/packages/incus/lib/cluster/index.js +++ b/packages/incus/lib/cluster/index.js @@ -1,12 +1,17 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/incus/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - if (!!config.prevision) { + handler: async function ({ config }) { + if (config.prevision) { await this.call(config, config.prevision); } // Create a network @@ -15,90 +20,103 @@ export default { await this.incus.network({ $header: `Network ${networkName}`, network: networkName, - properties: networkProperties + properties: networkProperties, }); } - if (!!config.prevision_container) { + if (config.prevision_container) { for (const containerName in config.containers) { const containerConfig = config.containers[containerName]; - await this.call({ - container: containerName - }, containerConfig, config.prevision_container); + await this.call( + { + container: containerName, + }, + containerConfig, + config.prevision_container, + ); } } // Init containers for (const containerName in config.containers) { const containerConfig = config.containers[containerName]; - await this.call({ - $header: `Container ${containerName}` - }, async function() { - // Set configuration - await this.incus.init({ - $header: 'Init', - ...utils.object.filter(containerConfig, ['disk', 'nic', 'properties', 'proxy', 'user', 'ssh']) - }); - // Set config - if (containerConfig != null ? containerConfig.properties : void 0) { - await this.incus.config.set({ - $header: 'Properties', - container: containerName, - properties: containerConfig.properties + await this.call( + { + $header: `Container ${containerName}`, + }, + async function () { + // Set configuration + await this.incus.init({ + $header: "Init", + ...utils.object.filter(containerConfig, [ + "disk", + "nic", + "properties", + "proxy", + "user", + "ssh", + ]), }); - } - // Create disk device - for (const deviceName in containerConfig.disk) { - const configDisk = containerConfig.disk[deviceName]; - await this.incus.config.device({ - $header: `Device ${deviceName} disk`, + // Set config + if (containerConfig != null ? containerConfig.properties : void 0) { + await this.incus.config.set({ + $header: "Properties", + container: containerName, + properties: containerConfig.properties, + }); + } + // Create disk device + for (const deviceName in containerConfig.disk) { + const configDisk = containerConfig.disk[deviceName]; + await this.incus.config.device({ + $header: `Device ${deviceName} disk`, + container: containerName, + device: deviceName, + type: "disk", + properties: configDisk, + }); + } + // Create nic device + for (const deviceName in containerConfig.nic) { + const configNic = containerConfig.nic[deviceName]; + // note: `confignic.config.parent` is not required for each type + // throw Error "Required Property: nic.#{device}.parent" unless confignic.config.parent + await this.incus.config.device({ + $header: `Device ${deviceName} nic`, + container: containerName, + device: deviceName, + type: "nic", + properties: utils.object.filter(configNic, ["ip", "netmask"]), + }); + } + // Create proxy device + for (const deviceName in containerConfig.proxy) { + const configProxy = containerConfig.proxy[deviceName]; + // todo: add host detection and port forwarding to VirtualBox + // VBoxManage controlvm 'incus' natpf1 'ipa_ui,tcp,0.0.0.0,2443,,2443' + await this.incus.config.device({ + $header: `Device ${deviceName} proxy`, + container: containerName, + device: deviceName, + type: "proxy", + properties: configProxy, + }); + } + // Start container + await this.incus.start({ + $header: "Start", container: containerName, - device: deviceName, - type: 'disk', - properties: configDisk }); - } - // Create nic device - for (const deviceName in containerConfig.nic) { - const configNic = containerConfig.nic[deviceName]; - // note: `confignic.config.parent` is not required for each type - // throw Error "Required Property: nic.#{device}.parent" unless confignic.config.parent - await this.incus.config.device({ - $header: `Device ${deviceName} nic`, + // Wait until container is ready + await this.incus.wait.ready({ + $header: "Wait for container to be ready to use", container: containerName, - device: deviceName, - type: 'nic', - properties: utils.object.filter(configNic, ['ip', 'netmask']) + nat: true, + nat_check: process.env.CI ? "wget -q google.com" : undefined, }); - } - // Create proxy device - for (const deviceName in containerConfig.proxy) { - const configProxy = containerConfig.proxy[deviceName]; - // todo: add host detection and port forwarding to VirtualBox - // VBoxManage controlvm 'incus' natpf1 'ipa_ui,tcp,0.0.0.0,2443,,2443' - await this.incus.config.device({ - $header: `Device ${deviceName} proxy`, + // Openssl is required by the `incus.file.push` action + await this.incus.exec({ + $header: "OpenSSL", container: containerName, - device: deviceName, - type: 'proxy', - properties: configProxy - }); - } - // Start container - await this.incus.start({ - $header: 'Start', - container: containerName - }); - // Wait until container is ready - await this.incus.wait.ready({ - $header: 'Wait for container to be ready to use', - container: containerName, - nat: true, - nat_check: !!process.env.CI ? 'wget -q google.com' : void 0 - }); - // Openssl is required by the `incus.file.push` action - await this.incus.exec({ - $header: 'OpenSSL', - container: containerName, - command: dedent` + command: dedent` command -v openssl && exit 42 if command -v yum >/dev/null 2>&1; then yum -y install openssl @@ -111,15 +129,15 @@ export default { fi command -v openssl `, - trap: true, - code: [0, 42] - }); - // Enable SSH - if (containerConfig.ssh?.enabled) { - await this.incus.exec({ - $header: 'SSH', - container: containerName, - command: dedent` + trap: true, + code: [0, 42], + }); + // Enable SSH + if (containerConfig.ssh?.enabled) { + await this.incus.exec({ + $header: "SSH", + container: containerName, + command: dedent` if command -v systemctl >/dev/null 2>&1; then srv=\`systemctl list-units --all --type=service | grep ssh | sed 's/ *\\(ssh.*\\)\.service.*/\\1/'\` [ ! -z $srv ] && systemctl status $srv && exit 42 || echo '' > /dev/null @@ -149,81 +167,89 @@ export default { echo "Unsupported init system" >&2 && exit 3 fi `, - trap: true, - code: [0, 42] - }); - } - // Create users - for (const userName in containerConfig.user) { - const configUser = containerConfig.user[userName]; - await this.call({ - $header: `User ${userName}` - }, async function() { - await this.incus.exec({ - $header: 'Create', - container: containerName, - command: dedent` + trap: true, + code: [0, 42], + }); + } + // Create users + for (const userName in containerConfig.user) { + const configUser = containerConfig.user[userName]; + await this.call( + { + $header: `User ${userName}`, + }, + async function () { + await this.incus.exec({ + $header: "Create", + container: containerName, + command: dedent` id ${userName} && exit 42 useradd --create-home --system ${userName} mkdir -p /home/${userName}/.ssh chown ${userName}.${userName} /home/${userName}/.ssh chmod 700 /home/${userName}/.ssh `, - trap: true, - code: [0, 42] - }); - // Enable sudo access - await this.incus.exec({ - $if: configUser.sudo, - $header: 'Sudo', - container: containerName, - command: dedent` + trap: true, + code: [0, 42], + }); + // Enable sudo access + await this.incus.exec({ + $if: configUser.sudo, + $header: "Sudo", + container: containerName, + command: dedent` yum install -y sudo command -v sudo cat /etc/sudoers | grep "${userName}" && exit 42 echo "${userName} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers `, - trap: true, - code: [0, 42] - }); - // Add SSH public key to authorized_keys file - await this.incus.file.push({ - $if: configUser.authorized_keys, - $header: 'Authorize', - container: containerName, - gid: `${userName}`, - uid: `${userName}`, - mode: 600, - source: `${configUser.authorized_keys}`, - target: `/home/${userName}/.ssh/authorized_keys` - }); - }); - } - }); + trap: true, + code: [0, 42], + }); + // Add SSH public key to authorized_keys file + await this.incus.file.push({ + $if: configUser.authorized_keys, + $header: "Authorize", + container: containerName, + gid: `${userName}`, + uid: `${userName}`, + mode: 600, + source: `${configUser.authorized_keys}`, + target: `/home/${userName}/.ssh/authorized_keys`, + }); + }, + ); + } + }, + ); } - if (!!config.provision_container) { + if (config.provision_container) { for (const containerName in config.containers) { const containerConfig = config.containers[containerName]; - await this.call({ - container: containerName - }, containerConfig, config.provision_container); + await this.call( + { + container: containerName, + }, + containerConfig, + config.provision_container, + ); } } - if (!!config.provision) { + if (config.provision) { await this.call(config, config.provision); } }, hooks: { on_action: { - before: ['@nikitajs/core/src/plugins/metadata/schema'], - handler: function({config}) { + before: ["@nikitajs/core/src/plugins/metadata/schema"], + handler: function ({ config }) { for (const name in config.containers) { config.containers[name].container = name; } - } - } + }, + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/cluster/samples/three_nodes.js b/packages/incus/lib/cluster/samples/three_nodes.js index 49f5838d2..84d465bdc 100644 --- a/packages/incus/lib/cluster/samples/three_nodes.js +++ b/packages/incus/lib/cluster/samples/three_nodes.js @@ -1,6 +1,7 @@ // Dependencies import path from "node:path"; -import nikita from '@nikitajs/core'; +import dedent from "dedent"; +import nikita from "@nikitajs/core"; import "@nikitajs/log/register"; import "@nikitajs/incus/register"; import "@nikitajs/tools/register"; @@ -152,7 +153,7 @@ nikita.log }, }, }, - prevision: async function ({ config }) { + prevision: async function () { return await this.tools.ssh.keygen({ $header: "SSH key", target: "./assets/id_ed25519", @@ -193,5 +194,5 @@ nikita.log }) .then( () => console.info("OK"), - (err) => console.error("KO", err) + (err) => console.error("KO", err), ); diff --git a/packages/incus/lib/cluster/stop/index.js b/packages/incus/lib/cluster/stop/index.js index b7fef3448..6381b931a 100644 --- a/packages/incus/lib/cluster/stop/index.js +++ b/packages/incus/lib/cluster/stop/index.js @@ -1,10 +1,14 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - if (!!config.pre_stop) { + handler: async function ({ config }) { + if (config.pre_stop) { await this.call(config, config.pre_stop); } // Stop containers @@ -12,22 +16,22 @@ export default { await this.incus.stop({ $header: `Container ${containerName} : stop`, container: containerName, - wait: config.wait + wait: config.wait, }); } return {}; }, hooks: { on_action: { - before: ['@nikitajs/core/src/plugins/metadata/schema'], - handler: function({config}) { + before: ["@nikitajs/core/src/plugins/metadata/schema"], + handler: function ({ config }) { for (const name in config.containers) { config.containers[name].container = name; } - } - } + }, + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/config/device/delete/index.js b/packages/incus/lib/config/device/delete/index.js index c91e7197a..2cfaaf53a 100644 --- a/packages/incus/lib/config/device/delete/index.js +++ b/packages/incus/lib/config/device/delete/index.js @@ -1,26 +1,37 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { - const {properties} = (await this.incus.config.device.show({ + handler: async function ({ config }) { + const { properties } = await this.incus.config.device.show({ container: config.container, - device: config.device - })); + device: config.device, + }); if (!properties) { return { - $status: false + $status: false, }; } - const {$status} = (await this.execute({ - command: ['incus', 'config', 'device', 'remove', config.container, config.device].join(' ') - })); + const { $status } = await this.execute({ + command: [ + "incus", + "config", + "device", + "remove", + config.container, + config.device, + ].join(" "), + }); return { - $status: $status + $status: $status, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/config/device/exists/index.js b/packages/incus/lib/config/device/exists/index.js index 2499f05ad..c76e5b69c 100644 --- a/packages/incus/lib/config/device/exists/index.js +++ b/packages/incus/lib/config/device/exists/index.js @@ -1,19 +1,23 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { - const {properties} = (await this.incus.config.device.show({ + handler: async function ({ config }) { + const { properties } = await this.incus.config.device.show({ container: config.container, - device: config.device - })); + device: config.device, + }); return { exists: !!properties, - properties: properties + properties: properties, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/config/device/index.js b/packages/incus/lib/config/device/index.js index 574bc0c08..2f8a2ea61 100644 --- a/packages/incus/lib/config/device/index.js +++ b/packages/incus/lib/config/device/index.js @@ -1,26 +1,31 @@ // Dependencies -import diff from 'object-diff'; +import diff from "object-diff"; import utils from "@nikitajs/incus/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // No properties, dont go further if (Object.keys(config.properties).length === 0) return false; // Normalize config for (const key in config.properties) { - const value = config.properties[key] - if (typeof value === 'string') { + const value = config.properties[key]; + if (typeof value === "string") { continue; } config.properties[key] = value.toString(); } // Obtain current device properties - const {properties} = await this.incus.config.device.show({ + const { properties } = await this.incus.config.device.show({ container: config.container, - device: config.device + device: config.device, }); try { if (!properties) { @@ -35,10 +40,7 @@ export default { config.device, config.type, ...Object.keys(config.properties).map( - (key) => - esa(key) + - "=" + - esa(config.properties[key]) + (key) => esa(key) + "=" + esa(config.properties[key]), ), ].join(" "), }); @@ -70,6 +72,6 @@ export default { } }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/config/device/show/index.js b/packages/incus/lib/config/device/show/index.js index c7df08369..0d1941d03 100644 --- a/packages/incus/lib/config/device/show/index.js +++ b/packages/incus/lib/config/device/show/index.js @@ -1,19 +1,23 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { - const {data} = (await this.incus.query({ - path: '/' + ['1.0', 'instances', config.container].join('/') - })); + handler: async function ({ config }) { + const { data } = await this.incus.query({ + path: "/" + ["1.0", "instances", config.container].join("/"), + }); return { $status: true, - properties: data.devices[config.device] + properties: data.devices[config.device], }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/config/set/index.js b/packages/incus/lib/config/set/index.js index ee87294f9..58fdf5016 100644 --- a/packages/incus/lib/config/set/index.js +++ b/packages/incus/lib/config/set/index.js @@ -2,7 +2,12 @@ import { merge } from "mixme"; import yaml from "js-yaml"; import diff from "object-diff"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/incus/lib/delete/index.js b/packages/incus/lib/delete/index.js index 5768e14dc..ed20f48ea 100644 --- a/packages/incus/lib/delete/index.js +++ b/packages/incus/lib/delete/index.js @@ -1,20 +1,25 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - return (await this.execute({ + handler: async function ({ config }) { + return await this.execute({ command: dedent` incus info ${config.container} > /dev/null || exit 42 - ${['incus', 'delete', config.container, config.force ? "--force" : void 0].join(' ')} + ${["incus", "delete", config.container, config.force ? "--force" : void 0].join(" ")} `, - code: [0, 42] - })); + code: [0, 42], + }); }, metadata: { - argument_to_config: 'container', - definitions: definitions - } + argument_to_config: "container", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/exec/index.js b/packages/incus/lib/exec/index.js index d10aebeb3..5c9ff34d0 100644 --- a/packages/incus/lib/exec/index.js +++ b/packages/incus/lib/exec/index.js @@ -1,24 +1,31 @@ // Dependencies import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; import execute from "@nikitajs/core/actions/execute"; - -const properties = Object.keys(execute.metadata.definitions.config.properties).filter( - (prop) => !["command", "trap", "env"].includes(prop) +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), ); +const properties = Object.keys( + execute.metadata.definitions.config.properties, +).filter((prop) => !["command", "trap", "env"].includes(prop)); + // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { const opt = [ // Incus `--user` only support user ID (integer) config.user && `--user ${config.user}`, config.cwd && `--cwd ${esa(config.cwd)}`, ...Object.keys(config.env).map( - (k) => `--env ${esa(k)}=${esa(config.env[k])}` + (k) => `--env ${esa(k)}=${esa(config.env[k])}`, ), - ].filter(Boolean).join(" "); + ] + .filter(Boolean) + .join(" "); return await this.execute( // `trap` and `env` apply to `incus exec` and not to `execute` // { ...config, env: undefined, trap: undefined }, @@ -29,11 +36,13 @@ export default { config.trap && "set -e", config.command, "NIKITAINCUSEXEC", - ].filter(Boolean).join("\n"), - } + ] + .filter(Boolean) + .join("\n"), + }, ); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/exists/index.js b/packages/incus/lib/exists/index.js index 5d02777cb..15a532d0f 100644 --- a/packages/incus/lib/exists/index.js +++ b/packages/incus/lib/exists/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/incus/lib/file/exists/index.js b/packages/incus/lib/file/exists/index.js index 9ad3dda98..eb397ff2f 100644 --- a/packages/incus/lib/file/exists/index.js +++ b/packages/incus/lib/file/exists/index.js @@ -1,21 +1,25 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status} = await this.incus.exec({ + handler: async function ({ config }) { + const { $status } = await this.incus.exec({ $header: `Check if file exists in container ${config.container}`, container: config.container, command: `test -f ${config.target}`, - code: [0, 1] + code: [0, 1], }); return { - exists: $status + exists: $status, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/file/pull/index.js b/packages/incus/lib/file/pull/index.js index 9ebcd7473..a30aa5aa3 100644 --- a/packages/incus/lib/file/pull/index.js +++ b/packages/incus/lib/file/pull/index.js @@ -1,8 +1,13 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; import utils from "@nikitajs/incus/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -47,8 +52,8 @@ export default { if (error.exit_code === 3) { throw Error( `Invalid Option: source is not a file, got ${JSON.stringify( - config.source - )}` + config.source, + )}`, ); } if (error.exit_code === 4) { diff --git a/packages/incus/lib/file/push/index.js b/packages/incus/lib/file/push/index.js index 7415bb721..507ccfa2c 100644 --- a/packages/incus/lib/file/push/index.js +++ b/packages/incus/lib/file/push/index.js @@ -1,8 +1,13 @@ // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; import utils from "@nikitajs/incus/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -11,7 +16,7 @@ export default { if (config.content != null) { const tmpfile = path.join( tmpdir, - `nikita.${Date.now()}${Math.round(Math.random() * 1000)}` + `nikita.${Date.now()}${Math.round(Math.random() * 1000)}`, ); await this.fs.writeFile({ target: tmpfile, @@ -31,7 +36,7 @@ export default { let isTargetIdentical; if (isContainerRunning) { try { - const {$status} = await this.execute({ + const { $status } = await this.execute({ command: dedent` # Ensure source is a file [ -f "${config.source}" ] || exit 2 @@ -50,13 +55,13 @@ export default { code: [0, 42], trap: true, }); - isTargetIdentical = $status + isTargetIdentical = $status; } catch (error) { if (error.exit_code === 2) { throw Error( `Invalid Option: source is not a file, got ${JSON.stringify( - config.source - )}` + config.source, + )}`, ); } if (error.exit_code === 3) { @@ -83,7 +88,9 @@ export default { typeof config.gid === "number" && "--gid", typeof config.uid === "number" && "--uid", config.mode && `--mode ${config.mode}`, - ].filter(Boolean).join(" ")}`, + ] + .filter(Boolean) + .join(" ")}`, trap: true, trim: true, }); diff --git a/packages/incus/lib/file/read/index.js b/packages/incus/lib/file/read/index.js index 85f182e41..f38b965c2 100644 --- a/packages/incus/lib/file/read/index.js +++ b/packages/incus/lib/file/read/index.js @@ -1,24 +1,28 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - let {data} = (await this.incus.query({ + handler: async function ({ config }) { + let { data } = await this.incus.query({ $header: `Check if file exists in container ${config.container}`, path: `/1.0/instances/${config.container}/files?path=${config.target}`, - format: 'string' - })); + format: "string", + }); if (config.trim) { data = data.trim(); } return { $status: true, - data: data + data: data, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/goodies/prlimit/index.js b/packages/incus/lib/goodies/prlimit/index.js index 8e2c21871..3fa13d17e 100644 --- a/packages/incus/lib/goodies/prlimit/index.js +++ b/packages/incus/lib/goodies/prlimit/index.js @@ -1,29 +1,36 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/incus/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_LXC_PRLIMIT_MISSING: function() { - return utils.error('NIKITA_LXC_PRLIMIT_MISSING', ['this action requires prlimit installed on the host']); - } + NIKITA_LXC_PRLIMIT_MISSING: function () { + return utils.error("NIKITA_LXC_PRLIMIT_MISSING", [ + "this action requires prlimit installed on the host", + ]); + }, }; // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { try { // TODO: pass sudo as a config instead of inside the command - const {stdout} = await this.execute({ + const { stdout } = await this.execute({ command: dedent` command -v prlimit || exit 3 sudo prlimit -p $(incus info ${config.container} | awk '$1=="PID:"{print $2}') - ` + `, }); - const limits = (function() { + const limits = (function () { const lines = utils.string.lines(stdout); - lines.shift() + lines.shift(); const results = []; for (const line of lines) { const [resource, description, soft, hard, units] = line.split(/\s+/); @@ -32,24 +39,24 @@ export default { description: description, soft: soft, hard: hard, - units: units + units: units, }); } return results; })(); return { stdout: stdout, - limits: limits + limits: limits, }; } catch (error) { if (error.exit_code === 3) { - error = errors.NIKITA_LXC_PRLIMIT_MISSING(); + throw errors.NIKITA_LXC_PRLIMIT_MISSING(); } throw error; } }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/info/index.js b/packages/incus/lib/info/index.js index 0d0bd539d..44676a95c 100644 --- a/packages/incus/lib/info/index.js +++ b/packages/incus/lib/info/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/incus/lib/init/index.js b/packages/incus/lib/init/index.js index 2ed8fab6f..b292e11bf 100644 --- a/packages/incus/lib/init/index.js +++ b/packages/incus/lib/init/index.js @@ -1,12 +1,19 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; import { escapeshellarg as esa } from "@nikitajs/utils/string"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const configValue = Object.entries(config.config).map(([key, value]) => `--config ${key}=${value}`).join(` `) + handler: async function ({ config }) { + const configValue = Object.entries(config.config) + .map(([key, value]) => `--config ${key}=${value}`) + .join(` `); const commandInit = [ "incus", "init", @@ -19,14 +26,16 @@ export default { config.vm && "--vm", config.profile && `--profile ${config.profile}`, config.target && `--target ${config.target}`, - ].filter(Boolean).join(" "); + ] + .filter(Boolean) + .join(" "); // Execution - const {$status} = await this.execute({ + const { $status } = await this.execute({ command: dedent` incus info ${config.container} >/dev/null && exit 42 echo '' | ${commandInit} `, - code: [0, 42] + code: [0, 42], }); if (config.vm) { // See `agent:config` annoucement in 0.5.1 @@ -36,14 +45,14 @@ export default { incus config device add ${esa(config.container)} agent disk source=agent:config `, }); - } + } await this.incus.start({ $if: config.start, - container: config.container + container: config.container, }); return $status; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/list/index.js b/packages/incus/lib/list/index.js index 291552505..82abc02c4 100644 --- a/packages/incus/lib/list/index.js +++ b/packages/incus/lib/list/index.js @@ -1,20 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { - const {data} = (await this.incus.query({ + handler: async function ({ config }) { + const { data } = await this.incus.query({ $shy: false, - path: `/1.0/${config.filter}` - })); + path: `/1.0/${config.filter}`, + }); return { - list: data.map(line => line.split('/').pop()) + list: data.map((line) => line.split("/").pop()), }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/network/attach/index.js b/packages/incus/lib/network/attach/index.js index 7b70daaa9..33f257a09 100644 --- a/packages/incus/lib/network/attach/index.js +++ b/packages/incus/lib/network/attach/index.js @@ -1,11 +1,16 @@ // Dependencies import dedent from "dedent"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { //Build command const command_attach = [ "incus", @@ -15,15 +20,15 @@ export default { esa(config.container), ].join(" "); //Execute - return (await this.execute({ + return await this.execute({ command: dedent` incus config device list ${esa(config.container)} | grep ${esa(config.network)} && exit 42 ${command_attach} `, - code: [0, 42] - })); + code: [0, 42], + }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/network/delete/index.js b/packages/incus/lib/network/delete/index.js index 00bec7b53..e8dd236f1 100644 --- a/packages/incus/lib/network/delete/index.js +++ b/packages/incus/lib/network/delete/index.js @@ -1,17 +1,21 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { return await this.incus.query({ path: `/1.0/networks/${config.network}`, - request: 'DELETE', - format: 'string', - code: [0, 1] + request: "DELETE", + format: "string", + code: [0, 1], }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/network/detach/index.js b/packages/incus/lib/network/detach/index.js index 406329393..b002291eb 100644 --- a/packages/incus/lib/network/detach/index.js +++ b/packages/incus/lib/network/detach/index.js @@ -1,20 +1,25 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status} = await this.execute({ + handler: async function ({ config }) { + const { $status } = await this.execute({ command: dedent` incus config device list ${config.container} | grep ${config.network} || exit 42 - ${['incus', 'network', 'detach', config.network, config.container].join(' ')} + ${["incus", "network", "detach", config.network, config.container].join(" ")} `, - code: [0, 42] + code: [0, 42], }); - return $status + return $status; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/network/index.js b/packages/incus/lib/network/index.js index 3447a7a98..ad850c3ec 100644 --- a/packages/incus/lib/network/index.js +++ b/packages/incus/lib/network/index.js @@ -1,20 +1,25 @@ // Dependencies import dedent from "dedent"; -import yaml from 'js-yaml'; -import diff from 'object-diff'; -import {merge} from 'mixme'; +import yaml from "js-yaml"; +import diff from "object-diff"; +import { merge } from "mixme"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { + handler: async function ({ config }) { // Normalize config for (const key in config.properties) { config.properties[key] = config.properties[key].toString(); } // Command if the network does not yet exist - let { stdout, code, $status } = await this.execute({ + let { stdout, code } = await this.execute({ // return code 5 indicates a version of incus where 'network' command is not implemented command: dedent` incus network 2>/dev/null || exit 5 @@ -25,14 +30,16 @@ export default { "create", config.network, ...Object.keys(config.properties).map( - (key) => esa(key) + "=" + esa(config.properties[key]) + (key) => esa(key) + "=" + esa(config.properties[key]), ), ].join(" ")} `, code: [0, [5, 42]], }); if (code === 5) { - throw Error("This version of incus does not support the network command."); + throw Error( + "This version of incus does not support the network command.", + ); } // Network was created if (code === 0) { @@ -45,10 +52,10 @@ export default { const current = yaml.load(stdout); const changes = diff( current.config, - merge(current.config, config.properties) + merge(current.config, config.properties), ); - if (Object.keys(changes).length === 0){ - return false + if (Object.keys(changes).length === 0) { + return false; } for (const key in changes) { const value = changes[key]; @@ -66,6 +73,6 @@ export default { return true; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/network/list/index.js b/packages/incus/lib/network/list/index.js index d94807a8e..0cc23add5 100644 --- a/packages/incus/lib/network/list/index.js +++ b/packages/incus/lib/network/list/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -9,7 +13,7 @@ export default { }); return { $status: true, - list: data.map(line => line.split('/').pop()) + list: data.map((line) => line.split("/").pop()), }; }, metadata: { diff --git a/packages/incus/lib/query/index.js b/packages/incus/lib/query/index.js index 87e1df34f..75c6eacac 100644 --- a/packages/incus/lib/query/index.js +++ b/packages/incus/lib/query/index.js @@ -1,10 +1,15 @@ // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { const { $status, stdout } = await this.execute({ command: [ "incus", @@ -14,35 +19,36 @@ export default { config.request, config.data != null && `--data ${esa(config.data)}`, config.path, - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), code: config.code, }); switch (config.format) { - case 'json': + case "json": if ($status) { return { - data: JSON.parse(stdout) + data: JSON.parse(stdout), }; } else { return { - data: {} + data: {}, }; } - break; - case 'string': + case "string": if ($status) { return { - data: stdout + data: stdout, }; } else { return { - data: "" + data: "", }; } } }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/register.js b/packages/incus/lib/register.js index bebc69f68..048734e1b 100644 --- a/packages/incus/lib/register.js +++ b/packages/incus/lib/register.js @@ -1,74 +1,73 @@ - // Dependencies import registry from "@nikitajs/core/registry"; // Action registration -import '@nikitajs/file/register'; -import '@nikitajs/network/register'; +import "@nikitajs/file/register"; +import "@nikitajs/network/register"; // Actions const actions = { incus: { cluster: { - '': '@nikitajs/incus/cluster', - stop: '@nikitajs/incus/cluster/stop', - delete: '@nikitajs/incus/cluster/delete' + "": "@nikitajs/incus/cluster", + stop: "@nikitajs/incus/cluster/stop", + delete: "@nikitajs/incus/cluster/delete", }, config: { device: { - '': '@nikitajs/incus/config/device', - delete: '@nikitajs/incus/config/device/delete', - exists: '@nikitajs/incus/config/device/exists', - show: '@nikitajs/incus/config/device/show' + "": "@nikitajs/incus/config/device", + delete: "@nikitajs/incus/config/device/delete", + exists: "@nikitajs/incus/config/device/exists", + show: "@nikitajs/incus/config/device/show", }, - set: '@nikitajs/incus/config/set' + set: "@nikitajs/incus/config/set", }, - exists: '@nikitajs/incus/exists', - init: '@nikitajs/incus/init', - info: '@nikitajs/incus/info', - delete: '@nikitajs/incus/delete', - start: '@nikitajs/incus/start', - state: '@nikitajs/incus/state', - stop: '@nikitajs/incus/stop', - exec: '@nikitajs/incus/exec', + exists: "@nikitajs/incus/exists", + init: "@nikitajs/incus/init", + info: "@nikitajs/incus/info", + delete: "@nikitajs/incus/delete", + start: "@nikitajs/incus/start", + state: "@nikitajs/incus/state", + stop: "@nikitajs/incus/stop", + exec: "@nikitajs/incus/exec", file: { - exists: '@nikitajs/incus/file/exists', - pull: '@nikitajs/incus/file/pull', - push: '@nikitajs/incus/file/push', - read: '@nikitajs/incus/file/read' + exists: "@nikitajs/incus/file/exists", + pull: "@nikitajs/incus/file/pull", + push: "@nikitajs/incus/file/push", + read: "@nikitajs/incus/file/read", }, goodies: { - prlimit: '@nikitajs/incus/goodies/prlimit' + prlimit: "@nikitajs/incus/goodies/prlimit", }, network: { - '': '@nikitajs/incus/network', - create: '@nikitajs/incus/network', - attach: '@nikitajs/incus/network/attach', - detach: '@nikitajs/incus/network/detach', - delete: '@nikitajs/incus/network/delete', - list: '@nikitajs/incus/network/list' + "": "@nikitajs/incus/network", + create: "@nikitajs/incus/network", + attach: "@nikitajs/incus/network/attach", + detach: "@nikitajs/incus/network/detach", + delete: "@nikitajs/incus/network/delete", + list: "@nikitajs/incus/network/list", }, - query: '@nikitajs/incus/query', - list: '@nikitajs/incus/list', - running: '@nikitajs/incus/running', + query: "@nikitajs/incus/query", + list: "@nikitajs/incus/list", + running: "@nikitajs/incus/running", storage: { - '': '@nikitajs/incus/storage', - delete: '@nikitajs/incus/storage/delete', - exists: '@nikitajs/incus/storage/exists', - list: '@nikitajs/incus/storage/list', + "": "@nikitajs/incus/storage", + delete: "@nikitajs/incus/storage/delete", + exists: "@nikitajs/incus/storage/exists", + list: "@nikitajs/incus/storage/list", volume: { - '': '@nikitajs/incus/storage/volume', - delete: '@nikitajs/incus/storage/volume/delete', - list: '@nikitajs/incus/storage/volume/list', - get: '@nikitajs/incus/storage/volume/get', - attach: '@nikitajs/incus/storage/volume/attach' - } + "": "@nikitajs/incus/storage/volume", + delete: "@nikitajs/incus/storage/volume/delete", + list: "@nikitajs/incus/storage/volume/list", + get: "@nikitajs/incus/storage/volume/get", + attach: "@nikitajs/incus/storage/volume/attach", + }, }, wait: { - ready: '@nikitajs/incus/wait/ready' + ready: "@nikitajs/incus/wait/ready", }, - resources: '@nikitajs/incus/resources' - } + resources: "@nikitajs/incus/resources", + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/incus/lib/resources/index.js b/packages/incus/lib/resources/index.js index 54f03c9d6..6300d6d4f 100644 --- a/packages/incus/lib/resources/index.js +++ b/packages/incus/lib/resources/index.js @@ -1,19 +1,23 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function() { - const {data, $status} = await this.incus.query({ - path: "/1.0/resources" + handler: async function () { + const { data, $status } = await this.incus.query({ + path: "/1.0/resources", }); return { $status: $status, - config: data + config: data, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/running/index.js b/packages/incus/lib/running/index.js index 52fcabb1e..47e6cf436 100644 --- a/packages/incus/lib/running/index.js +++ b/packages/incus/lib/running/index.js @@ -1,17 +1,21 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { return await this.execute({ command: `incus list -c ns --format csv | grep '${config.container},RUNNING' || exit 42`, - code: [0, 42] + code: [0, 42], }); }, metadata: { - argument_to_config: 'container', + argument_to_config: "container", definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/start/index.js b/packages/incus/lib/start/index.js index bf04cdf03..fa9be956e 100644 --- a/packages/incus/lib/start/index.js +++ b/packages/incus/lib/start/index.js @@ -1,22 +1,26 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Check if container is not already running - const {$status: running} = await this.incus.running(config.container) + const { $status: running } = await this.incus.running(config.container); if (running) { return false; } // Start the container return await this.execute({ - command: ['incus', 'start', config.container].join(' '), - code: [0, 42] + command: ["incus", "start", config.container].join(" "), + code: [0, 42], }); }, metadata: { - argument_to_config: 'container', - definitions: definitions - } + argument_to_config: "container", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/state/index.js b/packages/incus/lib/state/index.js index b64b8cf78..918559799 100644 --- a/packages/incus/lib/state/index.js +++ b/packages/incus/lib/state/index.js @@ -1,19 +1,23 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {data, $status} = await this.incus.query({ - path: `/1.0/instances/${config.container}/state` + handler: async function ({ config }) { + const { data, $status } = await this.incus.query({ + path: `/1.0/instances/${config.container}/state`, }); return { $status: $status, - config: data + config: data, }; }, metadata: { - argument_to_config: 'container', - definitions: definitions - } + argument_to_config: "container", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/stop/index.js b/packages/incus/lib/stop/index.js index 5d8439049..c7829abcb 100644 --- a/packages/incus/lib/stop/index.js +++ b/packages/incus/lib/stop/index.js @@ -1,31 +1,35 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Check if container is running - const {$status: running} = await this.incus.running(config.container) + const { $status: running } = await this.incus.running(config.container); if (!running) { return false; } // Stop the container await this.execute({ command: `incus stop ${config.container}`, - code: [0, 42] + code: [0, 42], }); if (config.wait) { await this.execute.wait({ $shy: true, command: `incus info ${config.container} | grep 'Status: STOPPED'`, retry: config.wait_retry, - interval: config.wait_interval + interval: config.wait_interval, }); } return true; }, metadata: { - argument_to_config: 'container', - definitions: definitions - } + argument_to_config: "container", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/storage/delete/index.js b/packages/incus/lib/storage/delete/index.js index 33d61cece..279445617 100644 --- a/packages/incus/lib/storage/delete/index.js +++ b/packages/incus/lib/storage/delete/index.js @@ -1,22 +1,27 @@ // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Check if storage exists - const {exists} = await this.incus.storage.exists(config.name); + const { exists } = await this.incus.storage.exists(config.name); if (!exists) return false; // Remove the storage await this.execute({ command: `incus storage delete ${esa(config.name)}`, - code: [0, 42] + code: [0, 42], }); return true; }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/storage/exists/index.js b/packages/incus/lib/storage/exists/index.js index 1c350209c..77b9183a8 100644 --- a/packages/incus/lib/storage/exists/index.js +++ b/packages/incus/lib/storage/exists/index.js @@ -1,16 +1,20 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {storages} = await this.incus.storage.list() + handler: async function ({ config }) { + const { storages } = await this.incus.storage.list(); return { - exists: !!storages.find( storage => storage.name === config.name) - } + exists: !!storages.find((storage) => storage.name === config.name), + }; }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/incus/lib/storage/index.js b/packages/incus/lib/storage/index.js index 6862af605..b514c0ca5 100644 --- a/packages/incus/lib/storage/index.js +++ b/packages/incus/lib/storage/index.js @@ -1,16 +1,21 @@ // Dependencies -import dedent from 'dedent'; -import yaml from 'js-yaml'; -import diff from 'object-diff'; -import definitions from "./schema.json" with { type: "json" }; +import dedent from "dedent"; +import yaml from "js-yaml"; +import diff from "object-diff"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Normalize config for (const k in config.properties) { const v = config.properties[k]; - if (typeof v === 'string') { + if (typeof v === "string") { continue; } config.properties[k] = v.toString(); @@ -49,14 +54,21 @@ export default { for (const key in changes) { const value = changes[key]; await this.execute({ - command: ['incus', 'storage', 'set', config.name, key, `'${value.replace('\'', '\\\'')}'`].join(' ') + command: [ + "incus", + "storage", + "set", + config.name, + key, + `'${value.replace("'", "\\'")}'`, + ].join(" "), }); } return { - $status: Object.keys(changes).length > 0 + $status: Object.keys(changes).length > 0, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/incus/lib/storage/list/index.js b/packages/incus/lib/storage/list/index.js index 0575244b7..388006b7c 100644 --- a/packages/incus/lib/storage/list/index.js +++ b/packages/incus/lib/storage/list/index.js @@ -1,18 +1,22 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function() { - const {data: storages} = await this.incus.query({ + handler: async function () { + const { data: storages } = await this.incus.query({ path: `/1.0/storage-pools?recursion=1`, }); return { - storages: storages + storages: storages, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/storage/volume/attach/index.js b/packages/incus/lib/storage/volume/attach/index.js index 90726e58b..cf47164bb 100644 --- a/packages/incus/lib/storage/volume/attach/index.js +++ b/packages/incus/lib/storage/volume/attach/index.js @@ -1,9 +1,13 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // note, getting the volume to make sure it exists const { $status: volumeExists, data: volume } = await this.incus.storage.volume.get({ @@ -12,53 +16,63 @@ export default { type: config.type, }); if (!volumeExists) { - throw new Error(`NIKITA_INCUS_VOLUME_ATTACH: volume ${JSON.stringify(config.name)} does not exist.`); + throw new Error( + `NIKITA_INCUS_VOLUME_ATTACH: volume ${JSON.stringify(config.name)} does not exist.`, + ); } // note, getting the container to make sure it exists const { $status: containerExists, data: container } = await this.incus.info( config.container, - { $relax: true } + { $relax: true }, ); if (!containerExists) { - throw new Error(`NIKITA_INCUS_VOLUME_ATTACH: container ${JSON.stringify(config.container)} does not exist.`); + throw new Error( + `NIKITA_INCUS_VOLUME_ATTACH: container ${JSON.stringify(config.container)} does not exist.`, + ); } switch (container.type) { - case 'virtual-machine': + case "virtual-machine": if (volume.content_type === "filesystem") { - throw new Error(`Type: ${container.type} can only mount block type volumes.`); + throw new Error( + `Type: ${container.type} can only mount block type volumes.`, + ); } break; - case 'container': + case "container": if (volume.content_type === "block") { - throw new Error(`Type: ${container.type} can only mount filesystem type volumes.`); + throw new Error( + `Type: ${container.type} can only mount filesystem type volumes.`, + ); } } - if (volume.content_type === "filesystem" && (config.path == null)) { - throw new Error("Missing requirement: Path is required for filesystem type volumes."); + if (volume.content_type === "filesystem" && config.path == null) { + throw new Error( + "Missing requirement: Path is required for filesystem type volumes.", + ); } - const {$status} = await this.incus.query({ + const { $status } = await this.incus.query({ path: `/1.0/instances/${config.container}`, - request: 'PATCH', + request: "PATCH", data: JSON.stringify({ devices: { [`${config.device}`]: { pool: config.pool, source: config.name, type: "disk", - path: config.path != null ? config.path : null - } - } + path: config.path != null ? config.path : null, + }, + }, }), wait: true, format: "string", - code: [0, 1] + code: [0, 1], }); return { - $status: $status + $status: $status, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/storage/volume/delete/index.js b/packages/incus/lib/storage/volume/delete/index.js index 3399160c1..2beb664cd 100644 --- a/packages/incus/lib/storage/volume/delete/index.js +++ b/packages/incus/lib/storage/volume/delete/index.js @@ -1,21 +1,25 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Actions export default { - handler: async function({config}) { - const {$status} = await this.incus.query({ + handler: async function ({ config }) { + const { $status } = await this.incus.query({ path: `/1.0/storage-pools/${config.pool}/volumes/${config.type}/${config.name}`, request: "DELETE", - format: 'string', - code: [0, 1] + format: "string", + code: [0, 1], }); return { - $status: $status + $status: $status, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/storage/volume/get/index.js b/packages/incus/lib/storage/volume/get/index.js index 2aa279fba..cad63a7e9 100644 --- a/packages/incus/lib/storage/volume/get/index.js +++ b/packages/incus/lib/storage/volume/get/index.js @@ -1,20 +1,24 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status, data} = await this.incus.query({ + handler: async function ({ config }) { + const { $status, data } = await this.incus.query({ path: `/1.0/storage-pools/${config.pool}/volumes/${config.type}/${config.name}`, - code: [0, 1] + code: [0, 1], }); return { $status: $status, - data: data + data: data, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/storage/volume/index.js b/packages/incus/lib/storage/volume/index.js index f7ae08cfb..600393c1f 100644 --- a/packages/incus/lib/storage/volume/index.js +++ b/packages/incus/lib/storage/volume/index.js @@ -1,27 +1,31 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {$status} = await this.incus.query({ + handler: async function ({ config }) { + const { $status } = await this.incus.query({ path: `/1.0/storage-pools/${config.pool}/volumes/${config.type}`, request: "POST", data: JSON.stringify({ name: config.name, config: config.properties != null ? config.properties : {}, content_type: config.content != null ? config.content : null, - description: config.description != null ? config.description : null + description: config.description != null ? config.description : null, }), - format: 'string', - code: [0, 1] + format: "string", + code: [0, 1], }); return { - $status: $status + $status: $status, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/storage/volume/list/index.js b/packages/incus/lib/storage/volume/list/index.js index ff3f7732f..c8812ec76 100644 --- a/packages/incus/lib/storage/volume/list/index.js +++ b/packages/incus/lib/storage/volume/list/index.js @@ -1,23 +1,27 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - let {$status, data} = await this.incus.query({ + handler: async function ({ config }) { + let { $status, data } = await this.incus.query({ path: `/1.0/storage-pools/${config.pool}/volumes/${config.type}`, - code: [0, 1] + code: [0, 1], }); - if(!Array.isArray(data)){ - data = [] // empty list of volumes return `{}` instead of `[]` + if (!Array.isArray(data)) { + data = []; // empty list of volumes return `{}` instead of `[]` } return { $status: $status, - list: data.map( paths => paths.split('/').pop()) + list: data.map((paths) => paths.split("/").pop()), }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/incus/lib/utils/index.js b/packages/incus/lib/utils/index.js index d8e247c3d..0b8b965e0 100644 --- a/packages/incus/lib/utils/index.js +++ b/packages/incus/lib/utils/index.js @@ -1,8 +1,8 @@ // Dependencies import utils from "@nikitajs/core/utils"; -import stderr_to_error_message from '@nikitajs/incus/utils/stderr_to_error_message'; +import stderr_to_error_message from "@nikitajs/incus/utils/stderr_to_error_message"; export default { ...utils, - stderr_to_error_message: stderr_to_error_message + stderr_to_error_message: stderr_to_error_message, }; diff --git a/packages/incus/lib/utils/stderr_to_error_message.js b/packages/incus/lib/utils/stderr_to_error_message.js index 835be6c15..52afe4f92 100644 --- a/packages/incus/lib/utils/stderr_to_error_message.js +++ b/packages/incus/lib/utils/stderr_to_error_message.js @@ -1,9 +1,9 @@ // Dependencies import utils from "@nikitajs/core/utils"; -export default function(err, stderr) { +export default function (err, stderr) { stderr = stderr.trim(); if (utils.string.lines(stderr).length === 1) { - return err.message = stderr; + return (err.message = stderr); } -}; +} diff --git a/packages/incus/lib/wait/ready/index.js b/packages/incus/lib/wait/ready/index.js index d14360a03..e39e0560e 100644 --- a/packages/incus/lib/wait/ready/index.js +++ b/packages/incus/lib/wait/ready/index.js @@ -1,6 +1,11 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -49,7 +54,7 @@ export default { throw Error("Reschedule: Internet not ready"); } } - } + }, ); return { $status: $status, diff --git a/packages/ipa/env/ipa/index.js b/packages/ipa/env/ipa/index.js index 13138433f..a1b7fa933 100644 --- a/packages/ipa/env/ipa/index.js +++ b/packages/ipa/env/ipa/index.js @@ -1,8 +1,7 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const __dirname = new URL( '.', import.meta.url).pathname; +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const __dirname = new URL(".", import.meta.url).pathname; // Note: @@ -32,9 +31,9 @@ const __dirname = new URL( '.', import.meta.url).pathname; // Long term solution: // Disable the re-generation of resolv.conf by /usr/sbin/dhclient-script runner({ - cwd: '/nikita/packages/ipa', - container: 'nikita-ipa', - logdir: path.resolve(__dirname, './logs'), + cwd: "/nikita/packages/ipa", + container: "nikita-ipa", + logdir: path.resolve(__dirname, "./logs"), cluster: { // FreeIPA do a reverse lookup on initialisation // Using the default bridge yields to the error "The host name @@ -42,55 +41,61 @@ runner({ // reverse lookup on IP address fd42:f662:97ea:ba7f:216:3eff:fe1d:96f2%215" networks: { nktipapub: { - 'ipv4.address': '10.10.11.1/24', - 'ipv4.nat': true, - 'ipv6.address': 'none', - 'dns.domain': 'nikita.local' - } + "ipv4.address": "10.10.11.1/24", + "ipv4.nat": true, + "ipv6.address": "none", + "dns.domain": "nikita.local", + }, }, containers: { - 'nikita-ipa': { - image: 'images:almalinux/8', + "nikita-ipa": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/ipa/env/ipa/test.coffee', - 'raw.idmap': process.env['NIKITA_INCUS_IN_VAGRANT'] ? 'both 1000 0' : `both ${process.getuid()} 0` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/ipa/env/ipa/test.coffee", + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" + : `both ${process.getuid()} 0`, }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(__dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || + path.join(__dirname, "../../../../"), + }, }, nic: { eth0: { - name: 'eth0', - nictype: 'bridged', - parent: 'nktipapub', - 'ipv4.address': '10.10.11.2' - } + name: "eth0", + nictype: "bridged", + parent: "nktipapub", + "ipv4.address": "10.10.11.2", + }, }, proxy: { ssh: { - listen: 'tcp:0.0.0.0:2200', - connect: 'tcp:127.0.0.1:22' + listen: "tcp:0.0.0.0:2200", + connect: "tcp:127.0.0.1:22", }, ipa_ui_http: { - listen: 'tcp:0.0.0.0:2080', - connect: 'tcp:127.0.0.1:80' + listen: "tcp:0.0.0.0:2080", + connect: "tcp:127.0.0.1:80", }, ipa_ui_https: { - listen: 'tcp:0.0.0.0:2443', - connect: 'tcp:127.0.0.1:443' - } + listen: "tcp:0.0.0.0:2443", + connect: "tcp:127.0.0.1:443", + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", code: [0, 42], command: dedent` dnf install -y tar # Not present on almalinux @@ -100,10 +105,10 @@ runner({ nvm install 22 `, container: config.container, - trap: true + trap: true, }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", code: [0, 42], command: dedent` grep "\`cat /root/.ssh/id_rsa.pub\`" /root/.ssh/authorized_keys && exit 42 @@ -114,10 +119,10 @@ runner({ fi `, container: config.container, - trap: true + trap: true, }); await this.incus.exec({ - $header: 'Install FreeIPA', + $header: "Install FreeIPA", code: [0, 42], // Other possibilities to check ipa status: // echo > /dev/tcp/localhost/443 @@ -130,8 +135,8 @@ runner({ dnf install -y freeipa-server ipa-server-dns hostnamectl set-hostname ipa.nikita.local --static ${[ - 'ipa-server-install', - '-U', + "ipa-server-install", + "-U", // Basic options "-a admin_pw", "-p manager_pw", @@ -152,23 +157,23 @@ runner({ // Chrony doesnt start inside a container, no permission to change clock // Fatal error : adjtimex(0x8001) failed : Operation not permitted // See https://bugs.launchpad.net/ubuntu/+source/chrony/+bug/1589780 - "--no-ntp" - ].join(' ')} + "--no-ntp", + ].join(" ")} `, - container: config.container + container: config.container, }); // ipa-server-install --uninstall // ipa-server-install -U -a admin_pw -p manager_pw --hostname ipa.nikita.local --domain nikita.local --auto-reverse --setup-dns --auto-forwarders -r NIKITA.LOCAL await this.incus.exec({ - $header: 'Immutable DNS', + $header: "Immutable DNS", code: [0, 42], command: dedent` cat /etc/sysconfig/network-scripts/ifcfg-eth0 | egrep '^PEERDNS=no' && exit 42 echo 'PEERDNS=no' >> /etc/sysconfig/network-scripts/ifcfg-eth0 `, container: config.container, - trap: true + trap: true, }); - } - } + }, + }, }); diff --git a/packages/ipa/lib/group/add_member/index.js b/packages/ipa/lib/group/add_member/index.js index 29a30992d..9933cdec7 100644 --- a/packages/ipa/lib/group/add_member/index.js +++ b/packages/ipa/lib/group/add_member/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "group_add_member/1", params: [[config.cn], config.attributes], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -22,10 +26,10 @@ export default { } return { $status: true, - result: data.result.result + result: data.result.result, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/group/del/index.js b/packages/ipa/lib/group/del/index.js index 3735f42e6..be8506621 100644 --- a/packages/ipa/lib/group/del/index.js +++ b/packages/ipa/lib/group/del/index.js @@ -1,30 +1,34 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {$status: exists} = await this.ipa.group.exists({ + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { $status: exists } = await this.ipa.group.exists({ $shy: false, connection: config.connection, - cn: config.cn + cn: config.cn, }); if (!exists) { return; } return await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "group_del/1", params: [[config.cn], {}], - id: 0 - } + id: 0, + }, }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/group/exists/index.js b/packages/ipa/lib/group/exists/index.js index b970620c6..d710fff45 100644 --- a/packages/ipa/lib/group/exists/index.js +++ b/packages/ipa/lib/group/exists/index.js @@ -1,32 +1,37 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; try { await this.ipa.group.show({ connection: config.connection, - cn: config.cn + cn: config.cn, }); return { $status: true, - exists: true + exists: true, }; } catch (error) { - if (error.code !== 4001) { // group not found + if (error.code !== 4001) { + // group not found throw error; } return { $status: false, - exists: false + exists: false, }; } }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/ipa/lib/group/index.js b/packages/ipa/lib/group/index.js index 45b0853de..df5ba2794 100644 --- a/packages/ipa/lib/group/index.js +++ b/packages/ipa/lib/group/index.js @@ -1,24 +1,28 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {exists} = await this.ipa.group.exists({ + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { exists } = await this.ipa.group.exists({ connection: config.connection, - cn: config.cn + cn: config.cn, }); // Add or modify a group - const {data} = await this.network.http(config.connection, { + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: !exists ? "group_add/1" : "group_mod/1", params: [[config.cn], config.attributes], - id: 0 - } + id: 0, + }, }); let result, $status; if (data.error != null) { @@ -35,17 +39,17 @@ export default { } // Get info even when no modification was performed if (!result) { - ({result} = await this.ipa.group.show({ + ({ result } = await this.ipa.group.show({ connection: config.connection, - cn: config.cn + cn: config.cn, })); } return { $status: $status, - result: result + result: result, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/group/show/index.js b/packages/ipa/lib/group/show/index.js index 217958417..a9805fb50 100644 --- a/packages/ipa/lib/group/show/index.js +++ b/packages/ipa/lib/group/show/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "group_show/1", params: [[config.cn], {}], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -21,11 +25,11 @@ export default { throw error; } else { return { - result: data.result.result + result: data.result.result, }; } }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/register.js b/packages/ipa/lib/register.js index dfadced2e..d67bd6e68 100644 --- a/packages/ipa/lib/register.js +++ b/packages/ipa/lib/register.js @@ -1,35 +1,34 @@ - // Dependencies -import '@nikitajs/network/register'; +import "@nikitajs/network/register"; import registry from "@nikitajs/core/registry"; // Action registration const actions = { ipa: { group: { - '': '@nikitajs/ipa/group', - add_member: '@nikitajs/ipa/group/add_member', - del: '@nikitajs/ipa/group/del', - exists: '@nikitajs/ipa/group/exists', - show: '@nikitajs/ipa/group/show' + "": "@nikitajs/ipa/group", + add_member: "@nikitajs/ipa/group/add_member", + del: "@nikitajs/ipa/group/del", + exists: "@nikitajs/ipa/group/exists", + show: "@nikitajs/ipa/group/show", }, user: { - '': '@nikitajs/ipa/user', - disable: '@nikitajs/ipa/user/disable', - del: '@nikitajs/ipa/user/del', - enable: '@nikitajs/ipa/user/enable', - exists: '@nikitajs/ipa/user/exists', - find: '@nikitajs/ipa/user/find', - show: '@nikitajs/ipa/user/show', - status: '@nikitajs/ipa/user/status' + "": "@nikitajs/ipa/user", + disable: "@nikitajs/ipa/user/disable", + del: "@nikitajs/ipa/user/del", + enable: "@nikitajs/ipa/user/enable", + exists: "@nikitajs/ipa/user/exists", + find: "@nikitajs/ipa/user/find", + show: "@nikitajs/ipa/user/show", + status: "@nikitajs/ipa/user/status", }, service: { - '': '@nikitajs/ipa/service', - del: '@nikitajs/ipa/service/del', - exists: '@nikitajs/ipa/service/exists', - show: '@nikitajs/ipa/service/show' - } - } + "": "@nikitajs/ipa/service", + del: "@nikitajs/ipa/service/del", + exists: "@nikitajs/ipa/service/exists", + show: "@nikitajs/ipa/service/show", + }, + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/ipa/lib/service/del/index.js b/packages/ipa/lib/service/del/index.js index c5d33af6d..24b80fab2 100644 --- a/packages/ipa/lib/service/del/index.js +++ b/packages/ipa/lib/service/del/index.js @@ -1,30 +1,34 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {$status: exists} = await this.ipa.service.exists({ + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { $status: exists } = await this.ipa.service.exists({ $shy: false, connection: config.connection, - principal: config.principal + principal: config.principal, }); if (!exists) { return; } await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "service_del/1", params: [[config.principal], {}], - id: 0 - } + id: 0, + }, }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/service/exists/index.js b/packages/ipa/lib/service/exists/index.js index 820180dd7..b71e37b21 100644 --- a/packages/ipa/lib/service/exists/index.js +++ b/packages/ipa/lib/service/exists/index.js @@ -1,32 +1,37 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; try { await this.ipa.service.show({ connection: config.connection, - principal: config.principal + principal: config.principal, }); return { $status: true, - exists: true + exists: true, }; } catch (error) { - if (error.code !== 4001) { // service not found + if (error.code !== 4001) { + // service not found throw error; } return { $status: false, - exists: false + exists: false, }; } }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/ipa/lib/service/index.js b/packages/ipa/lib/service/index.js index a3a3cdfaa..7c814ff68 100644 --- a/packages/ipa/lib/service/index.js +++ b/packages/ipa/lib/service/index.js @@ -1,23 +1,28 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "service_add/1", params: [[config.principal], {}], - id: 0 - } + id: 0, + }, }); let status = true; if (data.error !== null) { - if (data.error.code !== 4002) { // principal alredy exists + if (data.error.code !== 4002) { + // principal alredy exists const error = Error(data.error.message); error.code = data.error.code; throw error; @@ -25,10 +30,10 @@ export default { status = false; } return { - $status: status + $status: status, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/service/show/index.js b/packages/ipa/lib/service/show/index.js index 01a617db9..a020e5dcb 100644 --- a/packages/ipa/lib/service/show/index.js +++ b/packages/ipa/lib/service/show/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { - method: 'service_show/1', + method: "service_show/1", params: [[config.principal], {}], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -21,11 +25,11 @@ export default { throw error; } else { return { - result: data.result.result + result: data.result.result, }; } }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/del/index.js b/packages/ipa/lib/user/del/index.js index 49098ff9c..21fbd2d04 100644 --- a/packages/ipa/lib/user/del/index.js +++ b/packages/ipa/lib/user/del/index.js @@ -1,38 +1,42 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {$status} = await this.ipa.user.exists({ + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { $status } = await this.ipa.user.exists({ $shy: false, connection: config.connection, - uid: config.uid + uid: config.uid, }); if (!$status) { return; } await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "user_del/1", params: [[config.uid], {}], - id: 0 - } + id: 0, + }, }); }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } return delete config.username; - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/disable/index.js b/packages/ipa/lib/user/disable/index.js index 7b7f0cc78..d1d23344d 100644 --- a/packages/ipa/lib/user/disable/index.js +++ b/packages/ipa/lib/user/disable/index.js @@ -1,40 +1,44 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; const { - result: {nsaccountlock} + result: { nsaccountlock }, } = await this.ipa.user.show({ $shy: false, connection: config.connection, - uid: config.uid + uid: config.uid, }); if (nsaccountlock === true) { return false; } await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "user_disable/1", params: [[config.uid], {}], - id: 0 - } + id: 0, + }, }); }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } return delete config.username; - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/enable/index.js b/packages/ipa/lib/user/enable/index.js index 425a68652..81e251a31 100644 --- a/packages/ipa/lib/user/enable/index.js +++ b/packages/ipa/lib/user/enable/index.js @@ -1,11 +1,15 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; const { result: { nsaccountlock }, } = await this.ipa.user.show({ @@ -18,23 +22,23 @@ export default { } await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { method: "user_enable/1", params: [[config.uid], {}], - id: 0 - } + id: 0, + }, }); }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } return delete config.username; - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/exists/index.js b/packages/ipa/lib/user/exists/index.js index 33a8a9d1b..7160d7179 100644 --- a/packages/ipa/lib/user/exists/index.js +++ b/packages/ipa/lib/user/exists/index.js @@ -1,40 +1,45 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; try { await this.ipa.user.show({ connection: config.connection, - uid: config.uid + uid: config.uid, }); return { $status: true, - exists: true + exists: true, }; } catch (error) { - if (error.code !== 4001) { // user not found + if (error.code !== 4001) { + // user not found throw error; } return { $status: false, - exists: false + exists: false, }; } }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } return delete config.username; - } + }, }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/ipa/lib/user/find/index.js b/packages/ipa/lib/user/find/index.js index aa2d7d19c..748e7f7d7 100644 --- a/packages/ipa/lib/user/find/index.js +++ b/packages/ipa/lib/user/find/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { - method: 'user_find/1', + method: "user_find/1", params: [[], config.criterias || {}], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -21,10 +25,10 @@ export default { throw error; } return { - result: data.result.result + result: data.result.result, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/index.js b/packages/ipa/lib/user/index.js index 1f71dba52..06c071bbe 100644 --- a/packages/ipa/lib/user/index.js +++ b/packages/ipa/lib/user/index.js @@ -1,64 +1,70 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {exists} = await this.ipa.user.exists({ + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { exists } = await this.ipa.user.exists({ connection: config.connection, - uid: config.uid + uid: config.uid, }); if (exists && !config.force_userpassword) { config.attributes.userpassword = undefined; } - const {data} = await this.network.http(config.connection, { + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { - method: !exists ? 'user_add/1' : 'user_mod/1', + method: !exists ? "user_add/1" : "user_mod/1", params: [[config.uid], config.attributes], - id: 0 - } + id: 0, + }, }); - let result, $status = true; + let result, + $status = true; if (data.error !== null) { - if (data.error.code !== 4202) { // no modifications to be performed + if (data.error.code !== 4202) { + // no modifications to be performed const error = Error(data.error.message); error.code = data.error.code; throw error; } $status = false; - }else{ + } else { result = data.result.result; } // Get info even when no modification was performed if (!result) { - ({result} = await this.ipa.user.show({ + ({ result } = await this.ipa.user.show({ connection: config.connection, uid: config.uid, })); } return { result: result, - $status: $status + $status: $status, }; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } delete config.username; if (config.attributes) { - if (typeof config.attributes.mail === 'string') { - return config.attributes.mail = [config.attributes.mail]; + if (typeof config.attributes.mail === "string") { + return (config.attributes.mail = [config.attributes.mail]); } } - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/show/index.js b/packages/ipa/lib/user/show/index.js index 8b3474921..500fbbcd3 100644 --- a/packages/ipa/lib/user/show/index.js +++ b/packages/ipa/lib/user/show/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { - method: 'user_show/1', + method: "user_show/1", params: [[config.uid], {}], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -21,18 +25,18 @@ export default { throw error; } return { - result: data.result.result + result: data.result.result, }; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } return delete config.username; - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ipa/lib/user/status/index.js b/packages/ipa/lib/user/status/index.js index 969fb723c..3961d5497 100644 --- a/packages/ipa/lib/user/status/index.js +++ b/packages/ipa/lib/user/status/index.js @@ -1,19 +1,23 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.connection.http_headers['Referer'] ??= config.connection.referer || config.connection.url; - const {data} = await this.network.http(config.connection, { + handler: async function ({ config }) { + config.connection.http_headers["Referer"] ??= + config.connection.referer || config.connection.url; + const { data } = await this.network.http(config.connection, { negotiate: true, - method: 'POST', + method: "POST", data: { - method: 'user_status/1', + method: "user_status/1", params: [[config.uid], {}], - id: 0 - } + id: 0, + }, }); if (data.error) { const error = Error(data.error.message); @@ -22,19 +26,19 @@ export default { } else { return { // Note, result is an array, get the first and only element - result: data.result.result[0] + result: data.result.result[0], }; } }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.uid == null) { config.uid = config.username; } delete config.username; - } + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/java/lib/keystore/add/index.js b/packages/java/lib/keystore/add/index.js index 370675d43..f89a66f51 100644 --- a/packages/java/lib/keystore/add/index.js +++ b/packages/java/lib/keystore/add/index.js @@ -2,7 +2,12 @@ import dedent from "dedent"; import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -15,17 +20,17 @@ export default { // Update paths in case of download const files = { cert: - ssh && config.local && config.cert != null - ? `${tmpdir}/${path.local.basename(config.cert)}` - : config.cert, + ssh && config.local && config.cert != null ? + `${tmpdir}/${path.local.basename(config.cert)}` + : config.cert, cacert: - ssh && config.local && config.cacert != null - ? `${tmpdir}/${path.local.basename(config.cacert)}` - : config.cacert, + ssh && config.local && config.cacert != null ? + `${tmpdir}/${path.local.basename(config.cacert)}` + : config.cacert, key: - ssh && config.local && config.key != null - ? `${tmpdir}/${path.local.basename(config.key)}` - : config.key, + ssh && config.local && config.key != null ? + `${tmpdir}/${path.local.basename(config.key)}` + : config.key, }; // Temporary directory // Used to upload certificates and to isolate certificates from their file @@ -67,7 +72,7 @@ export default { target: path.dirname(config.keystore), }); try { - if (!!config.cert) { + if (config.cert) { await this.execute({ bash: true, command: dedent` @@ -185,7 +190,7 @@ export default { "Keystore password is invalid,", "change it manually with:", `\`keytool -storepasswd -keystore ${esa( - config.keystore + config.keystore, )} -storepass -new '\``, ]); } diff --git a/packages/java/lib/keystore/exists/index.js b/packages/java/lib/keystore/exists/index.js index 772fb8552..83b498395 100644 --- a/packages/java/lib/keystore/exists/index.js +++ b/packages/java/lib/keystore/exists/index.js @@ -2,7 +2,12 @@ import dedent from "dedent"; import utils from "@nikitajs/core/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/java/lib/keystore/remove/index.js b/packages/java/lib/keystore/remove/index.js index 61617eb04..1e5b3d402 100644 --- a/packages/java/lib/keystore/remove/index.js +++ b/packages/java/lib/keystore/remove/index.js @@ -1,11 +1,17 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const aliases = [...config.caname, ...config.name].join(' ').trim(); + handler: async function ({ config }) { + const aliases = [...config.caname, ...config.name].join(" ").trim(); await this.execute({ bash: true, command: dedent` @@ -27,7 +33,7 @@ export default { [ $count -eq 0 ] && exit 3 exit 0 `, - code: [0, 3] + code: [0, 3], }).catch((error) => { if (error.exit_code === 43) { throw utils.error("NIKITA_JAVA_KEYTOOL_NOT_FOUND", [ @@ -40,6 +46,6 @@ export default { }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/krb5/lib/addprinc/index.js b/packages/krb5/lib/addprinc/index.js index b0def295b..9333b4968 100644 --- a/packages/krb5/lib/addprinc/index.js +++ b/packages/krb5/lib/addprinc/index.js @@ -1,33 +1,38 @@ - // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { + handler: async function ({ config }) { if (/.*@.*/.test(config.admin?.principal)) { // Normalize realm and principal for later usage of config if (config.admin.realm == null) { - config.admin.realm = config.admin.principal.split('@')[1]; + config.admin.realm = config.admin.principal.split("@")[1]; } } if (!/^\S+@\S+$/.test(config.principal)) { config.principal = `${config.principal}@${config.admin.realm}`; } // Start execution - const {$status: exists} = await this.krb5.execute({ + const { $status: exists } = await this.krb5.execute({ $shy: true, admin: config.admin, command: `getprinc ${config.principal}`, - grep: new RegExp(`^.*${utils.regexp.escape(config.principal)}$`) + grep: new RegExp(`^.*${utils.regexp.escape(config.principal)}$`), }); if (!exists) { await this.krb5.execute({ $retry: 3, admin: config.admin, - command: config.password - ? `addprinc -pw ${config.password} ${config.principal}` + command: + config.password ? + `addprinc -pw ${config.password} ${config.principal}` : `addprinc -randkey ${config.principal}`, }); } @@ -39,18 +44,22 @@ export default { // On success, write the ticket to a temporary location before cleanup $unless_execute: `if ! echo ${config.password} | kinit '${config.principal}' -c '${cache_name}'; then exit 1; else kdestroy -c '${cache_name}'; fi`, admin: config.admin, - command: `cpw -pw ${config.password} ${config.principal}` + command: `cpw -pw ${config.password} ${config.principal}`, }); } if (!config.keytab) { return; } await this.krb5.ktadd({ - ...utils.object.filter(config, [], ["admin", "gid", "keytab", "mode", "principal", "realm", "uid"]), + ...utils.object.filter( + config, + [], + ["admin", "gid", "keytab", "mode", "principal", "realm", "uid"], + ), }); }, metadata: { - global: 'krb5', - definitions: definitions - } + global: "krb5", + definitions: definitions, + }, }; diff --git a/packages/krb5/lib/delprinc/index.js b/packages/krb5/lib/delprinc/index.js index 69280c6d5..3aece6aef 100644 --- a/packages/krb5/lib/delprinc/index.js +++ b/packages/krb5/lib/delprinc/index.js @@ -1,39 +1,43 @@ - // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (/.*@.*/.test(config.admin.principal)) { // Normalize realm and principal for later usage of config if (config.realm == null) { - config.realm = config.admin.principal.split('@')[1]; + config.realm = config.admin.principal.split("@")[1]; } } if (!/^\S+@\S+$/.test(config.principal)) { config.principal = `${config.principal}@${config.realm}`; } // Prepare commands - const {$status} = await this.krb5.execute({ + const { $status } = await this.krb5.execute({ $shy: true, admin: config.admin, command: `getprinc ${config.principal}`, - grep: new RegExp(`^.*${utils.regexp.escape(config.principal)}$`) + grep: new RegExp(`^.*${utils.regexp.escape(config.principal)}$`), }); await this.krb5.execute({ $if: $status, admin: config.admin, - command: `delprinc -force ${config.principal}` + command: `delprinc -force ${config.principal}`, }); await this.fs.remove({ $if: config.keytab, - target: config.keytab + target: config.keytab, }); }, metadata: { - global: 'krb5', - definitions: definitions - } + global: "krb5", + definitions: definitions, + }, }; diff --git a/packages/krb5/lib/execute/index.js b/packages/krb5/lib/execute/index.js index 4b58516ab..fec29c3dd 100644 --- a/packages/krb5/lib/execute/index.js +++ b/packages/krb5/lib/execute/index.js @@ -1,21 +1,28 @@ - // Dependencies import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const realm = config.admin.realm ? `-r ${config.admin.realm}` : ''; - const {stdout} = await this.execute({ - command: config.admin.principal ? `kadmin ${realm} -p ${config.admin.principal} -s ${config.admin.server} -w ${config.admin.password} -q '${config.command}'` : `kadmin.local ${realm} -q '${config.command}'` + handler: async function ({ config }) { + const realm = config.admin.realm ? `-r ${config.admin.realm}` : ""; + const { stdout } = await this.execute({ + command: + config.admin.principal ? + `kadmin ${realm} -p ${config.admin.principal} -s ${config.admin.server} -w ${config.admin.password} -q '${config.command}'` + : `kadmin.local ${realm} -q '${config.command}'`, }); - if (config.grep && typeof config.grep === 'string') { + if (config.grep && typeof config.grep === "string") { return { stdout: stdout, - $status: stdout.split('\n').some(function(line) { + $status: stdout.split("\n").some(function (line) { return line === config.grep; - }) + }), }; } if (config.grep && utils.regexp.is(config.grep)) { @@ -26,18 +33,18 @@ export default { } return { $status: true, - stdout: stdout + stdout: stdout, }; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (config.egrep != null) { - throw Error('Deprecated config `egrep`'); + throw Error("Deprecated config `egrep`"); } - } + }, }, metadata: { - global: 'krb5', - definitions: definitions - } + global: "krb5", + definitions: definitions, + }, }; diff --git a/packages/krb5/lib/ktadd/index.js b/packages/krb5/lib/ktadd/index.js index 6aa23fc3b..7697f81a0 100644 --- a/packages/krb5/lib/ktadd/index.js +++ b/packages/krb5/lib/ktadd/index.js @@ -1,18 +1,19 @@ - // Dependencies -import path from 'node:path' +import path from "node:path"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { if (/^\S+@\S+$/.test(config.admin.principal)) { if (config.realm == null) { - config.realm = config.admin.principal.split('@')[1]; + config.realm = config.admin.principal.split("@")[1]; } } else { if (!config.realm) { @@ -23,38 +24,41 @@ export default { let keytab = {}; let princ = {}; // Get keytab information - const {$status: entriesExist, stdout: entriesStdout} = await this.execute({ - $shy: true, - command: `export TZ=GMT; klist -kt ${config.keytab}`, - code: [0, 1] - }); + const { $status: entriesExist, stdout: entriesStdout } = await this.execute( + { + $shy: true, + command: `export TZ=GMT; klist -kt ${config.keytab}`, + code: [0, 1], + }, + ); if (entriesExist) { - log('DEBUG', "Keytab exists, check kvno validity"); + log("DEBUG", "Keytab exists, check kvno validity"); const lines = utils.string.lines(entriesStdout); for (const line of lines) { - const match = /^\s*(\d+)\s+([\d\/:]+\s+[\d\/:]+)\s+(.*)\s*$/.exec(line) + const match = /^\s*(\d+)\s+([\d/:]+\s+[\d/:]+)\s+(.*)\s*$/.exec(line); if (!match) { continue; } - let [_, kvno, mdate, principal] = match; + let [, kvno, mdate, principal] = match; kvno = parseInt(kvno, 10); mdate = Date.parse(`${mdate} GMT`); // keytab[principal] ?= {kvno: null, mdate: null} if (!keytab[principal] || keytab[principal].kvno < kvno) { keytab[principal] = { kvno: kvno, - mdate: mdate + mdate: mdate, }; } } } // Get principal information if (keytab[config.principal] != null) { - const {$status: princExists, stdout: princStdout} = await this.krb5.execute({ - $shy: true, - admin: config.admin, - command: `getprinc -terse ${config.principal}` - }); + const { $status: princExists, stdout: princStdout } = + await this.krb5.execute({ + $shy: true, + admin: config.admin, + command: `getprinc -terse ${config.principal}`, + }); if (princExists) { // return do_ktadd() unless -1 is stdout.indexOf 'does not exist' let values = utils.string.lines(princStdout)[1]; @@ -62,48 +66,63 @@ export default { // Check if a ticket exists for this throw Error(`Principal does not exist: '${config.principal}'`); } - values = values.split('\t'); + values = values.split("\t"); princ = { mdate: parseInt(values[2], 10) * 1000, - kvno: parseInt(values[8], 10) + kvno: parseInt(values[8], 10), }; - log('INFO', `Keytab kvno '${keytab[config.principal].kvno}', principal kvno '${princ.kvno}'`); - log('INFO', `Keytab mdate '${new Date(keytab[config.principal].mdate)}', principal mdate '${new Date(princ.mdate)}'`); + log( + "INFO", + `Keytab kvno '${keytab[config.principal].kvno}', principal kvno '${princ.kvno}'`, + ); + log( + "INFO", + `Keytab mdate '${new Date(keytab[config.principal].mdate)}', principal mdate '${new Date(princ.mdate)}'`, + ); } } // Remove principal from keytab await this.krb5.execute({ - $if: keytab[config.principal] != null && (keytab[config.principal].kvno !== princ.kvno || keytab[config.principal].mdate !== princ.mdate), + $if: + keytab[config.principal] != null && + (keytab[config.principal].kvno !== princ.kvno || + keytab[config.principal].mdate !== princ.mdate), admin: config.admin, - command: `ktremove -k ${config.keytab} ${config.principal}` + command: `ktremove -k ${config.keytab} ${config.principal}`, }); // Create keytab and add principal await this.fs.mkdir({ - $if: keytab[config.principal] == null || (keytab[config.principal].kvno !== princ.kvno || keytab[config.principal].mdate !== princ.mdate), - target: `${path.dirname(config.keytab)}` + $if: + keytab[config.principal] == null || + keytab[config.principal].kvno !== princ.kvno || + keytab[config.principal].mdate !== princ.mdate, + target: `${path.dirname(config.keytab)}`, }); await this.krb5.execute({ - $if: keytab[config.principal] == null || (keytab[config.principal].kvno !== princ.kvno || keytab[config.principal].mdate !== princ.mdate), + $if: + keytab[config.principal] == null || + keytab[config.principal].kvno !== princ.kvno || + keytab[config.principal].mdate !== princ.mdate, admin: config.admin, - command: `ktadd -k ${config.keytab} ${config.principal}` + command: `ktadd -k ${config.keytab} ${config.principal}`, }); // Keytab ownership and permissions await this.fs.chown({ $if: config.uid != null || config.gid != null, target: config.keytab, uid: config.uid, - gid: config.gid + gid: config.gid, }); await this.fs.chmod({ $if: config.mode != null, target: config.keytab, - mode: config.mode + mode: config.mode, }); }, metadata: { - global: 'krb5', - definitions: definitions - } + global: "krb5", + definitions: definitions, + }, }; // ## Fields in 'getprinc -terse' output diff --git a/packages/krb5/lib/ktutil/add/index.js b/packages/krb5/lib/ktutil/add/index.js index 843f0bff7..df7100743 100644 --- a/packages/krb5/lib/ktutil/add/index.js +++ b/packages/krb5/lib/ktutil/add/index.js @@ -1,7 +1,12 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -20,7 +25,7 @@ export default { let princ_entries = []; let princ = {}; // Get keytab entries - const { $status: entriesExist, stdout: entriesStdout, stderr } = await this.execute( + const { $status: entriesExist, stdout: entriesStdout } = await this.execute( { $shy: true, command: dedent` @@ -31,20 +36,20 @@ export default { CMD `, code: [0, 42, 1], - } + }, ); if (entriesExist) { log("DEBUG", "Principals exist in Keytab, check kvno validity"); const lines = utils.string.lines(entriesStdout); for (const line of lines) { const match = - /^\s*(\d+)\s*(\d+)\s+([\d\/:]+\s+[\d\/:]+)\s+(.*)\s*\(([\w|-]*)\)\s*$/.exec( - line + /^\s*(\d+)\s*(\d+)\s+([\d/:]+\s+[\d/:]+)\s+(.*)\s*\(([\w|-]*)\)\s*$/.exec( + line, ); if (!match) { continue; } - const [_, slot, kvno, timestamp, principal, enctype] = match; + const [, slot, kvno, timestamp, principal, enctype] = match; entries.push({ slot: slot, kvno: parseInt(kvno, 10), @@ -80,19 +85,19 @@ export default { const removeCommand = config.enctypes .map((enctype) => { const filteredPrincEntries = princ_entries.filter( - (entry) => entry.enctype === enctype + (entry) => entry.enctype === enctype, ); const entry = - filteredPrincEntries.length === 1 - ? entries.filter((entry) => entry.enctype === enctype)[0] - : null; + filteredPrincEntries.length === 1 ? + entries.filter((entry) => entry.enctype === enctype)[0] + : null; // remove entry if kvno not identical if (entry === null || entry?.kvno === princ.kvno) { return; } log( "INFO", - `Remove from Keytab kvno '${entry.kvno}', principal kvno '${princ.kvno}'` + `Remove from Keytab kvno '${entry.kvno}', principal kvno '${princ.kvno}'`, ); return `delete_entry ${entry != null ? entry.slot : void 0}`; }) @@ -107,7 +112,7 @@ export default { ${removeCommand.join("\n")} write_kt ${tmp_keytab} EOF - ` + `, }); await this.fs.move({ $if: removeCommand.length, @@ -124,12 +129,12 @@ export default { const createCommand = config.enctypes .map((enctype) => { const filteredPrincEntries = princ_entries.filter( - (entry) => entry.enctype === enctype + (entry) => entry.enctype === enctype, ); const entry = - filteredPrincEntries.length === 1 - ? entries.filter((entry) => entry.enctype === enctype)[0] - : null; + filteredPrincEntries.length === 1 ? + entries.filter((entry) => entry.enctype === enctype)[0] + : null; if (entry?.kvno === princ.kvno) { return; } @@ -143,7 +148,7 @@ export default { ${createCommand.join("\n")} wkt ${config.keytab} EOF - ` + `, }); // Keytab ownership and permissions await this.fs.chown({ diff --git a/packages/krb5/lib/register.js b/packages/krb5/lib/register.js index 09489e411..3a8daa9ac 100644 --- a/packages/krb5/lib/register.js +++ b/packages/krb5/lib/register.js @@ -1,19 +1,18 @@ - // Dependencies import registry from "@nikitajs/core/registry"; // Action registration const actions = { krb5: { - addprinc: '@nikitajs/krb5/addprinc', - delprinc: '@nikitajs/krb5/delprinc', - execute: '@nikitajs/krb5/execute', - ktadd: '@nikitajs/krb5/ktadd', - ticket: '@nikitajs/krb5/ticket', + addprinc: "@nikitajs/krb5/addprinc", + delprinc: "@nikitajs/krb5/delprinc", + execute: "@nikitajs/krb5/execute", + ktadd: "@nikitajs/krb5/ktadd", + ticket: "@nikitajs/krb5/ticket", ktutil: { - add: '@nikitajs/krb5/ktutil/add' - } - } + add: "@nikitajs/krb5/ktutil/add", + }, + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/krb5/lib/ticket/index.js b/packages/krb5/lib/ticket/index.js index 42e8dc0a5..7e19ad208 100644 --- a/packages/krb5/lib/ticket/index.js +++ b/packages/krb5/lib/ticket/index.js @@ -1,30 +1,36 @@ - // Dependencies import dedent from "dedent"; -import utils from '@nikitajs/krb5/utils'; -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/krb5/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { await this.execute({ command: dedent` - if ${utils.krb5.su(config, 'klist -s')}; then exit 3; fi + if ${utils.krb5.su(config, "klist -s")}; then exit 3; fi ${utils.krb5.kinit(config)} `, - code: [0, 3] + code: [0, 3], }); - if (!((config.uid != null || config.gid != null) && config.keytab != null)) { + if ( + !((config.uid != null || config.gid != null) && config.keytab != null) + ) { return; } await this.fs.chown({ uid: config.uid, gid: config.gid, - target: config.keytab + target: config.keytab, }); }, metadata: { // global: 'krb5', - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/krb5/lib/utils/index.js b/packages/krb5/lib/utils/index.js index f1e0b0481..0be9ff8b7 100644 --- a/packages/krb5/lib/utils/index.js +++ b/packages/krb5/lib/utils/index.js @@ -1,8 +1,7 @@ - import utils from "@nikitajs/core/utils"; -import krb5 from '@nikitajs/krb5/utils/krb5' +import krb5 from "@nikitajs/krb5/utils/krb5"; export default { ...utils, - krb5: krb5 + krb5: krb5, }; diff --git a/packages/ldap/lib/acl/index.js b/packages/ldap/lib/acl/index.js index c33771473..18d9c79b4 100644 --- a/packages/ldap/lib/acl/index.js +++ b/packages/ldap/lib/acl/index.js @@ -1,7 +1,12 @@ // Dependencies -import {is_object_literal, merge} from 'mixme'; +import { is_object_literal, merge } from "mixme"; import utils from "@nikitajs/ldap/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -123,7 +128,8 @@ export default { add: true, }; } - const old = olcAccess.old ? utils.ldap.acl.stringify(olcAccess.old) : undefined; + const old = + olcAccess.old ? utils.ldap.acl.stringify(olcAccess.old) : undefined; olcAccess = utils.ldap.acl.stringify(olcAccess); const operations = { dn: config.dn, @@ -156,9 +162,9 @@ export default { return $status; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (is_object_literal(config.acls)) { - return config.acls = [config.acls]; + return (config.acls = [config.acls]); } }, }, diff --git a/packages/ldap/lib/add/index.js b/packages/ldap/lib/add/index.js index 20ef6da2b..47206d21f 100644 --- a/packages/ldap/lib/add/index.js +++ b/packages/ldap/lib/add/index.js @@ -1,8 +1,13 @@ // Dependencies import dedent from "dedent"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import utils from "@nikitajs/ldap/utils" -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/ldap/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -31,12 +36,12 @@ export default { ldif += "\n"; ldif += `dn: ${entry.dn}\n`; ldif += "changetype: add\n"; - const [_, k, v] = /^(.*?)=(.+?),.*$/.exec(entry.dn); + const [, k, v] = /^(.*?)=(.+?),.*$/.exec(entry.dn); ldif += `${k}: ${v}\n`; if (entry[k]) { if (entry[k] !== v) { throw Error( - `Inconsistent value: ${entry[k]} is not ${v} for attribute ${k}` + `Inconsistent value: ${entry[k]} is not ${v} for attribute ${k}`, ); } delete entry[k]; @@ -60,15 +65,9 @@ export default { [ "ldapmodify", config.continuous ? "-c" : void 0, - config.mesh - ? `-Y ${esa(config.mesh)}` - : void 0, - config.binddn - ? `-D ${esa(config.binddn)}` - : void 0, - config.passwd - ? `-w ${esa(config.passwd)}` - : void 0, + config.mesh ? `-Y ${esa(config.mesh)}` : void 0, + config.binddn ? `-D ${esa(config.binddn)}` : void 0, + config.passwd ? `-w ${esa(config.passwd)}` : void 0, config.uri ? `-H ${esa(config.uri)}` : void 0, ].join(" "), dedent` diff --git a/packages/ldap/lib/delete/index.js b/packages/ldap/lib/delete/index.js index 182934994..5a35345ec 100644 --- a/packages/ldap/lib/delete/index.js +++ b/packages/ldap/lib/delete/index.js @@ -1,32 +1,36 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Auth related config - const binddn = config.binddn ? `-D ${config.binddn}` : ''; - const passwd = config.passwd ? `-w ${config.passwd}` : ''; + const binddn = config.binddn ? `-D ${config.binddn}` : ""; + const passwd = config.passwd ? `-w ${config.passwd}` : ""; if (config.uri === true) { if (config.mesh == null) { - config.mesh = 'EXTERNAL'; + config.mesh = "EXTERNAL"; } - config.uri = 'ldapi:///'; + config.uri = "ldapi:///"; } - const uri = config.uri ? `-H ${config.uri}` : ''; // URI is obtained from local openldap conf unless provided + const uri = config.uri ? `-H ${config.uri}` : ""; // URI is obtained from local openldap conf unless provided if (!Array.isArray(config.dn)) { // Add related config config.dn = [config.dn]; } - const dn = config.dn.map((dn) => `'${dn}'` ).join(' '); + const dn = config.dn.map((dn) => `'${dn}'`).join(" "); await this.execute({ // Check that the entry exists $if_execute: `ldapsearch ${binddn} ${passwd} ${uri} -b ${dn} -s base`, - command: `ldapdelete ${binddn} ${passwd} ${uri} ${dn}` + command: `ldapdelete ${binddn} ${passwd} ${uri} ${dn}`, }); }, metadata: { - global: 'ldap', - definitions: definitions - } + global: "ldap", + definitions: definitions, + }, }; diff --git a/packages/ldap/lib/index/index.js b/packages/ldap/lib/index/index.js index d06cac23a..0eb9cdb2a 100644 --- a/packages/ldap/lib/index/index.js +++ b/packages/ldap/lib/index/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/ldap/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -25,7 +30,8 @@ export default { filter: "(olcDbIndex=*)", }); for (const line of utils.string.lines(stdout)) { - let match; if (!(match = /^olcDbIndex:\s+(.*)\s+(.*)/.exec(line))) { + let match; + if (!(match = /^olcDbIndex:\s+(.*)\s+(.*)/.exec(line))) { continue; } const [, attrlist, indices] = match; diff --git a/packages/ldap/lib/modify/index.js b/packages/ldap/lib/modify/index.js index 8cf3c3603..e84ebdf1d 100644 --- a/packages/ldap/lib/modify/index.js +++ b/packages/ldap/lib/modify/index.js @@ -1,33 +1,38 @@ // Dependencies import dedent from "dedent"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import utils from '@nikitajs/ldap/utils' -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/ldap/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Auth related config if (config.uri === true) { if (config.mesh == null) { - config.mesh = 'EXTERNAL'; + config.mesh = "EXTERNAL"; } - config.uri = 'ldapi:///'; + config.uri = "ldapi:///"; } // const uri = config.uri ? `-H ${config.uri}` : ''; // URI is obtained from local openldap conf unless provided // Add related config - let ldif = ''; + let ldif = ""; const originals = []; for (const operation of config.operations) { if (!config.shortcut) { - const {stdout} = await this.ldap.search({ + const { stdout } = await this.ldap.search({ ...utils.ldap.config_connection(config), - base: operation.dn + base: operation.dn, }); originals.push(stdout); } // Generate ldif content - ldif += '\n'; + ldif += "\n"; ldif += `dn: ${operation.dn}\n`; ldif += "changetype: modify\n"; for (const attribute of operation.attributes) { @@ -35,7 +40,7 @@ export default { if (attribute.value) { ldif += `${attribute.name}: ${attribute.value}\n`; } - ldif += '-\n'; + ldif += "-\n"; } } await this.execute({ @@ -43,17 +48,13 @@ export default { [ "ldapmodify", config.continuous ? "-c" : undefined, - config.mesh - ? `-Y ${esa(config.mesh)}` - : undefined, - config.binddn - ? `-D ${esa(config.binddn)}` - : undefined, - config.passwd - ? `-w ${esa(config.passwd)}` - : undefined, + config.mesh ? `-Y ${esa(config.mesh)}` : undefined, + config.binddn ? `-D ${esa(config.binddn)}` : undefined, + config.passwd ? `-w ${esa(config.passwd)}` : undefined, config.uri ? `-H ${esa(config.uri)}` : undefined, - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), dedent` <<-EOF ${ldif} @@ -65,9 +66,9 @@ export default { for (const i in config.operations) { const operation = config.operations[i]; if (!config.shortcut) { - const {stdout} = await this.ldap.search({ + const { stdout } = await this.ldap.search({ ...utils.ldap.config_connection(config), - base: operation.dn + base: operation.dn, }); if (stdout !== originals[i]) { status = true; @@ -77,14 +78,14 @@ export default { return status; }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { if (!Array.isArray(config.operations)) { - return config.operations = [config.operations]; + return (config.operations = [config.operations]); } - } + }, }, metadata: { - global: 'ldap' + global: "ldap", }, - definitions: definitions + definitions: definitions, }; diff --git a/packages/ldap/lib/schema/index.js b/packages/ldap/lib/schema/index.js index 6ebe227f3..6d67afca3 100644 --- a/packages/ldap/lib/schema/index.js +++ b/packages/ldap/lib/schema/index.js @@ -1,5 +1,11 @@ // Dependencies -import definitions from "./schema.json" with { type: "json" }; +import path from "node:path"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -28,7 +34,7 @@ export default { // -b "cn=schema,cn=config" \ // "cn={8}samba,cn=schema,cn=config" const { $status: exists } = await this.execute({ - command: `ldapsearch -LLL ${binddn} ${passwd} ${uri} -b \"cn=schema,cn=config\" | grep -E cn=\\{[0-9]+\\}${config.name},cn=schema,cn=config`, + command: `ldapsearch -LLL ${binddn} ${passwd} ${uri} -b "cn=schema,cn=config" | grep -E cn=\\{[0-9]+\\}${config.name},cn=schema,cn=config`, code: [1, 0], }); if (!exists) { @@ -106,7 +112,7 @@ export default { await this.execute({ command: `ldapadd ${uri} ${binddn} ${passwd} -f ${ldifTmpDir}/cn=config/cn=schema/cn=${config.name}.ldif`, }); - log("INFO" `Schema added: ${config.name}`); + log("INFO"`Schema added: ${config.name}`); }, metadata: { tmpdir: true, diff --git a/packages/ldap/lib/search/index.js b/packages/ldap/lib/search/index.js index 701074d4e..15f0d6ac8 100644 --- a/packages/ldap/lib/search/index.js +++ b/packages/ldap/lib/search/index.js @@ -1,26 +1,31 @@ // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // ## Exports export default { - handler: async function({config}) { + handler: async function ({ config }) { // TODO: use nikita.ldap.search // Auth related config if (config.uri === true) { if (config.mesh == null) { - config.mesh = 'EXTERNAL'; + config.mesh = "EXTERNAL"; } - config.uri = 'ldapi:///'; + config.uri = "ldapi:///"; } // Add related config return await this.execute({ code: config.code, command: [ - 'ldapsearch', - '-o ldif-wrap=no', - '-LLL', // Remove comments - config.continuous ? '-c' : undefined, + "ldapsearch", + "-o ldif-wrap=no", + "-LLL", // Remove comments + config.continuous ? "-c" : undefined, config.mesh ? `-Y ${esa(config.mesh)}` : undefined, config.binddn ? `-D ${esa(config.binddn)}` : undefined, config.passwd ? `-w ${esa(config.passwd)}` : undefined, @@ -28,14 +33,16 @@ export default { `-b ${esa(config.base)}`, config.scope ? `-s ${esa(config.scope)}` : undefined, config.filter ? `${esa(config.filter)}` : undefined, - ...(config.attributes.map(esa)), - '2>/dev/null' - ].filter(Boolean).join(' ') + ...config.attributes.map(esa), + "2>/dev/null", + ] + .filter(Boolean) + .join(" "), }); }, metadata: { - global: 'ldap', + global: "ldap", shy: true, - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/ldap/lib/tools/database/index.js b/packages/ldap/lib/tools/database/index.js index 437badedc..b9159323c 100644 --- a/packages/ldap/lib/tools/database/index.js +++ b/packages/ldap/lib/tools/database/index.js @@ -1,25 +1,30 @@ // Dependencies -import utils from '@nikitajs/ldap/utils' -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/ldap/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {stdout} = await this.ldap.search({ + handler: async function ({ config }) { + const { stdout } = await this.ldap.search({ ...utils.ldap.config_connection(config), base: config.base, filter: `(olcSuffix= ${config.suffix})`, - attributes: ['dn'] + attributes: ["dn"], }); - const [, dn] = stdout.split(':').map(el => el.trim()); + const [, dn] = stdout.split(":").map((el) => el.trim()); const [, database] = /^olcDatabase=(.*),/.exec(dn); return { dn: dn, - database: database + database: database, }; }, metadata: { - global: 'ldap', - definitions: definitions - } + global: "ldap", + definitions: definitions, + }, }; diff --git a/packages/ldap/lib/tools/databases/index.js b/packages/ldap/lib/tools/databases/index.js index 7d4270ccf..ea661b501 100644 --- a/packages/ldap/lib/tools/databases/index.js +++ b/packages/ldap/lib/tools/databases/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/ldap/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -20,7 +25,7 @@ export default { }) .map(function (line) { return line.split(" ")[1]; - }) + }), ); return { databases: databases, diff --git a/packages/ldap/lib/user/index.js b/packages/ldap/lib/user/index.js index 92a4ac643..4d83ed575 100644 --- a/packages/ldap/lib/user/index.js +++ b/packages/ldap/lib/user/index.js @@ -1,7 +1,11 @@ // Dependencies -import {merge} from 'mixme'; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -51,18 +55,10 @@ export default { await this.execute({ command: [ "ldappasswd", - config.mesh - ? `-Y ${esa(config.mesh)}` - : void 0, - config.binddn - ? `-D ${esa(config.binddn)}` - : void 0, - config.passwd - ? `-w ${esa(config.passwd)}` - : void 0, - config.uri - ? `-H ${esa(config.uri)}` - : void 0, + config.mesh ? `-Y ${esa(config.mesh)}` : void 0, + config.binddn ? `-D ${esa(config.binddn)}` : void 0, + config.passwd ? `-w ${esa(config.passwd)}` : void 0, + config.uri ? `-H ${esa(config.uri)}` : void 0, `-s ${user.userPassword}`, `${esa(user.dn)}`, ].join(" "), diff --git a/packages/ldap/lib/utils/index.js b/packages/ldap/lib/utils/index.js index ed6c5389a..0feebdc63 100644 --- a/packages/ldap/lib/utils/index.js +++ b/packages/ldap/lib/utils/index.js @@ -1,8 +1,7 @@ - import utils from "@nikitajs/core/utils"; -import ldap from '@nikitajs/ldap/utils/ldap'; +import ldap from "@nikitajs/ldap/utils/ldap"; export default { ...utils, - ldap: ldap + ldap: ldap, }; diff --git a/packages/ldap/lib/utils/ldap.js b/packages/ldap/lib/utils/ldap.js index a44787caf..fc999b8ec 100644 --- a/packages/ldap/lib/utils/ldap.js +++ b/packages/ldap/lib/utils/ldap.js @@ -1,4 +1,4 @@ -import utils from "@nikitajs/core/utils" +import utils from "@nikitajs/core/utils"; export default { acl: { @@ -24,19 +24,19 @@ export default { ] ``` */ - parse: function(olcAccesses) { + parse: function (olcAccesses) { const isArray = Array.isArray(olcAccesses); if (!isArray) { olcAccesses = [olcAccesses]; } - olcAccesses = olcAccesses.map( olcAccess => { - const match = /^\{(\d+)\}to\s+(.*?)(\s*by\s+|$)(.*)$/.exec(olcAccess) - if (!match) throw Error('Invalid olcAccess entry'); + olcAccesses = olcAccesses.map((olcAccess) => { + const match = /^\{(\d+)\}to\s+(.*?)(\s*by\s+|$)(.*)$/.exec(olcAccess); + if (!match) throw Error("Invalid olcAccess entry"); return { index: parseInt(match[1], 10), to: match[2], by: match[4].split(/\s+by\s+/), - } + }; }); if (isArray) { return olcAccesses; @@ -49,7 +49,7 @@ export default { Stringify one or multiple "olcAccess" entries. */ - stringify: function(olcAccesses) { + stringify: function (olcAccesses) { const isArray = Array.isArray(olcAccesses); if (!isArray) { olcAccesses = [olcAccesses]; @@ -67,10 +67,10 @@ export default { } else { return olcAccesses[0]; } - } + }, }, - config_connection(config){ - return utils.object.filter(config, [], ['binddn', 'mesh', 'passwd', 'uri']) + config_connection(config) { + return utils.object.filter(config, [], ["binddn", "mesh", "passwd", "uri"]); }, index: { /* @@ -78,16 +78,16 @@ export default { Parse one or multiple "olcDbIndex" entries. */ - parse: function(indexes) { + parse: function (indexes) { const isArray = Array.isArray(indexes); if (!isArray) { indexes = [indexes]; } - indexes.forEach(function(index, i) { + indexes.forEach(function (index, i) { if (i === 0) { indexes = {}; } - const [k, v] = index.split(' '); + const [k, v] = index.split(" "); indexes[k] = v; }); if (isArray) { @@ -101,17 +101,17 @@ export default { Stringify one or multiple "olcDbIndex" entries. */ - stringify: function(indexes) { + stringify: function (indexes) { const isArray = Array.isArray(indexes); if (!isArray) { indexes = [indexes]; } - indexes = indexes.map((v, k) => `${k} ${v}`) + indexes = indexes.map((v, k) => `${k} ${v}`); if (isArray) { return indexes; } else { return indexes[0]; } - } - } + }, + }, }; diff --git a/packages/log/lib/cli/index.js b/packages/log/lib/cli/index.js index 85dff4d2e..62b5444b3 100644 --- a/packages/log/lib/cli/index.js +++ b/packages/log/lib/cli/index.js @@ -1,9 +1,14 @@ // Dependencies -import colors from 'colors/safe.js'; -import {merge} from 'mixme'; -import pad from 'pad'; -import utils from '@nikitajs/core/utils'; -import definitions from "./schema.json" with { type: "json" }; +import colors from "colors/safe.js"; +import { merge } from "mixme"; +import pad from "pad"; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Utils const format_line = function ({ host, header, status, time }, config) { @@ -24,7 +29,9 @@ const format_line = function ({ host, header, status, time }, config) { status, time && config.time ? config.separator.time : "", time, - ].filter(Boolean).join(""); + ] + .filter(Boolean) + .join(""); }; // Action @@ -74,25 +81,31 @@ export default { // }, "nikita:resolved": function ({ action }) { const color = config.colors ? config.colors.status_true : false; - let line = format_line({ - host: config.host ?? action.ssh?.config?.host ?? "local", - header: "", - status: "♥", - time: "", - }, config); + let line = format_line( + { + host: config.host ?? action.ssh?.config?.host ?? "local", + header: "", + status: "♥", + time: "", + }, + config, + ); if (color) { line = color(line); } return line + "\n"; }, - "nikita:rejected": function ({ action, error }) { + "nikita:rejected": function ({ action }) { const color = config.colors ? config.colors.status_error : false; - let line = format_line({ - host: config.host ?? action.ssh?.config?.host ?? "local", - header: "", - status: "✘", - time: "", - }, config); + let line = format_line( + { + host: config.host ?? action.ssh?.config?.host ?? "local", + header: "", + status: "✘", + time: "", + }, + config, + ); if (color) { line = color(line); } @@ -108,32 +121,39 @@ export default { // TODO: I don't like this, the `end` event should receive raw output // with error not placed inside output by the history plugin error = error || (action.metadata.relax && output.error); - const status = error - ? "✘" - : (output != null ? output.$status : void 0) && !action.metadata.shy - ? "✔" + const status = + error ? "✘" + : (output != null ? output.$status : void 0) && !action.metadata.shy ? + "✔" : "-"; - const color = !config.colors ? false : error - ? config.colors.status_error - : (output != null ? output.$status : void 0) - ? config.colors.status_true - : config.colors.status_false; + const color = + !config.colors ? false + : error ? config.colors.status_error + : ( + output != null ? output.$status : void 0 + ) ? + config.colors.status_true + : config.colors.status_false; if (action.metadata.disabled) { return null; } - const headers = get_headers(action); - let line = format_line({ - // error in relax mode don't yet have ssh inherited - host: config.host ?? action.ssh?.config?.host ?? "local", - header: headers.join(config.divider), - status: status, - // error in relax mode don't set time_start - time: config.time && action.metadata.time_start - ? utils.string.print_time( - action.metadata.time_end - action.metadata.time_start - ) - : "", - }, config); + const headers = get_headers(action); + let line = format_line( + { + // error in relax mode don't yet have ssh inherited + host: config.host ?? action.ssh?.config?.host ?? "local", + header: headers.join(config.divider), + status: status, + // error in relax mode don't set time_start + time: + config.time && action.metadata.time_start ? + utils.string.print_time( + action.metadata.time_end - action.metadata.time_start, + ) + : "", + }, + config, + ); if (color) { line = color(line); } @@ -152,15 +172,15 @@ export default { }, }; -const get_headers = function(action) { - const walk = function(parent) { +const get_headers = function (action) { + const walk = function (parent) { const precious = parent.metadata.header; const results = []; if (precious !== undefined) { results.push(precious); } if (parent.parent) { - results.push(...(walk(parent.parent))); + results.push(...walk(parent.parent)); } return results; }; diff --git a/packages/log/lib/csv/index.js b/packages/log/lib/csv/index.js index e942085fe..a5762cd06 100644 --- a/packages/log/lib/csv/index.js +++ b/packages/log/lib/csv/index.js @@ -1,16 +1,21 @@ // Dependencies -import {merge} from 'mixme'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: function({config}) { + handler: function ({ config }) { const serializer = { - 'nikita:action:start': function({action}) { + "nikita:action:start": function ({ action }) { if (!action.metadata.header) { return; } - const walk = function(parent) { + const walk = function (parent) { const precious = parent.metadata.header; const results = []; if (precious !== undefined) { @@ -22,12 +27,12 @@ export default { return results; }; const headers = walk(action); - const header = headers.reverse().join(' : '); + const header = headers.reverse().join(" : "); return `header,,${JSON.stringify(header)}\n`; }, - 'text': function(log) { + text: function (log) { return `${log.type},${log.level},${JSON.stringify(log.message)}\n`; - } + }, }; return this.log.fs({ archive: config.archive, @@ -37,6 +42,6 @@ export default { }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/log/lib/fs/index.js b/packages/log/lib/fs/index.js index 4849c63ec..3ecc20876 100644 --- a/packages/log/lib/fs/index.js +++ b/packages/log/lib/fs/index.js @@ -1,11 +1,16 @@ // Dependencies -import fs from 'node:fs' -import path from 'node:path' -import definitions from "./schema.json" with { type: "json" }; +import fs from "node:fs"; +import path from "node:path"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Normalization let logdir = path.dirname(config.filename); if (config.basedir) { @@ -14,17 +19,20 @@ export default { // Archive config let latestdir; if (config.archive) { - latestdir = path.resolve(logdir, 'latest'); + latestdir = path.resolve(logdir, "latest"); const now = new Date(); if (config.archive === true) { - config.archive = `${now.getFullYear()}`.slice(-2) + `0${now.getFullYear()}`.slice(-2) + `0${now.getDate()}`.slice(-2); + config.archive = + `${now.getFullYear()}`.slice(-2) + + `0${now.getFullYear()}`.slice(-2) + + `0${now.getDate()}`.slice(-2); } logdir = path.resolve(config.basedir, config.archive); } try { - await fs.promises.mkdir(logdir, {recursive: true}); + await fs.promises.mkdir(logdir, { recursive: true }); } catch (error) { - if (error.code !== 'EEXIST') { + if (error.code !== "EEXIST") { throw error; } } @@ -34,29 +42,33 @@ export default { // } await this.log.stream({ serializer: config.serializer, - stream: config.stream ?? fs.createWriteStream(path.resolve(logdir, path.basename(config.filename))), + stream: + config.stream ?? + fs.createWriteStream( + path.resolve(logdir, path.basename(config.filename)), + ), }); // Handle link to latest directory await this.fs.symlink({ $if: latestdir, $ssh: false, source: logdir, - target: latestdir + target: latestdir, }); }, hooks: { on_action: { - before: ['@nikitajs/core/plugins/metadata/schema'], - after: ['@nikitajs/core/plugins/ssh'], - handler: function({config, ssh}) { + before: ["@nikitajs/core/plugins/metadata/schema"], + after: ["@nikitajs/core/plugins/ssh"], + handler: function ({ config, ssh }) { // With ssh, filename contain the host or ip address - config.filename ??= `${ssh?.config?.host || 'local'}.log`; + config.filename ??= `${ssh?.config?.host || "local"}.log`; // Log is always local // config.ssh = false; - } - } + }, + }, }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/log/lib/md/index.js b/packages/log/lib/md/index.js index 8d3c238ed..ccaf6a9f6 100644 --- a/packages/log/lib/md/index.js +++ b/packages/log/lib/md/index.js @@ -1,37 +1,41 @@ - // Dependencies -import {merge} from 'mixme'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { const state = {}; const serializer = { - 'diff': function(log) { + diff: function (log) { if (log.message) { return `\n\`\`\`diff\n${log.message}\`\`\`\n`; } }, - 'nikita:action:start': function({action}) { + "nikita:action:start": function ({ action }) { const content = []; // Header message if (action.metadata.header) { - const walk = function(parent) { + const walk = function (parent) { const precious = parent.metadata.header; const results = []; if (precious !== void 0) { results.push(precious); } if (parent.parent) { - results.push(...(walk(parent.parent))); + results.push(...walk(parent.parent)); } return results; }; const headers = walk(action); const header = headers.reverse().join(config.divider); - content.push('\n'); - content.push('#'.repeat(headers.length)); + content.push("\n"); + content.push("#".repeat(headers.length)); content.push(` ${header}\n`); } // Entering message @@ -44,33 +48,42 @@ export default { } act = act.parent; } - if (config.enter && action.metadata.module && action.metadata.log !== false && bastard !== true) { - content.push([ - '\n', - 'Entering', - ' ', - `${action.metadata.module}`, - ' ', - '(', - `${(action.metadata.position.map(function(index) { - return index + 1; - })).join('.')}`, - ')', - '\n' - ].join('')); + if ( + config.enter && + action.metadata.module && + action.metadata.log !== false && + bastard !== true + ) { + content.push( + [ + "\n", + "Entering", + " ", + `${action.metadata.module}`, + " ", + "(", + `${action.metadata.position + .map(function (index) { + return index + 1; + }) + .join(".")}`, + ")", + "\n", + ].join(""), + ); } - return content.join(''); + return content.join(""); }, - 'stdin': function(log) { + stdin: function (log) { const out = []; - if (log.message.indexOf('\n') === -1) { + if (log.message.indexOf("\n") === -1) { out.push(`\nRunning Command: \`${log.message}\`\n`); } else { out.push(`\n\`\`\`stdin\n${log.message}\n\`\`\`\n`); } - return out.join(''); + return out.join(""); }, - 'stdout_stream': function(log) { + stdout_stream: function (log) { if (log.message === null) { state.stdout_count = 0; } else if (state.stdout_count === void 0) { @@ -80,34 +93,34 @@ export default { } const out = []; if (state.stdout_count === 1) { - out.push('\n```stdout\n'); + out.push("\n```stdout\n"); } if (state.stdout_count > 0) { out.push(log.message); } if (state.stdout_count === 0) { - out.push('\n```\n'); + out.push("\n```\n"); } - return out.join(''); + return out.join(""); }, - 'text': function(log) { + text: function (log) { const out = []; out.push(`\n${log.message}`); - if (log.module && log.module !== '@nikitajs/core/actions/call') { + if (log.module && log.module !== "@nikitajs/core/actions/call") { out.push(` (${log.depth}.${log.level}, written by ${log.module})`); } out.push("\n"); - return out.join(''); - } + return out.join(""); + }, }; await this.log.fs({ archive: config.archive, basedir: config.basedir, filename: config.filename, - serializer: merge(serializer, config.serializer) + serializer: merge(serializer, config.serializer), }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/log/lib/stream/index.js b/packages/log/lib/stream/index.js index 7704caba7..eea873f8c 100644 --- a/packages/log/lib/stream/index.js +++ b/packages/log/lib/stream/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -26,7 +30,7 @@ export default { } const data = await config.serializer["nikita:action:start"].apply( null, - arguments + arguments, ); if (data != null) { return config.stream.write(data); @@ -36,23 +40,32 @@ export default { if (!config.serializer["nikita:action:end"]) { return; } - const data = config.serializer["nikita:action:end"].apply(null, arguments); + const data = config.serializer["nikita:action:end"].apply( + null, + arguments, + ); if (data != null) { return config.stream.write(data); } }); - events.on("nikita:resolved", function ({ action }) { + events.on("nikita:resolved", function () { if (config.serializer["nikita:resolved"]) { - const data = config.serializer["nikita:resolved"].apply(null, arguments); + const data = config.serializer["nikita:resolved"].apply( + null, + arguments, + ); if (data != null) { config.stream.write(data); } } return close(); }); - events.on("nikita:rejected", function ({ action }) { + events.on("nikita:rejected", function () { if (config.serializer["nikita:rejected"]) { - const data = config.serializer["nikita:rejected"].apply(null, arguments); + const data = config.serializer["nikita:rejected"].apply( + null, + arguments, + ); if (data != null) { config.stream.write(data); } diff --git a/packages/log/package.json b/packages/log/package.json index c01de901b..da6f70da6 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -40,8 +40,6 @@ }, "devDependencies": { "coffeescript": "^2.7.0", - "eslint": "^9.8.0", - "eslint-plugin-coffee": "^0.1.15", "mocha": "^10.7.0", "mocha-they": "^0.1.3", "should": "^13.2.3" diff --git a/packages/network/lib/http/index.js b/packages/network/lib/http/index.js index 39762c288..d467f3081 100644 --- a/packages/network/lib/http/index.js +++ b/packages/network/lib/http/index.js @@ -2,19 +2,24 @@ import dedent from "dedent"; import utils from "@nikitajs/network/utils"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config }) { if (config.principal && !config.password) { throw Error( - "Required Option: `password` is required if principal is provided" + "Required Option: `password` is required if principal is provided", ); } if ((config.method === "POST" || config.method === "PUT") && !config.data) { throw Error( - "Required Option: `data` is required with POST and PUT requests" + "Required Option: `data` is required with POST and PUT requests", ); } if (config.data != null && typeof config.data !== "string") { @@ -45,43 +50,41 @@ export default { const { stdout } = await this.execute({ command: dedent` ${ - !config.principal - ? "" - : [ - "echo", - config.password, - "|", - "kinit", - config.principal, - ">/dev/null", - ].join(" ") + !config.principal ? "" : ( + [ + "echo", + config.password, + "|", + "kinit", + config.principal, + ">/dev/null", + ].join(" ") + ) } command -v curl >/dev/null || exit 90 ${[ "curl", - config.timeout - ? `--max-time '${Math.max(config.timeout / 1000)}'` - : void 0, + config.timeout ? + `--max-time '${Math.max(config.timeout / 1000)}'` + : void 0, "--include", // Include protocol headers in the output (H/F) "--silent", // Dont print progression to stderr config.fail ? "--fail" : void 0, - !config.cacert && config.url.startsWith("https:") - ? "--insecure" - : void 0, + !config.cacert && config.url.startsWith("https:") ? + "--insecure" + : void 0, config.cacert ? "--cacert #{config.cacert}" : void 0, config.negotiate ? "--negotiate -u:" : void 0, config.location ? "--location" : void 0, ...Object.keys(config.http_headers).map( (header) => - `--header ${esa(header + ": " + config.http_headers[header])}` + `--header ${esa(header + ": " + config.http_headers[header])}`, ), ...config.cookies.map((cookie) => `--cookie ${esa(cookie)}`), config.target ? `-o ${config.target}` : void 0, config.proxy ? `-x ${config.proxy}` : void 0, config.method !== "GET" ? `-X ${config.method}` : void 0, - config.data - ? `--data ${esa(config.data)}` - : void 0, + config.data ? `--data ${esa(config.data)}` : void 0, `${config.url}`, ].join(" ")} `, diff --git a/packages/network/lib/http/wait/index.js b/packages/network/lib/http/wait/index.js index 5d72048f8..10a456321 100644 --- a/packages/network/lib/http/wait/index.js +++ b/packages/network/lib/http/wait/index.js @@ -1,12 +1,19 @@ // Dependencies import utils from "@nikitajs/network/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Errors const errors = { - NIKITA_HTTP_WAIT_TIMEOUT: function({config}) { - return utils.error('NIKITA_HTTP_WAIT_TIMEOUT', [`timeout reached after ${config.timeout}ms.`]); - } + NIKITA_HTTP_WAIT_TIMEOUT: function ({ config }) { + return utils.error("NIKITA_HTTP_WAIT_TIMEOUT", [ + `timeout reached after ${config.timeout}ms.`, + ]); + }, }; // Action @@ -28,8 +35,9 @@ export default { timeout: config.timeout, }); log({ - message: error - ? `Attemp ${count} failed with error` + message: + error ? + `Attemp ${count} failed with error` : `Attemp ${count} return status ${status_code}`, attempt: count, status_code: status_code, diff --git a/packages/network/lib/register.js b/packages/network/lib/register.js index 1eb298a1d..7c218c5b1 100644 --- a/packages/network/lib/register.js +++ b/packages/network/lib/register.js @@ -1,19 +1,18 @@ - // Dependencies import registry from "@nikitajs/core/registry"; // Action registration -const actions ={ +const actions = { network: { http: { - '': '@nikitajs/network/http', - 'wait': '@nikitajs/network/http/wait' + "": "@nikitajs/network/http", + wait: "@nikitajs/network/http/wait", }, tcp: { - 'assert': '@nikitajs/network/tcp/assert', - 'wait': '@nikitajs/network/tcp/wait' - } - } + assert: "@nikitajs/network/tcp/assert", + wait: "@nikitajs/network/tcp/wait", + }, + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/network/lib/tcp/assert/index.js b/packages/network/lib/tcp/assert/index.js index 947ee641e..dc81743f2 100644 --- a/packages/network/lib/tcp/assert/index.js +++ b/packages/network/lib/tcp/assert/index.js @@ -1,6 +1,11 @@ // Dependencies -import definitions from "./schema.json" with { type: "json" }; import wait from "@nikitajs/network/tcp/wait"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -12,12 +17,12 @@ export default { command: `bash -c 'echo > /dev/tcp/${server.host}/${server.port}'`, }); if (config.not === true) { - error = `Address listening: \"${server.host}:${server.port}\"`; + error = `Address listening: "${server.host}:${server.port}"`; break; } - } catch (err) { + } catch { if (config.not !== true) { - error = `Address not listening: \"${server.host}:${server.port}\"`; + error = `Address not listening: "${server.host}:${server.port}"`; break; } } diff --git a/packages/network/lib/tcp/wait/index.js b/packages/network/lib/tcp/wait/index.js index be8f8fd7e..8b015f9b1 100644 --- a/packages/network/lib/tcp/wait/index.js +++ b/packages/network/lib/tcp/wait/index.js @@ -1,7 +1,12 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -169,7 +174,7 @@ export default { (config.port || []).map((port) => ({ host: host, port: port, - })) + })), ) .flat(Infinity); }; diff --git a/packages/network/lib/utils/curl.js b/packages/network/lib/utils/curl.js index 0f2d12f30..8c00e438d 100644 --- a/packages/network/lib/utils/curl.js +++ b/packages/network/lib/utils/curl.js @@ -1,165 +1,164 @@ - // See `man 3 libcurl-errors` -const error = function(exit_code) { +const error = function (exit_code) { switch (exit_code) { case 1: - return 'CURLE_UNSUPPORTED_PROTOCOL'; + return "CURLE_UNSUPPORTED_PROTOCOL"; case 2: - return 'CURLE_FAILED_INIT'; + return "CURLE_FAILED_INIT"; case 3: - return 'CURLE_URL_MALFORMAT'; + return "CURLE_URL_MALFORMAT"; case 4: - return 'CURLE_NOT_BUILT_IN'; + return "CURLE_NOT_BUILT_IN"; case 5: - return 'CURLE_COULDNT_RESOLVE_PROXY'; + return "CURLE_COULDNT_RESOLVE_PROXY"; case 6: - return 'CURLE_COULDNT_RESOLVE_HOST'; + return "CURLE_COULDNT_RESOLVE_HOST"; case 7: - return 'CURLE_COULDNT_CONNECT'; + return "CURLE_COULDNT_CONNECT"; case 8: - return 'CURLE_FTP_WEIRD_SERVER_REPLY'; + return "CURLE_FTP_WEIRD_SERVER_REPLY"; case 9: - return 'CURLE_REMOTE_ACCESS_DENIED'; + return "CURLE_REMOTE_ACCESS_DENIED"; case 10: - return 'CURLE_FTP_ACCEPT_FAILED'; + return "CURLE_FTP_ACCEPT_FAILED"; case 11: - return 'CURLE_FTP_WEIRD_PASS_REPLY'; + return "CURLE_FTP_WEIRD_PASS_REPLY"; case 12: - return 'CURLE_FTP_ACCEPT_TIMEOUT'; + return "CURLE_FTP_ACCEPT_TIMEOUT"; case 13: - return 'CURLE_FTP_WEIRD_PASV_REPLY'; + return "CURLE_FTP_WEIRD_PASV_REPLY"; case 14: - return 'CURLE_FTP_WEIRD_227_FORMAT'; + return "CURLE_FTP_WEIRD_227_FORMAT"; case 15: - return 'CURLE_FTP_CANT_GET_HOST'; + return "CURLE_FTP_CANT_GET_HOST"; case 17: - return 'CURLE_FTP_COULDNT_SET_TYPE'; + return "CURLE_FTP_COULDNT_SET_TYPE"; case 18: - return 'CURLE_PARTIAL_FILE'; + return "CURLE_PARTIAL_FILE"; case 19: - return 'CURLE_FTP_COULDNT_RETR_FILE'; + return "CURLE_FTP_COULDNT_RETR_FILE"; case 21: - return 'CURLE_QUOTE_ERROR'; + return "CURLE_QUOTE_ERROR"; case 22: - return 'CURLE_HTTP_RETURNED_ERROR'; + return "CURLE_HTTP_RETURNED_ERROR"; case 23: - return 'CURLE_WRITE_ERROR'; + return "CURLE_WRITE_ERROR"; case 25: - return 'CURLE_UPLOAD_FAILED'; + return "CURLE_UPLOAD_FAILED"; case 26: - return 'CURLE_READ_ERROR'; + return "CURLE_READ_ERROR"; case 27: - return 'CURLE_OUT_OF_MEMORY'; + return "CURLE_OUT_OF_MEMORY"; case 28: - return 'CURLE_OPERATION_TIMEDOUT'; + return "CURLE_OPERATION_TIMEDOUT"; case 30: - return 'CURLE_FTP_PORT_FAILED'; + return "CURLE_FTP_PORT_FAILED"; case 31: - return 'CURLE_FTP_COULDNT_USE_REST'; + return "CURLE_FTP_COULDNT_USE_REST"; case 33: - return 'CURLE_RANGE_ERROR'; + return "CURLE_RANGE_ERROR"; case 34: - return 'CURLE_HTTP_POST_ERROR'; + return "CURLE_HTTP_POST_ERROR"; case 35: - return 'CURLE_SSL_CONNECT_ERROR'; + return "CURLE_SSL_CONNECT_ERROR"; case 36: - return 'CURLE_BAD_DOWNLOAD_RESUME'; + return "CURLE_BAD_DOWNLOAD_RESUME"; case 37: - return 'CURLE_FILE_COULDNT_READ_FILE'; + return "CURLE_FILE_COULDNT_READ_FILE"; case 38: - return 'CURLE_LDAP_CANNOT_BIND'; + return "CURLE_LDAP_CANNOT_BIND"; case 39: - return 'CURLE_LDAP_SEARCH_FAILED'; + return "CURLE_LDAP_SEARCH_FAILED"; case 41: - return 'CURLE_FUNCTION_NOT_FOUND'; + return "CURLE_FUNCTION_NOT_FOUND"; case 42: - return 'CURLE_ABORTED_BY_CALLBACK'; + return "CURLE_ABORTED_BY_CALLBACK"; case 43: - return 'CURLE_BAD_FUNCTION_ARGUMENT'; + return "CURLE_BAD_FUNCTION_ARGUMENT"; case 45: - return 'CURLE_INTERFACE_FAILED'; + return "CURLE_INTERFACE_FAILED"; case 47: - return 'CURLE_TOO_MANY_REDIRECTS'; + return "CURLE_TOO_MANY_REDIRECTS"; case 48: - return 'CURLE_UNKNOWN_OPTION'; + return "CURLE_UNKNOWN_OPTION"; case 49: - return 'CURLE_TELNET_OPTION_SYNTAX'; + return "CURLE_TELNET_OPTION_SYNTAX"; case 51: - return 'CURLE_PEER_FAILED_VERIFICATION'; + return "CURLE_PEER_FAILED_VERIFICATION"; case 52: - return 'CURLE_GOT_NOTHING'; + return "CURLE_GOT_NOTHING"; case 53: - return 'CURLE_SSL_ENGINE_NOTFOUND'; + return "CURLE_SSL_ENGINE_NOTFOUND"; case 54: - return 'CURLE_SSL_ENGINE_SETFAILED'; + return "CURLE_SSL_ENGINE_SETFAILED"; case 55: - return 'CURLE_SEND_ERROR'; + return "CURLE_SEND_ERROR"; case 56: - return 'CURLE_RECV_ERROR'; + return "CURLE_RECV_ERROR"; case 58: - return 'CURLE_SSL_CERTPROBLEM'; + return "CURLE_SSL_CERTPROBLEM"; case 59: - return 'CURLE_SSL_CIPHER'; + return "CURLE_SSL_CIPHER"; case 60: - return 'CURLE_SSL_CACERT'; + return "CURLE_SSL_CACERT"; case 61: - return 'CURLE_BAD_CONTENT_ENCODING'; + return "CURLE_BAD_CONTENT_ENCODING"; case 62: - return 'CURLE_LDAP_INVALID_URL'; + return "CURLE_LDAP_INVALID_URL"; case 63: - return 'CURLE_FILESIZE_EXCEEDED'; + return "CURLE_FILESIZE_EXCEEDED"; case 64: - return 'CURLE_USE_SSL_FAILED'; + return "CURLE_USE_SSL_FAILED"; case 65: - return 'CURLE_SEND_FAIL_REWIND'; + return "CURLE_SEND_FAIL_REWIND"; case 66: - return 'CURLE_SSL_ENGINE_INITFAILED'; + return "CURLE_SSL_ENGINE_INITFAILED"; case 67: - return 'CURLE_LOGIN_DENIED'; + return "CURLE_LOGIN_DENIED"; case 68: - return 'CURLE_TFTP_NOTFOUND'; + return "CURLE_TFTP_NOTFOUND"; case 69: - return 'CURLE_TFTP_PERM'; + return "CURLE_TFTP_PERM"; case 70: - return 'CURLE_REMOTE_DISK_FULL'; + return "CURLE_REMOTE_DISK_FULL"; case 71: - return 'CURLE_TFTP_ILLEGAL'; + return "CURLE_TFTP_ILLEGAL"; case 72: - return 'CURLE_TFTP_UNKNOWNID'; + return "CURLE_TFTP_UNKNOWNID"; case 73: - return 'CURLE_REMOTE_FILE_EXISTS'; + return "CURLE_REMOTE_FILE_EXISTS"; case 74: - return 'CURLE_TFTP_NOSUCHUSER'; + return "CURLE_TFTP_NOSUCHUSER"; case 75: - return 'CURLE_CONV_FAILED'; + return "CURLE_CONV_FAILED"; case 76: - return 'CURLE_CONV_REQD'; + return "CURLE_CONV_REQD"; case 77: - return 'CURLE_SSL_CACERT_BADFILE'; + return "CURLE_SSL_CACERT_BADFILE"; case 78: - return 'CURLE_REMOTE_FILE_NOT_FOUND'; + return "CURLE_REMOTE_FILE_NOT_FOUND"; case 79: - return 'CURLE_SSH'; + return "CURLE_SSH"; case 80: - return 'CURLE_SSL_SHUTDOWN_FAILED'; + return "CURLE_SSL_SHUTDOWN_FAILED"; case 81: - return 'CURLE_AGAIN'; + return "CURLE_AGAIN"; case 82: - return 'CURLE_SSL_CRL_BADFILE'; + return "CURLE_SSL_CRL_BADFILE"; case 83: - return 'CURLE_SSL_ISSUER_ERROR'; + return "CURLE_SSL_ISSUER_ERROR"; case 84: - return 'CURLE_FTP_PRET_FAILED'; + return "CURLE_FTP_PRET_FAILED"; case 85: - return 'CURLE_RTSP_CSEQ_ERROR'; + return "CURLE_RTSP_CSEQ_ERROR"; case 86: - return 'CURLE_RTSP_SESSION_ERROR'; + return "CURLE_RTSP_SESSION_ERROR"; case 87: - return 'CURLE_FTP_BAD_FILE_LIST'; + return "CURLE_FTP_BAD_FILE_LIST"; case 88: - return 'CURLE_CHUNK_FAILED'; + return "CURLE_CHUNK_FAILED"; case 89: - return 'CURLE_NO_CONNECTION_AVAILABLE'; + return "CURLE_NO_CONNECTION_AVAILABLE"; default: return void 0; } @@ -168,5 +167,5 @@ const error = function(exit_code) { export { error }; export default { - error: error + error: error, }; diff --git a/packages/nikita/test/index.js b/packages/nikita/test/index.js index f9b495a53..b8d58b519 100644 --- a/packages/nikita/test/index.js +++ b/packages/nikita/test/index.js @@ -1,8 +1,8 @@ import assert from "node:assert"; import nikita from "nikita"; -describe("core", () => { - it("load nikita", async () => { +describe("core", function () { + it("load nikita", async function () { const { stdout } = await nikita.execute({ command: "hostname", }); diff --git a/packages/service/env/systemctl/index.js b/packages/service/env/systemctl/index.js index 25e4815d6..e499fb6cc 100644 --- a/packages/service/env/systemctl/index.js +++ b/packages/service/env/systemctl/index.js @@ -14,8 +14,9 @@ await runner({ properties: { "environment.NIKITA_TEST_MODULE": "/nikita/packages/service/env/systemctl/test.coffee", - "raw.idmap": process.env["NIKITA_INCUS_IN_VAGRANT"] - ? "both 1000 0" + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" : `both ${process.getuid()} 0`, }, disk: { @@ -45,7 +46,7 @@ await runner({ code: [0, 42], }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", container: config.container, command: dedent` mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -54,7 +55,7 @@ await runner({ cat /root/.ssh/id_ed25519.pub > /root/.ssh/authorized_keys fi `, - trap: true + trap: true, }); }, }, diff --git a/packages/service/lib/assert/index.js b/packages/service/lib/assert/index.js index a62c2108a..033da5d66 100644 --- a/packages/service/lib/assert/index.js +++ b/packages/service/lib/assert/index.js @@ -1,36 +1,41 @@ // Dependencies import dedent from "dedent"; -import utils from '@nikitajs/core/utils' -import definitions from "./schema.json" with { type: "json" }; +import utils from "@nikitajs/core/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.srv_name == null) { config.srv_name = config.name; } config.name = [config.name]; // Assert a Package is installed if (config.installed != null) { - const {packages} = await this.service.installed(); - const notInstalled = config.name.filter( pck => !packages.includes(pck)); + const { packages } = await this.service.installed(); + const notInstalled = config.name.filter((pck) => !packages.includes(pck)); if (notInstalled.length) { throw utils.error("NIKITA_SERVICE_ASSERT_NOT_INSTALLED", [ - notInstalled.length > 1 - ? `services ${notInstalled - .map(JSON.stringify) - .join(", ")} are not installed.` - : `service ${JSON.stringify(notInstalled[0])} is not installed.`, + notInstalled.length > 1 ? + `services ${notInstalled + .map(JSON.stringify) + .join(", ")} are not installed.` + : `service ${JSON.stringify(notInstalled[0])} is not installed.`, ]); } } // Assert a Service is started or stopped // Note, this doesnt check wether a service is installed or not. - if (!((config.started != null) || (config.stopped != null))) { + if (!(config.started != null || config.stopped != null)) { return; } try { - const {$status} = await this.execute({ + const { $status } = await this.execute({ command: dedent` ls /lib/systemd/system/*.service /etc/systemd/system/*.service /etc/rc.d/* /etc/init.d/* 2>/dev/null | grep -w "${config.srv_name}" || exit 3 if command -v systemctl >/dev/null 2>&1; then @@ -42,7 +47,7 @@ export default { exit 2 fi `, - code: [0, 3] + code: [0, 3], }); if (config.started != null) { if (config.started && !$status) { @@ -64,11 +69,11 @@ export default { if (error.exit_code === 2) { throw Error("Unsupported Loader"); } - throw error + throw error; } }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/service/lib/discover/index.js b/packages/service/lib/discover/index.js index 38f658ffe..58e8afddb 100644 --- a/packages/service/lib/discover/index.js +++ b/packages/service/lib/discover/index.js @@ -1,6 +1,11 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -17,14 +22,12 @@ export default { `, code: [[1, 2], 3], }); - const loader = - data.code === 1 - ? "systemctl" - : data.code === 2 - ? "service" - : undefined; + let loader = + data.code === 1 ? "systemctl" + : data.code === 2 ? "service" + : undefined; if (loader == null && config.strict) { - throw Error("Undetected Operating System Loader") + throw Error("Undetected Operating System Loader"); } if (config.cache) { state["nikita:service:loader"] = loader; diff --git a/packages/service/lib/index.js b/packages/service/lib/index.js index ee8253d28..521b1f98b 100644 --- a/packages/service/lib/index.js +++ b/packages/service/lib/index.js @@ -1,10 +1,15 @@ // Dependencies -import {merge} from 'mixme'; -import definitions from "./schema.json" with { type: "json" }; +import { merge } from "mixme"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config, parent, state}) { + handler: async function ({ config, parent, state }) { const pkgname = config.yum_name || config.name; const chkname = config.chk_name || config.srv_name || config.name; const srvname = config.srv_name || config.chk_name || config.name; @@ -16,47 +21,47 @@ export default { cacheonly: config.cacheonly, installed: config.installed, outdated: config.outdated, - pacman_flags: config.pacman_flags + pacman_flags: config.pacman_flags, }); parent.state = merge(parent.state, state); } if (config.startup != null) { await this.service.startup({ name: chkname, - startup: config.startup + startup: config.startup, }); } if (config.state) { - const {started} = await this.service.status({ + const { started } = await this.service.status({ $shy: true, - name: srvname + name: srvname, }); - if (!started && config.state.includes('started')) { + if (!started && config.state.includes("started")) { await this.service.start({ - name: srvname + name: srvname, }); } - if (started && config.state.includes('stopped')) { + if (started && config.state.includes("stopped")) { await this.service.stop({ - name: srvname + name: srvname, }); } - if (started && config.state.includes('restarted')) { + if (started && config.state.includes("restarted")) { await this.service.restart({ - name: srvname + name: srvname, }); } } }, hooks: { - on_action: function({config}) { - if (typeof config.state === 'string') { - return config.state = config.state.split(','); + on_action: function ({ config }) { + if (typeof config.state === "string") { + return (config.state = config.state.split(",")); } - } + }, }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/service/lib/init/index.js b/packages/service/lib/init/index.js index f9aff20cb..6c1c3e410 100644 --- a/packages/service/lib/init/index.js +++ b/packages/service/lib/init/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -31,12 +35,12 @@ export default { source: config.source, target: config.target, uid: config.uid, - } + }; await (config.context ? this.file.render(args) : this.file(args)); if (config.loader === "systemctl") { const reload = await this.execute({ $shy: true, - command: `systemctl status ${config.name} 2>\&1 | egrep '(Reason: No such file or directory)|(Unit ${config.name}.service could not be found)|(${config.name}.service changed on disk)'`, + command: `systemctl status ${config.name} 2>&1 | egrep '(Reason: No such file or directory)|(Unit ${config.name}.service could not be found)|(${config.name}.service changed on disk)'`, code: [0, 1], }).then(({ $status }) => $status); await this.execute({ diff --git a/packages/service/lib/install/index.js b/packages/service/lib/install/index.js index a19cb103f..c216058d2 100644 --- a/packages/service/lib/install/index.js +++ b/packages/service/lib/install/index.js @@ -1,11 +1,16 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function ({ config, parent: { state }, tools: { log } }) { + handler: async function ({ config, tools: { log } }) { let packages = { // installed: config.cache ? state["nikita:service:packages:installed"] : undefined, // installed: config.cache ? state["nikita:service:packages:outdated"] : undefined, @@ -38,14 +43,16 @@ export default { // Start real work log("INFO", `Install service ${config.name}`); // List installed packages - const installed = packages.installed - ? packages.installed.includes(config.name) + const installed = + packages.installed ? + packages.installed.includes(config.name) : await this.service .installed(config.name) .then(({ installed }) => installed); // List packages waiting for update - const outdated = packages.outdated - ? packages.outdated.includes(config.name) + const outdated = + packages.outdated ? + packages.outdated.includes(config.name) : await this.service .outdated(config.name, { cacheonly: config.cacheonly }) .then(({ outdated }) => outdated); @@ -69,17 +76,17 @@ export default { `, code: config.code, }); - log("WARN", `Package \"${config.name}\" is installed`); + log("WARN", `Package "${config.name}" is installed`); } catch (error) { if (error.exit_code === 2) { throw Error( - "Unsupported Package Manager: apt-get, pacman, yay, yum supported" + "Unsupported Package Manager: apt-get, pacman, yay, yum supported", ); } - throw utils.error( - "NIKITA_SERVICE_INSTALL", - ["failed to install package,", `name is ${JSON.stringify(config.name)}`], - ); + throw utils.error("NIKITA_SERVICE_INSTALL", [ + "failed to install package,", + `name is ${JSON.stringify(config.name)}`, + ]); } } // Enrich installed array with package name unless already there diff --git a/packages/service/lib/installed/index.js b/packages/service/lib/installed/index.js index 04315d31a..1d4d24081 100644 --- a/packages/service/lib/installed/index.js +++ b/packages/service/lib/installed/index.js @@ -1,16 +1,22 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, parent: { state }, tools: { log } }) { - let packages = config.cache ? state["nikita:service:packages:installed"] : undefined; + let packages = + config.cache ? state["nikita:service:packages:installed"] : undefined; if (packages !== undefined) { return { packages: packages, - } + }; } try { ({ data: packages } = await this.execute({ @@ -28,7 +34,7 @@ export default { fi `, // code: [0, 1], - format: ({stdout}) => utils.string.lines(stdout), + format: ({ stdout }) => utils.string.lines(stdout), stdout_log: false, })); log("INFO", "Installed packages retrieved"); @@ -36,30 +42,30 @@ export default { if (error.exit_code === 2) { throw utils.error( "NIKITA_SERVICE_INSTALLED_UNSUPPORTED_PACKAGE_MANAGER", - "at the moment, rpm (yum, dnf, ...), pacman and dpkg (apt, apt-get, ...) are supported." + "at the moment, rpm (yum, dnf, ...), pacman and dpkg (apt, apt-get, ...) are supported.", ); } throw error; } if (config.cache) { - log("INFO", 'Caching installed packages.'); + log("INFO", "Caching installed packages."); state["nikita:service:packages:installed"] = packages; } - if(config.name) { + if (config.name) { return { - installed: packages.includes(config.name) - } - }else{ + installed: packages.includes(config.name), + }; + } else { return { packages: packages, - } + }; } }, metadata: { argument_to_config: "name", definitions: definitions, metadata: { - shy: true - } + shy: true, + }, }, }; diff --git a/packages/service/lib/outdated/index.js b/packages/service/lib/outdated/index.js index 7f904f5c0..7fee42a14 100644 --- a/packages/service/lib/outdated/index.js +++ b/packages/service/lib/outdated/index.js @@ -1,11 +1,16 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function ({ metadata, config, parent: { state }, tools: { log } }) { + handler: async function ({ config, tools: { log } }) { const cacheonly = config.cacheonly ? "-C" : ""; // Error inside the pipeline are not catched (eg no sudo permission). // A possible solution includes breaking the pipeline into multiple calls. @@ -34,8 +39,8 @@ export default { line .split(" ") .map((pck) => pck.trim()) - .filter((pck) => pck !== "") - ) + .filter((pck) => pck !== ""), + ), ), stdout_log: false, }) @@ -44,32 +49,32 @@ export default { if (error.exit_code === 43) { throw utils.error( "NIKITA_SERVICE_OUTDATED_UNSUPPORTED_PACKAGE_MANAGER", - "at the moment, rpm (yum, dnf, ...), pacman and dpkg (apt, apt-get, ...) are supported." + "at the moment, rpm (yum, dnf, ...), pacman and dpkg (apt, apt-get, ...) are supported.", ); } else if (error.exit_code === 100) { throw utils.error( "NIKITA_SERVICE_OUTDATED_SUDO", - "permission denied, maybe run this command as sudoer or with the `$debug` configuration." + "permission denied, maybe run this command as sudoer or with the `$debug` configuration.", ); } throw error; }); log("Outdated packages retrieved"); - if(config.name) { + if (config.name) { return { - outdated: packages.includes(config.name) - } - }else{ + outdated: packages.includes(config.name), + }; + } else { return { packages: packages, - } + }; } }, metadata: { argument_to_config: "name", definitions: definitions, metadata: { - shy: true - } + shy: true, + }, }, }; diff --git a/packages/service/lib/register.js b/packages/service/lib/register.js index 247415910..10d289ff9 100644 --- a/packages/service/lib/register.js +++ b/packages/service/lib/register.js @@ -1,4 +1,3 @@ - // Dependencies import registry from "@nikitajs/core/registry"; import "@nikitajs/file/register"; @@ -6,20 +5,20 @@ import "@nikitajs/file/register"; // Action registration const actions = { service: { - '': '@nikitajs/service', - assert: '@nikitajs/service/assert', - discover: '@nikitajs/service/discover', - install: '@nikitajs/service/install', - installed: '@nikitajs/service/installed', - init: '@nikitajs/service/init', - outdated: '@nikitajs/service/outdated', - remove: '@nikitajs/service/remove', - restart: '@nikitajs/service/restart', - start: '@nikitajs/service/start', - startup: '@nikitajs/service/startup', - status: '@nikitajs/service/status', - stop: '@nikitajs/service/stop' - } + "": "@nikitajs/service", + assert: "@nikitajs/service/assert", + discover: "@nikitajs/service/discover", + install: "@nikitajs/service/install", + installed: "@nikitajs/service/installed", + init: "@nikitajs/service/init", + outdated: "@nikitajs/service/outdated", + remove: "@nikitajs/service/remove", + restart: "@nikitajs/service/restart", + start: "@nikitajs/service/start", + startup: "@nikitajs/service/startup", + status: "@nikitajs/service/status", + stop: "@nikitajs/service/stop", + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/service/lib/remove/index.js b/packages/service/lib/remove/index.js index 929c95deb..5c55cfca6 100644 --- a/packages/service/lib/remove/index.js +++ b/packages/service/lib/remove/index.js @@ -1,7 +1,11 @@ // Dependencies -import dedent from "dedent"; import utils from "@nikitajs/core/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -31,28 +35,31 @@ export default { }); // Log information log( - $status - ? { - message: "Service removed", - level: "WARN", - } - : { - message: "Service already removed", - level: "INFO", - } + $status ? + { + message: "Service removed", + level: "WARN", + } + : { + message: "Service already removed", + level: "INFO", + }, ); - } catch (error) { + } catch { throw utils.error( "NIKITA_SERVICE_REMOVE_INVALID_SERVICE", - `Invalid Service Name: ${config.name}` + `Invalid Service Name: ${config.name}`, ); } if (config.cache) { - log("INFO", 'Remove package from cache key in "nikita:service:packages:installed"'); + log( + "INFO", + 'Remove package from cache key in "nikita:service:packages:installed"', + ); const packages = state["nikita:service:packages"]; state["nikita:service:packages:installed"] = packages.splice( packages.indexOf(config.name), - 1 + 1, ); } }, diff --git a/packages/service/lib/restart/index.js b/packages/service/lib/restart/index.js index 6af4415a8..707b85924 100644 --- a/packages/service/lib/restart/index.js +++ b/packages/service/lib/restart/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/service/lib/start/index.js b/packages/service/lib/start/index.js index 607abf8b1..baf4e5726 100644 --- a/packages/service/lib/start/index.js +++ b/packages/service/lib/start/index.js @@ -1,6 +1,11 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/service/lib/startup/index.js b/packages/service/lib/startup/index.js index 2fd147767..abf5f46fe 100644 --- a/packages/service/lib/startup/index.js +++ b/packages/service/lib/startup/index.js @@ -1,14 +1,16 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { - log({ - message: `Startup service ${config.name}`, - level: "INFO", - }); + log(`Startup service ${config.name}`); if (!config.command) { const { stdout } = await this.execute({ $shy: true, @@ -34,160 +36,155 @@ export default { throw Error("Unsupported Loader"); } } - switch (config.command) { - case "systemctl": // systemd - try { - const { $status } = await this.execute({ - command: ` - startup=${config.startup ? "1" : ""} - if systemctl is-enabled ${config.name}; then - [ -z "$startup" ] || exit 3 - echo 'Disable ${config.name}' - systemctl disable ${config.name} - else - [ -z "$startup" ] && exit 3 - echo 'Enable ${config.name}' - systemctl enable ${config.name} - fi - `, - trap: true, - code: [0, 3], - }); - // arch_chroot: config.arch_chroot - // arch_chroot_rootdir: config.arch_chroot_rootdir - const message = config.startup ? "activated" : "disabled"; - return log( - $status - ? { - message: `Service startup updated: ${message}`, - level: "WARN", - } - : { - message: `Service startup not modified: ${message}`, - level: "INFO", - } - ); - } catch { - if (config.startup) { - throw Error(`Startup Enable Failed: ${config.name}`); - } - if (!config.startup) { - throw Error(`Startup Disable Failed: ${config.name}`); - } - } - break; - case "chkconfig": - try { - const { $status, stdout, stderr } = await this.execute({ - $shy: true, - command: `chkconfig --list ${config.name}`, - code: [0, 1], - }); - // Invalid service name return code is 0 and message in stderr start by error - if (/^error/.test(stderr)) { - log({ - message: `Invalid chkconfig name for \"${config.name}\"`, - level: "ERROR", - }); - throw Error(`Invalid chkconfig name for \`${config.name}\``); - } - let current_startup = ""; - if ($status) { - for (const c of stdout.split(" ").pop().trim().split("\t")) { - const [level, status] = c.split(":"); - if (["on", "marche"].indexOf(status) > -1) { - current_startup += level; - } - } - } - if (config.startup === true && current_startup.length) { - return; - } - if (config.startup === current_startup) { - return; - } - if ($status && config.startup === false && current_startup === "") { - return; - } - if (config.startup) { - let command = `chkconfig --add ${config.name};`; - if (typeof config.startup === "string") { - let startup_on = startup_off = ""; - for (i = k = 0; k < 6; i = ++k) { - if (config.startup.indexOf(i) !== -1) { - startup_on += i; - } else { - startup_off += i; - } - } - if (startup_on) { - command += `chkconfig --level ${startup_on} ${config.name} on;`; - } - if (startup_off) { - command += `chkconfig --level ${startup_off} ${config.name} off;`; - } - } else { - command += `chkconfig ${config.name} on;`; - } - await this.execute({ - command: command, - }); - } - if (!config.startup) { - log({ - message: "Desactivating startup rules", - level: "DEBUG", - }); - // Setting the level to off. An alternative is to delete it: `chkconfig --del #{config.name}` - await this.execute({ - command: `chkconfig ${config.name} off`, - }); - } - const message = config.startup ? "activated" : "disabled"; - return log( - $status - ? { - message: `Service startup updated: ${message}`, - level: "WARN", - } - : { - message: `Service startup not modified: ${message}`, - level: "INFO", - } - ); - } catch (error) { - throw error - } - case "update-rc": // System-V + if (config.command === "systemctl") { + // systemd + try { const { $status } = await this.execute({ - command: dedent` + command: ` startup=${config.startup ? "1" : ""} - if ls /etc/rc*.d/S??${config.name}; then + if systemctl is-enabled ${config.name}; then [ -z "$startup" ] || exit 3 echo 'Disable ${config.name}' - update-rc.d -f ${config.name} disable + systemctl disable ${config.name} else [ -z "$startup" ] && exit 3 echo 'Enable ${config.name}' - update-rc.d -f ${config.name} enable + systemctl enable ${config.name} fi `, + trap: true, code: [0, 3], }); // arch_chroot: config.arch_chroot // arch_chroot_rootdir: config.arch_chroot_rootdir const message = config.startup ? "activated" : "disabled"; - log( - $status - ? { - message: `Service startup updated: ${message}`, - level: "WARN", - } - : { - message: `Service startup not modified: ${message}`, - level: "INFO", - } + return log( + $status ? + { + message: `Service startup updated: ${message}`, + level: "WARN", + } + : { + message: `Service startup not modified: ${message}`, + level: "INFO", + }, ); + } catch { + if (config.startup) { + throw Error(`Startup Enable Failed: ${config.name}`); + } + if (!config.startup) { + throw Error(`Startup Disable Failed: ${config.name}`); + } + } + } else if (config.command === "chkconfig") { + const { $status, stdout, stderr } = await this.execute({ + $shy: true, + command: `chkconfig --list ${config.name}`, + code: [0, 1], + }); + // Invalid service name return code is 0 and message in stderr start by error + if (/^error/.test(stderr)) { + log({ + message: `Invalid chkconfig name for "${config.name}"`, + level: "ERROR", + }); + throw Error(`Invalid chkconfig name for "${config.name}"`); + } + let current_startup = ""; + if ($status) { + for (const c of stdout.split(" ").pop().trim().split("\t")) { + const [level, status] = c.split(":"); + if (["on", "marche"].indexOf(status) > -1) { + current_startup += level; + } + } + } + if (config.startup === true && current_startup.length) { + return; + } + if (config.startup === current_startup) { + return; + } + if ($status && config.startup === false && current_startup === "") { + return; + } + if (config.startup) { + let command = `chkconfig --add ${config.name};`; + if (typeof config.startup === "string") { + let startup_on = ""; + let startup_off = ""; + for (let i = 0; i < 6; i++) { + if (config.startup.indexOf(i) !== -1) { + startup_on += i; + } else { + startup_off += i; + } + } + if (startup_on) { + command += `chkconfig --level ${startup_on} ${config.name} on;`; + } + if (startup_off) { + command += `chkconfig --level ${startup_off} ${config.name} off;`; + } + } else { + command += `chkconfig ${config.name} on;`; + } + await this.execute({ + command: command, + }); + } + if (!config.startup) { + log("DEBUG", "Desactivating startup rules"); + // Setting the level to off. An alternative is to delete it: `chkconfig --del #{config.name}` + await this.execute({ + command: `chkconfig ${config.name} off`, + }); + } + const message = config.startup ? "activated" : "disabled"; + return log( + $status ? + { + message: `Service startup updated: ${message}`, + level: "WARN", + } + : { + message: `Service startup not modified: ${message}`, + level: "INFO", + }, + ); + } else if (config.command === "update-rc") { + // System-V + + const { $status } = await this.execute({ + command: dedent` + startup=${config.startup ? "1" : ""} + if ls /etc/rc*.d/S??${config.name}; then + [ -z "$startup" ] || exit 3 + echo 'Disable ${config.name}' + update-rc.d -f ${config.name} disable + else + [ -z "$startup" ] && exit 3 + echo 'Enable ${config.name}' + update-rc.d -f ${config.name} enable + fi + `, + code: [0, 3], + }); + // arch_chroot: config.arch_chroot + // arch_chroot_rootdir: config.arch_chroot_rootdir + const message = config.startup ? "activated" : "disabled"; + log( + $status ? + { + message: `Service startup updated: ${message}`, + level: "WARN", + } + : { + message: `Service startup not modified: ${message}`, + level: "INFO", + }, + ); } }, metadata: { diff --git a/packages/service/lib/status/index.js b/packages/service/lib/status/index.js index 8105ea0c7..db45ad6cf 100644 --- a/packages/service/lib/status/index.js +++ b/packages/service/lib/status/index.js @@ -1,11 +1,16 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { - log("INFO", `Status for service ${config.name}`); + log(`Status for service ${config.name}`); const { $status: started } = await this.execute({ $shy: true, command: dedent` @@ -20,19 +25,16 @@ export default { fi `, code: [0, 3], - }).catch(error => { + }).catch((error) => { if (error.exit_code === 2) { throw Error("Unsupported Loader"); } throw error; }); - log( - "INFO", - `Service ${config.name} is ${started ? "started" : "stoped"}.` - ); + log(`Service ${config.name} is ${started ? "started" : "stoped"}.`); return { - started: started - } + started: started, + }; }, metadata: { argument_to_config: "name", diff --git a/packages/service/lib/stop/index.js b/packages/service/lib/stop/index.js index 9b41c3aec..c7f441760 100644 --- a/packages/service/lib/stop/index.js +++ b/packages/service/lib/stop/index.js @@ -1,14 +1,16 @@ // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { - log({ - message: `Stop service ${config.name}`, - level: "INFO", - }); + log(`Stop service ${config.name}`); try { const { $status } = await this.execute({ command: dedent` @@ -27,16 +29,10 @@ export default { code: [0, 3], }); if ($status) { - log({ - message: "Service is stopped", - level: "INFO", - }); + log("Service is stopped"); } if (!$status) { - log({ - message: "Service already stopped", - level: "WARN", - }); + log("WARN", "Service already stopped"); } } catch (error) { if (error.exit_code === 2) { diff --git a/packages/system/env/cgroups/index.js b/packages/system/env/cgroups/index.js index a77f4883e..fec2a6d17 100644 --- a/packages/system/env/cgroups/index.js +++ b/packages/system/env/cgroups/index.js @@ -15,8 +15,9 @@ runner({ properties: { "environment.NIKITA_TEST_MODULE": "/nikita/packages/system/env/cgroups/test.coffee", - "raw.idmap": process.env["NIKITA_INCUS_IN_VAGRANT"] - ? "both 1000 0" + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" : `both ${process.getuid()} 0`, }, disk: { diff --git a/packages/system/lib/cgroups/index.js b/packages/system/lib/cgroups/index.js index de859797e..b28f5256c 100644 --- a/packages/system/lib/cgroups/index.js +++ b/packages/system/lib/cgroups/index.js @@ -1,21 +1,25 @@ - // Dependencies -import path from 'node:path' -import {merge} from 'mixme'; +import path from "node:path"; +import { merge } from "mixme"; import utils from "@nikitajs/system/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - config.mounts ??= [] + handler: async function ({ config }) { + config.mounts ??= []; config.groups ??= {}; config.merge ??= true; config.cgconfig = {}; - config.cgconfig['mounts'] = config.mounts; - config.cgconfig['groups'] = config.groups; + config.cgconfig["mounts"] = config.mounts; + config.cgconfig["groups"] = config.groups; if (config.default != null) { - config.cgconfig['groups'][''] = config.default; + config.cgconfig["groups"][""] = config.default; } if (config.ignore == null) { config.ignore = []; @@ -24,83 +28,84 @@ export default { config.ignore = [config.ignore]; } // Detect Os and version - const {os} = await this.system.info.os(); + const { os } = await this.system.info.os(); // configure parameters based on previous OS dection const store = {}; // Enable cgroup for all distribution, it was restricted to rhel systems // if ['redhat','centos'].includes os.distribution - if (true) { - const {stdout} = await this.execute({ - $shy: true, - command: 'cgsnapshot -s 2>&1' - }); - const cgconfig = utils.cgconfig.parse(stdout); - if (cgconfig.mounts == null) { - cgconfig.mounts = []; - } - const cpus = cgconfig.mounts.filter(function(mount) { - return mount.type === 'cpu'; - }); - // const cpuaccts = cgconfig.mounts.filter(function(mount) { - // return mount.type === 'cpuacct'; - // }); - // We choose a path which is mounted by default - // if not @store['nikita:cgroups:cpu_path']? - if (cpus.length > 0) { - store.cpu_path = cpus[0]['path'].split(',')[0]; - } else { - // @store['nikita:cgroups:cpu_path'] ?= cpu_path - // a arbitrary path is given based on the - switch (os.distribution) { - case 'redhat': - case 'centos': - const majorVersion = os.version.split('.')[0]; - switch (majorVersion) { - case '6': - store.cpu_path = '/cgroups/cpu'; - break; - case '7': - store.cpu_path = '/sys/fs/cgroup/cpu'; - break; - default: - throw Error("Nikita does not support cgroups for your RedHat or CentOS version}"); - } - break; - default: - throw Error(`Nikita does not support cgroups on your OS ${os.distribution}`); - } - } - store.mount = `${path.posix.dirname(store.cpu_path)}`; - // Running docker containers are remove from cgsnapshot output - if (config.merge) { - const groups = {}; - for (const name in cgconfig.groups) { - if (!(name.includes('docker/') || config.ignore.includes(name))) { - groups[name] = cgconfig.groups[name]; + const { stdout } = await this.execute({ + $shy: true, + command: "cgsnapshot -s 2>&1", + }); + const cgconfig = utils.cgconfig.parse(stdout); + if (cgconfig.mounts == null) { + cgconfig.mounts = []; + } + const cpus = cgconfig.mounts.filter(function (mount) { + return mount.type === "cpu"; + }); + // const cpuaccts = cgconfig.mounts.filter(function(mount) { + // return mount.type === 'cpuacct'; + // }); + // We choose a path which is mounted by default + // if not @store['nikita:cgroups:cpu_path']? + if (cpus.length > 0) { + store.cpu_path = cpus[0]["path"].split(",")[0]; + } else { + // @store['nikita:cgroups:cpu_path'] ?= cpu_path + // a arbitrary path is given based on the + switch (os.distribution) { + case "redhat": + case "centos": + switch (os.version.split(".")[0]) { + case "6": + store.cpu_path = "/cgroups/cpu"; + break; + case "7": + store.cpu_path = "/sys/fs/cgroup/cpu"; + break; + default: + throw Error( + "Nikita does not support cgroups for your RedHat or CentOS version}", + ); } + break; + default: + throw Error( + `Nikita does not support cgroups on your OS ${os.distribution}`, + ); + } + } + store.mount = `${path.posix.dirname(store.cpu_path)}`; + // Running docker containers are remove from cgsnapshot output + if (config.merge) { + const groups = {}; + for (const name in cgconfig.groups) { + if (!(name.includes("docker/") || config.ignore.includes(name))) { + groups[name] = cgconfig.groups[name]; } - config.cgconfig.groups = merge(groups, config.groups); - config.cgconfig.mounts.push(...cgconfig.mounts); } + config.cgconfig.groups = merge(groups, config.groups); + config.cgconfig.mounts.push(...cgconfig.mounts); } - if (['redhat', 'centos'].includes(os.distribution)) { + if (["redhat", "centos"].includes(os.distribution)) { // Write the configuration if (config.target == null) { - config.target = '/etc/cgconfig.conf'; + config.target = "/etc/cgconfig.conf"; } } await this.file({ target: config.target, - content: utils.cgconfig.stringify(config.cgconfig) + content: utils.cgconfig.stringify(config.cgconfig), }); return { cgroups: { cpu_path: store.cpu_path, - mount: store.mount - } + mount: store.mount, + }, }; }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/system/lib/group/index.js b/packages/system/lib/group/index.js index 450adeeb9..c45d127c5 100644 --- a/packages/system/lib/group/index.js +++ b/packages/system/lib/group/index.js @@ -1,7 +1,11 @@ - // Dependencies import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -11,9 +15,9 @@ export default { const info = groups[config.name]; log( "DEBUG", - info - ? `Got group information for ${JSON.stringify(config.name)}` - : `Group ${JSON.stringify(config.name)} not present` + info ? + `Got group information for ${JSON.stringify(config.name)}` + : `Group ${JSON.stringify(config.name)} not present`, ); if (!info) { // Create group @@ -21,21 +25,23 @@ export default { command: [ "groupadd", config.system && "-r", - config.gid != null && `-g ${esa(''+config.gid)}`, + config.gid != null && `-g ${esa("" + config.gid)}`, esa(config.name), - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), code: [0, 9], }); if (!$status) { // Modify group - log({ - message: "Group defined elsewhere than '/etc/group', exit code is 9", - level: "WARN", - }); + log( + "WARN", + "Group defined elsewhere than '/etc/group', exit code is 9", + ); } } else { - const changes = ["gid"].filter( (k) => - config[k] != null && `${info[k]}` !== `${config[k]}` + const changes = ["gid"].filter( + (k) => config[k] != null && `${info[k]}` !== `${config[k]}`, ); if (changes.length) { await this.execute({ @@ -45,15 +51,9 @@ export default { esa(config.name), ].join(" "), }); - log({ - message: "Group information modified", - level: "WARN", - }); + log("WARN", "Group information modified"); } else { - log({ - message: "Group information unchanged", - level: "INFO", - }); + log("Group information unchanged"); } } }, diff --git a/packages/system/lib/group/read/index.js b/packages/system/lib/group/read/index.js index a8e2a5431..3881db3d6 100644 --- a/packages/system/lib/group/read/index.js +++ b/packages/system/lib/group/read/index.js @@ -1,13 +1,17 @@ - // Dependencies -import definitions from "./schema.json" with { type: "json" }; import utils from "@nikitajs/system/utils"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Parse the groups output const str2groups = function (data) { const groups = {}; for (const line of utils.string.lines(data)) { - const group = /(.*)\:(.*)\:(.*)\:(.*)/.exec(line); + const group = /(.*):(.*):(.*):(.*)/.exec(line); if (!group) { continue; } @@ -52,7 +56,7 @@ export default { const group = groups[config.gid]; if (!group) { throw Error( - `Invalid Option: no gid matching ${JSON.stringify(config.gid)}` + `Invalid Option: no gid matching ${JSON.stringify(config.gid)}`, ); } return { @@ -61,11 +65,11 @@ export default { } else { // Return a group by gid const group = Object.values(groups).find( - (group) => group.gid === config.gid + (group) => group.gid === config.gid, ); if (!group) { throw Error( - `Invalid Option: no gid matching ${JSON.stringify(config.gid)}` + `Invalid Option: no gid matching ${JSON.stringify(config.gid)}`, ); } return { diff --git a/packages/system/lib/group/remove/index.js b/packages/system/lib/group/remove/index.js index 2da14868b..e22b09f90 100644 --- a/packages/system/lib/group/remove/index.js +++ b/packages/system/lib/group/remove/index.js @@ -1,17 +1,20 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: function({metadata, config}) { + handler: function ({ config }) { this.execute({ command: `groupdel ${config.name}`, - code: [0, 6] + code: [0, 6], }); }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/system/lib/info/disks/index.js b/packages/system/lib/info/disks/index.js index ba385ef5b..03e80a426 100644 --- a/packages/system/lib/info/disks/index.js +++ b/packages/system/lib/info/disks/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/system/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/system/lib/info/os/index.js b/packages/system/lib/info/os/index.js index 79fa826e9..f3d57c674 100644 --- a/packages/system/lib/info/os/index.js +++ b/packages/system/lib/info/os/index.js @@ -1,6 +1,11 @@ // Dependencies import utils from "@nikitajs/system/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/system/lib/limits/index.js b/packages/system/lib/limits/index.js index 86e1e8816..e37206d11 100644 --- a/packages/system/lib/limits/index.js +++ b/packages/system/lib/limits/index.js @@ -1,6 +1,11 @@ // Dependencies import regexp from "@nikitajs/utils/regexp"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -11,8 +16,8 @@ export default { { system: config.system, user: config.user, - } - )}` + }, + )}`, ); } if (config.system) { @@ -38,13 +43,17 @@ export default { } else if (typeof config.nofile === "number") { if (config.nofile >= kern_limit) { throw Error( - `Invalid nofile configuration property. Please set int value lesser than kernel limit: ${kern_limit}` + `Invalid nofile configuration property. Please set int value lesser than kernel limit: ${kern_limit}`, ); } } else if (typeof config.nofile === "object") { - Object.values(config.nofile).filter(v => v >= kern_limit).forEach((v) => { - throw Error(`Invalid nofile configuration property. Please set int value lesser than kernel limit: ${kern_limit}`); - }); + Object.values(config.nofile) + .filter((v) => v >= kern_limit) + .forEach(() => { + throw Error( + `Invalid nofile configuration property. Please set int value lesser than kernel limit: ${kern_limit}`, + ); + }); } } // Calculate nproc from kernel limit @@ -59,14 +68,14 @@ export default { } else if (typeof config.nproc === "number") { if (config.nproc >= kern_limit) { throw Error( - `Invalid nproc configuration property. Please set int value lesser than kernel limit: ${kern_limit}` + `Invalid nproc configuration property. Please set int value lesser than kernel limit: ${kern_limit}`, ); } } else if (typeof config.nproc === "object") { for (const v of config.nproc) { if (v >= kern_limit) { throw Error( - `Invalid nproc configuration property. Please set int value lesser than kernel limit: ${kern_limit}` + `Invalid nproc configuration property. Please set int value lesser than kernel limit: ${kern_limit}`, ); } } @@ -116,7 +125,7 @@ export default { write.push({ match: RegExp( `^${regexp.escape(config.user)} +${regexp.escape(k)} +${opt}.+$`, - "m" + "m", ), replace: `${config.user} ${k} ${opt} ${config[opt][k]}`, append: true, @@ -126,14 +135,14 @@ export default { if (!write.length) { return false; } - const {$status} = await this.file({ + const { $status } = await this.file({ target: config.target, write: write, eof: true, uid: config.uid, gid: config.gid, }); - return $status + return $status; }, metadata: { definitions: definitions, diff --git a/packages/system/lib/mod/index.js b/packages/system/lib/mod/index.js index 0fc3ccdd4..cacb74802 100644 --- a/packages/system/lib/mod/index.js +++ b/packages/system/lib/mod/index.js @@ -1,24 +1,28 @@ - // Dependencies -import path from 'node:path' +import path from "node:path"; import quote from "regexp-quote"; import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { for (const module in config.modules) { const active = config.modules[module]; config.target ??= `${module}.conf`; - config.target = path.resolve('/etc/modules-load.d', config.target); + config.target = path.resolve("/etc/modules-load.d", config.target); await this.execute({ $if: config.load && active, command: dedent` lsmod | grep ${module} && exit 3 modprobe ${module} `, - code: [0, 3] + code: [0, 3], }); await this.execute({ $if: config.load && !active, @@ -26,29 +30,29 @@ export default { lsmod | grep ${module} || exit 3 modprobe -r ${module} `, - code: [0, 3] + code: [0, 3], }); await this.file({ $if: config.persist, target: config.target, match: RegExp(`^${quote(module)}(\\n|$)`, "mg"), - replace: active ? `${module}\n` : '', + replace: active ? `${module}\n` : "", append: true, - eof: true + eof: true, }); } }, hooks: { - on_action: function({config}) { - if (typeof config.modules === 'string') { + on_action: function ({ config }) { + if (typeof config.modules === "string") { config.modules = { - [config.modules]: true + [config.modules]: true, }; } - } + }, }, metadata: { definitions: definitions, - argument_to_config: 'modules' - } + argument_to_config: "modules", + }, }; diff --git a/packages/system/lib/register.js b/packages/system/lib/register.js index e012213af..f1eeff490 100644 --- a/packages/system/lib/register.js +++ b/packages/system/lib/register.js @@ -1,31 +1,30 @@ - // Dependencies -import '@nikitajs/file/register'; -import registry from '@nikitajs/core/registry'; +import "@nikitajs/file/register"; +import registry from "@nikitajs/core/registry"; const actions = { system: { - cgroups: '@nikitajs/system/cgroups', + cgroups: "@nikitajs/system/cgroups", group: { - '': '@nikitajs/system/group', - read: '@nikitajs/system/group/read', - remove: '@nikitajs/system/group/remove' + "": "@nikitajs/system/group", + read: "@nikitajs/system/group/read", + remove: "@nikitajs/system/group/remove", }, info: { - disks: '@nikitajs/system/info/disks', - os: '@nikitajs/system/info/os' + disks: "@nikitajs/system/info/disks", + os: "@nikitajs/system/info/os", }, - limits: '@nikitajs/system/limits', - mod: '@nikitajs/system/mod', - running: '@nikitajs/system/running', - tmpfs: '@nikitajs/system/tmpfs', - uid_gid: '@nikitajs/system/uid_gid', + limits: "@nikitajs/system/limits", + mod: "@nikitajs/system/mod", + running: "@nikitajs/system/running", + tmpfs: "@nikitajs/system/tmpfs", + uid_gid: "@nikitajs/system/uid_gid", user: { - '': '@nikitajs/system/user', - read: '@nikitajs/system/user/read', - remove: '@nikitajs/system/user/remove' - } - } + "": "@nikitajs/system/user", + read: "@nikitajs/system/user/read", + remove: "@nikitajs/system/user/remove", + }, + }, }; -await registry.register(actions) +await registry.register(actions); diff --git a/packages/system/lib/running/index.js b/packages/system/lib/running/index.js index 2968edbc9..ca51b4881 100644 --- a/packages/system/lib/running/index.js +++ b/packages/system/lib/running/index.js @@ -1,42 +1,41 @@ - // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { if (!(config.pid != null || config.target)) { // Validate parameters - throw Error('Invalid Options: one of pid or target must be provided'); + throw Error("Invalid Options: one of pid or target must be provided"); } - if ((config.pid != null) && config.target) { - throw Error('Invalid Options: either pid or target must be provided'); + if (config.pid != null && config.target) { + throw Error("Invalid Options: either pid or target must be provided"); } if (config.pid) { - const {code} = await this.execute({ + const { code } = await this.execute({ command: `kill -s 0 '${config.pid}' >/dev/null 2>&1 || exit 42`, - code: [0, 42] + code: [0, 42], }); log( "INFO", - code === 0 - ? `PID ${config.pid} is running` - : code === 42 - ? `PID ${config.pid} is not running` - : undefined + code === 0 ? `PID ${config.pid} is running` + : code === 42 ? `PID ${config.pid} is not running` + : undefined, ); if (code === 0) { return { - running: true + running: true, }; } } if (config.target) { - const {code, stdout} = await this.execute({ + const { code, stdout } = await this.execute({ command: dedent` [ -f '${config.target}' ] || exit 43 pid=\`cat '${config.target}'\` @@ -47,37 +46,40 @@ export default { fi `, code: [0, [42, 43]], - stdout_trim: true + stdout_trim: true, }); - log('INFO', (function() { - switch (code) { - case 0: - return `PID ${stdout} is running`; - case 42: - return `PID ${stdout} is not running`; - case 43: - return `PID file ${config.target} does not exists`; - } - })()); + log( + "INFO", + (function () { + switch (code) { + case 0: + return `PID ${stdout} is running`; + case 42: + return `PID ${stdout} is not running`; + case 43: + return `PID file ${config.target} does not exists`; + } + })(), + ); if (code === 0) { return { - running: true + running: true, }; } } return { - running: false + running: false, }; }, hooks: { - on_action: function({config}) { - if (typeof config.pid === 'string') { - return config.pid = parseInt(config.pid, 10); + on_action: function ({ config }) { + if (typeof config.pid === "string") { + return (config.pid = parseInt(config.pid, 10)); } - } + }, }, metadata: { // raw_output: true - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/system/lib/tmpfs/index.js b/packages/system/lib/tmpfs/index.js index 5e05d33c2..1b8df77c9 100644 --- a/packages/system/lib/tmpfs/index.js +++ b/packages/system/lib/tmpfs/index.js @@ -1,8 +1,12 @@ - // Dependencies -import {merge} from 'mixme'; +import { merge } from "mixme"; import utils from "@nikitajs/system/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -27,9 +31,9 @@ export default { } if (config.target == null) { config.target = - config.name != null - ? `/etc/tmpfiles.d/${config.name}.conf` - : "/etc/tmpfiles.d/default.conf"; + config.name != null ? + `/etc/tmpfiles.d/${config.name}.conf` + : "/etc/tmpfiles.d/default.conf"; } log("DEBUG", `target set to ${config.target}`); if (config.merge) { diff --git a/packages/system/lib/uid_gid/index.js b/packages/system/lib/uid_gid/index.js index 9d2fb27e9..f8f7c5d77 100644 --- a/packages/system/lib/uid_gid/index.js +++ b/packages/system/lib/uid_gid/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/system/lib/user/index.js b/packages/system/lib/user/index.js index 68ed98ba7..7094020db 100644 --- a/packages/system/lib/user/index.js +++ b/packages/system/lib/user/index.js @@ -1,36 +1,41 @@ - // Dependencies -import path from 'node:path' +import path from "node:path"; import dedent from "dedent"; import { escapeshellarg as esa } from "@nikitajs/utils/string"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { - log('DEBUG', 'Entering user'); - if (typeof config.shell === "function" ? config.shell(typeof config.shell !== 'string') : void 0) { + handler: async function ({ config, tools: { log } }) { + log("DEBUG", "Entering user"); + if ( + typeof config.shell === "function" ? + config.shell(typeof config.shell !== "string") + : void 0 + ) { throw Error(`Invalid option 'shell': ${JSON.strinfigy(config.shell)}`); } - const {users} = await this.system.user.read(); + const { users } = await this.system.user.read(); const user_info = users[config.name]; log( "DEBUG", - user_info - ? `Got user information for ${JSON.stringify(config.name)}` - : `User ${JSON.stringify(config.name)} not present` + user_info ? + `Got user information for ${JSON.stringify(config.name)}` + : `User ${JSON.stringify(config.name)} not present`, ); // Get group information if // * user already exists // * we need to compare groups membership - const {groups: groups_info} = await this.system.group.read({ - $if: user_info && config.groups + const { groups: groups_info } = await this.system.group.read({ + $if: user_info && config.groups, }); if (groups_info) { - log('DEBUG', `Got group information for ${JSON.stringify(config.name)}`); + log("DEBUG", `Got group information for ${JSON.stringify(config.name)}`); } if (config.home) { await this.fs.mkdir({ @@ -38,7 +43,7 @@ export default { target: path.dirname(config.home), uid: 0, gid: 0, - mode: 0o0644 // Same as '/home' + mode: 0o0644, // Same as '/home' }); } if (!user_info) { @@ -60,7 +65,9 @@ export default { config.groups && `-G ${config.groups.join(",")}`, config.skel && `-k ${config.skel}`, `${config.name}`, - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), }, { $if: config.home, @@ -70,8 +77,8 @@ export default { log("WARN", "User defined elsewhere than '/etc/passwd', exit code is 9"); } else { const changed = []; - for (const k of ['uid', 'home', 'shell', 'comment', 'gid']) { - if ((config[k] != null) && user_info[k] !== config[k]) { + for (const k of ["uid", "home", "shell", "comment", "gid"]) { + if (config[k] != null && user_info[k] !== config[k]) { changed.push(k); } } @@ -81,17 +88,21 @@ export default { throw Error(`Group does not exist: ${group}`); } if (groups_info[group].users.indexOf(config.name) === -1) { - changed.push('groups'); + changed.push("groups"); } } } - log(changed.length ? { - message: `User ${config.name} modified`, - level: 'WARN' - } : { - message: `User ${config.name} not modified`, - level: 'DEBUG' - }); + log( + changed.length ? + { + message: `User ${config.name} modified`, + level: "WARN", + } + : { + message: `User ${config.name} not modified`, + level: "DEBUG", + }, + ); try { await this.execute({ $if: changed.length, @@ -104,7 +115,9 @@ export default { config.groups && `-G ${config.groups.join(",")}`, config.uid && `-u ${config.uid}`, `${config.name}`, - ].filter(Boolean).join(" "), + ] + .filter(Boolean) + .join(" "), }); } catch (error) { if (error.exit_code === 8) { @@ -119,40 +132,40 @@ export default { $unless: config.no_home_ownership, target: config.home, uid: config.uid, - gid: config.gid + gid: config.gid, }); } } // TODO, detect changes in password // echo #{config.password} | passwd --stdin #{config.name} if (config.password_sync && config.password) { - const {$status} = await this.execute({ + const { $status } = await this.execute({ command: dedent` hash=$(echo ${config.password} | openssl passwd -1 -stdin) usermod --pass="$hash" ${config.name} - ` + `, }); if ($status) { - return log('WARN', "Password modified"); + return log("WARN", "Password modified"); } } }, hooks: { - on_action: function({config}) { + on_action: function ({ config }) { switch (config.shell) { case true: - config.shell = '/bin/sh'; + config.shell = "/bin/sh"; break; case false: - config.shell = '/sbin/nologin'; + config.shell = "/sbin/nologin"; } - if (typeof config.groups === 'string') { - config.groups = config.groups.split(','); + if (typeof config.groups === "string") { + config.groups = config.groups.split(","); } - } + }, }, metadata: { - argument_to_config: 'name', - definitions: definitions - } + argument_to_config: "name", + definitions: definitions, + }, }; diff --git a/packages/system/lib/user/read/index.js b/packages/system/lib/user/read/index.js index fa1bb4710..843a2f026 100644 --- a/packages/system/lib/user/read/index.js +++ b/packages/system/lib/user/read/index.js @@ -1,12 +1,17 @@ // Dependencies import utils from "@nikitajs/system/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Parse the passwd output const str2passwd = function (data) { const passwd = {}; for (const line of utils.string.lines(data)) { - const record = /(.*)\:\w\:(.*)\:(.*)\:(.*)\:(.*)\:(.*)/.exec(line); + const record = /(.*):\w:(.*):(.*):(.*):(.*):(.*)/.exec(line); if (!record) { continue; } @@ -53,7 +58,7 @@ export default { const user = passwd[config.uid]; if (!user) { throw Error( - `Invalid Option: no uid matching ${JSON.stringify(config.uid)}` + `Invalid Option: no uid matching ${JSON.stringify(config.uid)}`, ); } return { @@ -66,7 +71,7 @@ export default { })[0]; if (!user) { throw Error( - `Invalid Option: no uid matching ${JSON.stringify(config.uid)}` + `Invalid Option: no uid matching ${JSON.stringify(config.uid)}`, ); } return { diff --git a/packages/system/lib/user/remove/index.js b/packages/system/lib/user/remove/index.js index 0d1177a7c..63b186de6 100644 --- a/packages/system/lib/user/remove/index.js +++ b/packages/system/lib/user/remove/index.js @@ -1,17 +1,20 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: function({config}) { + handler: function ({ config }) { this.execute({ command: `userdel ${config.name}`, - code: [0, 6] + code: [0, 6], }); }, metadata: { - argument_to_config: 'name' + argument_to_config: "name", }, - definitions: definitions + definitions: definitions, }; diff --git a/packages/system/lib/utils/cgconfig.js b/packages/system/lib/utils/cgconfig.js index 6ac2e4841..de6afb7ea 100644 --- a/packages/system/lib/utils/cgconfig.js +++ b/packages/system/lib/utils/cgconfig.js @@ -1,13 +1,13 @@ -import string from '@nikitajs/utils/string'; +import string from "@nikitajs/utils/string"; export default { - parse: function(str) { + parse: function (str) { let list_of_mount_sections = []; let list_of_group_sections = {}; // variable which hold the cursor position let current_mount = false; let current_group = false; - let current_group_name = ''; + let current_group_name = ""; let current_group_controller = false; let current_group_perm = false; let current_group_perm_content = false; @@ -17,27 +17,30 @@ export default { let current_group_section = null; // group section is a tree but only of group let current_controller_name = null; let current_group_section_perm_name = null; - string.lines(str).forEach(function(line, _, __) { + string.lines(str).forEach(function (line) { if (!line || line.match(/^\s*$/)) { return; } if (!current_mount && !current_group && !current_default) { - if (/^mount\s{$/.test(line)) { // start of a mount object + if (/^mount\s{$/.test(line)) { + // start of a mount object current_mount = true; current_mount_section = []; } - if (/^(group)\s([A-z|0-9|\/]*)\s{$/.test(line)) { // start of a group object + if (/^(group)\s([A-z|0-9|/]*)\s{$/.test(line)) { + // start of a group object current_group = true; - const match = /^(group)\s([A-z|0-9|\/]*)\s{$/.exec(line); + const match = /^(group)\s([A-z|0-9|/]*)\s{$/.exec(line); current_group_name = match[2]; current_group_section = {}; if (list_of_group_sections[current_group_name] == null) { list_of_group_sections[current_group_name] = {}; } } - if (/^(default)\s{$/.test(line)) { // start of a special group object named default + if (/^(default)\s{$/.test(line)) { + // start of a special group object named default current_group = true; - current_group_name = ''; + current_group_name = ""; current_group_section = {}; list_of_group_sections[current_group_name] ??= {}; } @@ -45,18 +48,19 @@ export default { // we are parsing a mount object // ^(cpuset|cpu|cpuacct|memory|devices|freezer|net_cls|blkio)\s=\s[aA-zZ|\s]* if (current_mount) { - if (/^}$/.test(line)) { // close the mount object + if (/^}$/.test(line)) { + // close the mount object list_of_mount_sections.push(...current_mount_section); current_mount = false; current_mount_section = []; } else { // add the line to mont object - line = line.replace(';', ''); - const sep = line.indexOf(':') !== -1 ? ':' : '='; + line = line.replace(";", ""); + const sep = line.indexOf(":") !== -1 ? ":" : "="; line = line.split(sep); current_mount_section.push({ type: `${line[0].trim()}`, - path: `${line[1].trim()}` + path: `${line[1].trim()}`, }); } } @@ -83,39 +87,56 @@ export default { } } else { //closing the group object - const match = /^\s*(cpuset|cpu|cpuacct|blkio|memory|devices|freezer|net_cls|perf_event|net_prio|hugetlb|pids|rdma)\s{$/.exec(line); + const match = + /^\s*(cpuset|cpu|cpuacct|blkio|memory|devices|freezer|net_cls|perf_event|net_prio|hugetlb|pids|rdma)\s{$/.exec( + line, + ); if (!current_group_perm && !current_group_controller) { //if neither working in perm or controller section, we are declaring one of them - if (/^\s*perm\s{$/.test(line)) { // perm declaration + if (/^\s*perm\s{$/.test(line)) { + // perm declaration current_group_perm = true; - current_group_section['perm'] = {}; - list_of_group_sections[`${current_group_name}`]['perm'] = {}; + current_group_section["perm"] = {}; + list_of_group_sections[`${current_group_name}`]["perm"] = {}; } - if (match) { //controller declaration + if (match) { + //controller declaration current_group_controller = true; current_controller_name = match[1]; current_group_section[`${current_controller_name}`] = {}; - list_of_group_sections[`${current_group_name}`][current_controller_name] ??= {}; + list_of_group_sections[`${current_group_name}`][ + current_controller_name + ] ??= {}; } - } else if (current_group_perm && current_group_perm_content) { // perm config - line = line.replace(';', ''); - line = line.split('='); + } else if (current_group_perm && current_group_perm_content) { + // perm config + line = line.replace(";", ""); + line = line.split("="); const [type, value] = line; - current_group_section['perm'][current_group_section_perm_name][type.trim()] = value.trim(); - list_of_group_sections[`${current_group_name}`]['perm'][current_group_section_perm_name][type.trim()] = value.trim(); - } else if (current_group_controller) { // controller config - line = line.replace(';', ''); - const sep = line.indexOf(':') !== -1 ? ':' : '='; + current_group_section["perm"][current_group_section_perm_name][ + type.trim() + ] = value.trim(); + list_of_group_sections[`${current_group_name}`]["perm"][ + current_group_section_perm_name + ][type.trim()] = value.trim(); + } else if (current_group_controller) { + // controller config + line = line.replace(";", ""); + const sep = line.indexOf(":") !== -1 ? ":" : "="; const [type, value] = line.split(sep); - list_of_group_sections[`${current_group_name}`][`${current_controller_name}`][type.trim()] ??= value.trim() + list_of_group_sections[`${current_group_name}`][ + `${current_controller_name}` + ][type.trim()] ??= value.trim(); } else { const match_admin = /^\s*(admin|task)\s{$/.exec(line); - if (match_admin) { // admin or task declaration - const [_, name] = match_admin; //the name is either admin or task + if (match_admin) { + // admin or task declaration + const [, name] = match_admin; //the name is either admin or task current_group_perm_content = true; current_group_section_perm_name = name; - current_group_section['perm'][name] = {}; - list_of_group_sections[`${current_group_name}`]['perm'][name] = {}; + current_group_section["perm"][name] = {}; + list_of_group_sections[`${current_group_name}`]["perm"][name] = + {}; } } } @@ -124,10 +145,10 @@ export default { }); return { mounts: list_of_mount_sections, - groups: list_of_group_sections + groups: list_of_group_sections, }; }, - stringify: function(obj, config = {}) { + stringify: function (obj, config = {}) { if (obj.mounts == null) { obj.mounts = []; } @@ -137,36 +158,36 @@ export default { if (config.indent == null) { config.indent = 2; } - let indent = ' '.repeat(config.indent); + let indent = " ".repeat(config.indent); const sections = []; if (obj.mounts.length !== 0) { let mount_render = "mount {\n"; for (const mount of obj.mounts) { mount_render += `${indent}${mount.type} = ${mount.path};\n`; } - mount_render += '}'; + mount_render += "}"; sections.push(mount_render); } - let count = 0; for (const name in obj.groups) { const group = obj.groups[name]; - let group_render = (name === '') || (name === 'default') ? 'default {\n' : `group ${name} {\n`; + let group_render = + name === "" || name === "default" ? "default {\n" : `group ${name} {\n`; for (const key in group) { const value = group[key]; - if (key === 'perm') { + if (key === "perm") { group_render += `${indent}perm {\n`; - if (value['admin'] != null) { + if (value["admin"] != null) { group_render += `${indent}${indent}admin {\n`; - for (const prop in value['admin']) { - const val = value['admin'][prop]; + for (const prop in value["admin"]) { + const val = value["admin"][prop]; group_render += `${indent}${indent}${indent}${prop} = ${val};\n`; } group_render += `${indent}${indent}}\n`; } - if (value['task'] != null) { + if (value["task"] != null) { group_render += `${indent}${indent}task {\n`; - for (const prop in value['task']) { - const val = value['task'][prop]; + for (const prop in value["task"]) { + const val = value["task"][prop]; group_render += `${indent}${indent}${indent}${prop} = ${val};\n`; } group_render += `${indent}${indent}}\n`; @@ -181,10 +202,9 @@ export default { group_render += `${indent}}\n`; } } - group_render += '}'; - count++; + group_render += "}"; sections.push(group_render); } return sections.join("\n"); - } + }, }; diff --git a/packages/system/lib/utils/tmpfs.js b/packages/system/lib/utils/tmpfs.js index 34456a9a7..f8bfe305e 100644 --- a/packages/system/lib/utils/tmpfs.js +++ b/packages/system/lib/utils/tmpfs.js @@ -1,12 +1,11 @@ - // parse the content of tmpfs daemon configuration file import string from "@nikitajs/utils/string"; -const properties = ['type', 'mount', 'perm', 'uid', 'gid', 'age', 'argu'] +const properties = ["type", "mount", "perm", "uid", "gid", "age", "argu"]; const parse = function (str) { const files = {}; - string.lines(str).forEach(function(line, _, __) { + string.lines(str).forEach(function (line) { if (!line || line.match(/^#.*$/)) { return; } @@ -16,7 +15,7 @@ const parse = function (str) { for (const i in properties) { const property = properties[i]; const value = values[i]; - record[property] = value === '-' ? undefined : value; + record[property] = value === "-" ? undefined : value; } files[mount] = record; }); @@ -31,7 +30,7 @@ const stringify = function (record) { v[key] = v[key] !== undefined ? v[key] : "-"; } lines.push( - `${v.type} ${v.mount} ${v.perm} ${v.uid} ${v.gid} ${v.age} ${v.argu}` + `${v.type} ${v.mount} ${v.perm} ${v.uid} ${v.gid} ${v.age} ${v.argu}`, ); } return lines.join("\n"); diff --git a/packages/tools/env/iptables/index.js b/packages/tools/env/iptables/index.js index 83e58e46b..eb9ff9724 100644 --- a/packages/tools/env/iptables/index.js +++ b/packages/tools/env/iptables/index.js @@ -1,35 +1,39 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const dirname = new URL( '.', import.meta.url).pathname +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const dirname = new URL(".", import.meta.url).pathname; runner({ - cwd: '/nikita/packages/tools', - container: 'nikita-tools-iptables', - logdir: path.resolve(dirname, './logs'), + cwd: "/nikita/packages/tools", + container: "nikita-tools-iptables", + logdir: path.resolve(dirname, "./logs"), cluster: { containers: { - 'nikita-tools-iptables': { - image: 'images:almalinux/8', + "nikita-tools-iptables": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/tools/env/iptables/test.coffee', - 'raw.idmap': process.env['NIKITA_INCUS_IN_VAGRANT'] ? 'both 1000 0' : `both ${process.getuid()} 0` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/tools/env/iptables/test.coffee", + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" + : `both ${process.getuid()} 0`, }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || path.join(dirname, "../../../../"), + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", container: config.container, command: dedent` yum install -y tar @@ -39,10 +43,10 @@ runner({ nvm install 22 `, trap: true, - code: [0, 42] + code: [0, 42], }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", container: config.container, command: dedent` mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -51,8 +55,8 @@ runner({ cat /root/.ssh/id_ed25519.pub > /root/.ssh/authorized_keys fi `, - trap: true + trap: true, }); - } - } + }, + }, }); diff --git a/packages/tools/env/npm/index.js b/packages/tools/env/npm/index.js index ccb0daba6..878c9dedb 100644 --- a/packages/tools/env/npm/index.js +++ b/packages/tools/env/npm/index.js @@ -1,35 +1,40 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const __dirname = new URL( '.', import.meta.url).pathname +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const __dirname = new URL(".", import.meta.url).pathname; runner({ - cwd: '/nikita/packages/tools', - container: 'nikita-tools-npm', - logdir: path.resolve(__dirname, './logs'), + cwd: "/nikita/packages/tools", + container: "nikita-tools-npm", + logdir: path.resolve(__dirname, "./logs"), cluster: { containers: { - 'nikita-tools-npm': { - image: 'images:almalinux/8', + "nikita-tools-npm": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/tools/env/npm/test.coffee', - 'raw.idmap': process.env['NIKITA_INCUS_IN_VAGRANT'] ? 'both 1000 0' : `both ${process.getuid()} 0` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/tools/env/npm/test.coffee", + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" + : `both ${process.getuid()} 0`, }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(__dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || + path.join(__dirname, "../../../../"), + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", container: config.container, command: dedent` yum install -y tar @@ -39,10 +44,10 @@ runner({ nvm install 22 `, trap: true, - code: [0, 42] + code: [0, 42], }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", container: config.container, command: dedent` mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -51,8 +56,8 @@ runner({ cat /root/.ssh/id_ed25519.pub > /root/.ssh/authorized_keys fi `, - trap: true + trap: true, }); - } - } + }, + }, }); diff --git a/packages/tools/env/rubygems/index.js b/packages/tools/env/rubygems/index.js index 527e65996..8af887fd4 100644 --- a/packages/tools/env/rubygems/index.js +++ b/packages/tools/env/rubygems/index.js @@ -1,35 +1,40 @@ - -import path from 'node:path'; -import dedent from 'dedent'; -import runner from '@nikitajs/incus-runner'; -const __dirname = new URL( '.', import.meta.url).pathname +import path from "node:path"; +import dedent from "dedent"; +import runner from "@nikitajs/incus-runner"; +const __dirname = new URL(".", import.meta.url).pathname; runner({ - cwd: '/nikita/packages/tools', - container: 'nikita-tools-rubygems', - logdir: path.resolve(__dirname, './logs'), + cwd: "/nikita/packages/tools", + container: "nikita-tools-rubygems", + logdir: path.resolve(__dirname, "./logs"), cluster: { containers: { - 'nikita-tools-rubygems': { - image: 'images:almalinux/8', + "nikita-tools-rubygems": { + image: "images:almalinux/8", properties: { - 'environment.NIKITA_TEST_MODULE': '/nikita/packages/tools/env/rubygems/test.coffee', - 'raw.idmap': process.env['NIKITA_INCUS_IN_VAGRANT'] ? 'both 1000 0' : `both ${process.getuid()} 0` + "environment.NIKITA_TEST_MODULE": + "/nikita/packages/tools/env/rubygems/test.coffee", + "raw.idmap": + process.env["NIKITA_INCUS_IN_VAGRANT"] ? + "both 1000 0" + : `both ${process.getuid()} 0`, }, disk: { nikitadir: { - path: '/nikita', - source: process.env['NIKITA_HOME'] || path.join(__dirname, '../../../../') - } + path: "/nikita", + source: + process.env["NIKITA_HOME"] || + path.join(__dirname, "../../../../"), + }, }, ssh: { - enabled: true - } - } + enabled: true, + }, + }, }, - provision_container: async function({config}) { + provision_container: async function ({ config }) { await this.incus.exec({ - $header: 'Node.js', + $header: "Node.js", container: config.container, command: dedent` yum install -y tar @@ -39,10 +44,10 @@ runner({ nvm install 22 `, trap: true, - code: [0, 42] + code: [0, 42], }); await this.incus.exec({ - $header: 'SSH keys', + $header: "SSH keys", container: config.container, command: dedent` mkdir -p /root/.ssh && chmod 700 /root/.ssh @@ -51,15 +56,15 @@ runner({ cat /root/.ssh/id_rsa.pub > /root/.ssh/authorized_keys fi `, - trap: true + trap: true, }); await this.incus.exec({ - $header: 'Ruby', + $header: "Ruby", container: config.container, command: `yum install -y gcc ruby ruby-devel`, trap: true, - code: [0, 42] + code: [0, 42], }); - } - } + }, + }, }); diff --git a/packages/tools/env/run.sh b/packages/tools/env/run.sh index e4b1834ad..771c5b9d2 100755 --- a/packages/tools/env/run.sh +++ b/packages/tools/env/run.sh @@ -6,6 +6,7 @@ cd `pwd`/`dirname ${BASH_SOURCE}` ./cron/run.sh ./dconf/run.sh ./repo-alma8/run.sh +./repo-rocky9/run.sh node ./iptables/index.js run node ./npm/index.js run node ./rubygems/index.js run diff --git a/packages/tools/lib/backup/index.js b/packages/tools/lib/backup/index.js index 917dc5150..361df2a97 100644 --- a/packages/tools/lib/backup/index.js +++ b/packages/tools/lib/backup/index.js @@ -2,7 +2,13 @@ import dayjs from "dayjs"; import dayjsUtc from "dayjs/plugin/utc.js"; import dayjsTimezone from "dayjs/plugin/timezone.js"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); +// Day.js dayjs.extend(dayjsUtc); dayjs.extend(dayjsTimezone); diff --git a/packages/tools/lib/compress/index.js b/packages/tools/lib/compress/index.js index 111c0d21c..7d36fb992 100644 --- a/packages/tools/lib/compress/index.js +++ b/packages/tools/lib/compress/index.js @@ -1,7 +1,9 @@ - - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); /** ## Extention to type @@ -9,17 +11,17 @@ import definitions from "./schema.json" with { type: "json" }; Convert a full path, a filename or an extension into a supported compression type. */ -const ext_to_type = function(name, path) { +const ext_to_type = function (name, path) { if (/((.+\.)|^\.|^)(tar\.gz|tgz)$/.test(name)) { - return 'tgz'; + return "tgz"; } else if (/((.+\.)|^\.|^)tar$/.test(name)) { - return 'tar'; + return "tar"; } else if (/((.+\.)|^\.|^)zip$/.test(name)) { - return 'zip'; + return "zip"; } else if (/((.+\.)|^\.|^)bz2$/.test(name)) { - return 'bz2'; + return "bz2"; } else if (/((.+\.)|^\.|^)xz$/.test(name)) { - return 'xz'; + return "xz"; } else { throw Error(`Unsupported Extension: ${JSON.stringify(path.extname(name))}`); } @@ -27,42 +29,41 @@ const ext_to_type = function(name, path) { // Action export default { - handler: async function({ - config, - tools: {path} - }) { + handler: async function ({ config, tools: { path } }) { config.source = path.normalize(config.source); config.target = path.normalize(config.target); const dir = path.dirname(config.source); const name = path.basename(config.source); // Deal with format option - const format = config.format || ext_to_type(config.target, path) + const format = config.format || ext_to_type(config.target, path); // Run compression - const output = await this.execute((() => { - switch (format) { - case 'tgz': - return `tar czf ${config.target} -C ${dir} ${name}`; - case 'tar': - return `tar cf ${config.target} -C ${dir} ${name}`; - case 'bz2': - return `tar cjf ${config.target} -C ${dir} ${name}`; - case 'xz': - return `tar cJf ${config.target} -C ${dir} ${name}`; - case 'zip': - return `(cd ${dir} && zip -r ${config.target} ${name} && cd -)`; - } - })()); + const output = await this.execute( + (() => { + switch (format) { + case "tgz": + return `tar czf ${config.target} -C ${dir} ${name}`; + case "tar": + return `tar cf ${config.target} -C ${dir} ${name}`; + case "bz2": + return `tar cjf ${config.target} -C ${dir} ${name}`; + case "xz": + return `tar cJf ${config.target} -C ${dir} ${name}`; + case "zip": + return `(cd ${dir} && zip -r ${config.target} ${name} && cd -)`; + } + })(), + ); await this.fs.remove({ $if: config.clean, target: config.source, - recursive: true + recursive: true, }); return output; }, metadata: { - definitions: definitions + definitions: definitions, }, tools: { - ext_to_type: ext_to_type - } + ext_to_type: ext_to_type, + }, }; diff --git a/packages/tools/lib/cron/add/index.js b/packages/tools/lib/cron/add/index.js index cf0432cfc..5b4616b1f 100644 --- a/packages/tools/lib/cron/add/index.js +++ b/packages/tools/lib/cron/add/index.js @@ -1,14 +1,19 @@ // Dependencies -import dedent from "dedent"; import utils from "@nikitajs/tools/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { handler: async function ({ config, tools: { log } }) { const command = config.user ? `crontab -u ${config.user}` : "crontab"; // console.log(await this.tools.cron.list().then(({ entries }) => entries)) - const entries = await this.tools.cron.list() + const entries = await this.tools.cron + .list() .then(({ entries }) => entries.map(({ raw }) => raw)); const new_job = `${config.when} ${config.command}`; // remove useless last element @@ -56,24 +61,20 @@ export default { }; } await this.execute({ - command: [ - `${command} - < line.length > 0) - .filter((job) => config.match ? regex.test(job) : true) - .map( entry => ({ - raw: entry - })) + .filter((line) => line.length > 0) + .filter((job) => (config.match ? regex.test(job) : true)) + .map((entry) => ({ + raw: entry, + })); return { entries: entries, - } + }; }, metadata: { definitions: definitions, diff --git a/packages/tools/lib/cron/remove/index.js b/packages/tools/lib/cron/remove/index.js index 6165d65ed..c9d29efc2 100644 --- a/packages/tools/lib/cron/remove/index.js +++ b/packages/tools/lib/cron/remove/index.js @@ -1,27 +1,29 @@ // Dependencies import dedent from "dedent"; import utils from "@nikitajs/tools/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { const command = config.user ? `crontab -u ${config.user}` : "crontab"; let status = false; - const {stdout, stderr} = (await this.execute({ + const { stdout, stderr } = await this.execute({ $shy: true, - command: `${command} -l` - })); + command: `${command} -l`, + }); if (/^no crontab for/.test(stderr)) { - throw Error('User crontab not found'); + throw Error("User crontab not found"); } - let myjob = config.when ? utils.regexp.escape(config.when) : '.*'; + let myjob = config.when ? utils.regexp.escape(config.when) : ".*"; myjob += utils.regexp.escape(` ${config.command}`); let regex = new RegExp(myjob); - const jobs = stdout.trim().split('\n'); + const jobs = stdout.trim().split("\n"); for (const i in jobs) { const job = jobs[i]; if (!regex.test(job)) { @@ -29,14 +31,14 @@ export default { } log({ message: `Job '${job}' matches. Removing from list`, - level: 'WARN' + level: "WARN", }); status = true; jobs.splice(i, 1); } log({ message: "No Job matches. Skipping", - level: 'INFO' + level: "INFO", }); if (!status) { return; @@ -44,11 +46,11 @@ export default { await this.execute({ command: dedent` ${command} - < !installed.includes(name.split("@")[0]) + (name) => !installed.includes(name.split("@")[0]), ); if (!install.length) { return; diff --git a/packages/tools/lib/npm/list/index.js b/packages/tools/lib/npm/list/index.js index 8166c01d9..96b1081d3 100644 --- a/packages/tools/lib/npm/list/index.js +++ b/packages/tools/lib/npm/list/index.js @@ -1,21 +1,27 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {stdout} = await this.execute({ - command: ['npm list', '--json', config.global ? '--global' : void 0].join(' '), + handler: async function ({ config }) { + const { stdout } = await this.execute({ + command: ["npm list", "--json", config.global ? "--global" : void 0].join( + " ", + ), code: [0, 1], cwd: config.cwd, - stdout_log: false + stdout_log: false, }); return { - packages: JSON.parse(stdout).dependencies || {} + packages: JSON.parse(stdout).dependencies || {}, }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/tools/lib/npm/outdated/index.js b/packages/tools/lib/npm/outdated/index.js index 52edca124..49471cd25 100644 --- a/packages/tools/lib/npm/outdated/index.js +++ b/packages/tools/lib/npm/outdated/index.js @@ -1,21 +1,29 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { - const {stdout} = (await this.execute({ - command: ['npm outdated', '--json', config.global ? '--global' : void 0].join(' '), + handler: async function ({ config }) { + const { stdout } = await this.execute({ + command: [ + "npm outdated", + "--json", + config.global ? "--global" : void 0, + ].join(" "), code: [0, 1], cwd: config.cwd, - stdout_log: false - })); + stdout_log: false, + }); return { - packages: JSON.parse(stdout) + packages: JSON.parse(stdout), }; }, metadata: { definitions: definitions, - shy: true - } + shy: true, + }, }; diff --git a/packages/tools/lib/npm/uninstall/index.js b/packages/tools/lib/npm/uninstall/index.js index 6015e0572..3dcdf7736 100644 --- a/packages/tools/lib/npm/uninstall/index.js +++ b/packages/tools/lib/npm/uninstall/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/tools/lib/npm/upgrade/index.js b/packages/tools/lib/npm/upgrade/index.js index 5f8444007..197d6f38d 100644 --- a/packages/tools/lib/npm/upgrade/index.js +++ b/packages/tools/lib/npm/upgrade/index.js @@ -1,5 +1,9 @@ -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { diff --git a/packages/tools/lib/register.js b/packages/tools/lib/register.js index abd0c168d..8cf100a4e 100644 --- a/packages/tools/lib/register.js +++ b/packages/tools/lib/register.js @@ -1,47 +1,46 @@ - // Dependencies import registry from "@nikitajs/core/registry"; -import '@nikitajs/file/register'; -import '@nikitajs/service/register'; +import "@nikitajs/file/register"; +import "@nikitajs/service/register"; // Action registration const actions = { tools: { - backup: '@nikitajs/tools/backup', - compress: '@nikitajs/tools/compress', + backup: "@nikitajs/tools/backup", + compress: "@nikitajs/tools/compress", cron: { - add: '@nikitajs/tools/cron/add', - list: '@nikitajs/tools/cron/list', - remove: '@nikitajs/tools/cron/remove', - reset: '@nikitajs/tools/cron/reset' + add: "@nikitajs/tools/cron/add", + list: "@nikitajs/tools/cron/list", + remove: "@nikitajs/tools/cron/remove", + reset: "@nikitajs/tools/cron/reset", }, - extract: '@nikitajs/tools/extract', - dconf: '@nikitajs/tools/dconf', - iptables: '@nikitajs/tools/iptables', - git: '@nikitajs/tools/git', + extract: "@nikitajs/tools/extract", + dconf: "@nikitajs/tools/dconf", + iptables: "@nikitajs/tools/iptables", + git: "@nikitajs/tools/git", npm: { - '': '@nikitajs/tools/npm', - list: '@nikitajs/tools/npm/list', - outdated: '@nikitajs/tools/npm/outdated', - uninstall: '@nikitajs/tools/npm/uninstall', - upgrade: '@nikitajs/tools/npm/upgrade' + "": "@nikitajs/tools/npm", + list: "@nikitajs/tools/npm/list", + outdated: "@nikitajs/tools/npm/outdated", + uninstall: "@nikitajs/tools/npm/uninstall", + upgrade: "@nikitajs/tools/npm/upgrade", }, - repo: '@nikitajs/tools/repo', + repo: "@nikitajs/tools/repo", rubygems: { - 'fetch': '@nikitajs/tools/rubygems/fetch', - 'install': '@nikitajs/tools/rubygems/install', - 'remove': '@nikitajs/tools/rubygems/remove' + fetch: "@nikitajs/tools/rubygems/fetch", + install: "@nikitajs/tools/rubygems/install", + remove: "@nikitajs/tools/rubygems/remove", }, ssh: { - keygen: '@nikitajs/tools/ssh/keygen' + keygen: "@nikitajs/tools/ssh/keygen", }, sysctl: { - 'file': { - '': '@nikitajs/tools/sysctl/file', - 'read': '@nikitajs/tools/sysctl/file/read' - } - } - } + file: { + "": "@nikitajs/tools/sysctl/file", + read: "@nikitajs/tools/sysctl/file/read", + }, + }, + }, }; await registry.register(actions); diff --git a/packages/tools/lib/repo/index.js b/packages/tools/lib/repo/index.js index 09429cae0..4275fabd6 100644 --- a/packages/tools/lib/repo/index.js +++ b/packages/tools/lib/repo/index.js @@ -1,9 +1,13 @@ // Dependencies import each from "each"; import dedent from "dedent"; -import url from "node:url"; import utils from "@nikitajs/file/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -12,7 +16,7 @@ export default { if (config.source != null && config.target == null) { config.target = path.resolve( "/etc/yum.repos.d", - path.basename(config.source) + path.basename(config.source), ); } // Unless absolute, path is relative to the default yum repo location @@ -75,7 +79,7 @@ export default { target: config.target, encoding: "utf8", }) - .then(({ data }) => data) + .then(({ data }) => data), ); // Extract repo IDs const repoids = Object.keys(data); @@ -112,10 +116,12 @@ export default { command: `rpm --import ${config.gpg_dir}/${path.basename(gpgKey)}`, }); return isKeyUpdated; - }).then( statuses => statuses.some( status => status === true)); + }).then((statuses) => statuses.some((status) => status === true)); // Clean Metadata await this.execute({ - $if: path.relative("/etc/yum.repos.d", config.target) !== ".." && areKeysUpdated, + $if: + path.relative("/etc/yum.repos.d", config.target) !== ".." && + areKeysUpdated, // wdavidw: 180114, was "yum clean metadata" // explanation is provided in case of revert. // expire-cache is much faster, it forces yum to go redownload the small diff --git a/packages/tools/lib/rubygems/fetch/index.js b/packages/tools/lib/rubygems/fetch/index.js index d98df0140..c3416d8e9 100644 --- a/packages/tools/lib/rubygems/fetch/index.js +++ b/packages/tools/lib/rubygems/fetch/index.js @@ -1,38 +1,42 @@ - // Dependencies -import path from 'node:path' -import definitions from "./schema.json" with { type: "json" }; +import path from "node:path"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { // Get version if (!config.version) { - const {$status, stdout} = (await this.execute({ + const { $status, stdout } = await this.execute({ $shy: true, command: `${config.gem_bin} specification ${config.name} version -r | grep '^version' | sed 's/.*: \\(.*\\)$/\\1/'`, cwd: config.cwd, - bash: config.bash - })); + bash: config.bash, + }); if ($status) { config.version = stdout.trim(); } } config.target = `${config.name}-${config.version}.gem`; // Fetch package - const {$status} = (await this.execute({ + const { $status } = await this.execute({ command: `${config.gem_bin} fetch ${config.name} -v ${config.version}`, cwd: config.cwd, - bash: config.bash - })); + bash: config.bash, + }); return { $status: $status, filename: config.target, - filepath: path.resolve(config.cwd, config.target) + filepath: path.resolve(config.cwd, config.target), }; }, metadata: { - global: 'ruby', - definitions: definitions - } + global: "ruby", + definitions: definitions, + }, }; diff --git a/packages/tools/lib/rubygems/install/index.js b/packages/tools/lib/rubygems/install/index.js index 81720041e..666be2c3b 100644 --- a/packages/tools/lib/rubygems/install/index.js +++ b/packages/tools/lib/rubygems/install/index.js @@ -1,8 +1,12 @@ - // Dependencies -import semver from 'semver'; +import semver from "semver"; import utils from "@nikitajs/tools/utils"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { @@ -23,13 +27,14 @@ export default { continue; } const [name, version] = line - .match(/(.*?)(?:$| \((?:default:\s+)?([\d\., ]+)\))/) + .match(/(.*?)(?:$| \((?:default:\s+)?([\d., ]+)\))/) .slice(1, 4); currentGems[name] = version.split(", "); } // Make array of sources and filter - let sources = !config.source - ? [] + let sources = + !config.source ? + [] : await (async () => { const { files } = await this.fs.glob(config.source); const current_filenames = []; @@ -54,7 +59,7 @@ export default { } // Install if a version is demanded and no installed version satisfy it const isVersionMatching = currentGems[name].some((currentVersion) => - semver.satisfies(version, currentVersion) + semver.satisfies(version, currentVersion), ); if (version && !isVersionMatching) { continue; @@ -75,7 +80,7 @@ export default { config.build_flags && "--build-flags config.build_flags", ] .filter(Boolean) - .join(" ") + .join(" "), ) .join("\n"), code: [0, 2], diff --git a/packages/tools/lib/rubygems/remove/index.js b/packages/tools/lib/rubygems/remove/index.js index 1172ba8f4..05ed739a0 100644 --- a/packages/tools/lib/rubygems/remove/index.js +++ b/packages/tools/lib/rubygems/remove/index.js @@ -1,26 +1,30 @@ - // Dependencies import dedent from "dedent"; -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({config}) { + handler: async function ({ config }) { if (config.gem_bin == null) { - config.gem_bin = 'gem'; + config.gem_bin = "gem"; } - const version = config.version ? `-v ${config.version}` : '-a'; + const version = config.version ? `-v ${config.version}` : "-a"; await this.execute({ command: dedent` ${config.gem_bin} list -i ${config.name} || exit 3 ${config.gem_bin} uninstall ${config.name} ${version} `, code: [0, 3], - bash: config.bash + bash: config.bash, }); }, metadata: { - global: 'ruby', - definitions: definitions - } + global: "ruby", + definitions: definitions, + }, }; diff --git a/packages/tools/lib/ssh/keygen/index.js b/packages/tools/lib/ssh/keygen/index.js index 0fd65effb..9241b3988 100644 --- a/packages/tools/lib/ssh/keygen/index.js +++ b/packages/tools/lib/ssh/keygen/index.js @@ -1,32 +1,35 @@ - // Dependencies -import definitions from "./schema.json" with { type: "json" }; import { escapeshellarg as esa } from "@nikitajs/utils/string"; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {path} - }) { + handler: async function ({ config, tools: { path } }) { await this.fs.mkdir({ - target: `${path.dirname(config.target)}` + target: `${path.dirname(config.target)}`, }); await this.execute({ $unless_exists: `${config.target}`, command: [ - 'ssh-keygen', + "ssh-keygen", "-q", // Silence `-t ${config.type}`, `-b ${config.bits}`, config.key_format && `-m ${esa(config.key_format)}`, config.comment && `-C ${esa(config.comment)}`, `-N ${esa(config.passphrase)}`, - `-f ${esa(config.target)}` - ].filter(Boolean).join(' ') + `-f ${esa(config.target)}`, + ] + .filter(Boolean) + .join(" "), }); }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/tools/lib/sysctl/file/index.js b/packages/tools/lib/sysctl/file/index.js index 09124586f..ded24c06d 100644 --- a/packages/tools/lib/sysctl/file/index.js +++ b/packages/tools/lib/sysctl/file/index.js @@ -1,22 +1,22 @@ - -// Dependencies -import definitions from "./schema.json" with { type: "json" }; +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); // Action export default { - handler: async function({ - config, - tools: {log} - }) { + handler: async function ({ config, tools: { log } }) { let $status = false; // Read current properties - const current = await this.tools.sysctl.file.read({ - $relax: true, - target: config.target, - comment: config.comment, - }).then(({data}) => - data || {} - ); + const current = await this.tools.sysctl.file + .read({ + $relax: true, + target: config.target, + comment: config.comment, + }) + .then(({ data }) => data || {}); // Merge user properties const final = {}; if (config.merge) { @@ -29,13 +29,13 @@ export default { if (value == null) { continue; } - if (typeof value === 'number') { + if (typeof value === "number") { value = `${value}`; } if (current[key] === value) { continue; } - log(`Update Property: key \"${key}\" from \"${final[key]}\" to \"${value}\"`); + log(`Update Property: key "${key}" from "${final[key]}" to "${value}"`); final[key] = value; $status = true; } @@ -44,7 +44,9 @@ export default { target: config.target, backup: config.backup, content: Object.keys(final) - .map((key) => (final[key] != null ? `${key} = ${final[key]}` : `${key}`)) + .map((key) => + final[key] != null ? `${key} = ${final[key]}` : `${key}`, + ) .join("\n"), }); } @@ -53,6 +55,6 @@ export default { } }, metadata: { - definitions: definitions - } + definitions: definitions, + }, }; diff --git a/packages/tools/lib/sysctl/file/read/index.js b/packages/tools/lib/sysctl/file/read/index.js index 474be2e6a..de3e2984e 100644 --- a/packages/tools/lib/sysctl/file/read/index.js +++ b/packages/tools/lib/sysctl/file/read/index.js @@ -1,8 +1,11 @@ - // Dependencies import utils from "@nikitajs/tools/utils"; -import definitions from "./schema.json" with { type: "json" }; - +// Schema +// import definitions from "./schema.json" with { type: "json" }; +import { readFile } from "node:fs/promises"; +const definitions = JSON.parse( + await readFile(new URL("./schema.json", import.meta.url), "utf8"), +); export default { handler: async function ({ config, tools: { log } }) { diff --git a/packages/tools/lib/utils/index.js b/packages/tools/lib/utils/index.js index 311bba2c0..350cf229a 100644 --- a/packages/tools/lib/utils/index.js +++ b/packages/tools/lib/utils/index.js @@ -1,10 +1,9 @@ - import utils from "@nikitajs/core/utils"; -import { diff } from '@nikitajs/file/utils'; -import iptables from '@nikitajs/tools/utils/iptables'; +import { diff } from "@nikitajs/file/utils"; +import iptables from "@nikitajs/tools/utils/iptables"; export default { ...utils, diff: diff, - iptables: iptables + iptables: iptables, }; diff --git a/packages/tools/lib/utils/iptables.js b/packages/tools/lib/utils/iptables.js index 5571f74ab..f48c2daab 100644 --- a/packages/tools/lib/utils/iptables.js +++ b/packages/tools/lib/utils/iptables.js @@ -141,9 +141,8 @@ const constants = { state: ["--state"], comment: ["--comment"], limit: ["--limit"], - } -} - + }, +}; const command_args = function (command, rule) { for (const k in rule) { @@ -171,20 +170,14 @@ const command_replace = function (rule) { if (rule.rulenum == null) { rule.rulenum = 1; } - return command_args( - `iptables -R ${rule.chain} ${rule.rulenum}`, - rule - ); + return command_args(`iptables -R ${rule.chain} ${rule.rulenum}`, rule); }; const command_insert = function (rule) { if (rule.rulenum == null) { rule.rulenum = 1; } - return command_args( - `iptables -I ${rule.chain} ${rule.rulenum}`, - rule - ); + return command_args(`iptables -I ${rule.chain} ${rule.rulenum}`, rule); }; const command_append = function (rule) { @@ -221,12 +214,10 @@ const command = function (oldrules, newrules) { for (const newrule of newrules) { // break if newrule.rulenum? #or newrule.command is '-A' if (newrule.after && !newrule.rulenum) { - let rulenum = 0; for (const oldrule of oldrules) { if (!(oldrule.command === "-A" && oldrule.chain === newrule.chain)) { continue; } - rulenum++; if (_equals(newrule.after, oldrule, Object.keys(newrule.after))) { // newrule.rulenum = rulenum + 1 newrule.rulenum = oldrule.rulenum + 1; @@ -236,12 +227,10 @@ const command = function (oldrules, newrules) { delete newrule.after; } if (newrule.before && !newrule.rulenum) { - let rulenum = 0; for (const oldrule of oldrules) { if (!(oldrule.command === "-A" && oldrule.chain === newrule.chain)) { continue; } - rulenum++; if (_equals(newrule.before, oldrule, Object.keys(newrule.before))) { // newrule.rulenum = rulenum newrule.rulenum = oldrule.rulenum; @@ -254,7 +243,7 @@ const command = function (oldrules, newrules) { // Get add properties present in new rule const add_properties = array.intersect( constants.add_properties, - Object.keys(newrule) + Object.keys(newrule), ); for (const oldrule of oldrules) { if (oldrule.chain !== newrule.chain) { @@ -281,9 +270,9 @@ const command = function (oldrules, newrules) { // Add properties are different if (create) { commands.push( - newrule.command === "-A" - ? command_append(newrule) - : command_insert(newrule) + newrule.command === "-A" ? + command_append(newrule) + : command_insert(newrule), ); } } diff --git a/packages/tools/test/repo.coffee b/packages/tools/test/repo.coffee index 2a29334eb..de5d927ae 100644 --- a/packages/tools/test/repo.coffee +++ b/packages/tools/test/repo.coffee @@ -163,7 +163,7 @@ describe 'tools.repo', -> content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.0/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.4/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' @@ -171,13 +171,13 @@ describe 'tools.repo', -> await @service.install name: 'MariaDB-client' await @execute - command: "mariadb --version | egrep '11.0.[0-9]+-MariaDB'" + command: "mariadb --version | egrep '11.4.[0-9]+-MariaDB'" {$status} = await @tools.repo target: '/etc/yum.repos.d/mariadb.repo' content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.3/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.6/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' @@ -188,14 +188,14 @@ describe 'tools.repo', -> content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.3/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.6/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' 'gpgcheck': '1' $status.should.be.false() await @execute - command: "mariadb --version | egrep '11.0.[0-9]+-MariaDB'" + command: "mariadb --version | egrep '11.4.[0-9]+-MariaDB'" they 'config `update` is `true`', ({ssh, sudo}) -> nikita @@ -210,7 +210,7 @@ describe 'tools.repo', -> content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.0/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.4/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' @@ -218,14 +218,14 @@ describe 'tools.repo', -> await @service.install name: 'MariaDB-client' await @execute - command: "mariadb --version | egrep '11.0.[0-9]+-MariaDB'" + command: "mariadb --version | egrep '11.4.[0-9]+-MariaDB'" {$status} = await @tools.repo target: '/etc/yum.repos.d/mariadb.repo' update: true content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.3/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.6/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' @@ -237,14 +237,14 @@ describe 'tools.repo', -> content: 'mariadb': 'name': 'MariaDB' - 'baseurl': "https://yum.mariadb.org/11.3/#{test.mariadb.distrib}-#{test.mariadb.basearch}" + 'baseurl': "https://yum.mariadb.org/11.6/#{test.mariadb.distrib}-#{test.mariadb.basearch}" 'enabled':'1' 'module_hotfixes': '1' 'gpgkey': 'https://yum.mariadb.org/RPM-GPG-KEY-MariaDB' 'gpgcheck': '1' $status.should.be.false() await @execute - command: "mariadb --version | egrep '11.3.[0-9]+-MariaDB'" + command: "mariadb --version | egrep '11.6.[0-9]+-MariaDB'" they 'Download config `gpg_key` fails because `gpg_key` unset and not in .repo', ({ssh, sudo}) -> nikita diff --git a/packages/utils/lib/array.js b/packages/utils/lib/array.js index 682420ac2..52a66c42d 100644 --- a/packages/utils/lib/array.js +++ b/packages/utils/lib/array.js @@ -1,4 +1,3 @@ - // const compare = (array1, array2) -> // # Compare lengths and save some time // if array1.length isnt array2.length @@ -80,7 +79,7 @@ const multiply = function (...args) { results2.push([...action, arg_element]); } return results2; - })() + })(), ); } } diff --git a/packages/utils/lib/buffer.js b/packages/utils/lib/buffer.js index 1204ee356..87cc6fb82 100644 --- a/packages/utils/lib/buffer.js +++ b/packages/utils/lib/buffer.js @@ -1,13 +1,12 @@ - // Treat the buffer as a string and trim whitespace characters. -// Quick and dirt way to trim, alternative is to loop forward+backwark, +// Quick and dirt way to trim, alternative is to loop forward+backwark, // detect all whitespace charactes, get a start and end and finaly resize the buffer. -const trim = function(buf, encoding) { +const trim = function (buf, encoding) { return Buffer.from(buf.toString(encoding).trim()); -} +}; export { trim }; export default { - trim: trim + trim: trim, }; diff --git a/packages/utils/lib/error.js b/packages/utils/lib/error.js index 57fec7a0c..a1b2dae47 100644 --- a/packages/utils/lib/error.js +++ b/packages/utils/lib/error.js @@ -22,10 +22,9 @@ const NikitaError = class NikitaError extends Error { if (value === undefined) { continue; } - this[key] = Buffer.isBuffer(value) - ? value.toString() - : value === null - ? value + this[key] = + Buffer.isBuffer(value) ? value.toString() + : value === null ? value : JSON.parse(JSON.stringify(value)); } } @@ -51,7 +50,7 @@ const got = function (value, { depth = 0, max_depth = 3 } = {}) { got(el, { depth: depth + 1, max_depth: max_depth, - }) + }), ); } } diff --git a/packages/utils/lib/mode.js b/packages/utils/lib/mode.js index 27bea7bbd..b75cea5cb 100644 --- a/packages/utils/lib/mode.js +++ b/packages/utils/lib/mode.js @@ -14,7 +14,7 @@ const compare = function (...modes) { for (let i = 1; i < modes.length; i++) { const mode = this.stringify(modes[i]); if ( - !ref.some( (m) => { + !ref.some((m) => { const l = Math.min(m.length, mode.length); return m.slice(-l) === mode.slice(-l); }) diff --git a/packages/utils/lib/object.js b/packages/utils/lib/object.js index 72f1b8001..225d8786d 100644 --- a/packages/utils/lib/object.js +++ b/packages/utils/lib/object.js @@ -1,7 +1,8 @@ +import { is_object_literal, merge } from "mixme"; import array from "./array.js"; +import error from "./error.js"; import regexp from "./regexp.js"; import { snake_case as snake_case_str } from "./string.js"; -import { is_object_literal, merge } from "mixme"; const clean = function (content, undefinedOnly) { for (const k in content) { @@ -77,12 +78,11 @@ const diff = function (obj1, obj2, keys) { // return true const insert = function (source, keys, value) { - const result = source - if(!is_object_literal(source)) { + const result = source; + if (!is_object_literal(source)) { throw error("NIKITA_UTILS_INSERT", [ - 'Source must be an object literal,' - `got ${JSON.stringify(source)}`, - ]) + "Source must be an object literal,"`got ${JSON.stringify(source)}`, + ]); } for (let i = 0; i < keys.length; i++) { const key = keys[i]; @@ -103,7 +103,7 @@ const insert = function (source, keys, value) { source = source[key]; } } - return result + return result; }; const match = function (source, target) { diff --git a/packages/utils/lib/os.js b/packages/utils/lib/os.js index 72f04b403..4d87797bd 100644 --- a/packages/utils/lib/os.js +++ b/packages/utils/lib/os.js @@ -86,7 +86,7 @@ const whoami = function ({ ssh, platform = process.platform } = {}) { if (/^\/root$/.test(process.env["HOME"])) { return process.env["HOME"].split("/")[1]; } - if (/^\/home\/[^\/]+$/.test(process.env["HOME"])) { + if (/^\/home\/[^/]+$/.test(process.env["HOME"])) { return process.env["HOME"].split("/")[2]; } }; diff --git a/packages/utils/lib/promise.js b/packages/utils/lib/promise.js index 89b3492c4..c1498f8ab 100644 --- a/packages/utils/lib/promise.js +++ b/packages/utils/lib/promise.js @@ -4,7 +4,9 @@ import each from "each"; const array_filter = async function (items, concurrency, handler) { const fail = Symbol(); return ( - await each(items, concurrency, async (item) => ((await handler(item)) ? item : fail)) + await each(items, concurrency, async (item) => + (await handler(item)) ? item : fail, + ) ).filter((i) => i !== fail); }; @@ -12,9 +14,19 @@ const is = function (obj) { return util.types.isPromise(obj); }; -export { array_filter, is }; +const withResolvers = function () { + let resolve, reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, reject, resolve }; +}; + +export { array_filter, is, withResolvers }; export default { array_filter: array_filter, is: is, + withResolvers: withResolvers, }; diff --git a/packages/utils/lib/regexp.js b/packages/utils/lib/regexp.js index 01d9187e2..edd886336 100644 --- a/packages/utils/lib/regexp.js +++ b/packages/utils/lib/regexp.js @@ -1,13 +1,12 @@ - -import quote from 'regexp-quote'; +import quote from "regexp-quote"; // Escape RegExp related charracteres // eg `///^\*/\w+@#{misc.regexp.escape realm}\s+\*///mg` -const escape = function(str) { +const escape = function (str) { return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }; -const is = function(reg) { +const is = function (reg) { return reg instanceof RegExp; }; @@ -16,5 +15,5 @@ export { escape, is, quote }; export default { escape: escape, is: is, - quote: quote + quote: quote, }; diff --git a/packages/utils/lib/string.js b/packages/utils/lib/string.js index 94d41a633..a37d4552c 100644 --- a/packages/utils/lib/string.js +++ b/packages/utils/lib/string.js @@ -10,7 +10,7 @@ import error from "./error.js"; * @returns Single quote escaped argument */ const escapeshellarg = function (arg) { - const result = arg.replace(/'/g, (match) => "'\"'\"'"); + const result = arg.replace(/'/g, () => "'\"'\"'"); return `'${result}'`; }; diff --git a/packages/utils/lib/tilde.js b/packages/utils/lib/tilde.js index 63fa510aa..4f5557b3c 100644 --- a/packages/utils/lib/tilde.js +++ b/packages/utils/lib/tilde.js @@ -9,7 +9,7 @@ always posix but this is not yet handled and tested. */ const normalize = function (location) { - return new Promise(function (accept, reject) { + return new Promise(function (accept) { return tilde(location, function (location) { return accept(path.normalize(location)); }); diff --git a/packages/utils/package.json b/packages/utils/package.json index 51c6d8fb8..75f97993a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -51,7 +51,6 @@ "@babel/core": "^7.24.9", "@babel/preset-env": "^7.25.0", "coffeescript": "^2.7.0", - "eslint": "^9.8.0", "mocha": "^10.7.0", "mocha-they": "^0.1.3", "should": "^13.2.3" @@ -88,8 +87,6 @@ "directory": "packages/utils" }, "scripts": { - "lint": "eslint 'lib/**/*.coffee'", - "lint-fix": "eslint --fix 'lib/**/*.coffee'", "test": "npm run test:local", "test:local": "mocha --node-flags '--unhandled-rejections=strict' 'test/**/*.coffee'" }, diff --git a/packages/utils/test.sample.coffee b/packages/utils/test.sample.coffee index ad1b876a8..4436f856e 100644 --- a/packages/utils/test.sample.coffee +++ b/packages/utils/test.sample.coffee @@ -1,6 +1,7 @@ export default - tags: {} + tags: + api: true config: [ label: 'local' , diff --git a/packages/utils/test/loaders/all.js b/packages/utils/test/loaders/all.js index e83023aa7..5049b8304 100644 --- a/packages/utils/test/loaders/all.js +++ b/packages/utils/test/loaders/all.js @@ -1,13 +1,12 @@ - -import * as coffee from './coffee.js' +import * as coffee from "./coffee.js"; // import * as ts from 'ts-node/esm' const coffeeRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; -const tsRegex = /\.ts$/; +// const tsRegex = /\.ts$/; export function load(url, context, next) { if (coffeeRegex.test(url)) { - return coffee.load.apply(this, arguments) + return coffee.load.apply(this, arguments); } // if (tsRegex.test(url)) { // return ts.load.apply(this, arguments) diff --git a/packages/utils/test/loaders/coffee.js b/packages/utils/test/loaders/coffee.js index c7b277cb7..75b15abe0 100644 --- a/packages/utils/test/loaders/coffee.js +++ b/packages/utils/test/loaders/coffee.js @@ -1,11 +1,11 @@ -import CoffeeScript from 'coffeescript'; +import CoffeeScript from "coffeescript"; // See https://github.com/nodejs/node/issues/36396 const extensionsRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; export async function load(url, context, next) { if (extensionsRegex.test(url)) { - const format = 'module'; + const format = "module"; const { source: rawSource } = await next(url, { format }); const source = CoffeeScript.compile(rawSource.toString(), { bare: true, @@ -14,7 +14,7 @@ export async function load(url, context, next) { header: false, sourceMap: false, }); - return {format, source}; + return { format, source }; } return next(url, context); } diff --git a/packages/utils/test/promise.coffee b/packages/utils/test/promise.coffee index 5e5a1a0fd..b614788b0 100644 --- a/packages/utils/test/promise.coffee +++ b/packages/utils/test/promise.coffee @@ -48,3 +48,15 @@ describe 'utils.promise', -> it 'false', -> promise.is({}).should.be.false() + + describe 'withResolvers', -> + + it 'resolve', -> + { promise: p, resolve } = promise.withResolvers() + resolve('ok') + p.should.finally.eql 'ok' + + it 'reject', -> + { promise: p, reject } = promise.withResolvers() + reject(new Error('ok')) + p.should.be.rejectedWith 'ok'