@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,132 @@
|
|
|
1
|
+
import { lstat, readdir } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { readCurrent } from "../lib/current-link.js";
|
|
5
|
+
import { endpointsOf, healthUrl, mountPathOf, readAppEnv, } from "../lib/env-file.js";
|
|
6
|
+
import { checkHealth } from "../lib/health.js";
|
|
7
|
+
import { formatCommandLine, quoteForShell } from '@nocobase/cli-envelope';
|
|
8
|
+
import { installerCommand } from "../lib/invocation.js";
|
|
9
|
+
import { layoutOf, releaseDir } from "../lib/layout.js";
|
|
10
|
+
import { currentNodeMajor } from "../lib/prechecks.js";
|
|
11
|
+
import { nodeRebuildAdvice } from "../lib/source.js";
|
|
12
|
+
import { findRelease, readState } from "../lib/state.js";
|
|
13
|
+
export const STATUS_FLAGS = {
|
|
14
|
+
dir: Flags.string({
|
|
15
|
+
description: 'Installation root managed by app-installer. Defaults to the current directory.',
|
|
16
|
+
}),
|
|
17
|
+
json: Flags.boolean({
|
|
18
|
+
default: false,
|
|
19
|
+
description: 'Print one JSON result on stdout.',
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
/** Bytes used by a directory tree, not following symbolic links. */
|
|
23
|
+
export async function directorySize(dir) {
|
|
24
|
+
let total = 0;
|
|
25
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
const full = path.join(dir, entry.name);
|
|
28
|
+
if (entry.isDirectory()) {
|
|
29
|
+
total += await directorySize(full);
|
|
30
|
+
}
|
|
31
|
+
else if (entry.isFile()) {
|
|
32
|
+
total += (await lstat(full)).size;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return total;
|
|
36
|
+
}
|
|
37
|
+
function formatSize(bytes) {
|
|
38
|
+
return bytes >= 1024 ** 3
|
|
39
|
+
? `${(bytes / 1024 ** 3).toFixed(1)} GB`
|
|
40
|
+
: `${Math.round(bytes / 1024 ** 2)} MB`;
|
|
41
|
+
}
|
|
42
|
+
export async function status(input, deps) {
|
|
43
|
+
const root = path.resolve(deps.cwd ?? process.cwd(), input.flags.dir ?? '.');
|
|
44
|
+
const layout = layoutOf(root);
|
|
45
|
+
const state = await readState(layout);
|
|
46
|
+
const env = await readAppEnv(layout);
|
|
47
|
+
const link = await readCurrent(layout);
|
|
48
|
+
const releases = [];
|
|
49
|
+
for (const record of state.releases) {
|
|
50
|
+
const dir = releaseDir(layout, record.id);
|
|
51
|
+
releases.push({
|
|
52
|
+
id: record.id,
|
|
53
|
+
version: record.version,
|
|
54
|
+
current: record.id === state.current,
|
|
55
|
+
builtAt: record.builtAt,
|
|
56
|
+
installedAt: record.installedAt,
|
|
57
|
+
nodeMajor: record.buildTarget.nodeMajor,
|
|
58
|
+
sizeBytes: await directorySize(dir),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const backups = (await readdir(layout.backupsDir).catch(() => [])).sort();
|
|
62
|
+
const endpoints = endpointsOf(env);
|
|
63
|
+
if (endpoints.port === null) {
|
|
64
|
+
deps.reporter.warn(`APP_SERVER_PORT in app.env is "${env.APP_SERVER_PORT ?? ''}", which is not a port number; the application cannot listen on it.`);
|
|
65
|
+
}
|
|
66
|
+
const url = healthUrl(env);
|
|
67
|
+
const healthy = await checkHealth(url, deps.fetchImpl);
|
|
68
|
+
let processInfo = null;
|
|
69
|
+
try {
|
|
70
|
+
processInfo = (await deps.pm2.describe(state.name)) ?? null;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
deps.reporter.warn('pm2 could not be queried; process state is unknown.');
|
|
74
|
+
}
|
|
75
|
+
if (state.pending) {
|
|
76
|
+
deps.reporter.warn(`${state.pending.action === 'upgrade' ? 'An' : 'A'} ${state.pending.action} from ${state.pending.from} to ${state.pending.to}, started ${state.pending.startedAt}, did not finish. Recover with \`${installerCommand(`rollback --dir ${quoteForShell(root)}`, { registry: state.registry })}\`: it undoes an interrupted upgrade and finishes an interrupted rollback.`);
|
|
77
|
+
}
|
|
78
|
+
const currentRelease = findRelease(state, state.current);
|
|
79
|
+
const nodeMajor = currentNodeMajor();
|
|
80
|
+
const nodeMatches = currentRelease?.buildTarget.nodeMajor === nodeMajor;
|
|
81
|
+
if (!nodeMatches) {
|
|
82
|
+
const advice = nodeRebuildAdvice(state, root)
|
|
83
|
+
.map((step) => step.run
|
|
84
|
+
? `${step.message} \`${formatCommandLine(step.run)}\``
|
|
85
|
+
: step.message)
|
|
86
|
+
.join(' ');
|
|
87
|
+
deps.reporter.warn(`The current release was built for Node ${currentRelease?.buildTarget.nodeMajor ?? '?'}, but this machine runs Node ${nodeMajor}; it will not load its native modules until a release built for this machine replaces it. ${advice}`);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
status: 'success',
|
|
91
|
+
result: {
|
|
92
|
+
directory: root,
|
|
93
|
+
name: state.name,
|
|
94
|
+
appName: state.appName,
|
|
95
|
+
// Where the application is mounted now, as app.env says; installer.json keeps the path it was installed at.
|
|
96
|
+
basePath: mountPathOf(env) || '/',
|
|
97
|
+
source: state.source,
|
|
98
|
+
current: state.current,
|
|
99
|
+
version: currentRelease?.version ?? null,
|
|
100
|
+
builtAt: currentRelease?.builtAt ?? null,
|
|
101
|
+
currentLink: link ?? null,
|
|
102
|
+
dialect: state.dialect,
|
|
103
|
+
registry: state.registry,
|
|
104
|
+
endpoints,
|
|
105
|
+
releases,
|
|
106
|
+
backups,
|
|
107
|
+
health: { url, ok: healthy },
|
|
108
|
+
process: processInfo,
|
|
109
|
+
node: {
|
|
110
|
+
machine: nodeMajor,
|
|
111
|
+
release: currentRelease?.buildTarget.nodeMajor ?? null,
|
|
112
|
+
matches: nodeMatches,
|
|
113
|
+
},
|
|
114
|
+
pending: state.pending ?? null,
|
|
115
|
+
},
|
|
116
|
+
summary: [
|
|
117
|
+
`The application ${state.appName} ${currentRelease?.version ?? '?'} at ${root}`,
|
|
118
|
+
` Release ${state.current}${currentRelease ? `, built ${currentRelease.builtAt}` : ''}`,
|
|
119
|
+
' Source deployment archives',
|
|
120
|
+
` URL ${endpoints.url} (listening on ${endpoints.host}:${endpoints.port ?? `invalid port "${env.APP_SERVER_PORT ?? ''}"`})`,
|
|
121
|
+
` Health ${healthy ? 'ok' : 'not answering'} (${url})`,
|
|
122
|
+
` Process ${processInfo ? `${processInfo.status}, pid ${processInfo.pid}, ${processInfo.restarts} restarts` : 'not registered with pm2'} (${state.name})`,
|
|
123
|
+
` Node machine ${nodeMajor}, release ${currentRelease?.buildTarget.nodeMajor ?? '?'}${nodeMatches ? '' : ' — mismatch'}`,
|
|
124
|
+
' Releases',
|
|
125
|
+
...releases.map((release) => ` ${release.current ? '*' : ' '} ${release.id} ${formatSize(release.sizeBytes)} installed ${release.installedAt}`),
|
|
126
|
+
...(backups.length > 0
|
|
127
|
+
? [' Backups', ...backups.map((backup) => ` ${backup}`)]
|
|
128
|
+
: []),
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|