@blocklet/cli 1.16.33 → 1.16.34-beta-20241120-080738-bbbe036c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +32 -25
  2. package/bin/blocklet.js +292 -1
  3. package/config.example.yml +33 -0
  4. package/lib/arcblock.js +53 -0
  5. package/lib/commands/blocklet/add.js +124 -0
  6. package/lib/commands/blocklet/assets/git-ignore +28 -0
  7. package/lib/commands/blocklet/assets/index.html +9 -0
  8. package/lib/commands/blocklet/assets/index.js +14 -0
  9. package/lib/commands/blocklet/assets/logo.png +0 -0
  10. package/lib/commands/blocklet/bundle/bundle.js +184 -0
  11. package/lib/commands/blocklet/bundle/bundlers/blocklet.js +138 -0
  12. package/lib/commands/blocklet/bundle/bundlers/changelog.js +100 -0
  13. package/lib/commands/blocklet/bundle/bundlers/logo.js +56 -0
  14. package/lib/commands/blocklet/bundle/bundlers/markdown.js +241 -0
  15. package/lib/commands/blocklet/bundle/bundlers/preference.js +50 -0
  16. package/lib/commands/blocklet/bundle/bundlers/readme.js +43 -0
  17. package/lib/commands/blocklet/bundle/bundlers/screenshots.js +94 -0
  18. package/lib/commands/blocklet/bundle/bundlers/simple.js +70 -0
  19. package/lib/commands/blocklet/bundle/compact/bundle-compact-file.js +48 -0
  20. package/lib/commands/blocklet/bundle/compact/bundle-merge-extra.js +66 -0
  21. package/lib/commands/blocklet/bundle/compact/default-external.js +5 -0
  22. package/lib/commands/blocklet/bundle/compact/index.js +88 -0
  23. package/lib/commands/blocklet/bundle/index.js +139 -0
  24. package/lib/commands/blocklet/bundle/pack.js +8 -0
  25. package/lib/commands/blocklet/bundle/parse-external-dependencies.js +97 -0
  26. package/lib/commands/blocklet/bundle/simple/index.js +62 -0
  27. package/lib/commands/blocklet/bundle/zip/archive.js +35 -0
  28. package/lib/commands/blocklet/bundle/zip/dependencies.js +333 -0
  29. package/lib/commands/blocklet/bundle/zip/index.js +165 -0
  30. package/lib/commands/blocklet/bundle/zip/main.js +124 -0
  31. package/lib/commands/blocklet/bundle/zip/node.js +59 -0
  32. package/lib/commands/blocklet/bundle/zip/resolve.js +93 -0
  33. package/lib/commands/blocklet/cleanup.js +52 -0
  34. package/lib/commands/blocklet/config.js +108 -0
  35. package/lib/commands/blocklet/connect.js +87 -0
  36. package/lib/commands/blocklet/create.js +38 -0
  37. package/lib/commands/blocklet/deploy.js +435 -0
  38. package/lib/commands/blocklet/dev.js +1000 -0
  39. package/lib/commands/blocklet/document.js +39 -0
  40. package/lib/commands/blocklet/exec.js +106 -0
  41. package/lib/commands/blocklet/init.js +300 -0
  42. package/lib/commands/blocklet/meta.js +22 -0
  43. package/lib/commands/blocklet/remove.js +35 -0
  44. package/lib/commands/blocklet/test.js +201 -0
  45. package/lib/commands/blocklet/upload.js +105 -0
  46. package/lib/commands/blocklet/version.js +81 -0
  47. package/lib/commands/server/cleanup.js +32 -0
  48. package/lib/commands/server/command.js +131 -0
  49. package/lib/commands/server/info.js +92 -0
  50. package/lib/commands/server/init.js +433 -0
  51. package/lib/commands/server/logs.js +99 -0
  52. package/lib/commands/server/rescue.js +71 -0
  53. package/lib/commands/server/start.js +821 -0
  54. package/lib/commands/server/status.js +107 -0
  55. package/lib/commands/server/stop.js +163 -0
  56. package/lib/commands/server/upgrade.js +123 -0
  57. package/lib/constant.js +21 -2
  58. package/lib/debug.js +20 -0
  59. package/lib/manager/config.js +122 -0
  60. package/lib/manager/deploy.js +75 -0
  61. package/lib/manager/index.js +23 -0
  62. package/lib/manager/process.js +47 -0
  63. package/lib/node.js +214 -0
  64. package/lib/port.js +19 -0
  65. package/lib/postinstall.js +3 -0
  66. package/lib/process/daemon.js +196 -0
  67. package/lib/process/service.js +86 -0
  68. package/lib/ui.js +137 -0
  69. package/lib/util/blocklet/config.js +78 -0
  70. package/lib/util/blocklet/env.js +172 -0
  71. package/lib/util/blocklet/meta.js +36 -0
  72. package/lib/util/blocklet/payment.js +88 -0
  73. package/lib/util/blocklet/sign.js +21 -0
  74. package/lib/util/blocklet/tar.js +119 -0
  75. package/lib/util/convert-to-nosources-sourcemap.js +37 -0
  76. package/lib/util/docker-status-log.js +17 -0
  77. package/lib/util/exit-when-server-stopped.js +44 -0
  78. package/lib/util/get-cli-binary-name.js +8 -0
  79. package/lib/util/get-download-bundle-step.js +36 -0
  80. package/lib/util/get-service-instance-number.js +12 -0
  81. package/lib/util/index.js +626 -0
  82. package/lib/util/print-error.js +11 -0
  83. package/lib/util/print.js +9 -0
  84. package/lib/util/what-uri.js +40 -0
  85. package/package.json +123 -27
  86. package/lib/run.d.ts +0 -2
  87. package/lib/run.js +0 -73
