@vantaloom/cli 0.1.0 → 0.1.2
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/package.json +1 -1
- package/src/cli.mjs +140 -54
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { execFileSync, spawnSync } from "node:child_process"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
chmodSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
lstatSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
mkdtempSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
readFileSync,
|
|
10
|
+
readlinkSync,
|
|
11
|
+
rmSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from "node:fs"
|
|
3
14
|
import { cp, writeFile } from "node:fs/promises"
|
|
4
15
|
import os from "node:os"
|
|
5
16
|
import path from "node:path"
|
|
@@ -8,7 +19,7 @@ import { fileURLToPath } from "node:url"
|
|
|
8
19
|
const cliRoot = path.resolve(fileURLToPath(import.meta.url), "..", "..")
|
|
9
20
|
const repoCandidate = path.resolve(cliRoot, "..", "..")
|
|
10
21
|
const installedConfigPath = path.join(cliRoot, "config.json")
|
|
11
|
-
const
|
|
22
|
+
const defaultReleaseTag = "runtime-latest"
|
|
12
23
|
const defaultRepo = "Timefiles404/Vantaloom-next"
|
|
13
24
|
|
|
14
25
|
const runtimePackages = [
|
|
@@ -32,6 +43,8 @@ export async function main(argv) {
|
|
|
32
43
|
case "install":
|
|
33
44
|
if (options.package) {
|
|
34
45
|
await installFromPackage({ ...options, update: false })
|
|
46
|
+
} else if (shouldUseDistSync(options)) {
|
|
47
|
+
await syncFromRelease(options, "install")
|
|
35
48
|
} else {
|
|
36
49
|
await installFromSource(options)
|
|
37
50
|
}
|
|
@@ -39,8 +52,8 @@ export async function main(argv) {
|
|
|
39
52
|
case "update":
|
|
40
53
|
if (options.package) {
|
|
41
54
|
await installFromPackage({ ...options, update: true })
|
|
42
|
-
} else if (
|
|
43
|
-
await
|
|
55
|
+
} else if (shouldUseDistSync(options)) {
|
|
56
|
+
await syncFromRelease(options, "update")
|
|
44
57
|
} else {
|
|
45
58
|
await installFromSource({ ...options, update: true })
|
|
46
59
|
}
|
|
@@ -145,7 +158,7 @@ async function buildRuntimePackage(sourceRoot, packageRoot, options) {
|
|
|
145
158
|
buildGo(sourceRoot, buildBin, "vantaloomctl")
|
|
146
159
|
|
|
147
160
|
if (options.buildWeb) {
|
|
148
|
-
|
|
161
|
+
runPnpm(["--filter", "vantaloom-app", "build"], { cwd: sourceRoot })
|
|
149
162
|
}
|
|
150
163
|
|
|
151
164
|
await copyStandaloneWeb(sourceRoot, buildWeb)
|
|
@@ -176,7 +189,7 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
176
189
|
await cp(path.join(packageRoot, name), path.join(prefix, name), {
|
|
177
190
|
recursive: true,
|
|
178
191
|
force: true,
|
|
179
|
-
dereference:
|
|
192
|
+
dereference: false,
|
|
180
193
|
})
|
|
181
194
|
}
|
|
182
195
|
|
|
@@ -206,54 +219,71 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
206
219
|
return version
|
|
207
220
|
}
|
|
208
221
|
|
|
209
|
-
async function
|
|
222
|
+
async function syncFromRelease(options, action) {
|
|
210
223
|
const prefix = safeDirectory(options.prefix ?? defaultPrefix())
|
|
211
224
|
const installedConfig = readInstalledConfig(prefix)
|
|
212
225
|
const sourceRoot = installedConfig.sourceRoot
|
|
213
226
|
? tryAssertSourceRoot(installedConfig.sourceRoot)
|
|
214
227
|
: tryFindSourceRoot()
|
|
215
228
|
const sourceRemote = sourceRoot ? gitRemoteUrl(sourceRoot) : ""
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const distBranch = options.distBranch ?? installedConfig.distBranch ?? defaultDistBranch
|
|
219
|
-
const cloneUrl = remote || sshRemoteFromRepo(repo)
|
|
229
|
+
const repo = options.repo || installedConfig.repo || inferGitHubRepo(options.remote ?? installedConfig.remote ?? sourceRemote) || defaultRepo
|
|
230
|
+
const releaseTag = options.releaseTag || installedConfig.releaseTag || defaultReleaseTag
|
|
220
231
|
const tempRoot = mkdtempSync(path.join(os.tmpdir(), "vantaloom-update-"))
|
|
221
232
|
|
|
222
233
|
try {
|
|
223
|
-
const distRoot = path.join(tempRoot, "dist")
|
|
224
234
|
const extractRoot = path.join(tempRoot, "extract")
|
|
235
|
+
const archive = path.join(tempRoot, `vantaloom-${platformId()}.tar.gz`)
|
|
225
236
|
mkdirSync(extractRoot, { recursive: true })
|
|
226
237
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
distRoot,
|
|
235
|
-
])
|
|
236
|
-
|
|
237
|
-
const archive = findPackageArchive(distRoot, platformId())
|
|
238
|
+
await downloadReleaseAsset({
|
|
239
|
+
repo,
|
|
240
|
+
releaseTag,
|
|
241
|
+
assetName: `vantaloom-${platformId()}.tar.gz`,
|
|
242
|
+
target: archive,
|
|
243
|
+
token: options.githubToken,
|
|
244
|
+
})
|
|
238
245
|
run("tar", ["-xzf", archive, "-C", extractRoot])
|
|
239
246
|
|
|
240
247
|
const packageRoot = findExtractedPackage(extractRoot, platformId())
|
|
241
248
|
const version = await applyPackage(packageRoot, prefix, {
|
|
242
249
|
noStart: options.noStart,
|
|
243
250
|
sourceRoot: installedConfig.sourceRoot,
|
|
244
|
-
update:
|
|
251
|
+
update: action === "update",
|
|
245
252
|
})
|
|
246
253
|
|
|
247
|
-
console.log(
|
|
254
|
+
console.log(`${action === "update" ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
248
255
|
console.log(`version: ${version}`)
|
|
249
|
-
console.log(`source: ${repo}
|
|
256
|
+
console.log(`source: ${repo}@${releaseTag}`)
|
|
250
257
|
console.log(`run: ${displayCommand(prefix)} status`)
|
|
251
258
|
} finally {
|
|
252
259
|
removeKnownPath(tempRoot, os.tmpdir())
|
|
253
260
|
}
|
|
254
261
|
}
|
|
255
262
|
|
|
256
|
-
function
|
|
263
|
+
async function downloadReleaseAsset({ repo, releaseTag, assetName, target, token }) {
|
|
264
|
+
const url = `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`
|
|
265
|
+
const headers = {
|
|
266
|
+
"User-Agent": "vantaloom-cli",
|
|
267
|
+
}
|
|
268
|
+
const githubToken = token || process.env.VANTALOOM_GITHUB_TOKEN || process.env.GITHUB_TOKEN
|
|
269
|
+
if (githubToken) {
|
|
270
|
+
headers.Authorization = `Bearer ${githubToken}`
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const response = await fetch(url, { headers })
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
const detail = await response.text().catch(() => "")
|
|
276
|
+
const authHint = response.status === 404 || response.status === 403
|
|
277
|
+
? " If the repository is private, set VANTALOOM_GITHUB_TOKEN to a GitHub token that can read releases."
|
|
278
|
+
: ""
|
|
279
|
+
throw new Error(`failed to download ${assetName} from ${repo}@${releaseTag}: HTTP ${response.status}.${authHint}${detail ? ` ${detail.slice(0, 200)}` : ""}`)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const buffer = Buffer.from(await response.arrayBuffer())
|
|
283
|
+
await writeFile(target, buffer)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function shouldUseDistSync(options) {
|
|
257
287
|
return !options.local && !options.source && !options.buildWeb
|
|
258
288
|
}
|
|
259
289
|
|
|
@@ -287,7 +317,7 @@ function readJSONIfExists(filePath) {
|
|
|
287
317
|
|
|
288
318
|
function mergeRuntimeConfig(packageConfig, existingConfig, overrides) {
|
|
289
319
|
const merged = { ...packageConfig }
|
|
290
|
-
for (const key of ["sourceRoot", "remote", "repo", "
|
|
320
|
+
for (const key of ["sourceRoot", "remote", "repo", "releaseTag"]) {
|
|
291
321
|
if (!merged[key] && existingConfig[key]) {
|
|
292
322
|
merged[key] = existingConfig[key]
|
|
293
323
|
}
|
|
@@ -298,8 +328,8 @@ function mergeRuntimeConfig(packageConfig, existingConfig, overrides) {
|
|
|
298
328
|
if (!merged.repo) {
|
|
299
329
|
merged.repo = defaultRepo
|
|
300
330
|
}
|
|
301
|
-
if (!merged.
|
|
302
|
-
merged.
|
|
331
|
+
if (!merged.releaseTag) {
|
|
332
|
+
merged.releaseTag = defaultReleaseTag
|
|
303
333
|
}
|
|
304
334
|
return merged
|
|
305
335
|
}
|
|
@@ -311,23 +341,10 @@ function runtimeConfigFromSource(sourceRoot) {
|
|
|
311
341
|
...(process.env.GITHUB_ACTIONS ? {} : { sourceRoot }),
|
|
312
342
|
...(remote ? { remote } : {}),
|
|
313
343
|
repo,
|
|
314
|
-
|
|
344
|
+
releaseTag: defaultReleaseTag,
|
|
315
345
|
}
|
|
316
346
|
}
|
|
317
347
|
|
|
318
|
-
function findPackageArchive(distRoot, platform) {
|
|
319
|
-
const candidates = [
|
|
320
|
-
path.join(distRoot, "packages", `vantaloom-${platform}.tar.gz`),
|
|
321
|
-
path.join(distRoot, `vantaloom-${platform}.tar.gz`),
|
|
322
|
-
]
|
|
323
|
-
for (const candidate of candidates) {
|
|
324
|
-
if (existsSync(candidate)) {
|
|
325
|
-
return candidate
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
throw new Error(`missing CI package for ${platform} in ${distRoot}`)
|
|
329
|
-
}
|
|
330
|
-
|
|
331
348
|
function findExtractedPackage(extractRoot, platform) {
|
|
332
349
|
const expected = path.join(extractRoot, `vantaloom-${platform}`)
|
|
333
350
|
if (existsSync(expected)) {
|
|
@@ -384,10 +401,6 @@ function inferGitHubRepo(remote) {
|
|
|
384
401
|
return sshMatch?.[1] ?? ""
|
|
385
402
|
}
|
|
386
403
|
|
|
387
|
-
function sshRemoteFromRepo(repo) {
|
|
388
|
-
return `git@github.com:${repo}.git`
|
|
389
|
-
}
|
|
390
|
-
|
|
391
404
|
async function copyStandaloneWeb(sourceRoot, buildWeb) {
|
|
392
405
|
const standalone = path.join(sourceRoot, "apps", "vantaloom", ".next", "standalone")
|
|
393
406
|
const staticSource = path.join(sourceRoot, "apps", "vantaloom", ".next", "static")
|
|
@@ -399,7 +412,11 @@ async function copyStandaloneWeb(sourceRoot, buildWeb) {
|
|
|
399
412
|
}
|
|
400
413
|
|
|
401
414
|
removeKnownPath(buildWeb, path.dirname(buildWeb))
|
|
402
|
-
|
|
415
|
+
const preserveStandaloneLinks = process.platform !== "win32"
|
|
416
|
+
await copyDir(standalone, buildWeb, { dereference: !preserveStandaloneLinks })
|
|
417
|
+
if (preserveStandaloneLinks) {
|
|
418
|
+
await copyStandaloneHoistedTargets(sourceRoot, buildWeb)
|
|
419
|
+
}
|
|
403
420
|
await copyDir(staticSource, path.join(buildWeb, "apps", "vantaloom", ".next", "static"))
|
|
404
421
|
await copyDir(publicSource, path.join(buildWeb, "apps", "vantaloom", "public"))
|
|
405
422
|
|
|
@@ -486,13 +503,72 @@ async function copyPnpmRuntimePackage(sourceRoot, packageName, destinationNodeMo
|
|
|
486
503
|
await copyDir(source, path.join(destinationNodeModules, ...packageName.split("/")))
|
|
487
504
|
}
|
|
488
505
|
|
|
489
|
-
async function
|
|
506
|
+
async function copyStandaloneHoistedTargets(sourceRoot, buildWeb) {
|
|
507
|
+
const sourceHoisted = path.join(sourceRoot, "node_modules", ".pnpm", "node_modules")
|
|
508
|
+
const buildHoisted = path.join(buildWeb, "node_modules", ".pnpm", "node_modules")
|
|
509
|
+
const packageNames = findHoistedSymlinkPackages(path.join(buildWeb, "node_modules"))
|
|
510
|
+
|
|
511
|
+
for (const packageName of packageNames) {
|
|
512
|
+
const source = path.join(sourceHoisted, ...packageName.split("/"))
|
|
513
|
+
if (existsSync(source)) {
|
|
514
|
+
await copyDir(source, path.join(buildHoisted, ...packageName.split("/")))
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function findHoistedSymlinkPackages(nodeModules) {
|
|
520
|
+
const packages = new Set()
|
|
521
|
+
if (!existsSync(nodeModules)) {
|
|
522
|
+
return packages
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
for (const entry of readdirSync(nodeModules, { withFileTypes: true })) {
|
|
526
|
+
if (entry.name === ".pnpm" || entry.name.startsWith(".")) {
|
|
527
|
+
continue
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const entryPath = path.join(nodeModules, entry.name)
|
|
531
|
+
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
532
|
+
for (const scopedEntry of readdirSync(entryPath, { withFileTypes: true })) {
|
|
533
|
+
addHoistedSymlinkPackage(packages, path.join(entryPath, scopedEntry.name), `${entry.name}/${scopedEntry.name}`)
|
|
534
|
+
}
|
|
535
|
+
continue
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
addHoistedSymlinkPackage(packages, entryPath, entry.name)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return packages
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function addHoistedSymlinkPackage(packages, packagePath, packageName) {
|
|
545
|
+
let stat
|
|
546
|
+
try {
|
|
547
|
+
stat = lstatSync(packagePath)
|
|
548
|
+
} catch {
|
|
549
|
+
return
|
|
550
|
+
}
|
|
551
|
+
if (!stat.isSymbolicLink()) {
|
|
552
|
+
return
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const target = readlinkSync(packagePath).replaceAll("\\", "/")
|
|
556
|
+
if (target.includes(".pnpm/node_modules/")) {
|
|
557
|
+
packages.add(packageName)
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
async function copyDir(source, destination, options = {}) {
|
|
490
562
|
if (!existsSync(source)) {
|
|
491
563
|
throw new Error(`missing source directory: ${source}`)
|
|
492
564
|
}
|
|
493
565
|
removeKnownPath(destination, path.dirname(destination))
|
|
494
566
|
mkdirSync(destination, { recursive: true })
|
|
495
|
-
await cp(source, destination, {
|
|
567
|
+
await cp(source, destination, {
|
|
568
|
+
recursive: true,
|
|
569
|
+
force: true,
|
|
570
|
+
dereference: options.dereference ?? true,
|
|
571
|
+
})
|
|
496
572
|
}
|
|
497
573
|
|
|
498
574
|
function writeBuildManifest(buildRoot, version, platform) {
|
|
@@ -563,7 +639,8 @@ function parseOptions(args) {
|
|
|
563
639
|
case "output":
|
|
564
640
|
case "repo":
|
|
565
641
|
case "remote":
|
|
566
|
-
case "
|
|
642
|
+
case "release-tag":
|
|
643
|
+
case "github-token":
|
|
567
644
|
options[toCamel(key)] = inlineValue ?? args[++index]
|
|
568
645
|
if (!options[toCamel(key)]) {
|
|
569
646
|
throw new Error(`missing value for --${key}`)
|
|
@@ -621,6 +698,14 @@ function run(command, args, options = {}) {
|
|
|
621
698
|
}
|
|
622
699
|
}
|
|
623
700
|
|
|
701
|
+
function runPnpm(args, options = {}) {
|
|
702
|
+
if (process.platform === "win32") {
|
|
703
|
+
run("cmd.exe", ["/d", "/s", "/c", "pnpm", ...args], options)
|
|
704
|
+
return
|
|
705
|
+
}
|
|
706
|
+
run("pnpm", args, options)
|
|
707
|
+
}
|
|
708
|
+
|
|
624
709
|
function binaryName(name) {
|
|
625
710
|
return process.platform === "win32" ? `${name}.exe` : name
|
|
626
711
|
}
|
|
@@ -662,8 +747,9 @@ function printHelp() {
|
|
|
662
747
|
console.log(`Vantaloom CLI
|
|
663
748
|
|
|
664
749
|
Usage:
|
|
665
|
-
vantaloom install [--prefix <dir>] [--
|
|
666
|
-
vantaloom
|
|
750
|
+
vantaloom install [--prefix <dir>] [--repo <owner/name>] [--release-tag <tag>] [--github-token <token>] [--package <dir>] [--no-start]
|
|
751
|
+
vantaloom install --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start]
|
|
752
|
+
vantaloom update [--prefix <dir>] [--repo <owner/name>] [--release-tag <tag>] [--github-token <token>] [--no-start]
|
|
667
753
|
vantaloom update --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start]
|
|
668
754
|
vantaloom package [--source <repo>] [--output <dir>] [--build-web] [--archive]
|
|
669
755
|
vantaloom start [--prefix <dir>] [--component all|api|agent|web]
|