@nocobase/cli 2.1.0-alpha.37 → 2.1.0-alpha.39
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/bin/run.js +2 -1
- package/bin/session-env.js +12 -0
- package/dist/commands/app/restart.js +63 -1
- package/dist/commands/app/start.js +53 -17
- package/dist/commands/app/upgrade.js +16 -3
- package/dist/commands/install.js +11 -2
- package/dist/commands/source/dev.js +8 -1
- package/dist/commands/source/publish.js +92 -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/lib/app-managed-resources.js +30 -3
- package/dist/lib/bootstrap.js +1 -1
- package/dist/lib/docker-env-file.js +52 -0
- package/dist/lib/env-config.js +1 -0
- package/dist/lib/run-npm.js +8 -9
- package/dist/lib/source-publish.js +287 -0
- package/dist/lib/source-registry.js +188 -0
- package/package.json +2 -2
|
@@ -0,0 +1,188 @@
|
|
|
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 fsp from 'node:fs/promises';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { commandOutput, commandSucceeds, resolveCwd, resolveProjectCwd, run } from './run-npm.js';
|
|
12
|
+
import { resolveCliHomeRoot } from './cli-home.js';
|
|
13
|
+
export const DEFAULT_SOURCE_REGISTRY_HOST = '127.0.0.1';
|
|
14
|
+
export const DEFAULT_SOURCE_REGISTRY_PORT = 4873;
|
|
15
|
+
export const DEFAULT_SOURCE_REGISTRY_CONTAINER_NAME = 'nb-source-registry';
|
|
16
|
+
export const DEFAULT_SOURCE_REGISTRY_IMAGE = 'verdaccio/verdaccio';
|
|
17
|
+
export function parseSourceRegistryUrl(url) {
|
|
18
|
+
const parsed = new URL(url);
|
|
19
|
+
const host = trimValue(parsed.hostname) || DEFAULT_SOURCE_REGISTRY_HOST;
|
|
20
|
+
const portText = trimValue(parsed.port);
|
|
21
|
+
const port = portText ? Number(portText) : DEFAULT_SOURCE_REGISTRY_PORT;
|
|
22
|
+
return {
|
|
23
|
+
host,
|
|
24
|
+
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SOURCE_REGISTRY_PORT,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function trimValue(value) {
|
|
28
|
+
return String(value ?? '').trim();
|
|
29
|
+
}
|
|
30
|
+
function asPosixPathForDockerMount(value) {
|
|
31
|
+
return resolveCwd(value).replace(/\\/g, '/');
|
|
32
|
+
}
|
|
33
|
+
export function resolveSourceRegistryRootDir() {
|
|
34
|
+
return path.join(resolveCliHomeRoot(), 'verdaccio');
|
|
35
|
+
}
|
|
36
|
+
export function resolveSourceRegistryConfigPath() {
|
|
37
|
+
return path.join(resolveSourceRegistryRootDir(), 'config.yaml');
|
|
38
|
+
}
|
|
39
|
+
export function resolveSourceRegistryStorageDir() {
|
|
40
|
+
return path.join(resolveSourceRegistryRootDir(), 'storage');
|
|
41
|
+
}
|
|
42
|
+
export function resolveSourceRegistryUrl(host = DEFAULT_SOURCE_REGISTRY_HOST, port = DEFAULT_SOURCE_REGISTRY_PORT) {
|
|
43
|
+
return `http://${host}:${port}`;
|
|
44
|
+
}
|
|
45
|
+
export function getSourceRegistryInfo() {
|
|
46
|
+
const host = DEFAULT_SOURCE_REGISTRY_HOST;
|
|
47
|
+
const port = DEFAULT_SOURCE_REGISTRY_PORT;
|
|
48
|
+
const rootDir = resolveSourceRegistryRootDir();
|
|
49
|
+
return {
|
|
50
|
+
containerName: DEFAULT_SOURCE_REGISTRY_CONTAINER_NAME,
|
|
51
|
+
image: DEFAULT_SOURCE_REGISTRY_IMAGE,
|
|
52
|
+
host,
|
|
53
|
+
port,
|
|
54
|
+
url: resolveSourceRegistryUrl(host, port),
|
|
55
|
+
rootDir,
|
|
56
|
+
configPath: resolveSourceRegistryConfigPath(),
|
|
57
|
+
storageDir: resolveSourceRegistryStorageDir(),
|
|
58
|
+
status: 'missing',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function resolveSourceRegistryTemplatePath(cwd) {
|
|
62
|
+
return path.join(resolveProjectCwd(cwd), 'config.yaml');
|
|
63
|
+
}
|
|
64
|
+
function applySourceRegistryTemplateOverrides(template) {
|
|
65
|
+
return template
|
|
66
|
+
.replace(/\r\n/g, '\n')
|
|
67
|
+
.replace(/^storage:\s*.+$/m, 'storage: /verdaccio/storage')
|
|
68
|
+
.replace(/^(\s*)file:\s*\.\/*htpasswd\s*$/m, '$1file: /verdaccio/storage/htpasswd')
|
|
69
|
+
.replace(/^(\s*)publish:\s+\$authenticated\s*$/gm, '$1publish: $all')
|
|
70
|
+
.replace(/^(\s*)unpublish:\s+\$authenticated\s*$/gm, '$1unpublish: $all');
|
|
71
|
+
}
|
|
72
|
+
async function buildFallbackSourceRegistryConfigTemplate() {
|
|
73
|
+
return [
|
|
74
|
+
'storage: ./storage',
|
|
75
|
+
'auth:',
|
|
76
|
+
' htpasswd:',
|
|
77
|
+
' file: ./htpasswd',
|
|
78
|
+
'uplinks:',
|
|
79
|
+
' npmjs:',
|
|
80
|
+
' url: https://registry.npmmirror.com/',
|
|
81
|
+
'packages:',
|
|
82
|
+
" '@*/*':",
|
|
83
|
+
' access: $all',
|
|
84
|
+
' publish: $authenticated',
|
|
85
|
+
' unpublish: $authenticated',
|
|
86
|
+
' proxy: npmjs',
|
|
87
|
+
" '**':",
|
|
88
|
+
' access: $all',
|
|
89
|
+
' publish: $authenticated',
|
|
90
|
+
' unpublish: $authenticated',
|
|
91
|
+
' proxy: npmjs',
|
|
92
|
+
'server:',
|
|
93
|
+
' keepAliveTimeout: 60',
|
|
94
|
+
' dotfiles: ignore',
|
|
95
|
+
'max_body_size: 100mb',
|
|
96
|
+
'middlewares:',
|
|
97
|
+
' audit:',
|
|
98
|
+
' enabled: true',
|
|
99
|
+
'',
|
|
100
|
+
].join('\n');
|
|
101
|
+
}
|
|
102
|
+
export async function buildSourceRegistryConfig(cwd) {
|
|
103
|
+
const templatePath = resolveSourceRegistryTemplatePath(cwd);
|
|
104
|
+
try {
|
|
105
|
+
const template = await fsp.readFile(templatePath, 'utf8');
|
|
106
|
+
return applySourceRegistryTemplateOverrides(template);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
const fallback = await buildFallbackSourceRegistryConfigTemplate();
|
|
110
|
+
return applySourceRegistryTemplateOverrides(fallback);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export async function ensureSourceRegistryFiles(cwd) {
|
|
114
|
+
const info = getSourceRegistryInfo();
|
|
115
|
+
await fsp.mkdir(info.storageDir, { recursive: true });
|
|
116
|
+
await fsp.mkdir(info.rootDir, { recursive: true });
|
|
117
|
+
await fsp.writeFile(info.configPath, await buildSourceRegistryConfig(cwd), 'utf8');
|
|
118
|
+
return info;
|
|
119
|
+
}
|
|
120
|
+
export async function sourceRegistryContainerExists(containerName = DEFAULT_SOURCE_REGISTRY_CONTAINER_NAME) {
|
|
121
|
+
return await commandSucceeds('docker', ['container', 'inspect', containerName]);
|
|
122
|
+
}
|
|
123
|
+
export async function sourceRegistryContainerIsRunning(containerName = DEFAULT_SOURCE_REGISTRY_CONTAINER_NAME) {
|
|
124
|
+
try {
|
|
125
|
+
const output = await commandOutput('docker', ['inspect', '--format', '{{.State.Running}}', containerName], { errorName: 'docker inspect' });
|
|
126
|
+
return trimValue(output) === 'true';
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export async function resolveSourceRegistryInfo() {
|
|
133
|
+
const base = getSourceRegistryInfo();
|
|
134
|
+
if (!(await sourceRegistryContainerExists(base.containerName))) {
|
|
135
|
+
return base;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...base,
|
|
139
|
+
status: (await sourceRegistryContainerIsRunning(base.containerName)) ? 'running' : 'stopped',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export async function startSourceRegistry(options) {
|
|
143
|
+
const info = await ensureSourceRegistryFiles(options?.cwd);
|
|
144
|
+
const exists = await sourceRegistryContainerExists(info.containerName);
|
|
145
|
+
if (exists) {
|
|
146
|
+
if (await sourceRegistryContainerIsRunning(info.containerName)) {
|
|
147
|
+
return 'already-running';
|
|
148
|
+
}
|
|
149
|
+
await run('docker', ['start', info.containerName], {
|
|
150
|
+
errorName: 'docker start',
|
|
151
|
+
stdio: options?.stdio,
|
|
152
|
+
});
|
|
153
|
+
return 'started';
|
|
154
|
+
}
|
|
155
|
+
const configMount = `${asPosixPathForDockerMount(info.configPath)}:/verdaccio/conf/config.yaml`;
|
|
156
|
+
const storageMount = `${asPosixPathForDockerMount(info.storageDir)}:/verdaccio/storage`;
|
|
157
|
+
await run('docker', [
|
|
158
|
+
'run',
|
|
159
|
+
'-d',
|
|
160
|
+
'--name',
|
|
161
|
+
info.containerName,
|
|
162
|
+
'-p',
|
|
163
|
+
`${info.port}:4873`,
|
|
164
|
+
'-v',
|
|
165
|
+
configMount,
|
|
166
|
+
'-v',
|
|
167
|
+
storageMount,
|
|
168
|
+
info.image,
|
|
169
|
+
], {
|
|
170
|
+
errorName: 'docker run',
|
|
171
|
+
stdio: options?.stdio,
|
|
172
|
+
});
|
|
173
|
+
return 'started';
|
|
174
|
+
}
|
|
175
|
+
export async function stopSourceRegistry(options) {
|
|
176
|
+
const info = getSourceRegistryInfo();
|
|
177
|
+
if (!(await sourceRegistryContainerExists(info.containerName))) {
|
|
178
|
+
return 'already-stopped';
|
|
179
|
+
}
|
|
180
|
+
if (!(await sourceRegistryContainerIsRunning(info.containerName))) {
|
|
181
|
+
return 'already-stopped';
|
|
182
|
+
}
|
|
183
|
+
await run('docker', ['stop', info.containerName], {
|
|
184
|
+
errorName: 'docker stop',
|
|
185
|
+
stdio: options?.stdio,
|
|
186
|
+
});
|
|
187
|
+
return 'stopped';
|
|
188
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.1.0-alpha.
|
|
3
|
+
"version": "2.1.0-alpha.39",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"type": "git",
|
|
106
106
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
107
107
|
},
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "d06ed6b97030866c00e7ce40c9e1bcc773ebf12c"
|
|
109
109
|
}
|