@nocobase/app-installer 0.0.0-stage → 0.1.0-beta.4
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 +199 -2
- package/bin/run.js +43 -0
- package/dist/cli.js +168 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/install.js +319 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/rollback.js +284 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/status.js +132 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.js +549 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/lib/app-cli.js +89 -0
- package/dist/lib/app-cli.js.map +1 -0
- package/dist/lib/backup.js +167 -0
- package/dist/lib/backup.js.map +1 -0
- package/dist/lib/confirm.js +36 -0
- package/dist/lib/confirm.js.map +1 -0
- package/dist/lib/current-link.js +22 -0
- package/dist/lib/current-link.js.map +1 -0
- package/dist/lib/ecosystem.js +82 -0
- package/dist/lib/ecosystem.js.map +1 -0
- package/dist/lib/env-file.js +87 -0
- package/dist/lib/env-file.js.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/health.js +55 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/initial-admin.js +39 -0
- package/dist/lib/initial-admin.js.map +1 -0
- package/dist/lib/interrupt.js +50 -0
- package/dist/lib/interrupt.js.map +1 -0
- package/dist/lib/invocation.js +33 -0
- package/dist/lib/invocation.js.map +1 -0
- package/dist/lib/layout.js +48 -0
- package/dist/lib/layout.js.map +1 -0
- package/dist/lib/lock.js +59 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/mount-path.js +34 -0
- package/dist/lib/mount-path.js.map +1 -0
- package/dist/lib/output.js +61 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pm2.js +92 -0
- package/dist/lib/pm2.js.map +1 -0
- package/dist/lib/prechecks.js +199 -0
- package/dist/lib/prechecks.js.map +1 -0
- package/dist/lib/registry.js +9 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/release.js +173 -0
- package/dist/lib/release.js.map +1 -0
- package/dist/lib/run-command.js +108 -0
- package/dist/lib/run-command.js.map +1 -0
- package/dist/lib/service.js +100 -0
- package/dist/lib/service.js.map +1 -0
- package/dist/lib/source.js +44 -0
- package/dist/lib/source.js.map +1 -0
- package/dist/lib/state.js +84 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/version.js +51 -0
- package/dist/lib/version.js.map +1 -0
- package/package.json +51 -3
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, rename, rm } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { extract } from 'tar';
|
|
5
|
+
import { EXIT_INVALID, InstallerError, isInstallerError } from "./errors.js";
|
|
6
|
+
import { RELEASE_APP_DIR, releaseDir, releaseId, stagingDir, } from "./layout.js";
|
|
7
|
+
import { currentNodeMajor, rebuildCommandLine } from "./prechecks.js";
|
|
8
|
+
import { CommandFailedError, tail } from "./run-command.js";
|
|
9
|
+
/** Every official database dialect; each has its driver in `@nocobase/db-<dialect>`. */
|
|
10
|
+
export const DIALECTS = [
|
|
11
|
+
'sqlite',
|
|
12
|
+
'postgres',
|
|
13
|
+
'mysql',
|
|
14
|
+
'mssql',
|
|
15
|
+
'oracle',
|
|
16
|
+
'dameng',
|
|
17
|
+
'kingbase',
|
|
18
|
+
'oceanbase',
|
|
19
|
+
];
|
|
20
|
+
export function verifyBuildTarget(target, expected = {
|
|
21
|
+
platform: process.platform,
|
|
22
|
+
arch: process.arch,
|
|
23
|
+
nodeMajor: currentNodeMajor(),
|
|
24
|
+
}) {
|
|
25
|
+
if (!target ||
|
|
26
|
+
target.platform !== expected.platform ||
|
|
27
|
+
target.arch !== expected.arch ||
|
|
28
|
+
target.nodeMajor !== expected.nodeMajor) {
|
|
29
|
+
throw new InstallerError('BUILD_TARGET_MISMATCH', `The build targets ${target ? `${target.platform}-${target.arch} on Node ${target.nodeMajor}` : 'an unknown platform'}, but this machine is ${expected.platform}-${expected.arch} on Node ${expected.nodeMajor}.`);
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
}
|
|
33
|
+
export async function readReleaseManifest(dir) {
|
|
34
|
+
return JSON.parse(await readFile(path.join(dir, 'dist/package.json'), 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
function stepFailure(code, step, error) {
|
|
37
|
+
// An interrupt, or a failure that already says what went wrong, passes through as it is.
|
|
38
|
+
if (isInstallerError(error))
|
|
39
|
+
return error;
|
|
40
|
+
const output = error instanceof CommandFailedError
|
|
41
|
+
? tail(`${error.stdout}\n${error.stderr}`)
|
|
42
|
+
: undefined;
|
|
43
|
+
return new InstallerError(code, `${step} failed${error instanceof Error ? `: ${error.message}` : '.'}`, { cause: error, ...(output ? { details: { output } } : {}) });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Unpacks a deployment archive into a staging directory, reads which release it is from its manifest, checks that it
|
|
47
|
+
* was built for this machine, and moves it to `releases/<id>/app`. A release already on disk under the same id is the
|
|
48
|
+
* same build, so the staged copy is dropped and the existing one is used. Nothing here touches the running application,
|
|
49
|
+
* and on failure the staging directory is removed.
|
|
50
|
+
*/
|
|
51
|
+
export async function unpackRelease(options) {
|
|
52
|
+
const staging = stagingDir(options.layout);
|
|
53
|
+
const stagedApp = path.join(staging, RELEASE_APP_DIR);
|
|
54
|
+
await rm(staging, { recursive: true, force: true });
|
|
55
|
+
try {
|
|
56
|
+
await mkdir(stagedApp, { recursive: true });
|
|
57
|
+
try {
|
|
58
|
+
// The library `pnpm build --tar` packs with, so a deployment needs no `tar` of its own. Synchronous for the same
|
|
59
|
+
// reason the packing is: on a tree this size the promise form can leave the event loop with nothing pending.
|
|
60
|
+
extract({
|
|
61
|
+
file: options.archive,
|
|
62
|
+
cwd: stagedApp,
|
|
63
|
+
strict: true,
|
|
64
|
+
sync: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw stepFailure('UNPACK_FAILED', 'Unpacking the deployment archive', error);
|
|
69
|
+
}
|
|
70
|
+
let manifest;
|
|
71
|
+
try {
|
|
72
|
+
manifest = await readReleaseManifest(stagedApp);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new InstallerError('ARCHIVE_INVALID', `${options.archive} holds no dist/package.json; it is not a deployment archive from \`pnpm build --tar\`.`, { exitCode: EXIT_INVALID, cause: error });
|
|
76
|
+
}
|
|
77
|
+
let buildTarget;
|
|
78
|
+
try {
|
|
79
|
+
buildTarget = verifyBuildTarget(manifest.nocobase?.buildTarget);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (!isInstallerError(error))
|
|
83
|
+
throw error;
|
|
84
|
+
throw new InstallerError(error.code, error.message, {
|
|
85
|
+
exitCode: EXIT_INVALID,
|
|
86
|
+
suggestions: [
|
|
87
|
+
{
|
|
88
|
+
message: 'Build the archive for this machine in the application project, then run this again:',
|
|
89
|
+
run: rebuildCommandLine(),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const version = manifest.version ?? '0.0.0';
|
|
95
|
+
const builtAt = manifest.nocobase?.builtAt;
|
|
96
|
+
const relocatable = manifest.nocobase?.relocatable === true;
|
|
97
|
+
const basePath = relocatable ? undefined : manifest.nocobase?.basePath;
|
|
98
|
+
if (!builtAt || (!relocatable && !basePath) || !manifest.name) {
|
|
99
|
+
throw new InstallerError('ARCHIVE_TOO_OLD', `${options.archive} does not record where its client can be mounted and when it was built; it comes from a \`pnpm build\` older than app-installer needs.`, {
|
|
100
|
+
exitCode: EXIT_INVALID,
|
|
101
|
+
suggestions: [
|
|
102
|
+
{
|
|
103
|
+
message: 'Upgrade @nocobase/app-cli in the application project, build the archive again, then run this again:',
|
|
104
|
+
run: rebuildCommandLine(),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const id = releaseId(version, builtAt);
|
|
110
|
+
const dir = releaseDir(options.layout, id);
|
|
111
|
+
const reused = existsSync(dir);
|
|
112
|
+
if (!reused) {
|
|
113
|
+
await mkdir(options.layout.releasesDir, { recursive: true });
|
|
114
|
+
await rename(staging, path.dirname(dir));
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
id,
|
|
118
|
+
dir,
|
|
119
|
+
appName: manifest.name,
|
|
120
|
+
version,
|
|
121
|
+
builtAt,
|
|
122
|
+
relocatable,
|
|
123
|
+
...(basePath === undefined ? {} : { basePath }),
|
|
124
|
+
buildTarget,
|
|
125
|
+
reused,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await rm(staging, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A deployment archive carries its database drivers in `dist/node_modules`, installed when it was built; nothing adds
|
|
134
|
+
* one afterwards. A dialect whose driver is absent would fail only when the application first connects.
|
|
135
|
+
*/
|
|
136
|
+
export function checkArchiveDriver(dir, dialect) {
|
|
137
|
+
if (dialect === 'sqlite')
|
|
138
|
+
return;
|
|
139
|
+
const driver = `@nocobase/db-${dialect}`;
|
|
140
|
+
if (existsSync(path.join(dir, 'dist/node_modules', driver, 'package.json'))) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
throw new InstallerError('DRIVER_MISSING', `The archive holds no ${driver}, which the ${dialect} dialect needs; a deployment archive carries the drivers it was built with.`, {
|
|
144
|
+
exitCode: EXIT_INVALID,
|
|
145
|
+
suggestions: [
|
|
146
|
+
{
|
|
147
|
+
message: 'Add the driver in the application project:',
|
|
148
|
+
run: { command: 'pnpm', args: ['add', driver] },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
message: 'Then build the archive again:',
|
|
152
|
+
run: rebuildCommandLine(),
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* A release older than `APP_STORAGE_DIR` ignores it and keeps its data in `storage/` beside `dist/`, inside the release
|
|
159
|
+
* directory, where the next upgrade would leave it behind. Its first database write shows it.
|
|
160
|
+
*/
|
|
161
|
+
export function assertStorageOutsideRelease(dir) {
|
|
162
|
+
if (!existsSync(path.join(dir, 'storage')))
|
|
163
|
+
return;
|
|
164
|
+
throw new InstallerError('STORAGE_IN_RELEASE', `The release wrote its data into ${path.join(dir, 'storage')} instead of the installation's storage directory: its @nocobase/app-server predates APP_STORAGE_DIR.`, {
|
|
165
|
+
suggestions: [
|
|
166
|
+
{
|
|
167
|
+
message: 'Upgrade @nocobase/app-server and @nocobase/app-cli in the application project, then build the archive again:',
|
|
168
|
+
run: rebuildCommandLine(),
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/lib/release.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { interruptError, onInterrupt, takeInterrupt } from "./interrupt.js";
|
|
3
|
+
export class CommandFailedError extends Error {
|
|
4
|
+
command;
|
|
5
|
+
exitCode;
|
|
6
|
+
stdout;
|
|
7
|
+
stderr;
|
|
8
|
+
constructor(command, exitCode, stdout, stderr, reason) {
|
|
9
|
+
super(reason ??
|
|
10
|
+
`${command} failed${exitCode === null ? '' : ` with exit code ${exitCode}`}.`);
|
|
11
|
+
this.name = 'CommandFailedError';
|
|
12
|
+
this.command = command;
|
|
13
|
+
this.exitCode = exitCode;
|
|
14
|
+
this.stdout = stdout;
|
|
15
|
+
this.stderr = stderr;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** How long a stopped command's process group gets to exit after SIGTERM before it is killed. */
|
|
19
|
+
const KILL_GRACE_MS = 10_000;
|
|
20
|
+
/**
|
|
21
|
+
* Signals the child's whole process group. `pnpm build` runs `tsc`, `vite` and native builds as its own children; killing
|
|
22
|
+
* only `pnpm` would leave them writing into a directory the caller is about to remove.
|
|
23
|
+
*/
|
|
24
|
+
function signalGroup(child, signal) {
|
|
25
|
+
if (child.pid === undefined)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
process.kill(-child.pid, signal);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
child.kill(signal);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Runs a child process, collecting its output, and rejects with `CommandFailedError` on a non-zero exit. The child leads
|
|
36
|
+
* its own process group, so a timeout or an interrupt stops everything it started, and the promise settles only once
|
|
37
|
+
* the group has exited.
|
|
38
|
+
*/
|
|
39
|
+
export const runCommand = (command, args, options = {}) => new Promise((resolve, reject) => {
|
|
40
|
+
const label = [command, ...args].join(' ');
|
|
41
|
+
if (takeInterrupt()) {
|
|
42
|
+
reject(interruptError());
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const child = spawn(command, args, {
|
|
46
|
+
cwd: options.cwd,
|
|
47
|
+
env: options.env,
|
|
48
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
49
|
+
detached: true,
|
|
50
|
+
});
|
|
51
|
+
let stdout = '';
|
|
52
|
+
let stderr = '';
|
|
53
|
+
let stopReason;
|
|
54
|
+
let killTimer;
|
|
55
|
+
const stop = (reason) => {
|
|
56
|
+
if (stopReason)
|
|
57
|
+
return;
|
|
58
|
+
stopReason = reason;
|
|
59
|
+
signalGroup(child, 'SIGTERM');
|
|
60
|
+
killTimer = setTimeout(() => signalGroup(child, 'SIGKILL'), KILL_GRACE_MS);
|
|
61
|
+
killTimer.unref();
|
|
62
|
+
};
|
|
63
|
+
const timer = options.timeoutMs
|
|
64
|
+
? setTimeout(() => stop('timeout'), options.timeoutMs)
|
|
65
|
+
: undefined;
|
|
66
|
+
timer?.unref();
|
|
67
|
+
const stopListening = onInterrupt(() => stop('interrupt'));
|
|
68
|
+
child.stdout.on('data', (chunk) => {
|
|
69
|
+
stdout += chunk.toString();
|
|
70
|
+
options.echo?.write(chunk);
|
|
71
|
+
});
|
|
72
|
+
child.stderr.on('data', (chunk) => {
|
|
73
|
+
stderr += chunk.toString();
|
|
74
|
+
options.echo?.write(chunk);
|
|
75
|
+
});
|
|
76
|
+
const settle = () => {
|
|
77
|
+
clearTimeout(timer);
|
|
78
|
+
clearTimeout(killTimer);
|
|
79
|
+
stopListening();
|
|
80
|
+
};
|
|
81
|
+
child.once('error', (error) => {
|
|
82
|
+
settle();
|
|
83
|
+
reject(error);
|
|
84
|
+
});
|
|
85
|
+
child.once('close', (code) => {
|
|
86
|
+
settle();
|
|
87
|
+
if (stopReason === 'interrupt') {
|
|
88
|
+
// The interrupt is this step's failure; later recovery steps must not see it again.
|
|
89
|
+
takeInterrupt();
|
|
90
|
+
reject(interruptError());
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (stopReason === 'timeout') {
|
|
94
|
+
reject(new CommandFailedError(label, code, stdout, stderr, `${label} timed out after ${Math.round(options.timeoutMs / 1000)}s.`));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (code === 0) {
|
|
98
|
+
resolve({ stdout, stderr });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
reject(new CommandFailedError(label, code, stdout, stderr));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
/** The last `lines` lines of a command's output, for an error message that has to fit on a screen. */
|
|
105
|
+
export function tail(text, lines = 20) {
|
|
106
|
+
return text.trimEnd().split('\n').slice(-lines).join('\n');
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=run-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/lib/run-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { realpathSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { EXIT_INVALID, InstallerError, } from "./errors.js";
|
|
5
|
+
import { checkHealth, pm2StartFailed, waitForHealthy } from "./health.js";
|
|
6
|
+
import { interruptError, takeInterrupt } from "./interrupt.js";
|
|
7
|
+
import { tail } from "./run-command.js";
|
|
8
|
+
function sameDirectory(a, b) {
|
|
9
|
+
const real = (dir) => {
|
|
10
|
+
try {
|
|
11
|
+
return realpathSync(dir);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return path.resolve(dir);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
return real(a) === real(b);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The pm2 process under the installation's name must be this installation's. Otherwise stopping it would stop another
|
|
21
|
+
* application, and `pm2 start` on the taken name would restart that process with this one's configuration.
|
|
22
|
+
*/
|
|
23
|
+
export async function checkPm2Ownership(options) {
|
|
24
|
+
const known = await options.pm2.describe(options.name);
|
|
25
|
+
if (known?.cwd && !sameDirectory(known.cwd, options.layout.root)) {
|
|
26
|
+
throw new InstallerError('PM2_NAME_IN_USE', `The pm2 process ${options.name} runs from ${known.cwd}, not from ${options.layout.root}.`, {
|
|
27
|
+
exitCode: EXIT_INVALID,
|
|
28
|
+
suggestions: [
|
|
29
|
+
{
|
|
30
|
+
message: `Stop that process or rename it; installer.json names ${options.name} for this installation.`,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Stops the application and waits until its health route stops answering. pm2 sends SIGINT and allows `kill_timeout`
|
|
38
|
+
* for it to finish what it is doing. An application pm2 does not know, such as one installed with `--no-start`, is
|
|
39
|
+
* simply not running.
|
|
40
|
+
*/
|
|
41
|
+
export async function stopApp(options) {
|
|
42
|
+
const known = await options.pm2.describe(options.name);
|
|
43
|
+
if (known)
|
|
44
|
+
await options.pm2.stop(options.name);
|
|
45
|
+
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
46
|
+
if (takeInterrupt())
|
|
47
|
+
throw interruptError();
|
|
48
|
+
if (!(await checkHealth(options.healthUrl, options.fetchImpl)))
|
|
49
|
+
return;
|
|
50
|
+
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`${options.healthUrl} still answers after stopping ${options.name}; another process may be serving the application's port.`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Starts whatever `current` points at and waits for it to be healthy. The process entry is deleted and registered again
|
|
56
|
+
* rather than restarted, so pm2's restart count starts from zero — the crash detection reads it — and a changed
|
|
57
|
+
* `ecosystem.config.cjs` is read again. A process pm2 reports as crashed ends the wait early.
|
|
58
|
+
*/
|
|
59
|
+
export async function startApp(options) {
|
|
60
|
+
await options.pm2.remove(options.name);
|
|
61
|
+
await options.pm2.start(options.layout.ecosystemFile, options.layout.root);
|
|
62
|
+
const healthy = await waitForHealthy(options.healthUrl, {
|
|
63
|
+
timeoutMs: options.timeoutMs,
|
|
64
|
+
fetchImpl: options.fetchImpl,
|
|
65
|
+
failed: pm2StartFailed(options.pm2, options.name),
|
|
66
|
+
});
|
|
67
|
+
if (healthy) {
|
|
68
|
+
await options.pm2.save();
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// A release that cannot start would otherwise be restarted by pm2 until it gives up.
|
|
72
|
+
await options.pm2.remove(options.name).catch(() => undefined);
|
|
73
|
+
}
|
|
74
|
+
return healthy;
|
|
75
|
+
}
|
|
76
|
+
export async function errorLogTail(layout) {
|
|
77
|
+
const text = await readFile(layout.errorLog, 'utf8').catch(() => '');
|
|
78
|
+
return tail(text, 30);
|
|
79
|
+
}
|
|
80
|
+
/** The command that shows more of the error log than `details.log` carries. */
|
|
81
|
+
export function errorLogCommandLine(layout) {
|
|
82
|
+
return { command: 'tail', args: ['-n', '100', layout.errorLog] };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* How to start the installation by hand once the cause is fixed. Two steps, since a suggestion runs one command: pm2
|
|
86
|
+
* starts it, then saves the process list so that `pm2 startup` brings it back after a reboot.
|
|
87
|
+
*/
|
|
88
|
+
export function startAdvice(layout, message) {
|
|
89
|
+
return [
|
|
90
|
+
{
|
|
91
|
+
message,
|
|
92
|
+
run: { command: 'pm2', args: ['start', layout.ecosystemFile] },
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
message: 'Then save the process list, so pm2 restores it after a reboot:',
|
|
96
|
+
run: { command: 'pm2', args: ['save'] },
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/lib/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { statSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { EXIT_INVALID, InstallerError } from "./errors.js";
|
|
4
|
+
import { quoteForShell } from '@nocobase/cli-envelope';
|
|
5
|
+
import { installerCommand } from "./invocation.js";
|
|
6
|
+
import { rebuildCommandLine } from "./prechecks.js";
|
|
7
|
+
/**
|
|
8
|
+
* The archive `--archive` names, as an absolute path to a file that exists. Only a local path is accepted for now:
|
|
9
|
+
* fetching one would need downloads, credentials and checksums of its own.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveArchivePath(cwd, value) {
|
|
12
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//iu.test(value)) {
|
|
13
|
+
throw new InstallerError('INVALID_USAGE', `--archive takes a local path; download ${value} to the server first.`, { exitCode: EXIT_INVALID });
|
|
14
|
+
}
|
|
15
|
+
const file = path.resolve(cwd, value);
|
|
16
|
+
let isFile = false;
|
|
17
|
+
try {
|
|
18
|
+
isFile = statSync(file).isFile();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Reported below.
|
|
22
|
+
}
|
|
23
|
+
if (!isFile) {
|
|
24
|
+
throw new InstallerError('ARCHIVE_NOT_FOUND', `${file} is not a file. Pass the deployment archive \`pnpm build --tar\` wrote to storage/exports/dist.tar.gz.`, { exitCode: EXIT_INVALID });
|
|
25
|
+
}
|
|
26
|
+
return file;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* How to get a release that runs on this machine's Node: the archive is built again, in the application project, and
|
|
30
|
+
* the installation upgrades to it.
|
|
31
|
+
*/
|
|
32
|
+
export function nodeRebuildAdvice(state, root) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
message: 'Build the archive again for this machine, in the application project:',
|
|
36
|
+
run: rebuildCommandLine(),
|
|
37
|
+
},
|
|
38
|
+
// No `run`: a suggestion's command runs as given, and the archive's path is not known here.
|
|
39
|
+
{
|
|
40
|
+
message: `Then copy it here and upgrade to it: ${installerCommand(`upgrade --dir ${quoteForShell(root)} --archive <the copied archive>`, { registry: state.registry })}`,
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/lib/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,cAAc,EAAmB,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,KAAa;IAC3D,IAAI,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,cAAc,CACtB,eAAe,EACf,0CAA0C,KAAK,uBAAuB,EACtE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAC3B,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,cAAc,CACtB,mBAAmB,EACnB,GAAG,IAAI,wGAAwG,EAC/G,EAAE,QAAQ,EAAE,YAAY,EAAE,CAC3B,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAuC,EACvC,IAAY;IAEZ,OAAO;QACL;YACE,OAAO,EACL,uEAAuE;YACzE,GAAG,EAAE,kBAAkB,EAAE;SAC1B;QACD,4FAA4F;QAC5F;YACE,OAAO,EAAE,wCAAwC,gBAAgB,CAAC,iBAAiB,aAAa,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE;SACzK;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readFile, rename, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { EXIT_INVALID, InstallerError } from "./errors.js";
|
|
3
|
+
import { installerCommandLine } from "./invocation.js";
|
|
4
|
+
import { compareVersions } from "./version.js";
|
|
5
|
+
/** Where a release has to be mounted, or `undefined` when it can be mounted anywhere. */
|
|
6
|
+
export function fixedMountPathOf(record, state) {
|
|
7
|
+
return record.relocatable ? undefined : (record.basePath ?? state.basePath);
|
|
8
|
+
}
|
|
9
|
+
export async function readState(layout) {
|
|
10
|
+
let text;
|
|
11
|
+
try {
|
|
12
|
+
text = await readFile(layout.stateFile, 'utf8');
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code === 'ENOENT') {
|
|
16
|
+
throw new InstallerError('NOT_INSTALLED', `${layout.root} holds no application installed by app-installer (installer.json is missing).`, {
|
|
17
|
+
exitCode: EXIT_INVALID,
|
|
18
|
+
suggestions: [
|
|
19
|
+
{
|
|
20
|
+
message: 'Run the command from the installation root, or name it with --dir.',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
const state = JSON.parse(text);
|
|
28
|
+
if (state.schemaVersion !== 1) {
|
|
29
|
+
throw new InstallerError('STATE_UNSUPPORTED', `installer.json has schemaVersion ${String(state.schemaVersion)}, which this app-installer does not understand.`, {
|
|
30
|
+
exitCode: EXIT_INVALID,
|
|
31
|
+
suggestions: [
|
|
32
|
+
{
|
|
33
|
+
message: 'Use a newer app-installer:',
|
|
34
|
+
run: installerCommandLine(['status', '--dir', layout.root], {
|
|
35
|
+
version: 'latest',
|
|
36
|
+
...(typeof state.registry === 'string'
|
|
37
|
+
? { registry: state.registry }
|
|
38
|
+
: {}),
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// `{ kind: 'template' }` was the published Hub template built on the server, which this installer no longer offers.
|
|
45
|
+
if (state.source.kind !== 'archive') {
|
|
46
|
+
throw new InstallerError('STATE_UNSUPPORTED', `${layout.root} was installed from a published template, which this app-installer no longer builds; it manages installations from deployment archives only.`, {
|
|
47
|
+
exitCode: EXIT_INVALID,
|
|
48
|
+
suggestions: [
|
|
49
|
+
{
|
|
50
|
+
message: 'Keep managing it with the app-installer version that installed it, or install the application again from a deployment archive built by `pnpm build --tar`.',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
57
|
+
/** Writes the state through a temporary file and a rename, so a crash never leaves half a document behind. */
|
|
58
|
+
export async function writeState(layout, state) {
|
|
59
|
+
const temporary = `${layout.stateFile}.${process.pid}.tmp`;
|
|
60
|
+
await writeFile(temporary, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
61
|
+
await rename(temporary, layout.stateFile);
|
|
62
|
+
}
|
|
63
|
+
export function findRelease(state, id) {
|
|
64
|
+
return state.releases.find((record) => record.id === id);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The release a `--to` names: an id exactly, or a version, meaning the newest build of it on record other than the
|
|
68
|
+
* running one. A version is what a person remembers; the id is what `status` prints when two builds of one version are
|
|
69
|
+
* on disk. Rolling back "to 1.0.0" while a later build of 1.0.0 runs means the earlier build, not the one already running.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveReleaseRef(state, ref) {
|
|
72
|
+
const exact = findRelease(state, ref);
|
|
73
|
+
if (exact)
|
|
74
|
+
return exact;
|
|
75
|
+
const builds = [...state.releases]
|
|
76
|
+
.filter((record) => record.version === ref)
|
|
77
|
+
.sort((a, b) => b.builtAt.localeCompare(a.builtAt));
|
|
78
|
+
return builds.find((record) => record.id !== state.current) ?? builds[0];
|
|
79
|
+
}
|
|
80
|
+
/** Semantic-version order of two releases' versions; builds of one version compare equal. */
|
|
81
|
+
export function compareReleaseVersions(a, b) {
|
|
82
|
+
return compareVersions(a.version, b.version) ?? 0;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/lib/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function parse(version) {
|
|
2
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/u.exec(version.trim());
|
|
3
|
+
if (!match)
|
|
4
|
+
return undefined;
|
|
5
|
+
return {
|
|
6
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
7
|
+
prerelease: match[4] ? match[4].split('.') : [],
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function compareIdentifiers(a, b) {
|
|
11
|
+
const numeric = /^\d+$/u;
|
|
12
|
+
if (numeric.test(a) && numeric.test(b))
|
|
13
|
+
return Number(a) - Number(b);
|
|
14
|
+
if (numeric.test(a))
|
|
15
|
+
return -1;
|
|
16
|
+
if (numeric.test(b))
|
|
17
|
+
return 1;
|
|
18
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Semantic version order: negative when `a` sorts first, positive when `b` does, zero when equal, and `undefined` when
|
|
22
|
+
* either is not a version at all. A prerelease sorts below its release, and `1.0.0-beta.10` above `1.0.0-beta.9`.
|
|
23
|
+
*/
|
|
24
|
+
export function compareVersions(a, b) {
|
|
25
|
+
const left = parse(a);
|
|
26
|
+
const right = parse(b);
|
|
27
|
+
if (!left || !right)
|
|
28
|
+
return undefined;
|
|
29
|
+
for (let index = 0; index < 3; index += 1) {
|
|
30
|
+
const difference = left.core[index] - right.core[index];
|
|
31
|
+
if (difference !== 0)
|
|
32
|
+
return difference;
|
|
33
|
+
}
|
|
34
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
35
|
+
return right.prerelease.length - left.prerelease.length;
|
|
36
|
+
}
|
|
37
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
38
|
+
for (let index = 0; index < length; index += 1) {
|
|
39
|
+
const x = left.prerelease[index];
|
|
40
|
+
const y = right.prerelease[index];
|
|
41
|
+
if (x === undefined)
|
|
42
|
+
return -1;
|
|
43
|
+
if (y === undefined)
|
|
44
|
+
return 1;
|
|
45
|
+
const difference = compareIdentifiers(x, y);
|
|
46
|
+
if (difference !== 0)
|
|
47
|
+
return difference;
|
|
48
|
+
}
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"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"}
|