apteva 0.11.2 → 0.12.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/cli.js +46 -11
- package/install.js +102 -24
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
// cli.js — npm shim. The user runs `apteva` (or `npx apteva`); npm
|
|
5
|
+
// resolves it to this file via package.json's "bin" field, and we
|
|
6
|
+
// hand off to the Go binary.
|
|
7
|
+
//
|
|
8
|
+
// Path resolution order:
|
|
9
|
+
//
|
|
10
|
+
// 1. ~/.apteva/bin/apteva — the load-bearing symlink chain that
|
|
11
|
+
// `apteva update` flips. Preferred so `apteva update` followed
|
|
12
|
+
// by re-running `apteva` actually picks up the new version
|
|
13
|
+
// (vs running the stale __dirname copy from npm's install).
|
|
14
|
+
//
|
|
15
|
+
// 2. __dirname/apteva — the defensive copy install.js drops into
|
|
16
|
+
// npm's package install dir. Fallback for environments where
|
|
17
|
+
// ~/.apteva can't host symlinks (CI, restricted containers,
|
|
18
|
+
// Windows without elevated privileges).
|
|
19
|
+
//
|
|
20
|
+
// APTEVA_SERVER_BIN / APTEVA_CORE_BIN propagate to the Go process
|
|
21
|
+
// so its findServerBinary / findCoreBinary helpers prefer the
|
|
22
|
+
// symlinked siblings rather than re-resolving against $PATH.
|
|
23
|
+
|
|
4
24
|
const os = require("os");
|
|
5
25
|
const path = require("path");
|
|
6
26
|
const fs = require("fs");
|
|
@@ -8,29 +28,44 @@ const { spawnSync } = require("child_process");
|
|
|
8
28
|
|
|
9
29
|
const ext = os.platform() === "win32" ? ".exe" : "";
|
|
10
30
|
const DIR = __dirname;
|
|
31
|
+
const APTEVA_HOME = process.env.APTEVA_HOME || path.join(os.homedir(), ".apteva");
|
|
32
|
+
const SYMLINKED_BIN_DIR = path.join(APTEVA_HOME, "bin");
|
|
33
|
+
|
|
34
|
+
function resolveBin(name) {
|
|
35
|
+
const linked = path.join(SYMLINKED_BIN_DIR, `${name}${ext}`);
|
|
36
|
+
// Use the symlink path even if the target is missing — when
|
|
37
|
+
// present, it's the canonical "active version" pointer that
|
|
38
|
+
// `apteva update` rewrites. fs.existsSync follows symlinks, so
|
|
39
|
+
// we get a positive hit only when the entire chain resolves.
|
|
40
|
+
if (fs.existsSync(linked)) return linked;
|
|
41
|
+
// Fallback: the per-package copy install.js dropped here.
|
|
42
|
+
const local = path.join(DIR, `${name}${ext}`);
|
|
43
|
+
if (fs.existsSync(local)) return local;
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
11
46
|
|
|
12
|
-
const aptevaBin =
|
|
13
|
-
const serverBin =
|
|
14
|
-
const coreBin =
|
|
47
|
+
const aptevaBin = resolveBin("apteva");
|
|
48
|
+
const serverBin = resolveBin("apteva-server");
|
|
49
|
+
const coreBin = resolveBin("apteva-core");
|
|
15
50
|
|
|
16
|
-
if (!
|
|
17
|
-
console.error(
|
|
51
|
+
if (!aptevaBin) {
|
|
52
|
+
console.error("apteva: binary not found — symlinks at ~/.apteva/bin/ and the npm install dir are both empty.");
|
|
18
53
|
console.error("Try: npm install -g apteva");
|
|
19
54
|
process.exit(1);
|
|
20
55
|
}
|
|
21
|
-
if (!
|
|
22
|
-
console.error(`apteva: warning - server binary not found
|
|
56
|
+
if (!serverBin) {
|
|
57
|
+
console.error(`apteva: warning - server binary not found`);
|
|
23
58
|
}
|
|
24
|
-
if (!
|
|
25
|
-
console.error(`apteva: warning - core binary not found
|
|
59
|
+
if (!coreBin) {
|
|
60
|
+
console.error(`apteva: warning - core binary not found`);
|
|
26
61
|
}
|
|
27
62
|
|
|
28
63
|
const result = spawnSync(aptevaBin, process.argv.slice(2), {
|
|
29
64
|
stdio: "inherit",
|
|
30
65
|
env: {
|
|
31
66
|
...process.env,
|
|
32
|
-
APTEVA_SERVER_BIN: serverBin,
|
|
33
|
-
APTEVA_CORE_BIN: coreBin,
|
|
67
|
+
APTEVA_SERVER_BIN: serverBin || "",
|
|
68
|
+
APTEVA_CORE_BIN: coreBin || "",
|
|
34
69
|
},
|
|
35
70
|
});
|
|
36
71
|
|
package/install.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
// install.js — npm postinstall hook.
|
|
5
|
+
//
|
|
6
|
+
// Downloads the platform tarball for `apteva@<VERSION>` from
|
|
7
|
+
// GitHub releases and unpacks it into ~/.apteva/versions/<VERSION>/.
|
|
8
|
+
// Sets up the symlink chain
|
|
9
|
+
//
|
|
10
|
+
// ~/.apteva/bin/current → ../versions/<VERSION>
|
|
11
|
+
// ~/.apteva/bin/apteva → current/apteva
|
|
12
|
+
// ~/.apteva/bin/apteva-server → current/apteva-server
|
|
13
|
+
// ~/.apteva/bin/apteva-core → current/apteva-core
|
|
14
|
+
//
|
|
15
|
+
// so cli.js (and `apteva update`'s atomic-flip path, and any systemd
|
|
16
|
+
// unit that points at ~/.apteva/bin/apteva-server) all resolve to
|
|
17
|
+
// the right binary regardless of which version is "active".
|
|
18
|
+
//
|
|
19
|
+
// Pre-v0.12, the layout was ~/.apteva/bin/<v>/<binaries> and the
|
|
20
|
+
// install dir held its own copies. We still drop copies into the
|
|
21
|
+
// install dir as a defensive fallback — cli.js prefers the symlink
|
|
22
|
+
// path but falls back to __dirname for environments where home
|
|
23
|
+
// isn't writable (CI, restricted containers, etc).
|
|
24
|
+
|
|
4
25
|
const os = require("os");
|
|
5
26
|
const fs = require("fs");
|
|
6
27
|
const path = require("path");
|
|
@@ -15,6 +36,17 @@ const DIR = __dirname;
|
|
|
15
36
|
const PLATFORM_MAP = { linux: "linux", darwin: "darwin", win32: "windows" };
|
|
16
37
|
const ARCH_MAP = { x64: "amd64", arm64: "arm64" };
|
|
17
38
|
|
|
39
|
+
// Path helpers — mirror layout.go in the apteva CLI. Kept in sync
|
|
40
|
+
// by hand; both files are short and the shape is fixed.
|
|
41
|
+
const APTEVA_HOME = process.env.APTEVA_HOME || path.join(os.homedir(), ".apteva");
|
|
42
|
+
const VERSIONS_DIR = path.join(APTEVA_HOME, "versions");
|
|
43
|
+
const BIN_DIR = path.join(APTEVA_HOME, "bin");
|
|
44
|
+
const RELEASES_DIR = path.join(APTEVA_HOME, "releases");
|
|
45
|
+
const VERSION_DIR = path.join(VERSIONS_DIR, VERSION);
|
|
46
|
+
const CURRENT_LINK = path.join(BIN_DIR, "current");
|
|
47
|
+
|
|
48
|
+
const BIN_NAMES = ["apteva", "apteva-server", "apteva-core"];
|
|
49
|
+
|
|
18
50
|
function download(url) {
|
|
19
51
|
return new Promise((resolve, reject) => {
|
|
20
52
|
const follow = (url, redirects) => {
|
|
@@ -39,6 +71,33 @@ function download(url) {
|
|
|
39
71
|
});
|
|
40
72
|
}
|
|
41
73
|
|
|
74
|
+
// pointSymlinks (re)creates the bin/ symlink chain pointing at
|
|
75
|
+
// VERSION_DIR. Idempotent — running it twice is a no-op. Mirrors
|
|
76
|
+
// the Go-side pointSymlinks() in apteva/layout.go; we duplicate it
|
|
77
|
+
// here so npm's postinstall doesn't need a Go runtime.
|
|
78
|
+
function pointSymlinks() {
|
|
79
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
80
|
+
|
|
81
|
+
// current → ../versions/<VERSION>. Relative target keeps the
|
|
82
|
+
// tree portable (move ~/.apteva to a different host home and it
|
|
83
|
+
// still resolves).
|
|
84
|
+
const relTarget = path.join("..", "versions", VERSION);
|
|
85
|
+
const tmp = CURRENT_LINK + ".tmp";
|
|
86
|
+
try { fs.unlinkSync(tmp); } catch {}
|
|
87
|
+
fs.symlinkSync(relTarget, tmp);
|
|
88
|
+
// POSIX-atomic rename onto current.
|
|
89
|
+
fs.renameSync(tmp, CURRENT_LINK);
|
|
90
|
+
|
|
91
|
+
// Per-binary shims: bin/<name> → current/<name>. Replace if
|
|
92
|
+
// already present — old shims pointing at a since-deleted version
|
|
93
|
+
// dir would fail to resolve.
|
|
94
|
+
for (const name of BIN_NAMES) {
|
|
95
|
+
const dst = path.join(BIN_DIR, name);
|
|
96
|
+
try { fs.unlinkSync(dst); } catch {}
|
|
97
|
+
fs.symlinkSync(path.join("current", name), dst);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
42
101
|
async function main() {
|
|
43
102
|
const platform = PLATFORM_MAP[os.platform()];
|
|
44
103
|
const arch = ARCH_MAP[os.arch()];
|
|
@@ -46,23 +105,25 @@ async function main() {
|
|
|
46
105
|
console.error(`apteva: unsupported platform ${os.platform()}-${os.arch()}`);
|
|
47
106
|
process.exit(1);
|
|
48
107
|
}
|
|
49
|
-
|
|
50
|
-
// Cache binaries in ~/.apteva/bin/<version>/ so repeated npx runs are instant
|
|
51
|
-
const cacheDir = path.join(os.homedir(), ".apteva", "bin", VERSION);
|
|
52
108
|
const ext = platform === "windows" ? ".exe" : "";
|
|
53
|
-
const cachedBin = path.join(cacheDir, `apteva${ext}`);
|
|
54
109
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
// If versions/<VERSION>/ already has our binaries (cached from
|
|
111
|
+
// a prior npx install of the same version), just point the
|
|
112
|
+
// symlinks and stash a defensive copy in DIR. No download.
|
|
113
|
+
const cachedAptevaBin = path.join(VERSION_DIR, `apteva${ext}`);
|
|
114
|
+
if (fs.existsSync(cachedAptevaBin)) {
|
|
115
|
+
if (platform !== "windows") {
|
|
116
|
+
try { pointSymlinks(); } catch (e) { /* non-fatal */ }
|
|
117
|
+
}
|
|
118
|
+
for (const name of BIN_NAMES) {
|
|
119
|
+
const src = path.join(VERSION_DIR, `${name}${ext}`);
|
|
59
120
|
const dst = path.join(DIR, `${name}${ext}`);
|
|
60
121
|
if (fs.existsSync(src)) {
|
|
61
122
|
fs.copyFileSync(src, dst);
|
|
62
123
|
if (platform !== "windows") fs.chmodSync(dst, 0o755);
|
|
63
124
|
}
|
|
64
125
|
}
|
|
65
|
-
console.log(`apteva: v${VERSION} loaded from
|
|
126
|
+
console.log(`apteva: v${VERSION} loaded from ~/.apteva/versions/${VERSION}/`);
|
|
66
127
|
return;
|
|
67
128
|
}
|
|
68
129
|
|
|
@@ -73,36 +134,53 @@ async function main() {
|
|
|
73
134
|
|
|
74
135
|
try {
|
|
75
136
|
const buffer = await download(url);
|
|
76
|
-
|
|
77
|
-
|
|
137
|
+
|
|
138
|
+
// Stash the tarball in releases/ so future flake-recovery
|
|
139
|
+
// paths can reuse it without re-downloading.
|
|
140
|
+
fs.mkdirSync(RELEASES_DIR, { recursive: true });
|
|
141
|
+
const releasePath = path.join(RELEASES_DIR, tarName);
|
|
142
|
+
fs.writeFileSync(releasePath, buffer);
|
|
78
143
|
|
|
79
144
|
console.log(`apteva: extracting (${(buffer.length / 1024 / 1024).toFixed(1)} MB)...`);
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
fs.mkdirSync(VERSION_DIR, { recursive: true });
|
|
146
|
+
execSync(`tar -xzf "${releasePath}" -C "${VERSION_DIR}"`, { stdio: "pipe" });
|
|
82
147
|
|
|
83
|
-
// Make binaries executable
|
|
84
148
|
if (platform !== "windows") {
|
|
85
|
-
for (const name of
|
|
86
|
-
const bin = path.join(
|
|
149
|
+
for (const name of BIN_NAMES) {
|
|
150
|
+
const bin = path.join(VERSION_DIR, name);
|
|
87
151
|
if (fs.existsSync(bin)) fs.chmodSync(bin, 0o755);
|
|
88
152
|
}
|
|
89
153
|
}
|
|
90
154
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
155
|
+
// Set up the symlink chain pointing at this version. Skip on
|
|
156
|
+
// Windows where symlinks need elevated privileges.
|
|
157
|
+
if (platform !== "windows") {
|
|
158
|
+
try { pointSymlinks(); }
|
|
159
|
+
catch (e) {
|
|
160
|
+
console.warn(`apteva: symlink setup failed: ${e.message}`);
|
|
161
|
+
console.warn("(falling back to per-package install dir; updates won't work without symlinks)");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Defensive copy into the npm package install dir so cli.js's
|
|
166
|
+
// fallback path works when ~/.apteva isn't usable.
|
|
167
|
+
for (const name of BIN_NAMES) {
|
|
168
|
+
const src = path.join(VERSION_DIR, `${name}${ext}`);
|
|
169
|
+
const dst = path.join(DIR, `${name}${ext}`);
|
|
170
|
+
if (fs.existsSync(src)) {
|
|
171
|
+
fs.copyFileSync(src, dst);
|
|
172
|
+
if (platform !== "windows") fs.chmodSync(dst, 0o755);
|
|
173
|
+
}
|
|
97
174
|
}
|
|
98
175
|
|
|
99
|
-
console.log(
|
|
176
|
+
console.log(`apteva: installed to ~/.apteva/versions/${VERSION}/`);
|
|
177
|
+
console.log("apteva: ready. (run 'apteva' to start, or 'apteva service install' for a background service)");
|
|
100
178
|
} catch (err) {
|
|
101
179
|
console.error(`apteva: binary download failed: ${err.message}`);
|
|
102
180
|
console.error("");
|
|
103
181
|
console.error("Falling back to local Go build...");
|
|
104
182
|
|
|
105
|
-
// Fallback: build from source if Go is available
|
|
183
|
+
// Fallback: build from source if Go is available.
|
|
106
184
|
try {
|
|
107
185
|
execSync("go version", { stdio: "pipe" });
|
|
108
186
|
console.log("apteva: building from source...");
|