@@ -0,0 +1,107 @@
1
+ const chalk = require('chalk');
2
+ const prettyMs = require('pretty-ms-i18n');
3
+ const upperFirst = require('lodash/upperFirst');
4
+ const isEmpty = require('lodash/isEmpty');
5
+ const Table = require('cli-table3');
6
+ const pm2 = require('@abtnode/util/lib/async-pm2');
7
+ const { encode: encodeBase32 } = require('@abtnode/util/lib/base32');
8
+ const { fromBlockletStatus } = require('@blocklet/constant');
9
+ const { PROCESS_NAME_DAEMON, DEFAULT_DID_DOMAIN } = require('@abtnode/constant');
10
+
11
+ const { print, printWarning, printSuccess, printAccessUrls, getDaemonAccessUrls } = require('../../util');
12
+ const { getNode } = require('../../node');
13
+ const { wrapSpinner } = require('../../ui');
14
+
15
+ const getProcessInfo = (name) =>
16
+ new Promise((resolve, reject) => {
17
+ pm2.describe(name, (err, [info]) => {
18
+ if (err) {
19
+ return reject(err);
20
+ }
21
+
22
+ return resolve(info);
23
+ });
24
+ });
25
+
26
+ const statusMap = {
27
+ online: 'running',
28
+ launching: 'starting',
29
+ errored: 'error',
30
+ stopping: 'stopping',
31
+ stopped: 'stopped',
32
+ };
33
+
34
+ const colorMap = {
35
+ running: 'green',
36
+ error: 'red',
37
+ launching: 'yellow',
38
+ stopping: 'orange',
39
+ stopped: 'gray',
40
+ };
41
+
42
+ exports.run = async () => {
43
+ const { node, getBaseUrls } = await getNode({ dir: process.cwd() });
44
+
45
+ try {
46
+ const info = await getProcessInfo(PROCESS_NAME_DAEMON);
47
+ if (!info) {
48
+ print('Blocklet Server is not started');
49
+ process.exit(0);
50
+ }
51
+
52
+ const nodeInfo = await node.getNodeInfo();
53
+ const status = statusMap[info.pm2_env.status];
54
+ const statusFn = chalk[colorMap[status]];
55
+ const time = status === 'running' ? ` (${statusFn(prettyMs(Date.now() - Number(info.pm2_env.pm_uptime)))})` : '';
56
+ print();
57
+ print(`Blocklet Server status: ${statusFn(upperFirst(status))}${time}`);
58
+ print(`Blocklet Server mode: ${chalk.cyan(upperFirst(nodeInfo.mode))}`);
59
+ print(`Blocklet Server Data Directory: ${chalk.cyan(info.pm2_env.env.ABT_NODE_DATA_DIR)}`);
60
+
61
+ print();
62
+ if (nodeInfo.initialized) {
63
+ let blocklets = [];
64
+
65
+ await wrapSpinner('Fetching the blocklets...', async () => {
66
+ blocklets = await node.getBlocklets({ includeRuntimeInfo: false });
67
+ });
68
+
69
+ if (blocklets.length) {
70
+ const table = new Table({
71
+ head: ['Name', 'Status', 'URL'],
72
+ style: { 'padding-left': 1, head: ['cyan', 'bold'] },
73
+ colWidths: [30, 15, 70],
74
+ });
75
+
76
+ print('Blocklets Status:');
77
+ // eslint-disable-next-line no-shadow
78
+ blocklets.forEach(({ meta, status }) =>
79
+ table.push([
80
+ meta.title,
81
+ fromBlockletStatus(status),
82
+ `https://${encodeBase32(meta.did)}.${DEFAULT_DID_DOMAIN}`,
83
+ ])
84
+ );
85
+ print(table.toString());
86
+ } else {
87
+ printWarning('No blocklets installed yet.');
88
+ }
89
+ }
90
+
91
+ if (status === 'running') {
92
+ print();
93
+ const accessUrls = await getDaemonAccessUrls({ info: nodeInfo, getBaseUrls });
94
+
95
+ if (!isEmpty(accessUrls)) {
96
+ printSuccess('You can access your blocklet server with either of the following URLs:');
97
+ printAccessUrls(accessUrls);
98
+ } else {
99
+ printWarning('No accessible URL found.');
100
+ }
101
+ }
102
+ } catch (err) {
103
+ console.error(err);
104
+ }
105
+
106
+ process.exit(0);
107
+ };
@@ -0,0 +1,163 @@
1
+ const chalk = require('chalk');
2
+ const capitalize = require('lodash/capitalize');
3
+
4
+ const { clearRouterByConfigKeyword } = require('@abtnode/router-provider');
5
+ const tryWithTimeout = require('@abtnode/util/lib/try-with-timeout');
6
+ const sleep = require('@abtnode/util/lib/sleep');
7
+ const pm2 = require('@abtnode/util/lib/async-pm2');
8
+
9
+ const {
10
+ PROCESS_NAME_DAEMON,
11
+ PROCESS_NAME_SERVICE,
12
+ PROCESS_NAME_EVENT_HUB,
13
+ CONFIG_FOLDER_NAME,
14
+ CONFIG_FOLDER_NAME_OLD,
15
+ EVENTS,
16
+ SERVER_STATUS,
17
+ } = require('@abtnode/constant');
18
+
19
+ const { BLOCKLET_MODES, BlockletStatus } = require('@blocklet/constant');
20
+
21
+ const debug = require('../../debug')('kill');
22
+ const {
23
+ printError,
24
+ printInfo,
25
+ printSuccess,
26
+ printWarning,
27
+ stopRouting,
28
+ getCLICommandName,
29
+ killPm2Process,
30
+ } = require('../../util');
31
+ const { getNode } = require('../../node');
32
+ const { checkRunning } = require('../../manager');
33
+ const { wrapSpinner } = require('../../ui');
34
+
35
+ exports.run = async ({ force = false }) => {
36
+ if (force) {
37
+ try {
38
+ const results = await Promise.all([
39
+ clearRouterByConfigKeyword(CONFIG_FOLDER_NAME),
40
+ clearRouterByConfigKeyword(CONFIG_FOLDER_NAME_OLD),
41
+ ]);
42
+
43
+ const clearedProvider = results.find(Boolean);
44
+ if (clearedProvider) {
45
+ printSuccess(`${capitalize(clearedProvider)} router is stopped successfully`);
46
+ }
47
+
48
+ await pm2.killDaemonAsync();
49
+ printSuccess('Blocklet Server related processes stopped successfully');
50
+ } catch (error) {
51
+ printError(`Blocklet Server related processes stop failed: ${error.message}`);
52
+ }
53
+
54
+ process.exit(0);
55
+ }
56
+
57
+ const { node, publishEvent } = await getNode({ dir: process.cwd() });
58
+
59
+ const isRunning = await checkRunning();
60
+ if (!isRunning) {
61
+ printWarning('Blocklet Server is not running!');
62
+ process.exit(0);
63
+ }
64
+
65
+ const stopOnReady = () =>
66
+ new Promise((resolve) => {
67
+ node.onReady(async () => {
68
+ let blocklets = [];
69
+
70
+ try {
71
+ blocklets = await node.getBlocklets({ includeRuntimeInfo: false });
72
+ } catch (err) {
73
+ printWarning('Blocklets ignored because:', err.message);
74
+ }
75
+
76
+ // Exit early if we have running blocklets in dev mode
77
+ // The node can only be stopped if no blocklet running in dev mode exist
78
+ const devBlocklet = blocklets.find((x) => x.mode === BLOCKLET_MODES.DEVELOPMENT);
79
+ if (devBlocklet && devBlocklet.status === BlockletStatus.running) {
80
+ printError(
81
+ `Unable to stop Blocklet Server, please stop the development by pressing ${chalk.cyan(
82
+ 'Ctrl + C'
83
+ )} in the terminal of ${chalk.cyan(devBlocklet.meta.name)}`
84
+ );
85
+ process.exit(0);
86
+ }
87
+
88
+ try {
89
+ await wrapSpinner('Sending shutdown notification to web dashboard users', async () => {
90
+ await publishEvent(EVENTS.NODE_STOPPED, {});
91
+ await sleep(2000);
92
+ }); // prettier-ignore
93
+ } catch (err) {
94
+ printError(`Failed to publish stop event to socket server: ${err.message}`);
95
+ }
96
+
97
+ const info = await node.getNodeInfo();
98
+
99
+ debug('blocklets to kill', blocklets);
100
+
101
+ try {
102
+ await stopRouting({ info, routerDir: node.dataDirs.router });
103
+ printSuccess('Routing engine is stopped successfully');
104
+ } catch (err) {
105
+ printError('Failed to stop routing engine', err.message);
106
+ }
107
+
108
+ for (let i = 0; i < blocklets.length; i++) {
109
+ const { title, did } = blocklets[i].meta;
110
+ if ([BlockletStatus.running, BlockletStatus.starting].includes(blocklets[i].status) === false) {
111
+ // eslint-disable-next-line no-continue
112
+ continue;
113
+ }
114
+ try {
115
+ // eslint-disable-next-line no-await-in-loop
116
+ await node.stopBlocklet({ did, updateStatus: false, silent: true });
117
+ printSuccess(`Blocklet ${title} is stopped successfully`);
118
+ } catch (err) {
119
+ printError(`Failed to stop blocklet ${title}`, err.message);
120
+ }
121
+ }
122
+
123
+ const actions = [
124
+ { action: 'kill', processName: PROCESS_NAME_DAEMON },
125
+ { action: 'kill', processName: PROCESS_NAME_SERVICE },
126
+ { action: 'kill', processName: PROCESS_NAME_EVENT_HUB },
127
+ { action: 'updateStatus' },
128
+ ];
129
+
130
+ for (let i = 0; i < actions.length; i++) {
131
+ const { action, processName } = actions[i];
132
+ if (action === 'kill') {
133
+ try {
134
+ // eslint-disable-next-line no-await-in-loop
135
+ await killPm2Process(processName);
136
+ printSuccess(`${processName} is stopped successfully`);
137
+ } catch (err) {
138
+ printError(`Failed to stop ${processName}`, err.message);
139
+ }
140
+ }
141
+
142
+ if (action === 'updateStatus') {
143
+ // eslint-disable-next-line no-await-in-loop
144
+ await node.updateNodeStatus(SERVER_STATUS.STOPPED);
145
+ }
146
+ }
147
+
148
+ printSuccess('Done!');
149
+ resolve(true);
150
+ process.exit(0);
151
+ });
152
+ });
153
+
154
+ const timeout = 60 * 1000 * 5; // 5 minute
155
+ try {
156
+ await tryWithTimeout(stopOnReady, timeout);
157
+ } catch (err) {
158
+ printError(`Blocklet Server can not stop within ${timeout} ms`);
159
+ printInfo(`You can stop the node with ${chalk.cyan(`${getCLICommandName()} stop --force`)}`);
160
+ } finally {
161
+ process.exit(0);
162
+ }
163
+ };
@@ -0,0 +1,123 @@
1
+ const path = require('path');
2
+ const shell = require('shelljs');
3
+ const semver = require('semver');
4
+ const chalk = require('chalk');
5
+ const fs = require('fs');
6
+
7
+ const { canReadAndWriteDir } = require('@abtnode/util/lib/fs');
8
+ const { getInstaller, getInstallCommands } = require('@abtnode/util/lib/get-installer');
9
+ const {
10
+ print,
11
+ printError,
12
+ printInfo,
13
+ printSuccess,
14
+ printWarning,
15
+ getCLIBinaryName,
16
+ getCLICommandName,
17
+ } = require('../../util');
18
+ const { version, name } = require('../../../package.json');
19
+ const { checkRunning, getRunningConfigDataDir } = require('../../manager');
20
+ const debug = require('../../debug')('upgrade');
21
+
22
+ // auto throw error when sync run shell.xxx
23
+ // must run sync
24
+ const wrap =
25
+ (shellFn) =>
26
+ (...args) => {
27
+ const { code, stdout, stderr } = shellFn.apply(shell, args);
28
+ if (code !== 0) {
29
+ throw new Error(stderr);
30
+ }
31
+ return stdout;
32
+ };
33
+
34
+ const getLatestVersion = () => {
35
+ const stdout = wrap(shell.exec)(`npm show ${name} version`, {
36
+ silent: true,
37
+ });
38
+ return stdout.trim();
39
+ };
40
+
41
+ const checkUpdate = (current, latest) => semver.gt(latest, current);
42
+
43
+ const stopNode = () => {
44
+ printInfo('Stopping Blocklet Server ...');
45
+ wrap(shell.exec)(`${getCLICommandName()} stop`, {
46
+ silent: true,
47
+ });
48
+ };
49
+
50
+ const installNode = () => {
51
+ const commandName = getCLICommandName();
52
+ const packageName = commandName === 'abtnode' ? '@abtnode/cli' : '@blocklet/cli';
53
+ const binaryName = getCLIBinaryName();
54
+ const installer = getInstaller(binaryName);
55
+ const commands = getInstallCommands({ packageName });
56
+ const command = commands[installer];
57
+
58
+ printInfo(`Installing Blocklet Server by ${chalk.cyan(command)} ...`);
59
+
60
+ wrap(shell.exec)(command, {
61
+ silent: false,
62
+ });
63
+ };
64
+
65
+ const restartNode = (originalRunningDataDir) => {
66
+ const currentWorkingDataDir = process.cwd();
67
+ debug('original running data directory', originalRunningDataDir);
68
+ debug('current working data directory', currentWorkingDataDir);
69
+
70
+ printInfo('Restarting Blocklet Server ...');
71
+
72
+ if (!fs.existsSync(originalRunningDataDir)) {
73
+ printWarning('Original running data directory does not exists, abort restart!');
74
+ return;
75
+ }
76
+
77
+ wrap(shell.exec)(`${getCLICommandName()} start`, {
78
+ silent: false,
79
+ cwd: originalRunningDataDir,
80
+ });
81
+ };
82
+
83
+ exports.run = async () => {
84
+ // save current bin path
85
+ const binaryName = getCLIBinaryName();
86
+ const commandName = getCLICommandName();
87
+ const curBinPath = wrap(shell.which)(binaryName, { silent: true });
88
+ printInfo('Using blocklet server from', chalk.cyan(curBinPath));
89
+
90
+ // Check permissions
91
+ printInfo('Checking permissions...');
92
+ if (canReadAndWriteDir(path.dirname(curBinPath)) === false) {
93
+ printError('Seems you do not have permission to upgrade Blocklet Server version');
94
+ printInfo(`Maybe you can try run ${chalk.cyan(`sudo ${commandName} upgrade`)}`);
95
+ process.exit(1);
96
+ }
97
+
98
+ const latestVersion = await getLatestVersion();
99
+ const needUpdate = await checkUpdate(version, latestVersion);
100
+ if (!needUpdate) {
101
+ print(`The current version ${version} is the latest version, no need to upgrade`);
102
+ process.exit(0);
103
+ }
104
+ print(`Current version is ${version}, found latest version ${latestVersion}`);
105
+ print('Begin upgrade');
106
+
107
+ // Do not start/stop the node when run as root
108
+ const isRunning = await checkRunning();
109
+ const runningDataDir = await getRunningConfigDataDir();
110
+
111
+ const needRestart = isRunning;
112
+ if (isRunning) {
113
+ await stopNode();
114
+ }
115
+ await installNode();
116
+
117
+ if (needRestart) {
118
+ await restartNode(runningDataDir);
119
+ }
120
+
121
+ printSuccess(`Blocklet Server upgrade success, current version is ${latestVersion}`);
122
+ process.exit(0);
123
+ };
package/lib/constant.js CHANGED
@@ -1,5 +1,24 @@
1
- const packageJson = require('../package.json');
1
+ const os = require('os');
2
+ const path = require('path');
3
+
4
+ const ABT_NODE_MAX_CLUSTER_SIZE = Math.min(Math.max(Number(process.env.ABT_NODE_MAX_CLUSTER_SIZE) || 1, 1), 32);
5
+
6
+ const CLI_MODE = 'blocklet';
7
+ const NODE_ENV = process.env.NODE_ENV || 'production';
8
+ const ABT_NODE_HOME = path.join(os.homedir(), '.arcblock');
9
+ const PM2_HOME = path.join(ABT_NODE_HOME, 'abtnode');
10
+ const ABT_NODE_CONFIG_FILE = path.join(ABT_NODE_HOME, 'blocklet.ini');
11
+ const INSTALL_FILE_PATH = path.join(ABT_NODE_HOME, '.is-new-server-install');
12
+ const HELP_DOCS_GITHUB_CODESPACES_URL =
13
+ 'https://www.arcblock.io/docs/blocklet-developer/en/develop-with-github-codespaces';
2
14
 
