@nocobase/cli 2.1.0-beta.9 → 2.2.0-alpha.1
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.
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +145 -0
- package/bin/session-env.js +39 -0
- package/dist/commands/api/resource/create.js +15 -0
- package/dist/commands/api/resource/destroy.js +15 -0
- package/dist/commands/api/resource/get.js +15 -0
- package/dist/commands/api/resource/index.js +20 -0
- package/dist/commands/api/resource/list.js +16 -0
- package/dist/commands/api/resource/query.js +15 -0
- package/dist/commands/api/resource/update.js +15 -0
- package/dist/commands/app/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +234 -0
- package/dist/commands/app/down.js +71 -0
- package/dist/commands/app/logs.js +115 -0
- package/dist/commands/app/restart.js +229 -0
- package/dist/commands/app/shared.js +123 -0
- package/dist/commands/app/start.js +416 -0
- package/dist/commands/app/stop.js +183 -0
- package/dist/commands/app/upgrade.js +523 -0
- package/dist/commands/backup/create.js +147 -0
- package/dist/commands/backup/index.js +20 -0
- package/dist/commands/backup/restore.js +105 -0
- package/{src/cli.js → dist/commands/build.js} +4 -11
- package/dist/commands/config/delete.js +42 -0
- package/dist/commands/config/get.js +39 -0
- package/dist/commands/config/index.js +20 -0
- package/dist/commands/config/list.js +29 -0
- package/dist/commands/config/set.js +49 -0
- package/dist/commands/db/check.js +240 -0
- package/dist/commands/db/logs.js +85 -0
- package/dist/commands/db/ps.js +47 -0
- package/dist/commands/db/shared.js +96 -0
- package/dist/commands/db/start.js +86 -0
- package/dist/commands/db/stop.js +71 -0
- package/{templates/plugin/src/client/models/index.ts → dist/commands/dev.js} +4 -4
- package/{src/commands/locale/react-js-cron/index.js → dist/commands/down.js} +3 -8
- package/dist/commands/download.js +13 -0
- package/dist/commands/env/add.js +406 -0
- package/dist/commands/env/auth.js +189 -0
- package/dist/commands/env/current.js +21 -0
- package/dist/commands/env/info.js +202 -0
- package/dist/commands/env/list.js +43 -0
- package/dist/commands/env/remove.js +174 -0
- package/dist/commands/env/shared.js +204 -0
- package/dist/commands/env/status.js +93 -0
- package/dist/commands/env/update.js +448 -0
- package/dist/commands/env/use.js +38 -0
- package/dist/commands/examples/prompts-stages.js +150 -0
- package/dist/commands/examples/prompts-test.js +181 -0
- package/dist/commands/init.js +1390 -0
- package/dist/commands/install.js +2609 -0
- package/dist/commands/license/activate.js +179 -0
- package/dist/commands/license/env.js +94 -0
- package/dist/commands/license/generate-id.js +108 -0
- package/dist/commands/license/id.js +70 -0
- package/dist/commands/license/index.js +20 -0
- package/dist/commands/license/plugins/clean.js +115 -0
- package/dist/commands/license/plugins/index.js +20 -0
- package/dist/commands/license/plugins/list.js +64 -0
- package/dist/commands/license/plugins/shared.js +382 -0
- package/dist/commands/license/plugins/sync.js +314 -0
- package/dist/commands/license/shared.js +423 -0
- package/dist/commands/license/status.js +64 -0
- package/dist/commands/logs.js +12 -0
- package/dist/commands/plugin/disable.js +86 -0
- package/dist/commands/plugin/enable.js +86 -0
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/plugin/list.js +82 -0
- package/dist/commands/pm/disable.js +12 -0
- package/dist/commands/pm/enable.js +12 -0
- package/dist/commands/pm/list.js +12 -0
- package/dist/commands/proxy/caddy/current.js +17 -0
- package/dist/commands/proxy/caddy/generate.js +69 -0
- package/dist/commands/proxy/caddy/index.js +28 -0
- package/dist/commands/proxy/caddy/info.js +31 -0
- package/dist/commands/proxy/caddy/reload.js +30 -0
- package/dist/commands/proxy/caddy/restart.js +28 -0
- package/dist/commands/proxy/caddy/start.js +30 -0
- package/dist/commands/proxy/caddy/status.js +19 -0
- package/dist/commands/proxy/caddy/stop.js +30 -0
- package/dist/commands/proxy/caddy/use.js +26 -0
- package/dist/commands/proxy/index.js +28 -0
- package/dist/commands/proxy/nginx/current.js +18 -0
- package/dist/commands/proxy/nginx/generate.js +68 -0
- package/dist/commands/proxy/nginx/index.js +28 -0
- package/dist/commands/proxy/nginx/info.js +34 -0
- package/dist/commands/proxy/nginx/reload.js +30 -0
- package/dist/commands/proxy/nginx/restart.js +28 -0
- package/dist/commands/proxy/nginx/start.js +30 -0
- package/dist/commands/proxy/nginx/status.js +19 -0
- package/dist/commands/proxy/nginx/stop.js +30 -0
- package/dist/commands/proxy/nginx/use.js +31 -0
- package/dist/commands/restart.js +12 -0
- package/dist/commands/revision/create.js +118 -0
- package/dist/commands/scaffold/migration.js +38 -0
- package/dist/commands/scaffold/plugin.js +37 -0
- package/dist/commands/self/check.js +71 -0
- package/dist/commands/self/index.js +20 -0
- package/dist/commands/self/update.js +152 -0
- package/dist/commands/session/id.js +24 -0
- package/dist/commands/session/remove.js +57 -0
- package/dist/commands/session/setup.js +62 -0
- package/dist/commands/skills/check.js +69 -0
- package/dist/commands/skills/index.js +20 -0
- package/dist/commands/skills/install.js +80 -0
- package/dist/commands/skills/remove.js +80 -0
- package/dist/commands/skills/update.js +87 -0
- package/dist/commands/source/build.js +58 -0
- package/dist/commands/source/dev.js +182 -0
- package/dist/commands/source/download.js +884 -0
- package/dist/commands/source/publish.js +109 -0
- package/dist/commands/source/registry/logs.js +70 -0
- package/dist/commands/source/registry/start.js +57 -0
- package/dist/commands/source/registry/status.js +33 -0
- package/dist/commands/source/registry/stop.js +48 -0
- package/dist/commands/source/test.js +476 -0
- package/dist/commands/start.js +12 -0
- package/dist/commands/stop.js +12 -0
- package/dist/commands/test.js +12 -0
- package/dist/commands/upgrade.js +12 -0
- package/dist/commands/v1.js +210 -0
- package/dist/generated/command-registry.js +134 -0
- package/dist/help/runtime-help.js +23 -0
- package/dist/lib/api-client.js +335 -0
- package/dist/lib/api-command-compat.js +641 -0
- package/dist/lib/app-health.js +139 -0
- package/dist/lib/app-managed-resources.js +337 -0
- package/dist/lib/app-public-path.js +80 -0
- package/dist/lib/app-runtime.js +189 -0
- package/dist/lib/auth-store.js +528 -0
- package/dist/lib/backup.js +171 -0
- package/dist/lib/bootstrap.js +409 -0
- package/dist/lib/build-config.js +18 -0
- package/dist/lib/builtin-db.js +86 -0
- package/dist/lib/cli-config.js +569 -0
- package/dist/lib/cli-entry-error.js +52 -0
- package/dist/lib/cli-home.js +47 -0
- package/dist/lib/cli-locale.js +141 -0
- package/dist/lib/command-discovery.js +39 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/db-connection-check.js +219 -0
- package/dist/lib/docker-env-file.js +60 -0
- package/dist/lib/docker-image.js +37 -0
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +963 -0
- package/dist/lib/env-command-config.js +45 -0
- package/dist/lib/env-config.js +108 -0
- package/dist/lib/env-guard.js +61 -0
- package/dist/lib/env-paths.js +101 -0
- package/dist/lib/env-proxy.js +1325 -0
- package/dist/lib/generated-command.js +203 -0
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/inquirer-theme.js +17 -0
- package/dist/lib/inquirer.js +243 -0
- package/dist/lib/managed-env-file.js +101 -0
- package/dist/lib/managed-init-env.js +32 -0
- package/dist/lib/naming.js +70 -0
- package/dist/lib/object-utils.js +76 -0
- package/dist/lib/openapi.js +62 -0
- package/dist/lib/plugin-import.js +279 -0
- package/dist/lib/plugin-storage.js +64 -0
- package/dist/lib/post-processors.js +23 -0
- package/dist/lib/prompt-catalog-core.js +186 -0
- package/dist/lib/prompt-catalog-terminal.js +374 -0
- package/{src/index.js → dist/lib/prompt-catalog.js} +2 -6
- package/dist/lib/prompt-validators.js +278 -0
- package/dist/lib/prompt-web-ui.js +2234 -0
- package/dist/lib/proxy-caddy.js +274 -0
- package/dist/lib/proxy-nginx.js +330 -0
- package/dist/lib/resource-command.js +357 -0
- package/dist/lib/resource-request.js +104 -0
- package/dist/lib/run-npm.js +429 -0
- package/dist/lib/runtime-env-vars.js +32 -0
- package/dist/lib/runtime-generator.js +498 -0
- package/dist/lib/runtime-store.js +56 -0
- package/dist/lib/self-manager.js +301 -0
- package/dist/lib/session-id.js +17 -0
- package/dist/lib/session-integration.js +703 -0
- package/dist/lib/session-store.js +118 -0
- package/dist/lib/skills-manager.js +438 -0
- package/dist/lib/source-publish.js +326 -0
- package/dist/lib/source-registry.js +188 -0
- package/dist/lib/startup-update.js +309 -0
- package/dist/lib/ui.js +159 -0
- package/dist/locale/en-US.json +526 -0
- package/dist/locale/zh-CN.json +526 -0
- package/dist/post-processors/data-modeling.js +84 -0
- package/dist/post-processors/data-source-manager.js +138 -0
- package/dist/post-processors/index.js +19 -0
- package/nocobase-ctl.config.json +388 -0
- package/package.json +128 -24
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/bin/index.js +0 -39
- package/nocobase.conf.tpl +0 -95
- package/src/commands/benchmark.js +0 -73
- package/src/commands/build.js +0 -49
- package/src/commands/clean.js +0 -30
- package/src/commands/client.js +0 -166
- package/src/commands/create-nginx-conf.js +0 -37
- package/src/commands/create-plugin.js +0 -33
- package/src/commands/dev.js +0 -200
- package/src/commands/doc.js +0 -76
- package/src/commands/e2e.js +0 -265
- package/src/commands/global.js +0 -43
- package/src/commands/index.js +0 -45
- package/src/commands/instance-id.js +0 -47
- package/src/commands/locale/cronstrue.js +0 -122
- package/src/commands/locale/react-js-cron/en-US.json +0 -75
- package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
- package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
- package/src/commands/locale.js +0 -81
- package/src/commands/p-test.js +0 -88
- package/src/commands/perf.js +0 -63
- package/src/commands/pkg.js +0 -321
- package/src/commands/pm2.js +0 -37
- package/src/commands/postinstall.js +0 -88
- package/src/commands/start.js +0 -148
- package/src/commands/tar.js +0 -36
- package/src/commands/test-coverage.js +0 -55
- package/src/commands/test.js +0 -107
- package/src/commands/umi.js +0 -33
- package/src/commands/update-deps.js +0 -72
- package/src/commands/upgrade.js +0 -47
- package/src/commands/view-license-key.js +0 -44
- package/src/license.js +0 -76
- package/src/logger.js +0 -75
- package/src/plugin-generator.js +0 -80
- package/src/util.js +0 -517
- package/templates/bundle-status.html +0 -338
- package/templates/create-app-package.json +0 -39
- package/templates/plugin/.npmignore.tpl +0 -2
- package/templates/plugin/README.md.tpl +0 -1
- package/templates/plugin/client.d.ts +0 -2
- package/templates/plugin/client.js +0 -1
- package/templates/plugin/package.json.tpl +0 -11
- package/templates/plugin/server.d.ts +0 -2
- package/templates/plugin/server.js +0 -1
- package/templates/plugin/src/client/client.d.ts +0 -249
- package/templates/plugin/src/client/index.tsx.tpl +0 -1
- package/templates/plugin/src/client/locale.ts +0 -21
- package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
- package/templates/plugin/src/index.ts +0 -2
- package/templates/plugin/src/locale/en-US.json +0 -1
- package/templates/plugin/src/locale/zh-CN.json +0 -1
- package/templates/plugin/src/server/collections/.gitkeep +0 -0
- package/templates/plugin/src/server/index.ts.tpl +0 -1
- package/templates/plugin/src/server/plugin.ts.tpl +0 -19
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { buildDefaultCdnBaseUrl, readDistClientActiveVersion } from '../../lib/app-public-path.js';
|
|
11
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
12
|
+
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
13
|
+
import { AppHealthCheckError, formatAppUrl, isAppReady, resolveManagedAppApiBaseUrl, waitForAppReady, } from '../../lib/app-health.js';
|
|
14
|
+
import { ensureBuiltinDbReady, ensureLocalPostinstall, ensureSavedLocalSource, recreateSavedDockerApp, } from '../../lib/app-managed-resources.js';
|
|
15
|
+
import { clearEnvRootSetup, getEnv, upsertEnv } from '../../lib/auth-store.js';
|
|
16
|
+
import { buildInitAppEnvVarsFromConfig, isPreparedSetupState } from '../../lib/managed-init-env.js';
|
|
17
|
+
import { resolveAppUrlFromApiBaseUrl } from '../env/shared.js';
|
|
18
|
+
import { readManagedRuntimeEnvValues } from '../../lib/managed-env-file.js';
|
|
19
|
+
import { run } from '../../lib/run-npm.js';
|
|
20
|
+
import { announceTargetEnv, failTask, printInfo, printWarning, startTask, succeedTask } from '../../lib/ui.js';
|
|
21
|
+
function shouldPrintStartSuccess() {
|
|
22
|
+
return process.env.NB_SKIP_APP_START_SUCCESS_LOG !== '1';
|
|
23
|
+
}
|
|
24
|
+
function argvHasToken(argv, tokens) {
|
|
25
|
+
return tokens.some((token) => argv.includes(token));
|
|
26
|
+
}
|
|
27
|
+
function buildLicenseSyncArgv(envName, options) {
|
|
28
|
+
const argv = ['--env', envName, '--skip-if-no-license'];
|
|
29
|
+
if (options.yes || options.explicitEnvSelection) {
|
|
30
|
+
argv.push('--yes');
|
|
31
|
+
}
|
|
32
|
+
if (options.verbose) {
|
|
33
|
+
argv.push('--verbose');
|
|
34
|
+
}
|
|
35
|
+
return argv;
|
|
36
|
+
}
|
|
37
|
+
async function runWithSuppressedTargetEnvLog(task) {
|
|
38
|
+
const previousTargetEnv = process.env.NB_SKIP_TARGET_ENV_LOG;
|
|
39
|
+
process.env.NB_SKIP_TARGET_ENV_LOG = '1';
|
|
40
|
+
try {
|
|
41
|
+
return await task();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
if (previousTargetEnv === undefined) {
|
|
45
|
+
delete process.env.NB_SKIP_TARGET_ENV_LOG;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
process.env.NB_SKIP_TARGET_ENV_LOG = previousTargetEnv;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function formatDockerStartFailure(envName, message) {
|
|
53
|
+
return [
|
|
54
|
+
`Couldn't start NocoBase for "${envName}".`,
|
|
55
|
+
'Check that the Docker runtime for this env is still available, then try again.',
|
|
56
|
+
`Details: ${message}`,
|
|
57
|
+
].join('\n');
|
|
58
|
+
}
|
|
59
|
+
function formatLocalStartFailure(envName, options) {
|
|
60
|
+
const sourceLabel = options?.source === 'git'
|
|
61
|
+
? 'the local Git checkout'
|
|
62
|
+
: options?.source === 'npm'
|
|
63
|
+
? 'the local npm app'
|
|
64
|
+
: 'the local app';
|
|
65
|
+
const portHint = options?.port ? ` Expected app port: ${options.port}.` : '';
|
|
66
|
+
return [
|
|
67
|
+
`Couldn't start NocoBase for "${envName}".`,
|
|
68
|
+
`The CLI was not able to start ${sourceLabel} successfully.`,
|
|
69
|
+
`Check that the app dependencies, database connection, and local env settings are ready, then try again.${portHint}`,
|
|
70
|
+
].join('\n');
|
|
71
|
+
}
|
|
72
|
+
function formatLocalReadyFailure(envName, message, options) {
|
|
73
|
+
const sourceLabel = options?.source === 'git'
|
|
74
|
+
? 'the local Git checkout'
|
|
75
|
+
: options?.source === 'npm'
|
|
76
|
+
? 'the local npm app'
|
|
77
|
+
: 'the local app';
|
|
78
|
+
const portHint = options?.port ? ` Expected app port: ${options.port}.` : '';
|
|
79
|
+
return [
|
|
80
|
+
`NocoBase did not become ready for "${envName}".`,
|
|
81
|
+
`The CLI started ${sourceLabel}, but the app did not pass its health check in time.`,
|
|
82
|
+
`Check the startup logs, database connection, and local env settings, then try again.${portHint}`,
|
|
83
|
+
`Details: ${message}`,
|
|
84
|
+
].join('\n');
|
|
85
|
+
}
|
|
86
|
+
function formatLocalClientExtractWarning(envName, message) {
|
|
87
|
+
return [
|
|
88
|
+
`Client assets were not extracted for "${envName}".`,
|
|
89
|
+
'NocoBase will keep starting, but versioned client files for CDN or external distribution may be stale or missing.',
|
|
90
|
+
`Details: ${message}`,
|
|
91
|
+
].join('\n');
|
|
92
|
+
}
|
|
93
|
+
function resolveDisplayAppUrl(apiBaseUrl, port, appPublicPath) {
|
|
94
|
+
const resolvedFromApiBaseUrl = resolveAppUrlFromApiBaseUrl(apiBaseUrl);
|
|
95
|
+
if (resolvedFromApiBaseUrl) {
|
|
96
|
+
return resolvedFromApiBaseUrl;
|
|
97
|
+
}
|
|
98
|
+
return formatAppUrl(port, appPublicPath);
|
|
99
|
+
}
|
|
100
|
+
async function resolveDefaultLocalCdnBaseUrl(runtime) {
|
|
101
|
+
let envValues = {};
|
|
102
|
+
if (runtime.env.config && typeof runtime.env.config === 'object') {
|
|
103
|
+
({ envValues } = await readManagedRuntimeEnvValues(runtime));
|
|
104
|
+
}
|
|
105
|
+
const explicitProcessCdnBaseUrl = String(process.env.CDN_BASE_URL ?? '').trim();
|
|
106
|
+
const explicitSavedCdnBaseUrl = String(runtime.env.envVars.CDN_BASE_URL ?? '').trim();
|
|
107
|
+
const explicitEnvFileCdnBaseUrl = String(envValues.CDN_BASE_URL ?? '').trim();
|
|
108
|
+
if (explicitProcessCdnBaseUrl || explicitSavedCdnBaseUrl || explicitEnvFileCdnBaseUrl) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const storagePath = String(runtime.env.storagePath ?? runtime.env.config?.storagePath ?? '').trim();
|
|
112
|
+
if (!storagePath) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const activeVersion = await readDistClientActiveVersion(storagePath);
|
|
116
|
+
if (!activeVersion) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return buildDefaultCdnBaseUrl(runtime.env.config?.appPublicPath || envValues.APP_PUBLIC_PATH, activeVersion);
|
|
120
|
+
}
|
|
121
|
+
async function finalizePreparedEnv(envName) {
|
|
122
|
+
const existingEnv = await getEnv(envName);
|
|
123
|
+
await clearEnvRootSetup(envName);
|
|
124
|
+
await upsertEnv(envName, {
|
|
125
|
+
...(existingEnv?.config.apiBaseUrl ? { apiBaseUrl: existingEnv.config.apiBaseUrl } : {}),
|
|
126
|
+
setupState: 'installed',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
export default class AppStart extends Command {
|
|
130
|
+
static hidden = false;
|
|
131
|
+
static description = 'Start NocoBase for the selected env. When applicable, the CLI synchronizes licensed commercial plugins first, then prepares and starts the app or recreates the saved Docker container.';
|
|
132
|
+
static examples = [
|
|
133
|
+
'<%= config.bin %> <%= command.id %>',
|
|
134
|
+
'<%= config.bin %> <%= command.id %> --env local',
|
|
135
|
+
'<%= config.bin %> <%= command.id %> --env local --verbose',
|
|
136
|
+
'<%= config.bin %> <%= command.id %> --env local-docker',
|
|
137
|
+
];
|
|
138
|
+
static flags = {
|
|
139
|
+
env: Flags.string({
|
|
140
|
+
char: 'e',
|
|
141
|
+
description: 'CLI env name to start. Defaults to the current env when omitted',
|
|
142
|
+
}),
|
|
143
|
+
yes: Flags.boolean({
|
|
144
|
+
char: 'y',
|
|
145
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
146
|
+
default: false,
|
|
147
|
+
}),
|
|
148
|
+
quickstart: Flags.boolean({
|
|
149
|
+
hidden: true,
|
|
150
|
+
description: 'Quickstart the application',
|
|
151
|
+
required: false,
|
|
152
|
+
default: true,
|
|
153
|
+
allowNo: true,
|
|
154
|
+
}),
|
|
155
|
+
'sync-licensed-plugins': Flags.boolean({
|
|
156
|
+
hidden: true,
|
|
157
|
+
description: 'Synchronize licensed commercial plugins before starting the application',
|
|
158
|
+
required: false,
|
|
159
|
+
default: true,
|
|
160
|
+
allowNo: true,
|
|
161
|
+
}),
|
|
162
|
+
daemon: Flags.boolean({
|
|
163
|
+
hidden: true,
|
|
164
|
+
description: 'Run the application as a daemon (default: true; use --no-daemon to stay in the foreground)',
|
|
165
|
+
char: 'd',
|
|
166
|
+
required: false,
|
|
167
|
+
default: true,
|
|
168
|
+
allowNo: true,
|
|
169
|
+
}),
|
|
170
|
+
verbose: Flags.boolean({
|
|
171
|
+
description: 'Show raw startup output from the underlying local or Docker command',
|
|
172
|
+
default: false,
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
async run() {
|
|
176
|
+
const { flags } = await this.parse(AppStart);
|
|
177
|
+
const quickstart = flags.quickstart ?? true;
|
|
178
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
179
|
+
const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
|
|
180
|
+
const shouldSyncLicensedPlugins = flags['sync-licensed-plugins'] ?? true;
|
|
181
|
+
if (explicitEnvSelection) {
|
|
182
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
183
|
+
command: this,
|
|
184
|
+
requestedEnv,
|
|
185
|
+
yes: flags.yes,
|
|
186
|
+
});
|
|
187
|
+
if (!confirmed) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const daemonFlagWasProvided = argvHasToken(this.argv, ['--daemon', '--no-daemon']);
|
|
192
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
193
|
+
const preparedInitEnvVars = buildInitAppEnvVarsFromConfig(runtime?.env.config);
|
|
194
|
+
const isPreparedEnv = isPreparedSetupState(runtime?.env.config?.setupState);
|
|
195
|
+
const runCommand = this.config.runCommand.bind(this.config);
|
|
196
|
+
const commandStdio = flags.verbose ? 'inherit' : 'ignore';
|
|
197
|
+
if (!runtime) {
|
|
198
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
199
|
+
}
|
|
200
|
+
if (runtime.kind === 'http') {
|
|
201
|
+
this.error([
|
|
202
|
+
`Can't start "${runtime.envName}" from this machine.`,
|
|
203
|
+
'This env only has an API connection, so there is no saved local app or Docker runtime to launch here.',
|
|
204
|
+
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed start and stop.',
|
|
205
|
+
].join('\n'));
|
|
206
|
+
}
|
|
207
|
+
if (runtime.kind === 'ssh') {
|
|
208
|
+
this.error([
|
|
209
|
+
`Can't start "${runtime.envName}" yet.`,
|
|
210
|
+
'SSH env support is reserved but not implemented yet.',
|
|
211
|
+
'Use a local or Docker env if you need CLI-managed start and stop right now.',
|
|
212
|
+
].join('\n'));
|
|
213
|
+
}
|
|
214
|
+
announceTargetEnv(runtime.envName);
|
|
215
|
+
if (runtime.kind === 'docker') {
|
|
216
|
+
const unsupportedFlags = [daemonFlagWasProvided ? (flags.daemon ? '--daemon' : '--no-daemon') : undefined].filter(Boolean);
|
|
217
|
+
if (unsupportedFlags.length > 0) {
|
|
218
|
+
this.error([
|
|
219
|
+
`Can't apply ${unsupportedFlags.join(', ')} to "${runtime.envName}".`,
|
|
220
|
+
'This env is managed by Docker, so those options are only available for local npm/git installs.',
|
|
221
|
+
`Run \`nb app start --env ${runtime.envName}\` to recreate the saved container, or recreate the env if you need different runtime settings.`,
|
|
222
|
+
].join('\n'));
|
|
223
|
+
}
|
|
224
|
+
if (shouldSyncLicensedPlugins) {
|
|
225
|
+
try {
|
|
226
|
+
await runWithSuppressedTargetEnvLog(async () => {
|
|
227
|
+
await runCommand('license:plugins:sync', buildLicenseSyncArgv(runtime.envName, {
|
|
228
|
+
explicitEnvSelection,
|
|
229
|
+
yes: flags.yes,
|
|
230
|
+
verbose: flags.verbose,
|
|
231
|
+
}));
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
await ensureBuiltinDbReady(runtime, {
|
|
239
|
+
verbose: flags.verbose,
|
|
240
|
+
onStartTask: startTask,
|
|
241
|
+
onSucceedTask: succeedTask,
|
|
242
|
+
onFailTask: failTask,
|
|
243
|
+
});
|
|
244
|
+
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime);
|
|
245
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, runtime.env.appPort === undefined || runtime.env.appPort === null ? undefined : String(runtime.env.appPort), runtime.env.config?.appPublicPath);
|
|
246
|
+
startTask(`Recreating the Docker app container for "${runtime.envName}"...`);
|
|
247
|
+
try {
|
|
248
|
+
await run('docker', ['rm', '-f', runtime.containerName], {
|
|
249
|
+
errorName: 'docker rm',
|
|
250
|
+
stdio: commandStdio,
|
|
251
|
+
}).catch(() => undefined);
|
|
252
|
+
await recreateSavedDockerApp(runtime, {
|
|
253
|
+
initEnvVars: isPreparedEnv ? preparedInitEnvVars : undefined,
|
|
254
|
+
verbose: flags.verbose,
|
|
255
|
+
});
|
|
256
|
+
succeedTask(`Docker app container is ready for "${runtime.envName}".`);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
260
|
+
failTask(`Failed to recreate NocoBase for "${runtime.envName}".`);
|
|
261
|
+
this.error(formatDockerStartFailure(runtime.envName, message));
|
|
262
|
+
}
|
|
263
|
+
await waitForAppReady({
|
|
264
|
+
envName: runtime.envName,
|
|
265
|
+
apiBaseUrl,
|
|
266
|
+
containerName: runtime.containerName,
|
|
267
|
+
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
268
|
+
...(flags.verbose ? { verbose: true } : {}),
|
|
269
|
+
});
|
|
270
|
+
if (isPreparedEnv) {
|
|
271
|
+
await finalizePreparedEnv(runtime.envName);
|
|
272
|
+
}
|
|
273
|
+
if (shouldPrintStartSuccess()) {
|
|
274
|
+
succeedTask(`NocoBase is running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
await ensureBuiltinDbReady(runtime, {
|
|
279
|
+
verbose: flags.verbose,
|
|
280
|
+
onStartTask: startTask,
|
|
281
|
+
onSucceedTask: succeedTask,
|
|
282
|
+
onFailTask: failTask,
|
|
283
|
+
});
|
|
284
|
+
if (runtime.source === 'npm' || runtime.source === 'git') {
|
|
285
|
+
const downloadableRuntime = runtime;
|
|
286
|
+
await ensureSavedLocalSource(downloadableRuntime, runCommand, {
|
|
287
|
+
verbose: flags.verbose,
|
|
288
|
+
onStartTask: startTask,
|
|
289
|
+
onSucceedTask: succeedTask,
|
|
290
|
+
onFailTask: failTask,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (isPreparedEnv && flags.daemon === false) {
|
|
294
|
+
this.error(`Can't start "${runtime.envName}" with --no-daemon yet. Run \`nb app start --env ${runtime.envName}\` to finish the first installation in daemon mode.`);
|
|
295
|
+
}
|
|
296
|
+
const npmArgs = ['start'];
|
|
297
|
+
if (quickstart) {
|
|
298
|
+
npmArgs.push('--quickstart');
|
|
299
|
+
}
|
|
300
|
+
if (runtime.env.appPort !== undefined &&
|
|
301
|
+
runtime.env.appPort !== null &&
|
|
302
|
+
String(runtime.env.appPort).trim() !== '') {
|
|
303
|
+
npmArgs.push('--port', String(runtime.env.appPort));
|
|
304
|
+
}
|
|
305
|
+
if (flags.daemon !== false) {
|
|
306
|
+
npmArgs.push('--daemon');
|
|
307
|
+
}
|
|
308
|
+
const effectivePort = runtime.env.appPort !== undefined && runtime.env.appPort !== null
|
|
309
|
+
? String(runtime.env.appPort).trim()
|
|
310
|
+
: undefined;
|
|
311
|
+
const apiBaseUrl = resolveManagedAppApiBaseUrl(runtime, {
|
|
312
|
+
portOverride: effectivePort,
|
|
313
|
+
});
|
|
314
|
+
const appUrl = resolveDisplayAppUrl(apiBaseUrl, effectivePort, runtime.env.config?.appPublicPath);
|
|
315
|
+
let defaultCdnBaseUrl;
|
|
316
|
+
if (await isAppReady(apiBaseUrl, { requestTimeoutMs: 1_500 })) {
|
|
317
|
+
if (flags.daemon === false) {
|
|
318
|
+
printInfo(`NocoBase is already running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}. Use \`nb app stop --env ${runtime.envName}\` before starting it again in the foreground.`);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
if (shouldPrintStartSuccess()) {
|
|
322
|
+
succeedTask(`NocoBase is already running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (shouldSyncLicensedPlugins) {
|
|
328
|
+
try {
|
|
329
|
+
await runWithSuppressedTargetEnvLog(async () => {
|
|
330
|
+
await runCommand('license:plugins:sync', buildLicenseSyncArgv(runtime.envName, {
|
|
331
|
+
explicitEnvSelection,
|
|
332
|
+
yes: flags.yes,
|
|
333
|
+
verbose: flags.verbose,
|
|
334
|
+
}));
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
await ensureLocalPostinstall(runtime, {
|
|
343
|
+
env: managedAppLifecycleEnvVars(),
|
|
344
|
+
verbose: flags.verbose,
|
|
345
|
+
onStartTask: startTask,
|
|
346
|
+
onSucceedTask: succeedTask,
|
|
347
|
+
onFailTask: failTask,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
startTask(`Extracting client assets for "${runtime.envName}"...`);
|
|
355
|
+
await runLocalNocoBaseCommand(runtime, ['client:extract'], {
|
|
356
|
+
env: managedAppLifecycleEnvVars(),
|
|
357
|
+
stdio: commandStdio,
|
|
358
|
+
});
|
|
359
|
+
succeedTask(`Client assets are ready for "${runtime.envName}".`);
|
|
360
|
+
defaultCdnBaseUrl = await resolveDefaultLocalCdnBaseUrl(runtime);
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
364
|
+
failTask(`Failed to extract client assets for "${runtime.envName}".`);
|
|
365
|
+
printWarning(formatLocalClientExtractWarning(runtime.envName, message));
|
|
366
|
+
}
|
|
367
|
+
if (flags.daemon === false) {
|
|
368
|
+
printInfo(`Starting NocoBase for "${runtime.envName}" in the foreground${appUrl ? ` at ${appUrl}` : ''}. Press Ctrl+C to stop.`);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
startTask(`Starting NocoBase for "${runtime.envName}" in the background...`);
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
const startEnv = defaultCdnBaseUrl
|
|
375
|
+
? {
|
|
376
|
+
...managedAppLifecycleEnvVars(),
|
|
377
|
+
CDN_BASE_URL: defaultCdnBaseUrl,
|
|
378
|
+
...(isPreparedEnv ? preparedInitEnvVars : {}),
|
|
379
|
+
}
|
|
380
|
+
: {
|
|
381
|
+
...managedAppLifecycleEnvVars(),
|
|
382
|
+
...(isPreparedEnv ? preparedInitEnvVars : {}),
|
|
383
|
+
};
|
|
384
|
+
await runLocalNocoBaseCommand(runtime, npmArgs, {
|
|
385
|
+
env: startEnv,
|
|
386
|
+
stdio: commandStdio,
|
|
387
|
+
});
|
|
388
|
+
if (flags.daemon !== false) {
|
|
389
|
+
await waitForAppReady({
|
|
390
|
+
envName: runtime.envName,
|
|
391
|
+
apiBaseUrl,
|
|
392
|
+
logHint: `You can inspect startup logs with \`nb app logs --env ${runtime.envName}\`.`,
|
|
393
|
+
});
|
|
394
|
+
if (isPreparedEnv) {
|
|
395
|
+
await finalizePreparedEnv(runtime.envName);
|
|
396
|
+
}
|
|
397
|
+
if (shouldPrintStartSuccess()) {
|
|
398
|
+
succeedTask(`NocoBase is running for "${runtime.envName}"${appUrl ? ` at ${appUrl}` : ''}.`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
failTask(`Failed to start NocoBase for "${runtime.envName}".`);
|
|
404
|
+
if (error instanceof AppHealthCheckError) {
|
|
405
|
+
this.error(formatLocalReadyFailure(runtime.envName, error.message, {
|
|
406
|
+
port: effectivePort,
|
|
407
|
+
source: runtime.source,
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
this.error(formatLocalStartFailure(runtime.envName, {
|
|
411
|
+
port: effectivePort,
|
|
412
|
+
source: runtime.source,
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { getCurrentEnvName } from '../../lib/auth-store.js';
|
|
11
|
+
import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
|
|
12
|
+
import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
|
|
13
|
+
import { announceTargetEnv, failTask, isInteractiveTerminal, printInfo, startTask, succeedTask } from '../../lib/ui.js';
|
|
14
|
+
import { builtinDbContainerName, removeDockerContainerIfExists } from './shared.js';
|
|
15
|
+
function formatStopFailure(envName, message) {
|
|
16
|
+
return [
|
|
17
|
+
`Couldn't stop NocoBase for "${envName}".`,
|
|
18
|
+
'Check that the local app or Docker runtime is still available, then try again.',
|
|
19
|
+
`Details: ${message}`,
|
|
20
|
+
].join('\n');
|
|
21
|
+
}
|
|
22
|
+
function formatStopCrossEnvConfirmationRequiredMessage(currentEnv, requestedEnv) {
|
|
23
|
+
return [
|
|
24
|
+
`Refusing to stop env "${requestedEnv}" because the current env is "${currentEnv}" and interactive confirmation is unavailable in the current session.`,
|
|
25
|
+
'',
|
|
26
|
+
'Re-run the command with `--yes` to confirm this one-off cross-env stop, or switch the current env first.',
|
|
27
|
+
].join('\n');
|
|
28
|
+
}
|
|
29
|
+
function shouldIgnoreLocalStopError(message) {
|
|
30
|
+
return (message.includes('spawn nocobase-v1 ENOENT') ||
|
|
31
|
+
message.includes('The specified --cwd does not exist:') ||
|
|
32
|
+
message.includes('The specified --cwd is not a directory:') ||
|
|
33
|
+
message.includes("Couldn't find a NocoBase source project from --cwd:"));
|
|
34
|
+
}
|
|
35
|
+
async function stopLocalRuntimeWithFallback(runtime, options) {
|
|
36
|
+
const env = managedAppLifecycleEnvVars();
|
|
37
|
+
try {
|
|
38
|
+
await runLocalNocoBaseCommand(runtime, ['pm2', 'kill'], {
|
|
39
|
+
env,
|
|
40
|
+
stdio: options.stdio,
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
46
|
+
if (!shouldIgnoreLocalStopError(message)) {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export default class AppStop extends Command {
|
|
52
|
+
static hidden = false;
|
|
53
|
+
static description = 'Stop NocoBase for the selected env. Local npm/git installs stop the app process, and Docker installs remove the saved app container.';
|
|
54
|
+
static examples = [
|
|
55
|
+
'<%= config.bin %> <%= command.id %>',
|
|
56
|
+
'<%= config.bin %> <%= command.id %> --env local',
|
|
57
|
+
'<%= config.bin %> <%= command.id %> --env local --verbose',
|
|
58
|
+
'<%= config.bin %> <%= command.id %> --env local-docker',
|
|
59
|
+
];
|
|
60
|
+
static flags = {
|
|
61
|
+
env: Flags.string({
|
|
62
|
+
char: 'e',
|
|
63
|
+
description: 'CLI env name to stop. Defaults to the current env when omitted',
|
|
64
|
+
}),
|
|
65
|
+
yes: Flags.boolean({
|
|
66
|
+
char: 'y',
|
|
67
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
68
|
+
default: false,
|
|
69
|
+
}),
|
|
70
|
+
force: Flags.boolean({
|
|
71
|
+
char: 'f',
|
|
72
|
+
hidden: true,
|
|
73
|
+
default: false,
|
|
74
|
+
}),
|
|
75
|
+
'with-db': Flags.boolean({
|
|
76
|
+
description: 'Also remove the CLI-managed built-in database container when present',
|
|
77
|
+
default: false,
|
|
78
|
+
}),
|
|
79
|
+
verbose: Flags.boolean({
|
|
80
|
+
description: 'Show raw shutdown output from the underlying local or Docker command',
|
|
81
|
+
default: false,
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
async run() {
|
|
85
|
+
const { flags } = await this.parse(AppStop);
|
|
86
|
+
const requestedEnv = flags.env?.trim() || undefined;
|
|
87
|
+
if (requestedEnv && hasExplicitEnvSelection(this.argv)) {
|
|
88
|
+
const skipCrossEnvConfirmation = flags.yes || flags.force;
|
|
89
|
+
if (!isInteractiveTerminal()) {
|
|
90
|
+
const currentEnv = await getCurrentEnvName();
|
|
91
|
+
const normalizedCurrentEnv = String(currentEnv ?? '').trim() || undefined;
|
|
92
|
+
if (normalizedCurrentEnv && normalizedCurrentEnv !== requestedEnv && !skipCrossEnvConfirmation) {
|
|
93
|
+
this.error(formatStopCrossEnvConfirmationRequiredMessage(normalizedCurrentEnv, requestedEnv));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
98
|
+
command: this,
|
|
99
|
+
requestedEnv,
|
|
100
|
+
yes: skipCrossEnvConfirmation,
|
|
101
|
+
});
|
|
102
|
+
if (!confirmed) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
108
|
+
const commandStdio = flags.verbose ? 'inherit' : 'ignore';
|
|
109
|
+
if (!runtime) {
|
|
110
|
+
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
111
|
+
}
|
|
112
|
+
if (runtime.kind === 'http') {
|
|
113
|
+
this.error([
|
|
114
|
+
`Can't stop "${runtime.envName}" from this machine.`,
|
|
115
|
+
'This env only has an API connection, so there is no saved local app or Docker runtime to stop here.',
|
|
116
|
+
'If the app is running on a server, stop it there or reconnect this env to a local runtime first.',
|
|
117
|
+
].join('\n'));
|
|
118
|
+
}
|
|
119
|
+
if (runtime.kind === 'ssh') {
|
|
120
|
+
this.error([
|
|
121
|
+
`Can't stop "${runtime.envName}" yet.`,
|
|
122
|
+
'SSH env support is reserved but not implemented yet.',
|
|
123
|
+
'Use a local or Docker env if you need CLI-managed stop right now.',
|
|
124
|
+
].join('\n'));
|
|
125
|
+
}
|
|
126
|
+
announceTargetEnv(runtime.envName);
|
|
127
|
+
if (runtime.kind === 'docker') {
|
|
128
|
+
startTask(`Removing the saved Docker app container for "${runtime.envName}"...`);
|
|
129
|
+
try {
|
|
130
|
+
const state = await removeDockerContainerIfExists(runtime.containerName, {
|
|
131
|
+
stdio: commandStdio,
|
|
132
|
+
});
|
|
133
|
+
succeedTask(state === 'removed'
|
|
134
|
+
? `Docker app container removed for "${runtime.envName}".`
|
|
135
|
+
: `No Docker app container found for "${runtime.envName}".`);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
139
|
+
failTask(`Failed to stop NocoBase for "${runtime.envName}".`);
|
|
140
|
+
this.error(formatStopFailure(runtime.envName, message));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
startTask(`Stopping NocoBase for "${runtime.envName}"...`);
|
|
145
|
+
try {
|
|
146
|
+
await stopLocalRuntimeWithFallback(runtime, {
|
|
147
|
+
stdio: commandStdio,
|
|
148
|
+
});
|
|
149
|
+
succeedTask(`NocoBase has stopped for "${runtime.envName}".`);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
153
|
+
failTask(`Failed to stop NocoBase for "${runtime.envName}".`);
|
|
154
|
+
this.error(formatStopFailure(runtime.envName, message));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!flags['with-db']) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (runtime.kind !== 'local' && runtime.kind !== 'docker') {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const dbContainerName = builtinDbContainerName(runtime);
|
|
164
|
+
if (!dbContainerName) {
|
|
165
|
+
printInfo(`Env "${runtime.envName}" does not use a CLI-managed built-in database. Only the app runtime was stopped.`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
startTask(`Removing the built-in database container for "${runtime.envName}"...`);
|
|
169
|
+
try {
|
|
170
|
+
const state = await removeDockerContainerIfExists(dbContainerName, {
|
|
171
|
+
stdio: commandStdio,
|
|
172
|
+
});
|
|
173
|
+
succeedTask(state === 'removed'
|
|
174
|
+
? `Built-in database container removed for "${runtime.envName}".`
|
|
175
|
+
: `No built-in database container found for "${runtime.envName}".`);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
179
|
+
failTask(`Failed to stop the built-in database for "${runtime.envName}".`);
|
|
180
|
+
this.error(formatStopFailure(runtime.envName, message));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|