@nocobase/cli 2.1.0-alpha.20 → 2.1.0-alpha.22
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/README.md +256 -89
- package/README.zh-CN.md +332 -0
- package/bin/run.js +21 -2
- package/dist/commands/build.js +7 -1
- package/dist/commands/db/logs.js +85 -0
- package/dist/commands/db/ps.js +60 -0
- package/dist/commands/db/shared.js +81 -0
- package/dist/commands/db/start.js +55 -7
- package/dist/commands/db/stop.js +70 -0
- package/dist/commands/dev.js +112 -21
- package/dist/commands/down.js +193 -0
- package/dist/commands/download.js +633 -183
- package/dist/commands/env/add.js +260 -131
- package/dist/commands/env/auth.js +9 -8
- package/dist/commands/init.js +723 -103
- package/dist/commands/install.js +1702 -565
- package/dist/commands/logs.js +90 -0
- package/dist/commands/pm/disable.js +35 -3
- package/dist/commands/pm/enable.js +35 -3
- package/dist/commands/pm/list.js +37 -4
- package/dist/commands/prompts-stages.js +150 -0
- package/dist/commands/prompts-test.js +181 -0
- package/dist/commands/ps.js +116 -0
- package/dist/commands/start.js +171 -15
- package/dist/commands/stop.js +90 -0
- package/dist/commands/upgrade.js +559 -11
- package/dist/lib/api-client.js +49 -5
- package/dist/lib/app-runtime.js +142 -0
- package/dist/lib/auth-store.js +44 -3
- package/dist/lib/bootstrap.js +7 -3
- package/dist/lib/cli-locale.js +115 -0
- package/dist/lib/env-auth.js +427 -82
- package/dist/lib/prompt-catalog.js +574 -0
- package/dist/lib/prompt-validators.js +185 -0
- package/dist/lib/prompt-web-ui.js +2061 -0
- package/dist/lib/run-npm.js +71 -7
- package/dist/lib/runtime-generator.js +12 -1
- package/dist/locale/en-US.json +282 -0
- package/dist/locale/zh-CN.json +282 -0
- package/package.json +5 -4
- package/dist/commands/restart.js +0 -32
- package/dist/lib/init-browser-wizard.js +0 -431
|
@@ -11,279 +11,729 @@ import { Command, Flags } from '@oclif/core';
|
|
|
11
11
|
import * as p from '@clack/prompts';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
|
|
14
|
+
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
15
|
+
import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, } from "../lib/cli-locale.js";
|
|
14
16
|
import { run } from "../lib/run-npm.js";
|
|
17
|
+
import { printVerbose, setVerboseMode, startTask, stopTask, updateTask } from '../lib/ui.js';
|
|
18
|
+
const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
|
|
19
|
+
const DEFAULT_DOCKER_REGISTRY_ZH_CN = 'registry.cn-shanghai.aliyuncs.com/nocobase/nocobase';
|
|
20
|
+
const DEFAULT_DOCKER_PLATFORM = 'auto';
|
|
21
|
+
const downloadText = (key, values) => localeText(`commands.download.${key}`, values);
|
|
22
|
+
function defaultOutputDirForVersion(versionTag) {
|
|
23
|
+
const safe = versionTag.replace(/[/\\]/g, '-');
|
|
24
|
+
return `./nocobase-${safe}`;
|
|
25
|
+
}
|
|
26
|
+
async function pathExists(target) {
|
|
27
|
+
try {
|
|
28
|
+
await fsp.access(target);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function defaultDockerRegistryForLang(lang) {
|
|
36
|
+
return String(lang ?? '').trim() === 'zh-CN'
|
|
37
|
+
? DEFAULT_DOCKER_REGISTRY_ZH_CN
|
|
38
|
+
: DEFAULT_DOCKER_REGISTRY;
|
|
39
|
+
}
|
|
40
|
+
function argvHasToken(argv, tokens) {
|
|
41
|
+
return tokens.some((t) => argv.includes(t));
|
|
42
|
+
}
|
|
43
|
+
function gitRefForVersion(versionSpec) {
|
|
44
|
+
const versionToRef = {
|
|
45
|
+
latest: 'main',
|
|
46
|
+
beta: 'next',
|
|
47
|
+
alpha: 'develop',
|
|
48
|
+
};
|
|
49
|
+
return versionToRef[versionSpec] || versionSpec;
|
|
50
|
+
}
|
|
51
|
+
/** `build-dts` only applies when `build` is true and source is npm/git. */
|
|
52
|
+
function normalizeBuildDts(source, build, wantDts) {
|
|
53
|
+
if (source !== 'npm' && source !== 'git') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return Boolean(build && wantDts);
|
|
57
|
+
}
|
|
58
|
+
function downloadSourceLabel(source) {
|
|
59
|
+
switch (source) {
|
|
60
|
+
case 'docker':
|
|
61
|
+
return 'Docker image';
|
|
62
|
+
case 'npm':
|
|
63
|
+
return 'npm package';
|
|
64
|
+
case 'git':
|
|
65
|
+
return 'Git repository';
|
|
66
|
+
default:
|
|
67
|
+
return source;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function normalizeDockerPlatform(value) {
|
|
71
|
+
const text = String(value ?? '').trim();
|
|
72
|
+
if (text === 'linux/amd64' || text === 'linux/arm64') {
|
|
73
|
+
return text;
|
|
74
|
+
}
|
|
75
|
+
return DEFAULT_DOCKER_PLATFORM;
|
|
76
|
+
}
|
|
77
|
+
function dockerPlatformArg(value) {
|
|
78
|
+
const platform = normalizeDockerPlatform(value);
|
|
79
|
+
if (platform === 'auto') {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return platform;
|
|
83
|
+
}
|
|
84
|
+
const EXTERNAL_COMMAND_LOADING_DELAY_MS = 8_000;
|
|
85
|
+
const EXTERNAL_COMMAND_LOADING_UPDATE_MS = 15_000;
|
|
15
86
|
export default class Download extends Command {
|
|
16
|
-
|
|
87
|
+
_flags;
|
|
88
|
+
preparationTaskActive = false;
|
|
89
|
+
static description = 'Scaffold or fetch NocoBase from npm, Docker, or Git. `--version` is the shared version input: package version for npm, image tag for Docker, and git ref for Git.';
|
|
17
90
|
static examples = [
|
|
18
91
|
'<%= config.bin %> <%= command.id %>',
|
|
19
|
-
'<%= config.bin %> <%= command.id %> -y --source npm --version
|
|
20
|
-
'<%= config.bin %> <%= command.id %> --source npm --version
|
|
21
|
-
'<%= config.bin %> <%= command.id %> --source npm --version
|
|
22
|
-
'<%= config.bin %> <%= command.id %> --source
|
|
23
|
-
'<%= config.bin %> <%= command.id %> --source
|
|
92
|
+
'<%= config.bin %> <%= command.id %> -y --source npm --version alpha',
|
|
93
|
+
'<%= config.bin %> <%= command.id %> -y --source npm --version alpha --no-build',
|
|
94
|
+
'<%= config.bin %> <%= command.id %> --source npm --version alpha',
|
|
95
|
+
'<%= config.bin %> <%= command.id %> --source npm --version alpha --output-dir=./app',
|
|
96
|
+
'<%= config.bin %> <%= command.id %> --source docker --version alpha --docker-registry=nocobase/nocobase --docker-platform=linux/arm64',
|
|
97
|
+
'<%= config.bin %> <%= command.id %> -y --source docker --version alpha --docker-save -o ./docker-images',
|
|
98
|
+
'<%= config.bin %> <%= command.id %> --source git --version alpha --git-url=git@github.com:nocobase/nocobase.git',
|
|
99
|
+
'<%= config.bin %> <%= command.id %> --source git --version fix/cli-v2',
|
|
100
|
+
'<%= config.bin %> <%= command.id %> -y --source git --version fix/cli-v2 --no-build',
|
|
101
|
+
'<%= config.bin %> <%= command.id %> -y --source npm --version alpha --build-dts',
|
|
102
|
+
'<%= config.bin %> <%= command.id %> -y --source npm --version alpha --npm-registry=https://registry.npmmirror.com',
|
|
24
103
|
];
|
|
25
104
|
static flags = {
|
|
26
105
|
yes: Flags.boolean({
|
|
27
106
|
char: 'y',
|
|
28
|
-
description: '
|
|
107
|
+
description: 'Use defaults and skip interactive prompts.',
|
|
108
|
+
default: false,
|
|
109
|
+
}),
|
|
110
|
+
verbose: Flags.boolean({
|
|
111
|
+
description: 'Show detailed command output',
|
|
112
|
+
default: false,
|
|
113
|
+
}),
|
|
114
|
+
locale: Flags.string({
|
|
115
|
+
description: CLI_LOCALE_FLAG_DESCRIPTION,
|
|
116
|
+
options: CLI_LOCALE_FLAG_OPTIONS,
|
|
117
|
+
}),
|
|
118
|
+
'no-intro': Flags.boolean({
|
|
119
|
+
hidden: true,
|
|
120
|
+
description: 'Skip command intro when invoked by another CLI command',
|
|
29
121
|
default: false,
|
|
30
122
|
}),
|
|
31
123
|
source: Flags.string({
|
|
32
124
|
char: 's',
|
|
33
|
-
description: '
|
|
125
|
+
description: 'How to get NocoBase: Docker image, npm package, or Git repository.',
|
|
34
126
|
options: ['docker', 'npm', 'git'],
|
|
35
127
|
required: false,
|
|
36
128
|
}),
|
|
37
129
|
version: Flags.string({
|
|
38
130
|
char: 'v',
|
|
39
|
-
description: 'npm
|
|
131
|
+
description: 'Shared version input. For npm this is the package version, for Docker the image tag, and for Git a git ref such as a branch name (for example: alpha, beta, latest, fix/cli-v2).',
|
|
40
132
|
}),
|
|
41
133
|
replace: Flags.boolean({
|
|
42
134
|
char: 'r',
|
|
43
|
-
description: '
|
|
135
|
+
description: 'Replace the target directory if it already exists.',
|
|
44
136
|
default: false,
|
|
45
137
|
}),
|
|
46
|
-
'dev': Flags.boolean({
|
|
47
|
-
|
|
138
|
+
'dev-dependencies': Flags.boolean({
|
|
139
|
+
char: 'D',
|
|
140
|
+
allowNo: true,
|
|
141
|
+
description: 'Install development dependencies for npm/git source installs.',
|
|
48
142
|
default: false,
|
|
49
143
|
}),
|
|
50
144
|
'output-dir': Flags.string({
|
|
51
145
|
char: 'o',
|
|
52
|
-
description: '
|
|
146
|
+
description: 'Download target directory, or Docker tarball directory when --docker-save is enabled.',
|
|
53
147
|
}),
|
|
54
148
|
'git-url': Flags.string({
|
|
55
|
-
description: '
|
|
149
|
+
description: 'Git repository URL to clone when --source git is used.',
|
|
56
150
|
}),
|
|
57
151
|
'docker-registry': Flags.string({
|
|
58
|
-
description: '
|
|
152
|
+
description: 'Docker registry to pull when --source docker is used; combine it with --version as the image tag.',
|
|
153
|
+
}),
|
|
154
|
+
'docker-platform': Flags.string({
|
|
155
|
+
description: 'Docker image platform to pull; use auto to let Docker choose.',
|
|
156
|
+
options: ['auto', 'linux/amd64', 'linux/arm64'],
|
|
157
|
+
}),
|
|
158
|
+
'docker-save': Flags.boolean({
|
|
159
|
+
allowNo: true,
|
|
160
|
+
description: 'Also save the pulled Docker image as a tarball.',
|
|
161
|
+
default: false,
|
|
162
|
+
}),
|
|
163
|
+
'npm-registry': Flags.string({
|
|
164
|
+
description: 'npm registry for npm/git downloads and dependency installation.',
|
|
59
165
|
}),
|
|
166
|
+
'build': Flags.boolean({
|
|
167
|
+
allowNo: true,
|
|
168
|
+
description: 'Build npm/git source after dependencies are installed.',
|
|
169
|
+
default: true,
|
|
170
|
+
}),
|
|
171
|
+
'build-dts': Flags.boolean({
|
|
172
|
+
description: 'Generate TypeScript declaration files during the npm/git build.',
|
|
173
|
+
default: false,
|
|
174
|
+
}),
|
|
175
|
+
};
|
|
176
|
+
static prompts = {
|
|
177
|
+
source: {
|
|
178
|
+
type: 'select',
|
|
179
|
+
message: downloadText('prompts.source.message'),
|
|
180
|
+
options: [
|
|
181
|
+
{ value: 'npm', label: downloadText('prompts.source.npmLabel') },
|
|
182
|
+
{ value: 'git', label: downloadText('prompts.source.gitLabel') },
|
|
183
|
+
{ value: 'docker', label: downloadText('prompts.source.dockerLabel') },
|
|
184
|
+
],
|
|
185
|
+
yesInitialValue: 'docker',
|
|
186
|
+
initialValue: 'docker',
|
|
187
|
+
required: true,
|
|
188
|
+
},
|
|
189
|
+
version: {
|
|
190
|
+
type: 'text',
|
|
191
|
+
message: downloadText('prompts.version.message'),
|
|
192
|
+
placeholder: downloadText('prompts.version.placeholder'),
|
|
193
|
+
initialValue: 'alpha',
|
|
194
|
+
yesInitialValue: 'alpha',
|
|
195
|
+
required: true,
|
|
196
|
+
},
|
|
197
|
+
dockerRegistry: {
|
|
198
|
+
type: 'text',
|
|
199
|
+
message: downloadText('prompts.dockerRegistry.message'),
|
|
200
|
+
placeholder: downloadText('prompts.dockerRegistry.placeholder'),
|
|
201
|
+
initialValue: (values) => defaultDockerRegistryForLang(values.lang),
|
|
202
|
+
yesInitialValue: DEFAULT_DOCKER_REGISTRY,
|
|
203
|
+
required: true,
|
|
204
|
+
hidden: (values) => values.source !== 'docker',
|
|
205
|
+
},
|
|
206
|
+
dockerPlatform: {
|
|
207
|
+
type: 'select',
|
|
208
|
+
message: downloadText('prompts.dockerPlatform.message'),
|
|
209
|
+
options: [
|
|
210
|
+
{
|
|
211
|
+
value: 'auto',
|
|
212
|
+
label: downloadText('prompts.dockerPlatform.autoLabel'),
|
|
213
|
+
hint: downloadText('prompts.dockerPlatform.autoHint'),
|
|
214
|
+
},
|
|
215
|
+
{ value: 'linux/amd64', label: 'linux/amd64' },
|
|
216
|
+
{ value: 'linux/arm64', label: 'linux/arm64' },
|
|
217
|
+
],
|
|
218
|
+
initialValue: DEFAULT_DOCKER_PLATFORM,
|
|
219
|
+
yesInitialValue: DEFAULT_DOCKER_PLATFORM,
|
|
220
|
+
required: true,
|
|
221
|
+
hidden: (values) => values.source !== 'docker',
|
|
222
|
+
},
|
|
223
|
+
dockerSave: {
|
|
224
|
+
type: 'boolean',
|
|
225
|
+
message: downloadText('prompts.dockerSave.message'),
|
|
226
|
+
initialValue: false,
|
|
227
|
+
hidden: (values) => values.source !== 'docker',
|
|
228
|
+
},
|
|
229
|
+
gitUrl: {
|
|
230
|
+
type: 'text',
|
|
231
|
+
message: downloadText('prompts.gitUrl.message'),
|
|
232
|
+
placeholder: downloadText('prompts.gitUrl.placeholder'),
|
|
233
|
+
initialValue: 'https://github.com/nocobase/nocobase.git',
|
|
234
|
+
yesInitialValue: 'https://github.com/nocobase/nocobase.git',
|
|
235
|
+
required: true,
|
|
236
|
+
hidden: (values) => values.source !== 'git',
|
|
237
|
+
},
|
|
238
|
+
outputDir: {
|
|
239
|
+
type: 'text',
|
|
240
|
+
message: downloadText('prompts.outputDir.message'),
|
|
241
|
+
placeholder: downloadText('prompts.outputDir.placeholder'),
|
|
242
|
+
initialValue: (values) => defaultOutputDirForVersion(String(values.version ?? 'latest').trim() || 'latest'),
|
|
243
|
+
required: true,
|
|
244
|
+
hidden: (values) => {
|
|
245
|
+
const s = values.source;
|
|
246
|
+
if (s === 'npm' || s === 'git') {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
if (s === 'docker') {
|
|
250
|
+
return !values.dockerSave;
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
npmRegistry: {
|
|
256
|
+
type: 'text',
|
|
257
|
+
message: downloadText('prompts.npmRegistry.message'),
|
|
258
|
+
placeholder: downloadText('prompts.npmRegistry.placeholder'),
|
|
259
|
+
initialValue: '',
|
|
260
|
+
hidden: (values) => values.source !== 'npm' && values.source !== 'git',
|
|
261
|
+
},
|
|
262
|
+
replace: {
|
|
263
|
+
type: 'boolean',
|
|
264
|
+
message: downloadText('prompts.replace.message'),
|
|
265
|
+
initialValue: false,
|
|
266
|
+
hidden: (values) => Download.hideOutputDirAndReplaceSteps(values),
|
|
267
|
+
},
|
|
268
|
+
devDependencies: {
|
|
269
|
+
type: 'boolean',
|
|
270
|
+
message: downloadText('prompts.devDependencies.message'),
|
|
271
|
+
initialValue: false,
|
|
272
|
+
hidden: (values) => values.source !== 'npm',
|
|
273
|
+
},
|
|
274
|
+
build: {
|
|
275
|
+
type: 'boolean',
|
|
276
|
+
message: downloadText('prompts.build.message'),
|
|
277
|
+
initialValue: true,
|
|
278
|
+
yesInitialValue: true,
|
|
279
|
+
hidden: () => true,
|
|
280
|
+
},
|
|
281
|
+
buildDts: {
|
|
282
|
+
type: 'boolean',
|
|
283
|
+
message: downloadText('prompts.buildDts.message'),
|
|
284
|
+
initialValue: false,
|
|
285
|
+
hidden: (values) => values.source !== 'git',
|
|
286
|
+
},
|
|
60
287
|
};
|
|
288
|
+
/** When true, `outputDir` / `replace` prompts are skipped (same condition for both). */
|
|
289
|
+
static hideOutputDirAndReplaceSteps(values) {
|
|
290
|
+
const s = values.source;
|
|
291
|
+
if (s === 'npm' || s === 'git') {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
if (s === 'docker') {
|
|
295
|
+
return !values.dockerSave;
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
61
299
|
resolveOutputDir(flags) {
|
|
62
300
|
const explicit = flags['output-dir'];
|
|
63
301
|
if (explicit) {
|
|
64
302
|
return explicit;
|
|
65
303
|
}
|
|
66
|
-
|
|
67
|
-
const safe = tag.replace(/[/\\]/g, '-');
|
|
68
|
-
return `./nocobase-${safe}`;
|
|
304
|
+
return defaultOutputDirForVersion(flags.version || 'latest');
|
|
69
305
|
}
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
306
|
+
async ensureOutputDirAvailable(outputDir, replace) {
|
|
307
|
+
const outputAbs = path.resolve(process.cwd(), outputDir);
|
|
308
|
+
if (replace) {
|
|
309
|
+
await fsp.rm(outputAbs, { recursive: true, force: true });
|
|
310
|
+
return outputAbs;
|
|
311
|
+
}
|
|
312
|
+
if (await pathExists(outputAbs)) {
|
|
313
|
+
this.error(`Download target already exists: ${outputDir}. Use --replace to remove it before continuing.`);
|
|
314
|
+
}
|
|
315
|
+
return outputAbs;
|
|
316
|
+
}
|
|
317
|
+
dockerTarPath(flags, outputAbs) {
|
|
318
|
+
const image = flags['docker-registry'] ?? DEFAULT_DOCKER_REGISTRY;
|
|
319
|
+
const tag = flags.version ?? 'latest';
|
|
320
|
+
const safeBase = `${image.replace(/[/:]/g, '-')}-${tag.replace(/[/\\]/g, '-')}`;
|
|
321
|
+
return path.join(outputAbs, `${safeBase}.tar`);
|
|
73
322
|
}
|
|
74
323
|
/**
|
|
75
|
-
*
|
|
324
|
+
* Defaults for prompts only. Keys present in **`preset`** are omitted so `runPromptCatalog` uses
|
|
325
|
+
* **`values`** (preset) alone for those steps — no duplicate prefill for skipped prompts.
|
|
76
326
|
*/
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
if (source
|
|
81
|
-
source =
|
|
82
|
-
}
|
|
83
|
-
let version = flags.version?.trim() || undefined;
|
|
84
|
-
let replace = flags.replace;
|
|
85
|
-
let dev = flags['dev'];
|
|
86
|
-
let outputDir = flags['output-dir']?.trim() || undefined;
|
|
87
|
-
if (outputDir === '') {
|
|
88
|
-
outputDir = undefined;
|
|
89
|
-
}
|
|
90
|
-
let gitUrl = flags['git-url']?.trim() || undefined;
|
|
91
|
-
if (gitUrl === '') {
|
|
92
|
-
gitUrl = undefined;
|
|
93
|
-
}
|
|
94
|
-
let dockerRegistry = flags['docker-registry']?.trim() || undefined;
|
|
95
|
-
if (dockerRegistry === '') {
|
|
96
|
-
dockerRegistry = undefined;
|
|
97
|
-
}
|
|
98
|
-
if (!interactive) {
|
|
99
|
-
if (!source) {
|
|
100
|
-
this.error('Distribution is required (--source npm|git|docker). Use a terminal for interactive setup, or pass -s/--source.');
|
|
101
|
-
}
|
|
102
|
-
const v = version || 'latest';
|
|
103
|
-
return {
|
|
104
|
-
source,
|
|
105
|
-
version: v,
|
|
106
|
-
replace,
|
|
107
|
-
'dev': dev,
|
|
108
|
-
'output-dir': outputDir,
|
|
109
|
-
'git-url': gitUrl,
|
|
110
|
-
'docker-registry': dockerRegistry,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
p.intro('nb download');
|
|
114
|
-
if (!source) {
|
|
115
|
-
const src = await p.select({
|
|
116
|
-
message: 'How do you want to get NocoBase?',
|
|
117
|
-
options: [
|
|
118
|
-
{ value: 'npm', label: 'npm — create-nocobase-app' },
|
|
119
|
-
{ value: 'git', label: 'git — shallow clone' },
|
|
120
|
-
{ value: 'docker', label: 'docker — pull image' },
|
|
121
|
-
],
|
|
122
|
-
initialValue: 'npm',
|
|
123
|
-
});
|
|
124
|
-
if (p.isCancel(src)) {
|
|
125
|
-
p.cancel('Download cancelled.');
|
|
126
|
-
this.exit(0);
|
|
127
|
-
}
|
|
128
|
-
source = src;
|
|
327
|
+
buildInitialValuesFromParsed(flags, preset) {
|
|
328
|
+
const initialValues = {};
|
|
329
|
+
const source = flags.source?.trim();
|
|
330
|
+
if (source) {
|
|
331
|
+
initialValues.source = source;
|
|
129
332
|
}
|
|
130
|
-
if (version
|
|
131
|
-
|
|
132
|
-
message: 'Version / dist-tag / image tag / branch alias (-v)',
|
|
133
|
-
placeholder: 'latest',
|
|
134
|
-
initialValue: 'latest',
|
|
135
|
-
});
|
|
136
|
-
if (p.isCancel(verAns)) {
|
|
137
|
-
p.cancel('Download cancelled.');
|
|
138
|
-
this.exit(0);
|
|
139
|
-
}
|
|
140
|
-
version = verAns.trim() || 'latest';
|
|
141
|
-
}
|
|
142
|
-
const versionResolved = version || 'latest';
|
|
143
|
-
if (source === 'docker') {
|
|
144
|
-
if (dockerRegistry === undefined) {
|
|
145
|
-
const reg = await p.text({
|
|
146
|
-
message: 'Docker image without tag (--docker-registry)',
|
|
147
|
-
placeholder: 'nocobase/nocobase',
|
|
148
|
-
initialValue: 'nocobase/nocobase',
|
|
149
|
-
});
|
|
150
|
-
if (p.isCancel(reg)) {
|
|
151
|
-
p.cancel('Download cancelled.');
|
|
152
|
-
this.exit(0);
|
|
153
|
-
}
|
|
154
|
-
dockerRegistry = reg.trim() || 'nocobase/nocobase';
|
|
155
|
-
}
|
|
333
|
+
if (flags.version !== undefined) {
|
|
334
|
+
initialValues.version = flags.version.trim() || 'latest';
|
|
156
335
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
336
|
+
initialValues.replace = flags.replace;
|
|
337
|
+
initialValues.devDependencies = flags['dev-dependencies'];
|
|
338
|
+
initialValues.build = flags.build;
|
|
339
|
+
initialValues.buildDts = flags['build-dts'];
|
|
340
|
+
if (flags['output-dir'] !== undefined) {
|
|
341
|
+
initialValues.outputDir = flags['output-dir']?.trim() ?? '';
|
|
342
|
+
}
|
|
343
|
+
if (flags['git-url'] !== undefined) {
|
|
344
|
+
initialValues.gitUrl = flags['git-url']?.trim() ?? '';
|
|
345
|
+
}
|
|
346
|
+
if (flags['docker-registry'] !== undefined) {
|
|
347
|
+
initialValues.dockerRegistry = String(flags['docker-registry'] ?? '').trim();
|
|
348
|
+
}
|
|
349
|
+
initialValues.dockerPlatform = normalizeDockerPlatform(flags['docker-platform']);
|
|
350
|
+
initialValues.dockerSave = flags['docker-save'];
|
|
351
|
+
if (flags['npm-registry'] !== undefined) {
|
|
352
|
+
initialValues.npmRegistry =
|
|
353
|
+
typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
354
|
+
}
|
|
355
|
+
for (const key of Object.keys(preset)) {
|
|
356
|
+
if (Object.prototype.hasOwnProperty.call(initialValues, key)) {
|
|
357
|
+
delete initialValues[key];
|
|
169
358
|
}
|
|
170
359
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
360
|
+
return initialValues;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Preset `values` for `runPromptCatalog`: any key here skips that prompt and fixes the result.
|
|
364
|
+
* Keys not listed are resolved interactively (TTY) or from catalog defaults / `initialValues` (non-TTY / `-y`).
|
|
365
|
+
*/
|
|
366
|
+
buildPresetValuesFromFlags(flags) {
|
|
367
|
+
const preset = {};
|
|
368
|
+
const argv = process.argv.slice(2);
|
|
369
|
+
if (flags.source !== undefined && String(flags.source).trim() !== '') {
|
|
370
|
+
preset.source = String(flags.source).trim();
|
|
371
|
+
}
|
|
372
|
+
if (flags.version !== undefined) {
|
|
373
|
+
preset.version = String(flags.version).trim() || 'latest';
|
|
374
|
+
}
|
|
375
|
+
if (flags['docker-registry'] !== undefined) {
|
|
376
|
+
const v = String(flags['docker-registry'] ?? '').trim();
|
|
377
|
+
if (v) {
|
|
378
|
+
preset.dockerRegistry = v;
|
|
184
379
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
380
|
+
}
|
|
381
|
+
if (argvHasToken(argv, ['--docker-platform'])) {
|
|
382
|
+
preset.dockerPlatform = normalizeDockerPlatform(flags['docker-platform']);
|
|
383
|
+
}
|
|
384
|
+
if (flags['output-dir'] !== undefined) {
|
|
385
|
+
const v = flags['output-dir']?.trim();
|
|
386
|
+
if (v) {
|
|
387
|
+
preset.outputDir = v;
|
|
192
388
|
}
|
|
193
|
-
replace = replaceAns;
|
|
194
389
|
}
|
|
195
|
-
if (
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
});
|
|
200
|
-
if (p.isCancel(devAns)) {
|
|
201
|
-
p.cancel('Download cancelled.');
|
|
202
|
-
this.exit(0);
|
|
390
|
+
if (flags['git-url'] !== undefined) {
|
|
391
|
+
const v = flags['git-url']?.trim();
|
|
392
|
+
if (v) {
|
|
393
|
+
preset.gitUrl = v;
|
|
203
394
|
}
|
|
204
|
-
dev = devAns;
|
|
205
395
|
}
|
|
396
|
+
if (flags['npm-registry'] !== undefined) {
|
|
397
|
+
preset.npmRegistry = typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
398
|
+
}
|
|
399
|
+
if (argvHasToken(argv, ['--replace', '-r'])) {
|
|
400
|
+
preset.replace = flags.replace;
|
|
401
|
+
}
|
|
402
|
+
if (argvHasToken(argv, ['--dev-dependencies', '--no-dev-dependencies', '-D'])) {
|
|
403
|
+
preset.devDependencies = flags['dev-dependencies'];
|
|
404
|
+
}
|
|
405
|
+
if (argvHasToken(argv, ['--docker-save', '--no-docker-save'])) {
|
|
406
|
+
preset.dockerSave = flags['docker-save'];
|
|
407
|
+
}
|
|
408
|
+
if (argvHasToken(argv, ['--build', '--no-build'])) {
|
|
409
|
+
preset.build = flags.build;
|
|
410
|
+
}
|
|
411
|
+
if (argvHasToken(argv, ['--build-dts', '--no-build-dts'])) {
|
|
412
|
+
preset.buildDts = flags['build-dts'];
|
|
413
|
+
}
|
|
414
|
+
return preset;
|
|
415
|
+
}
|
|
416
|
+
resolveEffectiveBuild(source, results, flags) {
|
|
417
|
+
if (source === 'npm' && !Boolean(results.devDependencies)) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
if (source === 'npm' || source === 'git') {
|
|
421
|
+
return results.build !== undefined ? Boolean(results.build) : flags.build;
|
|
422
|
+
}
|
|
423
|
+
return flags.build;
|
|
424
|
+
}
|
|
425
|
+
mapCatalogResultsToResolved(results, flags) {
|
|
426
|
+
const source = String(results.source);
|
|
427
|
+
const version = String(results.version ?? '').trim() || 'latest';
|
|
428
|
+
const devDependencies = source === 'npm' ? Boolean(results.devDependencies) : undefined;
|
|
429
|
+
const effectiveBuild = this.resolveEffectiveBuild(source, results, flags);
|
|
430
|
+
const buildDtsWant = results.buildDts !== undefined ? Boolean(results.buildDts) : flags['build-dts'];
|
|
431
|
+
const outputDir = results.outputDir !== undefined
|
|
432
|
+
? String(results.outputDir).trim() || undefined
|
|
433
|
+
: flags['output-dir']?.trim() || undefined;
|
|
434
|
+
const replace = results.replace !== undefined ? Boolean(results.replace) : flags.replace;
|
|
435
|
+
const gitUrl = results.gitUrl !== undefined
|
|
436
|
+
? String(results.gitUrl).trim() || undefined
|
|
437
|
+
: flags['git-url']?.trim() || undefined;
|
|
438
|
+
const dockerRegistry = results.dockerRegistry !== undefined
|
|
439
|
+
? String(results.dockerRegistry).trim() || undefined
|
|
440
|
+
: flags['docker-registry']?.trim() || undefined;
|
|
441
|
+
const dockerPlatform = source === 'docker'
|
|
442
|
+
? normalizeDockerPlatform(results.dockerPlatform !== undefined
|
|
443
|
+
? results.dockerPlatform
|
|
444
|
+
: flags['docker-platform'])
|
|
445
|
+
: undefined;
|
|
446
|
+
const dockerSave = source === 'docker'
|
|
447
|
+
? results.dockerSave !== undefined
|
|
448
|
+
? Boolean(results.dockerSave)
|
|
449
|
+
: flags['docker-save']
|
|
450
|
+
: false;
|
|
451
|
+
const npmRegistryRaw = results.npmRegistry !== undefined
|
|
452
|
+
? String(results.npmRegistry)
|
|
453
|
+
: flags['npm-registry'] ?? '';
|
|
454
|
+
const npmRegistry = npmRegistryRaw.trim() || undefined;
|
|
206
455
|
return {
|
|
207
456
|
source,
|
|
208
|
-
version
|
|
457
|
+
version,
|
|
209
458
|
replace,
|
|
210
|
-
'dev':
|
|
459
|
+
...(source === 'npm' ? { 'dev-dependencies': devDependencies } : {}),
|
|
460
|
+
'build': effectiveBuild,
|
|
461
|
+
'build-dts': normalizeBuildDts(source, effectiveBuild, buildDtsWant),
|
|
211
462
|
'output-dir': outputDir,
|
|
212
463
|
'git-url': gitUrl,
|
|
213
464
|
'docker-registry': dockerRegistry,
|
|
465
|
+
...(source === 'docker' ? { 'docker-platform': dockerPlatform } : {}),
|
|
466
|
+
...(source === 'docker' ? { 'docker-save': dockerSave } : {}),
|
|
467
|
+
...(npmRegistry ? { 'npm-registry': npmRegistry } : {}),
|
|
214
468
|
};
|
|
215
469
|
}
|
|
470
|
+
async resolveDownloadFlags(flags) {
|
|
471
|
+
const nonInteractive = !stdinStream.isTTY || !stdoutStream.isTTY || flags.yes;
|
|
472
|
+
if (nonInteractive && !flags.source?.trim()) {
|
|
473
|
+
this.error('Download source is required in non-interactive mode. Use --source npm, --source git, or --source docker.');
|
|
474
|
+
}
|
|
475
|
+
const presetValues = this.buildPresetValuesFromFlags(flags);
|
|
476
|
+
const initialValues = this.buildInitialValuesFromParsed(flags, presetValues);
|
|
477
|
+
const results = await runPromptCatalog(Download.prompts, {
|
|
478
|
+
initialValues,
|
|
479
|
+
values: presetValues,
|
|
480
|
+
yes: flags.yes,
|
|
481
|
+
command: this,
|
|
482
|
+
hooks: {
|
|
483
|
+
onCancel: () => {
|
|
484
|
+
p.cancel('Download cancelled.');
|
|
485
|
+
this.exit(0);
|
|
486
|
+
},
|
|
487
|
+
onMissingNonInteractive: (message) => {
|
|
488
|
+
this.error(message);
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
const source = String(results.source ?? '').trim();
|
|
493
|
+
if (!source || !['docker', 'npm', 'git'].includes(source)) {
|
|
494
|
+
this.error('Download source is required. Choose npm, git, or docker.');
|
|
495
|
+
}
|
|
496
|
+
if (flags['docker-save'] && source !== 'docker') {
|
|
497
|
+
this.error('--docker-save is only available when --source docker is selected.');
|
|
498
|
+
}
|
|
499
|
+
return this.mapCatalogResultsToResolved(results, flags);
|
|
500
|
+
}
|
|
501
|
+
npmRegistryUrl(flags) {
|
|
502
|
+
const url = flags['npm-registry']?.trim();
|
|
503
|
+
return url || undefined;
|
|
504
|
+
}
|
|
505
|
+
npmRegistryEnv(flags) {
|
|
506
|
+
const url = this.npmRegistryUrl(flags);
|
|
507
|
+
if (!url) {
|
|
508
|
+
return undefined;
|
|
509
|
+
}
|
|
510
|
+
return { npm_config_registry: url };
|
|
511
|
+
}
|
|
512
|
+
isVerbose() {
|
|
513
|
+
const flags = this._flags;
|
|
514
|
+
return Boolean(flags?.verbose);
|
|
515
|
+
}
|
|
516
|
+
commandStdio() {
|
|
517
|
+
return this.isVerbose() ? 'inherit' : 'ignore';
|
|
518
|
+
}
|
|
519
|
+
formatCommandForLog(name, args, cwd) {
|
|
520
|
+
const quotedArgs = args.map((arg) => (/\s/.test(arg) ? JSON.stringify(arg) : arg));
|
|
521
|
+
const commandLine = [name, ...quotedArgs].join(' ');
|
|
522
|
+
return cwd ? `${commandLine} (cwd: ${cwd})` : commandLine;
|
|
523
|
+
}
|
|
524
|
+
async runExternalCommand(name, args, options) {
|
|
525
|
+
const cwd = options?.cwd;
|
|
526
|
+
printVerbose(`Running command: ${this.formatCommandForLog(name, args, cwd)}`);
|
|
527
|
+
let loadingStarted = false;
|
|
528
|
+
let loadingTimer;
|
|
529
|
+
let updateTimer;
|
|
530
|
+
let elapsedSeconds = 0;
|
|
531
|
+
if (!this.isVerbose() && options?.loadingMessage) {
|
|
532
|
+
loadingTimer = setTimeout(() => {
|
|
533
|
+
loadingStarted = true;
|
|
534
|
+
elapsedSeconds = Math.floor(EXTERNAL_COMMAND_LOADING_DELAY_MS / 1000);
|
|
535
|
+
startTask(`${options.loadingMessage}. Please wait...`);
|
|
536
|
+
updateTimer = setInterval(() => {
|
|
537
|
+
elapsedSeconds += Math.floor(EXTERNAL_COMMAND_LOADING_UPDATE_MS / 1000);
|
|
538
|
+
updateTask(`${options.loadingMessage}. Still working... (${elapsedSeconds}s elapsed)`);
|
|
539
|
+
}, EXTERNAL_COMMAND_LOADING_UPDATE_MS);
|
|
540
|
+
}, EXTERNAL_COMMAND_LOADING_DELAY_MS);
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
await run(name, args, {
|
|
544
|
+
...options,
|
|
545
|
+
stdio: this.commandStdio(),
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
finally {
|
|
549
|
+
if (loadingTimer) {
|
|
550
|
+
clearTimeout(loadingTimer);
|
|
551
|
+
}
|
|
552
|
+
if (updateTimer) {
|
|
553
|
+
clearInterval(updateTimer);
|
|
554
|
+
}
|
|
555
|
+
if (loadingStarted) {
|
|
556
|
+
stopTask();
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
startPreparationTask(message) {
|
|
561
|
+
if (this.isVerbose()) {
|
|
562
|
+
p.log.step(message);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
this.preparationTaskActive = true;
|
|
566
|
+
startTask(message);
|
|
567
|
+
}
|
|
568
|
+
finishPreparationTask() {
|
|
569
|
+
if (!this.preparationTaskActive) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
this.preparationTaskActive = false;
|
|
573
|
+
stopTask();
|
|
574
|
+
}
|
|
575
|
+
runOptionsWithCwd(cwd, registryEnv) {
|
|
576
|
+
if (registryEnv) {
|
|
577
|
+
return { cwd, env: registryEnv };
|
|
578
|
+
}
|
|
579
|
+
return { cwd };
|
|
580
|
+
}
|
|
581
|
+
buildCommandArgv(projectRoot, flags) {
|
|
582
|
+
const argv = ['--cwd', projectRoot];
|
|
583
|
+
if (!flags['build-dts']) {
|
|
584
|
+
argv.push('--no-dts');
|
|
585
|
+
}
|
|
586
|
+
return argv;
|
|
587
|
+
}
|
|
216
588
|
async downloadFromDocker(flags) {
|
|
217
|
-
const image = flags['docker-registry'] ??
|
|
589
|
+
const image = flags['docker-registry'] ?? DEFAULT_DOCKER_REGISTRY;
|
|
218
590
|
const tag = flags.version ?? 'latest';
|
|
219
|
-
|
|
591
|
+
const imageRef = `${image}:${tag}`;
|
|
592
|
+
const platform = dockerPlatformArg(flags['docker-platform']);
|
|
593
|
+
const pullArgs = ['pull'];
|
|
594
|
+
if (platform) {
|
|
595
|
+
pullArgs.push('--platform', platform);
|
|
596
|
+
}
|
|
597
|
+
pullArgs.push(imageRef);
|
|
598
|
+
this.finishPreparationTask();
|
|
599
|
+
p.log.step(`Pulling Docker image ${imageRef}`);
|
|
600
|
+
await this.runExternalCommand('docker', pullArgs, {
|
|
601
|
+
errorName: 'docker pull',
|
|
602
|
+
loadingMessage: 'Pulling the Docker image',
|
|
603
|
+
});
|
|
604
|
+
p.log.info(`Docker image is ready: ${imageRef}`);
|
|
605
|
+
if (!flags['docker-save']) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const outputDir = this.resolveOutputDir(flags);
|
|
609
|
+
const outAbs = flags.replace
|
|
610
|
+
? path.resolve(process.cwd(), outputDir)
|
|
611
|
+
: await this.ensureOutputDirAvailable(outputDir, false);
|
|
612
|
+
if (flags.replace) {
|
|
613
|
+
await fsp.rm(outAbs, { recursive: true, force: true });
|
|
614
|
+
}
|
|
615
|
+
await fsp.mkdir(outAbs, { recursive: true });
|
|
616
|
+
const tarPath = this.dockerTarPath(flags, outAbs);
|
|
617
|
+
p.log.step(`Saving Docker image tarball to ${tarPath}`);
|
|
618
|
+
await this.runExternalCommand('docker', ['save', '-o', tarPath, imageRef], {
|
|
619
|
+
errorName: 'docker save',
|
|
620
|
+
loadingMessage: 'Saving the Docker image tarball',
|
|
621
|
+
});
|
|
622
|
+
p.log.info(`Docker image tarball saved: ${tarPath}`);
|
|
220
623
|
}
|
|
221
624
|
async downloadFromNpm(flags) {
|
|
222
625
|
const versionSpec = flags.version || 'latest';
|
|
223
626
|
const outputDir = this.resolveOutputDir(flags);
|
|
224
627
|
const projectRoot = path.resolve(process.cwd(), outputDir);
|
|
225
|
-
|
|
226
|
-
|
|
628
|
+
await this.ensureOutputDirAvailable(outputDir, flags.replace);
|
|
629
|
+
const parentDir = path.dirname(projectRoot);
|
|
630
|
+
const appName = path.basename(projectRoot);
|
|
631
|
+
const npxArgs = ['-y', `create-nocobase-app@${versionSpec}`, appName];
|
|
632
|
+
if (!flags['dev-dependencies']) {
|
|
227
633
|
npxArgs.push('--skip-dev-dependencies');
|
|
228
634
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
635
|
+
await fsp.mkdir(parentDir, { recursive: true });
|
|
636
|
+
const registryEnv = this.npmRegistryEnv(flags);
|
|
637
|
+
this.finishPreparationTask();
|
|
638
|
+
p.log.step(`Creating NocoBase app "${appName}" from npm`);
|
|
639
|
+
await this.runExternalCommand('npx', npxArgs, {
|
|
640
|
+
...this.runOptionsWithCwd(parentDir, registryEnv),
|
|
641
|
+
errorName: 'npx create-nocobase-app',
|
|
642
|
+
loadingMessage: 'Creating the app scaffold',
|
|
643
|
+
});
|
|
233
644
|
const installArgs = ['install'];
|
|
234
|
-
if (!flags['dev']) {
|
|
645
|
+
if (!flags['dev-dependencies']) {
|
|
235
646
|
installArgs.push('--production');
|
|
236
647
|
}
|
|
237
|
-
|
|
648
|
+
p.log.step(`Installing dependencies in ${projectRoot}`);
|
|
649
|
+
await this.runExternalCommand('yarn', installArgs, {
|
|
650
|
+
...this.runOptionsWithCwd(projectRoot, registryEnv),
|
|
651
|
+
errorName: 'yarn install',
|
|
652
|
+
loadingMessage: 'Installing dependencies',
|
|
653
|
+
});
|
|
654
|
+
if (flags.build && flags['dev-dependencies']) {
|
|
655
|
+
p.log.step(`Building app in ${projectRoot}`);
|
|
656
|
+
await this.config.runCommand('build', [
|
|
657
|
+
...this.buildCommandArgv(projectRoot, flags),
|
|
658
|
+
...(this.isVerbose() ? ['--verbose'] : []),
|
|
659
|
+
]);
|
|
660
|
+
}
|
|
661
|
+
p.log.info(`NocoBase app is ready at ${projectRoot}`);
|
|
238
662
|
return projectRoot;
|
|
239
663
|
}
|
|
240
664
|
async downloadFromGit(flags) {
|
|
241
665
|
const repoUrl = flags['git-url'] ?? 'https://github.com/nocobase/nocobase.git';
|
|
242
666
|
const versionSpec = flags.version || 'latest';
|
|
243
667
|
const outputDir = this.resolveOutputDir(flags);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
'beta': 'next',
|
|
247
|
-
'alpha': 'develop',
|
|
248
|
-
};
|
|
249
|
-
if (flags.replace) {
|
|
250
|
-
await fsp.rm(path.resolve(process.cwd(), outputDir), { recursive: true, force: true });
|
|
251
|
-
}
|
|
252
|
-
const branch = versionToRef[versionSpec] || versionSpec;
|
|
668
|
+
await this.ensureOutputDirAvailable(outputDir, flags.replace);
|
|
669
|
+
const branch = gitRefForVersion(versionSpec);
|
|
253
670
|
const gitArgs = ['clone'];
|
|
254
671
|
gitArgs.push('--branch', branch);
|
|
255
672
|
gitArgs.push('--depth', '1', repoUrl, outputDir);
|
|
256
|
-
|
|
673
|
+
this.finishPreparationTask();
|
|
674
|
+
p.log.step(branch === versionSpec
|
|
675
|
+
? `Cloning NocoBase from ${repoUrl} (${branch})`
|
|
676
|
+
: `Cloning NocoBase from ${repoUrl} (${branch}, resolved from ${versionSpec})`);
|
|
677
|
+
await this.runExternalCommand('git', gitArgs, {
|
|
678
|
+
errorName: 'git clone',
|
|
679
|
+
loadingMessage: 'Cloning the repository',
|
|
680
|
+
});
|
|
257
681
|
const projectRoot = path.resolve(process.cwd(), outputDir);
|
|
258
|
-
|
|
682
|
+
const registryEnv = this.npmRegistryEnv(flags);
|
|
683
|
+
p.log.step(`Installing dependencies in ${projectRoot}`);
|
|
684
|
+
await this.runExternalCommand('yarn', ['install'], {
|
|
685
|
+
...this.runOptionsWithCwd(projectRoot, registryEnv),
|
|
686
|
+
errorName: 'yarn install',
|
|
687
|
+
loadingMessage: 'Installing dependencies',
|
|
688
|
+
});
|
|
689
|
+
if (flags.build) {
|
|
690
|
+
p.log.step(`Building app in ${projectRoot}`);
|
|
691
|
+
await this.config.runCommand('build', [
|
|
692
|
+
...this.buildCommandArgv(projectRoot, flags),
|
|
693
|
+
...(this.isVerbose() ? ['--verbose'] : []),
|
|
694
|
+
]);
|
|
695
|
+
}
|
|
696
|
+
p.log.info(`NocoBase app is ready at ${projectRoot}`);
|
|
259
697
|
return projectRoot;
|
|
260
698
|
}
|
|
261
|
-
/**
|
|
262
|
-
* @returns Final resolved flags and, for npm/git, the absolute project directory.
|
|
263
|
-
*/
|
|
264
699
|
async download() {
|
|
265
700
|
const { flags } = await this.parse(Download);
|
|
701
|
+
this._flags = flags;
|
|
702
|
+
applyCliLocale(this._flags.locale);
|
|
703
|
+
setVerboseMode(Boolean(flags.verbose));
|
|
704
|
+
if (!flags['no-intro']) {
|
|
705
|
+
p.intro('Get NocoBase');
|
|
706
|
+
}
|
|
266
707
|
const resolved = await this.resolveDownloadFlags(flags);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
708
|
+
const source = resolved.source;
|
|
709
|
+
this.startPreparationTask(`Preparing download from ${downloadSourceLabel(source)}`);
|
|
710
|
+
try {
|
|
711
|
+
switch (source) {
|
|
712
|
+
case 'npm': {
|
|
713
|
+
const projectRoot = await this.downloadFromNpm(resolved);
|
|
714
|
+
return { resolved, projectRoot };
|
|
715
|
+
}
|
|
716
|
+
case 'docker': {
|
|
717
|
+
await this.downloadFromDocker(resolved);
|
|
718
|
+
return { resolved, projectRoot: undefined };
|
|
719
|
+
}
|
|
720
|
+
case 'git': {
|
|
721
|
+
const projectRoot = await this.downloadFromGit(resolved);
|
|
722
|
+
return { resolved, projectRoot };
|
|
723
|
+
}
|
|
724
|
+
default:
|
|
725
|
+
this.error(`Unsupported download source: ${resolved.source}`);
|
|
279
726
|
}
|
|
280
|
-
|
|
281
|
-
|
|
727
|
+
}
|
|
728
|
+
finally {
|
|
729
|
+
this.finishPreparationTask();
|
|
282
730
|
}
|
|
283
731
|
}
|
|
284
732
|
async run() {
|
|
285
733
|
try {
|
|
286
|
-
|
|
734
|
+
const result = await this.download();
|
|
735
|
+
p.outro(`Download completed via ${downloadSourceLabel(result.resolved.source)}.`);
|
|
736
|
+
return result;
|
|
287
737
|
}
|
|
288
738
|
catch (error) {
|
|
289
739
|
const message = error instanceof Error ? error.message : String(error);
|