3
15
  module.exports = {
4
- name: packageJson.name,
16
+ ABT_NODE_MAX_CLUSTER_SIZE,
17
+ CLI_MODE,
18
+ NODE_ENV,
19
+ ABT_NODE_HOME,
20
+ PM2_HOME,
21
+ ABT_NODE_CONFIG_FILE,
22
+ INSTALL_FILE_PATH,
23
+ HELP_DOCS_GITHUB_CODESPACES_URL,
5
24
  };
package/lib/debug.js ADDED
@@ -0,0 +1,20 @@
1
+ /* eslint-disable no-console */
2
+
3
+ const debug = require('debug');
4
+
5
+ if (process.env.FORGE_DEBUG) {
6
+ debug.enable(process.env.FORGE_DEBUG);
7
+ }
8
+
9
+ const instance = (name) => {
10
+ const tmp = debug(`@blocklet/cli:${name || 'info'}`);
11
+ tmp.error = (...args) => {
12
+ if (tmp.enabled) {
13
+ console.error(...args);
14
+ }
15
+ };
16
+
17
+ return tmp;
18
+ };
19
+
20
+ module.exports = instance;
@@ -0,0 +1,122 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const expandTilde = require('expand-tilde');
4
+
5
+ const {
6
+ CONFIG_FILENAME,
7
+ CONFIG_FOLDER_NAME,
8
+ CONFIG_FILENAME_OLD,
9
+ CONFIG_FOLDER_NAME_OLD,
10
+ } = require('@abtnode/constant');
11
+
12
+ const _join = (prefix, file) => {
13
+ return path.join(expandTilde(prefix), file);
14
+ };
15
+
16
+ const joinConfigDir = (dir) => _join(dir, CONFIG_FOLDER_NAME);
17
+
18
+ const joinConfigFile = (dir) => _join(dir, CONFIG_FILENAME);
19
+
20
+ const joinKFile = (dir) => _join(dir, '.sock');
21
+
22
+ const getDataDirectoryByConfigFile = (configFile) => {
23
+ if (!configFile) {
24
+ throw new Error('configFile can not be empty');
25
+ }
26
+
27
+ return path.dirname(configFile);
28
+ };
29
+
30
+ const getConfigDirFromCurrentDir = (currentDir) => {
31
+ const configDir = _join(currentDir, CONFIG_FOLDER_NAME);
32
+ const configDirOld = _join(currentDir, CONFIG_FOLDER_NAME_OLD);
33
+
34
+ if (fs.existsSync(configDir)) {
35
+ return configDir;
36
+ }
37
+
38
+ if (fs.existsSync(configDirOld)) {
39
+ return configDirOld;
40
+ }
41
+
42
+ return '';
43
+ };
44
+
45
+ const getConfigDirFromAncestors = (currentDir) => {
46
+ let dir = fs.statSync(currentDir).isDirectory() ? currentDir : path.dirname(currentDir);
47
+
48
+ do {
49
+ const configDir = getConfigDirFromCurrentDir(dir);
50
+ if (configDir) {
51
+ return configDir;
52
+ }
53
+
54
+ dir = path.dirname(dir);
55
+ } while (path.basename(dir) !== '');
56
+
57
+ return '';
58
+ };
59
+
60
+ const getConfigFileFromAncestors = (dir) => {
61
+ const configDir = getConfigDirFromAncestors(dir);
62
+ if (!configDir) {
63
+ return '';
64
+ }
65
+
66
+ if (configDir.endsWith(CONFIG_FOLDER_NAME_OLD)) {
67
+ return _join(configDir, CONFIG_FILENAME_OLD);
68
+ }
69
+
70
+ return _join(configDir, CONFIG_FILENAME);
71
+ };
72
+
73
+ /**
74
+ * get base configuration data directory
75
+ * @param {string} dir directory to check
76
+ */
77
+ const getBaseConfigDataDirectory = (dir) => {
78
+ if (!dir || !fs.existsSync(dir)) {
79
+ throw new Error(`directory ${dir} does not exist`);
80
+ }
81
+
82
+ if (dir.includes(CONFIG_FOLDER_NAME) || dir.includes(CONFIG_FOLDER_NAME_OLD)) {
83
+ return dir;
84
+ }
85
+
86
+ return '';
87
+ };
88
+
89
+ /**
90
+ * validate the `dir` directory has valid data directory, if not, throw error
91
+ * @param {string} dir the directory to validate
92
+ */
93
+ const verifyDataDirectory = (dir) => {
94
+ if (!dir) {
95
+ throw new Error('dir should not be empty');
96
+ }
97
+
98
+ if (!fs.existsSync(dir)) {
99
+ throw new Error(`directory ${dir} does not exist`);
100
+ }
101
+
102
+ const configFile = path.join(dir, CONFIG_FILENAME);
103
+ const configFileOld = path.join(dir, CONFIG_FILENAME_OLD);
104
+ if (!fs.existsSync(configFile) && !fs.existsSync(configFileOld)) {
105
+ throw new Error(`the config file does not exist in ${dir}`);
106
+ }
107
+ };
108
+
109
+ const getDaemonLogDir = (baseDir) => path.join(baseDir, 'logs', '_abtnode');
110
+
111
+ module.exports = {
112
+ joinConfigDir,
113
+ joinConfigFile,
114
+ joinKFile,
115
+ getBaseConfigDataDirectory,
116
+ getConfigDirFromAncestors,
117
+ getConfigDirFromCurrentDir,
118
+ getConfigFileFromAncestors,
119
+ getDaemonLogDir,
120
+ getDataDirectoryByConfigFile,
121
+ verifyDataDirectory,
122
+ };
@@ -0,0 +1,75 @@
1
+ const chalk = require('chalk');
2
+ const { minimatch } = require('minimatch');
3
+
4
+ const { print, printInfo } = require('../util');
5
+
6
+ const checkMatch = (file, match) => {
7
+ let m = match;
8
+ if (!m.includes('*')) {
9
+ return false;
10
+ }
11
+ if (!m.endsWith('*')) {
12
+ return minimatch(file, m);
13
+ }
14
+ if (!m.endsWith('**')) {
15
+ m = `${m}*`;
16
+ }
17
+
18
+ return minimatch(file, m);
19
+ };
20
+
21
+ const checkInclude = (list, f) =>
22
+ f === '.' ||
23
+ f === '' || // root folder maybe '.' and ''
24
+ list.some(
25
+ (x) =>
26
+ x.indexOf(f) === 0 || // f is 'website' && x is 'website/public'
27
+ f.indexOf(x) === 0 || // f is website/public/index.html && x is website/public
28
+ checkMatch(f, x) // f is hooks/pre-start.js && x is hooks/*
29
+ );
30
+
31
+ /**
32
+ * Whether a file should be deployed
33
+ * @param {string} file a file will be deployed
34
+ * @param {object} opts
35
+ * @param {array<string>} opts.diffList
36
+ * @param {BundleType} opts.bundleType
37
+ * @param {array<string>} opts.staticList
38
+ * @return {boolean} Should this file be deployed
39
+ */
40
+ const fileFilter = (file, opts = {}) => {
41
+ const { diffList, bundleType, staticList } = opts;
42
+ // only include diffList if has one
43
+ if (diffList) {
44
+ return checkInclude(diffList, file);
45
+ }
46
+ // only include staticList if bundleType is static
47
+ if (bundleType === 'static') {
48
+ if (!staticList) {
49
+ throw new Error('staticList should not be empty when bundleType is static');
50
+ }
51
+ return checkInclude(staticList, file);
52
+ }
53
+ // include all files
54
+ return true;
55
+ };
56
+
57
+ const printDeployFileInfo = (adds, changes, deletes) => {
58
+ const padLeft = ' - ';
59
+ printInfo(`Added Files: ${chalk.cyan(adds.length)}`);
60
+ adds.forEach((f) => print(padLeft, f));
61
+ if (typeof changes !== 'undefined') {
62
+ printInfo(`Changed Files: ${chalk.cyan(changes.length)}`);
63
+ changes.forEach((f) => print(padLeft, f));
64
+ }
65
+ if (typeof deletes !== 'undefined') {
66
+ printInfo(`Deleted Files: ${chalk.cyan(deletes.length)}`);
67
+ deletes.forEach((f) => print(padLeft, f));
68
+ }
69
+ };
70
+
71
+ module.exports = {
72
+ fileFilter,
73
+ printDeployFileInfo,
74
+ checkMatch,
75
+ };
@@ -0,0 +1,23 @@
1
+ const processManager = require('./process');
2
+ const configManager = require('./config');
3
+ const deployManager = require('./deploy');
4
+
5
+ const getConfigFile = async (configPathArg = process.cwd()) => {
6
+ const runningConfigFile = await processManager.getRunningConfigFile();
7
+ if (runningConfigFile) {
8
+ return runningConfigFile;
9
+ }
10
+
11
+ return configManager.getConfigFileFromAncestors(configPathArg);
12
+ };
13
+
14
+ const getConfigDir = async (configPathArg = process.cwd()) => {
15
+ const runningConfigDir = await processManager.getRunningConfigDataDir();
16
+ if (runningConfigDir) {
17
+ return runningConfigDir;
18
+ }
19
+
20
+ return configManager.getConfigDirFromAncestors(configPathArg);
21
+ };
22
+
23
+ module.exports = { ...processManager, ...configManager, deployManager, getConfigFile, getConfigDir };