sdkvm 1.0.3 → 1.0.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.en.md +123 -99
- package/README.md +124 -100
- package/dist/index.js +370 -89
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -3521,7 +3521,7 @@ var log = {
|
|
|
3521
3521
|
};
|
|
3522
3522
|
|
|
3523
3523
|
// src/cli/install.ts
|
|
3524
|
-
import
|
|
3524
|
+
import fs11 from "fs";
|
|
3525
3525
|
import path9 from "path";
|
|
3526
3526
|
|
|
3527
3527
|
// src/core/platform.ts
|
|
@@ -3809,6 +3809,63 @@ function parseNodeUserSpec(input) {
|
|
|
3809
3809
|
hint: "Expected: 22, 22.20.0, lts, latest, or with vendor prefix like nodejs-22.20.0"
|
|
3810
3810
|
});
|
|
3811
3811
|
}
|
|
3812
|
+
var MAVEN_VENDOR_IDS = ["maven"];
|
|
3813
|
+
function parseMavenVersion(vendor, input) {
|
|
3814
|
+
const raw = input.trim();
|
|
3815
|
+
const s = raw.replace(/^maven-/i, "").replace(/^v/i, "");
|
|
3816
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(s);
|
|
3817
|
+
if (!m || !m[1] || !m[2] || !m[3]) {
|
|
3818
|
+
throw new SdkvmError(`Invalid Maven version: "${input}"`, {
|
|
3819
|
+
hint: "Expected forms: 3, 3.9, 3.9.9, 4.0.0-rc-4, latest"
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
return {
|
|
3823
|
+
vendor,
|
|
3824
|
+
major: Number(m[1]),
|
|
3825
|
+
minor: Number(m[2]),
|
|
3826
|
+
patch: Number(m[3]),
|
|
3827
|
+
extra: m[4] ?? null,
|
|
3828
|
+
build: null,
|
|
3829
|
+
raw
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
function formatMavenVersion(v) {
|
|
3833
|
+
const base = `${v.major}.${v.minor}.${v.patch ?? 0}`;
|
|
3834
|
+
return v.extra ? `${base}-${v.extra}` : base;
|
|
3835
|
+
}
|
|
3836
|
+
function parseMavenDirName(dir) {
|
|
3837
|
+
const m = new RegExp(`^(${MAVEN_VENDOR_IDS.join("|")})-(.+)$`).exec(dir);
|
|
3838
|
+
if (!m || !m[1] || !m[2]) return null;
|
|
3839
|
+
try {
|
|
3840
|
+
return parseMavenVersion(m[1], m[2]);
|
|
3841
|
+
} catch {
|
|
3842
|
+
return null;
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
function parseMavenUserSpec(input) {
|
|
3846
|
+
let s = input.trim().toLowerCase();
|
|
3847
|
+
let vendor;
|
|
3848
|
+
const m = /^(maven)-(.+)$/.exec(s);
|
|
3849
|
+
if (m && m[2]) {
|
|
3850
|
+
vendor = "maven";
|
|
3851
|
+
s = m[2];
|
|
3852
|
+
}
|
|
3853
|
+
if (s === "latest") return { vendor, spec: { kind: "latest" } };
|
|
3854
|
+
if (s === "lts" || s === "--lts") {
|
|
3855
|
+
throw new SdkvmError(`Invalid Maven version: "${input}"`, {
|
|
3856
|
+
hint: 'Maven has no lts alias \u2014 use "3", "3.9", "3.9.9", or "latest"'
|
|
3857
|
+
});
|
|
3858
|
+
}
|
|
3859
|
+
if (/^\d+\.\d+\.\d+(-[0-9a-z.\-]+)?$/.test(s)) return { vendor, spec: { kind: "full", version: s } };
|
|
3860
|
+
const line = /^(\d+)\.(\d+)$/.exec(s);
|
|
3861
|
+
if (line && line[1] && line[2]) {
|
|
3862
|
+
return { vendor, spec: { kind: "line", major: Number(line[1]), minor: Number(line[2]) } };
|
|
3863
|
+
}
|
|
3864
|
+
if (/^\d+$/.test(s)) return { vendor, spec: { kind: "major", major: Number(s) } };
|
|
3865
|
+
throw new SdkvmError(`Invalid Maven version: "${input}"`, {
|
|
3866
|
+
hint: "Expected: 3, 3.9, 3.9.9, 4.0.0-rc-4, latest, or with vendor prefix like maven-3.9.9"
|
|
3867
|
+
});
|
|
3868
|
+
}
|
|
3812
3869
|
|
|
3813
3870
|
// src/core/lock.ts
|
|
3814
3871
|
import fs5 from "fs";
|
|
@@ -4399,16 +4456,109 @@ var nodejsVendor = {
|
|
|
4399
4456
|
}
|
|
4400
4457
|
};
|
|
4401
4458
|
|
|
4459
|
+
// src/vendor/maven.ts
|
|
4460
|
+
var META_URL = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/maven-metadata.xml";
|
|
4461
|
+
var REPO = "https://repo.maven.apache.org/maven2";
|
|
4462
|
+
var MIN_MAJOR = 3;
|
|
4463
|
+
function tryParse(raw) {
|
|
4464
|
+
try {
|
|
4465
|
+
const v = parseMavenVersion("maven", raw);
|
|
4466
|
+
if (v.major < MIN_MAJOR) return null;
|
|
4467
|
+
return { raw, v, stable: v.extra === null };
|
|
4468
|
+
} catch {
|
|
4469
|
+
return null;
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
async function fetchListed() {
|
|
4473
|
+
const xml = await httpText(META_URL);
|
|
4474
|
+
const out = [];
|
|
4475
|
+
for (const m of xml.matchAll(/<version>([^<]+)<\/version>/g)) {
|
|
4476
|
+
const raw = m[1];
|
|
4477
|
+
if (!raw) continue;
|
|
4478
|
+
const parsed = tryParse(raw);
|
|
4479
|
+
if (parsed) out.push(parsed);
|
|
4480
|
+
}
|
|
4481
|
+
return out;
|
|
4482
|
+
}
|
|
4483
|
+
function stablesDesc(listed) {
|
|
4484
|
+
return listed.filter((x) => x.stable).sort((a, b) => compareVersions(b.v, a.v));
|
|
4485
|
+
}
|
|
4486
|
+
function specLabel3(spec) {
|
|
4487
|
+
if (spec.kind === "major") return String(spec.major);
|
|
4488
|
+
if (spec.kind === "line") return `${spec.major}.${spec.minor}`;
|
|
4489
|
+
if (spec.kind === "full") return spec.version;
|
|
4490
|
+
return spec.kind;
|
|
4491
|
+
}
|
|
4492
|
+
function buildArtifact4(v, platform) {
|
|
4493
|
+
const display = formatMavenVersion(v);
|
|
4494
|
+
const ext = platform.os === "windows" ? "zip" : "tar.gz";
|
|
4495
|
+
const filename = `apache-maven-${display}-bin.${ext}`;
|
|
4496
|
+
const downloadUrl = `${REPO}/org/apache/maven/apache-maven/${display}/${filename}`;
|
|
4497
|
+
return {
|
|
4498
|
+
vendorId: "maven",
|
|
4499
|
+
version: v,
|
|
4500
|
+
dirName: `maven-${display}`,
|
|
4501
|
+
displayName: `Apache Maven ${display}`,
|
|
4502
|
+
downloadUrl,
|
|
4503
|
+
checksum: { kind: "sha512", url: `${downloadUrl}.sha512` },
|
|
4504
|
+
archive: ext === "zip" ? "zip" : "tar.gz"
|
|
4505
|
+
};
|
|
4506
|
+
}
|
|
4507
|
+
var mavenVendor = {
|
|
4508
|
+
id: "maven",
|
|
4509
|
+
label: "Apache Maven",
|
|
4510
|
+
sdk: "maven",
|
|
4511
|
+
supportsFullVersionList: true,
|
|
4512
|
+
/** 一条 minor 线(3.9)只含稳定版;预发布不单独成线 */
|
|
4513
|
+
async listMajors() {
|
|
4514
|
+
const versions = stablesDesc(await fetchListed());
|
|
4515
|
+
const lines = /* @__PURE__ */ new Map();
|
|
4516
|
+
for (const { v } of versions) {
|
|
4517
|
+
const key = `${v.major}.${v.minor}`;
|
|
4518
|
+
const cur = lines.get(key);
|
|
4519
|
+
if (!cur || compareVersions(v, cur) > 0) lines.set(key, v);
|
|
4520
|
+
}
|
|
4521
|
+
return [...lines.entries()].sort((a, b) => compareVersions(b[1], a[1])).map(([key, v]) => ({ key, lts: false, latestFullVersion: formatMavenVersion(v) }));
|
|
4522
|
+
},
|
|
4523
|
+
async resolve(spec, platform) {
|
|
4524
|
+
if (spec.kind === "lts") {
|
|
4525
|
+
throw new SdkvmError("Unsupported version spec for Maven: lts", {
|
|
4526
|
+
hint: 'Maven has no lts alias \u2014 use "3", "3.9", "3.9.9", or "latest"'
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
const listed = await fetchListed();
|
|
4530
|
+
const stables = stablesDesc(listed);
|
|
4531
|
+
let target;
|
|
4532
|
+
if (spec.kind === "latest") {
|
|
4533
|
+
target = stables[0];
|
|
4534
|
+
} else if (spec.kind === "major") {
|
|
4535
|
+
target = stables.find((x) => x.v.major === spec.major);
|
|
4536
|
+
} else if (spec.kind === "line") {
|
|
4537
|
+
target = stables.find((x) => x.v.major === spec.major && x.v.minor === spec.minor);
|
|
4538
|
+
} else {
|
|
4539
|
+
target = listed.find((x) => formatMavenVersion(x.v) === spec.version);
|
|
4540
|
+
}
|
|
4541
|
+
if (!target) {
|
|
4542
|
+
throw new SdkvmError(`No Maven release matches "${specLabel3(spec)}"`, {
|
|
4543
|
+
hint: `Run \`${cmdPath("maven")} ls -r\` to see available versions.`
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
return buildArtifact4(target.v, platform);
|
|
4547
|
+
}
|
|
4548
|
+
};
|
|
4549
|
+
|
|
4402
4550
|
// src/vendor/index.ts
|
|
4403
4551
|
var JAVA_VENDORS = [temurinVendor, zuluVendor, correttoVendor];
|
|
4404
4552
|
var GO_VENDORS = [golangVendor];
|
|
4405
4553
|
var FLUTTER_VENDORS = [flutterVendor];
|
|
4406
4554
|
var NODE_VENDORS = [nodejsVendor];
|
|
4555
|
+
var MAVEN_VENDORS = [mavenVendor];
|
|
4407
4556
|
function vendorsFor(type) {
|
|
4408
4557
|
if (type === "java") return JAVA_VENDORS;
|
|
4409
4558
|
if (type === "go") return GO_VENDORS;
|
|
4410
4559
|
if (type === "flutter") return FLUTTER_VENDORS;
|
|
4411
4560
|
if (type === "node") return NODE_VENDORS;
|
|
4561
|
+
if (type === "maven") return MAVEN_VENDORS;
|
|
4412
4562
|
throw new SdkvmError(`Unknown SDK type: ${type}`);
|
|
4413
4563
|
}
|
|
4414
4564
|
function allVendorIds(type) {
|
|
@@ -4536,14 +4686,40 @@ var nodeSdk = {
|
|
|
4536
4686
|
versionCheck: { args: ["--version"], stream: "stdout" }
|
|
4537
4687
|
};
|
|
4538
4688
|
|
|
4689
|
+
// src/sdk/maven.ts
|
|
4690
|
+
var mavenSdk = {
|
|
4691
|
+
id: "maven",
|
|
4692
|
+
label: "Maven",
|
|
4693
|
+
installDirName: "mavens",
|
|
4694
|
+
currentLinkName: "current-maven",
|
|
4695
|
+
envVar: "MAVEN_HOME",
|
|
4696
|
+
supportsLts: false,
|
|
4697
|
+
requiresJdk: true,
|
|
4698
|
+
vendors: MAVEN_VENDORS,
|
|
4699
|
+
parseUserSpec: parseMavenUserSpec,
|
|
4700
|
+
parseDirName: parseMavenDirName,
|
|
4701
|
+
formatVersion: formatMavenVersion,
|
|
4702
|
+
compareVersions,
|
|
4703
|
+
binRelPath(platform) {
|
|
4704
|
+
return `bin/${platform.os === "windows" ? "mvn.cmd" : "mvn"}`;
|
|
4705
|
+
},
|
|
4706
|
+
envBinSuffix(platform) {
|
|
4707
|
+
return platform.os === "windows" ? "\\bin" : "/bin";
|
|
4708
|
+
},
|
|
4709
|
+
// 归档是单根 apache-maven-<version>/ 目录
|
|
4710
|
+
locateHome: (root) => root,
|
|
4711
|
+
versionCheck: { args: ["-version"], stream: "stdout" }
|
|
4712
|
+
};
|
|
4713
|
+
|
|
4539
4714
|
// src/sdk/index.ts
|
|
4540
4715
|
var SPECS = {
|
|
4541
4716
|
java: javaSdk,
|
|
4542
4717
|
go: goSdk,
|
|
4543
4718
|
flutter: flutterSdk,
|
|
4544
|
-
node: nodeSdk
|
|
4719
|
+
node: nodeSdk,
|
|
4720
|
+
maven: mavenSdk
|
|
4545
4721
|
};
|
|
4546
|
-
var SDK_TYPES = ["java", "go", "flutter", "node"];
|
|
4722
|
+
var SDK_TYPES = ["java", "go", "flutter", "node", "maven"];
|
|
4547
4723
|
function getSdkType(id) {
|
|
4548
4724
|
const spec = SPECS[id];
|
|
4549
4725
|
if (!spec) throw new SdkvmError(`Unknown SDK type: ${id}`);
|
|
@@ -4724,7 +4900,7 @@ function updateConfig(mutator) {
|
|
|
4724
4900
|
}
|
|
4725
4901
|
|
|
4726
4902
|
// src/vendor/mirror.ts
|
|
4727
|
-
var MIRROR_REWRITE_VENDORS = /* @__PURE__ */ new Set(["temurin", "golang", "flutter", "nodejs"]);
|
|
4903
|
+
var MIRROR_REWRITE_VENDORS = /* @__PURE__ */ new Set(["temurin", "golang", "flutter", "nodejs", "maven"]);
|
|
4728
4904
|
function applyMirrorDetail(artifact, platform, mirrorRoot) {
|
|
4729
4905
|
if (!mirrorRoot?.trim()) return { artifact, applied: false };
|
|
4730
4906
|
const root = mirrorRoot.trim().replace(/\/+$/, "");
|
|
@@ -4746,6 +4922,11 @@ function applyMirrorDetail(artifact, platform, mirrorRoot) {
|
|
|
4746
4922
|
if (url2 === artifact.downloadUrl) return { artifact, applied: false };
|
|
4747
4923
|
return { artifact: { ...artifact, downloadUrl: url2 }, applied: true };
|
|
4748
4924
|
}
|
|
4925
|
+
if (artifact.vendorId === "maven") {
|
|
4926
|
+
const url2 = artifact.downloadUrl.replace(/^https:\/\/repo\.maven\.apache\.org\/maven2/, root);
|
|
4927
|
+
if (url2 === artifact.downloadUrl) return { artifact, applied: false };
|
|
4928
|
+
return { artifact: { ...artifact, downloadUrl: url2 }, applied: true };
|
|
4929
|
+
}
|
|
4749
4930
|
if (artifact.vendorId !== "temurin") return { artifact, applied: false };
|
|
4750
4931
|
const m = /^https:\/\/github\.com\/adoptium\/temurin(\d+)-binaries\/releases\/download\/[^/]+\/(.+)$/.exec(
|
|
4751
4932
|
artifact.downloadUrl
|
|
@@ -4754,6 +4935,13 @@ function applyMirrorDetail(artifact, platform, mirrorRoot) {
|
|
|
4754
4935
|
const url = `${root}/${m[1]}/jdk/${platform.arch}/${platform.os}/${m[2]}`;
|
|
4755
4936
|
return { artifact: { ...artifact, downloadUrl: url }, applied: true };
|
|
4756
4937
|
}
|
|
4938
|
+
function checksumSidecarFallback(officialDownload, officialChecksum, mirroredDownload) {
|
|
4939
|
+
if (!officialChecksum || mirroredDownload === officialDownload) return void 0;
|
|
4940
|
+
if (!officialChecksum.startsWith(officialDownload)) return void 0;
|
|
4941
|
+
const suffix = officialChecksum.slice(officialDownload.length);
|
|
4942
|
+
if (!/^\.[A-Za-z0-9.]+$/.test(suffix)) return void 0;
|
|
4943
|
+
return mirroredDownload + suffix;
|
|
4944
|
+
}
|
|
4757
4945
|
|
|
4758
4946
|
// src/net/download.ts
|
|
4759
4947
|
import crypto from "crypto";
|
|
@@ -4761,10 +4949,25 @@ import { once } from "events";
|
|
|
4761
4949
|
import fs7 from "fs";
|
|
4762
4950
|
import path6 from "path";
|
|
4763
4951
|
var IDLE_TIMEOUT_MS = 6e4;
|
|
4952
|
+
function watchWriteStream(out) {
|
|
4953
|
+
let streamError = null;
|
|
4954
|
+
out.on("error", (err) => {
|
|
4955
|
+
streamError ??= err;
|
|
4956
|
+
});
|
|
4957
|
+
return { error: () => streamError };
|
|
4958
|
+
}
|
|
4959
|
+
async function closeWriteStream(out) {
|
|
4960
|
+
if (out.closed) return;
|
|
4961
|
+
await new Promise((resolve) => {
|
|
4962
|
+
out.once("close", () => resolve());
|
|
4963
|
+
if (!out.destroyed) out.destroy();
|
|
4964
|
+
});
|
|
4965
|
+
}
|
|
4764
4966
|
async function downloadFile(url, destFile, onProgress) {
|
|
4765
4967
|
const partFile = `${destFile}.part`;
|
|
4766
4968
|
const hash = crypto.createHash("sha256");
|
|
4767
4969
|
const out = fs7.createWriteStream(partFile);
|
|
4970
|
+
const stream = watchWriteStream(out);
|
|
4768
4971
|
let bytes = 0;
|
|
4769
4972
|
let total = null;
|
|
4770
4973
|
let encoded2 = false;
|
|
@@ -4774,6 +4977,10 @@ async function downloadFile(url, destFile, onProgress) {
|
|
|
4774
4977
|
stalled = true;
|
|
4775
4978
|
ac.abort();
|
|
4776
4979
|
}, IDLE_TIMEOUT_MS);
|
|
4980
|
+
const throwIfStreamError = () => {
|
|
4981
|
+
const err = stream.error();
|
|
4982
|
+
if (err) throw err;
|
|
4983
|
+
};
|
|
4777
4984
|
try {
|
|
4778
4985
|
const res = await httpFetch(url, {
|
|
4779
4986
|
signal: ac.signal,
|
|
@@ -4785,26 +4992,28 @@ async function downloadFile(url, destFile, onProgress) {
|
|
|
4785
4992
|
if (!res.body) throw new SdkvmError(`Empty response body: ${url}`);
|
|
4786
4993
|
for await (const chunk of res.body) {
|
|
4787
4994
|
timer.refresh();
|
|
4995
|
+
throwIfStreamError();
|
|
4788
4996
|
if (!out.write(chunk)) await once(out, "drain");
|
|
4997
|
+
throwIfStreamError();
|
|
4789
4998
|
hash.update(chunk);
|
|
4790
4999
|
bytes += chunk.byteLength;
|
|
4791
5000
|
onProgress?.(bytes, total);
|
|
4792
5001
|
}
|
|
5002
|
+
throwIfStreamError();
|
|
4793
5003
|
await new Promise((resolve, reject) => {
|
|
4794
5004
|
out.end((err) => err ? reject(err) : resolve());
|
|
4795
5005
|
});
|
|
4796
5006
|
} catch (err) {
|
|
4797
|
-
await
|
|
4798
|
-
out.once("close", resolve);
|
|
4799
|
-
out.destroy();
|
|
4800
|
-
});
|
|
5007
|
+
await closeWriteStream(out);
|
|
4801
5008
|
fs7.rmSync(partFile, { force: true });
|
|
4802
5009
|
if (stalled) {
|
|
4803
5010
|
throw new SdkvmError(`Download stalled: no data for ${IDLE_TIMEOUT_MS / 1e3}s (${bytes} bytes so far)`, {
|
|
4804
5011
|
hint: url
|
|
4805
5012
|
});
|
|
4806
5013
|
}
|
|
4807
|
-
throw err;
|
|
5014
|
+
if (err instanceof SdkvmError) throw err;
|
|
5015
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
5016
|
+
throw new SdkvmError(`Download failed after ${bytes} bytes: ${detail}`, { hint: url });
|
|
4808
5017
|
} finally {
|
|
4809
5018
|
clearTimeout(timer);
|
|
4810
5019
|
}
|
|
@@ -4825,13 +5034,20 @@ function cacheFileName(url) {
|
|
|
4825
5034
|
}
|
|
4826
5035
|
|
|
4827
5036
|
// src/net/checksum.ts
|
|
5037
|
+
import crypto2 from "crypto";
|
|
5038
|
+
import fs8 from "fs";
|
|
4828
5039
|
var HEX64 = /^[0-9a-f]{64}$/i;
|
|
5040
|
+
var HEX128 = /^[0-9a-f]{128}$/i;
|
|
5041
|
+
function hexOf(value, kind) {
|
|
5042
|
+
const re = kind === "sha512" ? HEX128 : HEX64;
|
|
5043
|
+
return typeof value === "string" && re.test(value) ? value.toLowerCase() : null;
|
|
5044
|
+
}
|
|
4829
5045
|
function hex64(value) {
|
|
4830
|
-
return
|
|
5046
|
+
return hexOf(value, "sha256");
|
|
4831
5047
|
}
|
|
4832
|
-
function extractExpectedChecksum(text) {
|
|
5048
|
+
function extractExpectedChecksum(text, kind = "sha256") {
|
|
4833
5049
|
const trimmed = text.trim();
|
|
4834
|
-
if (trimmed.startsWith("{")) {
|
|
5050
|
+
if (kind === "sha256" && trimmed.startsWith("{")) {
|
|
4835
5051
|
try {
|
|
4836
5052
|
const obj = JSON.parse(trimmed);
|
|
4837
5053
|
const direct = hex64(obj.checksum) ?? hex64(obj.sha256);
|
|
@@ -4852,7 +5068,38 @@ function extractExpectedChecksum(text) {
|
|
|
4852
5068
|
return null;
|
|
4853
5069
|
}
|
|
4854
5070
|
const token = trimmed.split(/\s+/)[0] ?? "";
|
|
4855
|
-
return
|
|
5071
|
+
return hexOf(token, kind);
|
|
5072
|
+
}
|
|
5073
|
+
function hashFile(file, algorithm) {
|
|
5074
|
+
return new Promise((resolve, reject) => {
|
|
5075
|
+
const hash = crypto2.createHash(algorithm);
|
|
5076
|
+
fs8.createReadStream(file).on("error", reject).on("data", (chunk) => {
|
|
5077
|
+
hash.update(chunk);
|
|
5078
|
+
}).on("end", () => resolve(hash.digest("hex")));
|
|
5079
|
+
});
|
|
5080
|
+
}
|
|
5081
|
+
async function readFallbackChecksum(artifact, url, kind, strict) {
|
|
5082
|
+
let expected;
|
|
5083
|
+
try {
|
|
5084
|
+
expected = extractExpectedChecksum(await httpText(url), kind);
|
|
5085
|
+
} catch (err) {
|
|
5086
|
+
if (strict) {
|
|
5087
|
+
const detail = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
5088
|
+
throw new SdkvmError(`Cannot fetch checksum for ${artifact.displayName}`, {
|
|
5089
|
+
hint: `${detail}. Official and mirror checksum URLs were both unreachable.`
|
|
5090
|
+
});
|
|
5091
|
+
}
|
|
5092
|
+
log.warn(`cannot fetch mirror checksum for ${artifact.displayName}, skipping verification`);
|
|
5093
|
+
return null;
|
|
5094
|
+
}
|
|
5095
|
+
if (expected) return expected;
|
|
5096
|
+
if (strict) {
|
|
5097
|
+
throw new SdkvmError(`Checksum source has no valid hash for ${artifact.displayName}`, {
|
|
5098
|
+
hint: `Mirror sidecar ${url} did not contain a ${kind} hash.`
|
|
5099
|
+
});
|
|
5100
|
+
}
|
|
5101
|
+
log.warn(`mirror sidecar has no valid hash for ${artifact.displayName}, skipping verification`);
|
|
5102
|
+
return null;
|
|
4856
5103
|
}
|
|
4857
5104
|
async function verifyChecksum(artifact, actual, opts = {}) {
|
|
4858
5105
|
const strict = opts.strict === true;
|
|
@@ -4868,17 +5115,28 @@ async function verifyChecksum(artifact, actual, opts = {}) {
|
|
|
4868
5115
|
}
|
|
4869
5116
|
let expected = info.expected?.toLowerCase() ?? null;
|
|
4870
5117
|
if (!expected && info.url) {
|
|
5118
|
+
const fallback = opts.fallbackUrl && opts.fallbackUrl !== info.url ? opts.fallbackUrl : void 0;
|
|
4871
5119
|
try {
|
|
4872
|
-
expected = extractExpectedChecksum(await httpText(info.url));
|
|
5120
|
+
expected = extractExpectedChecksum(await httpText(info.url), info.kind);
|
|
4873
5121
|
} catch (err) {
|
|
4874
|
-
if (
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
5122
|
+
if (!fallback) {
|
|
5123
|
+
if (strict) {
|
|
5124
|
+
const detail = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
5125
|
+
throw new SdkvmError(`Cannot fetch checksum for ${artifact.displayName}`, {
|
|
5126
|
+
hint: `${detail}. Mirrored installs need a reachable checksum URL.`
|
|
5127
|
+
});
|
|
5128
|
+
}
|
|
5129
|
+
log.warn(`cannot fetch checksum for ${artifact.displayName}, skipping verification`);
|
|
5130
|
+
return;
|
|
4879
5131
|
}
|
|
4880
|
-
log.warn(`cannot fetch checksum for ${artifact.displayName},
|
|
4881
|
-
|
|
5132
|
+
log.warn(`cannot fetch official checksum for ${artifact.displayName}, trying the mirror sidecar`);
|
|
5133
|
+
expected = await readFallbackChecksum(artifact, fallback, info.kind, strict);
|
|
5134
|
+
if (!expected) return;
|
|
5135
|
+
}
|
|
5136
|
+
if (!expected && fallback) {
|
|
5137
|
+
log.warn(`official checksum has no valid hash for ${artifact.displayName}, trying the mirror sidecar`);
|
|
5138
|
+
expected = await readFallbackChecksum(artifact, fallback, info.kind, strict);
|
|
5139
|
+
if (!expected) return;
|
|
4882
5140
|
}
|
|
4883
5141
|
}
|
|
4884
5142
|
if (!expected) {
|
|
@@ -4898,7 +5156,7 @@ async function verifyChecksum(artifact, actual, opts = {}) {
|
|
|
4898
5156
|
}
|
|
4899
5157
|
|
|
4900
5158
|
// src/fs/extract.ts
|
|
4901
|
-
import
|
|
5159
|
+
import fs9 from "fs";
|
|
4902
5160
|
import path7 from "path";
|
|
4903
5161
|
|
|
4904
5162
|
// src/util/spawn.ts
|
|
@@ -4924,9 +5182,9 @@ async function run(cmd, args, opts = {}) {
|
|
|
4924
5182
|
// src/fs/extract.ts
|
|
4925
5183
|
var WIN_TAR = "C:\\Windows\\System32\\tar.exe";
|
|
4926
5184
|
async function extractArchive(archiveFile, archiveType, destDir, platform) {
|
|
4927
|
-
|
|
5185
|
+
fs9.mkdirSync(destDir, { recursive: true });
|
|
4928
5186
|
if (platform.os === "windows") {
|
|
4929
|
-
if (
|
|
5187
|
+
if (fs9.existsSync(WIN_TAR)) {
|
|
4930
5188
|
await run(WIN_TAR, ["-xf", archiveFile, "-C", destDir]);
|
|
4931
5189
|
} else {
|
|
4932
5190
|
await run("powershell.exe", [
|
|
@@ -4949,21 +5207,21 @@ function tmpExtractDir(base) {
|
|
|
4949
5207
|
}
|
|
4950
5208
|
|
|
4951
5209
|
// src/fs/layout.ts
|
|
4952
|
-
import
|
|
5210
|
+
import fs10 from "fs";
|
|
4953
5211
|
import path8 from "path";
|
|
4954
5212
|
function normalizeExtracted(tmpDir, platform, type) {
|
|
4955
5213
|
const spec = getSdkType(type);
|
|
4956
|
-
const entries =
|
|
5214
|
+
const entries = fs10.readdirSync(tmpDir).filter((e) => e !== "._" && !e.startsWith("._"));
|
|
4957
5215
|
const real = entries.filter((e) => e !== ".DS_Store");
|
|
4958
5216
|
let root;
|
|
4959
|
-
if (real.length === 1 &&
|
|
5217
|
+
if (real.length === 1 && fs10.statSync(path8.join(tmpDir, real[0])).isDirectory()) {
|
|
4960
5218
|
root = path8.join(tmpDir, real[0]);
|
|
4961
5219
|
} else {
|
|
4962
5220
|
root = tmpDir;
|
|
4963
5221
|
}
|
|
4964
5222
|
const home = spec.locateHome(root);
|
|
4965
5223
|
const bin = path8.join(home, spec.binRelPath(platform));
|
|
4966
|
-
if (!
|
|
5224
|
+
if (!fs10.existsSync(bin)) {
|
|
4967
5225
|
throw new SdkvmError(`Archive does not look like a valid ${spec.label} (bin not found)`, {
|
|
4968
5226
|
hint: `expected ${bin}`
|
|
4969
5227
|
});
|
|
@@ -5015,7 +5273,7 @@ function createProgress(label2) {
|
|
|
5015
5273
|
async function renameWithRetry(from, to, attempts = 3) {
|
|
5016
5274
|
for (let i = 1; ; i++) {
|
|
5017
5275
|
try {
|
|
5018
|
-
|
|
5276
|
+
fs11.renameSync(from, to);
|
|
5019
5277
|
return;
|
|
5020
5278
|
} catch (err) {
|
|
5021
5279
|
if (i >= attempts) throw err;
|
|
@@ -5049,7 +5307,7 @@ async function installCommand(type, specInput, opts) {
|
|
|
5049
5307
|
const hintVersion = type === "java" || type === "node" ? String(artifact.version.major) : `${artifact.version.major}.${artifact.version.minor}`;
|
|
5050
5308
|
await withLock(async () => {
|
|
5051
5309
|
ensureLayout();
|
|
5052
|
-
if (
|
|
5310
|
+
if (fs11.existsSync(finalDir)) {
|
|
5053
5311
|
if (!opts.force) {
|
|
5054
5312
|
log.warn(`${artifact.displayName} is already installed`);
|
|
5055
5313
|
log.info(`run: ${cmdPath(type)} use ${hintVersion}`);
|
|
@@ -5057,15 +5315,17 @@ async function installCommand(type, specInput, opts) {
|
|
|
5057
5315
|
}
|
|
5058
5316
|
log.warn(`--force: removing existing ${artifact.dirName}`);
|
|
5059
5317
|
}
|
|
5060
|
-
for (const f of
|
|
5061
|
-
if (f.endsWith(".part"))
|
|
5318
|
+
for (const f of fs11.readdirSync(paths.cache())) {
|
|
5319
|
+
if (f.endsWith(".part")) fs11.rmSync(path9.join(paths.cache(), f), { force: true });
|
|
5062
5320
|
}
|
|
5063
5321
|
const dest = path9.join(paths.cache(), cacheFileName(artifact.downloadUrl));
|
|
5064
5322
|
const progress = createProgress(`\u2193 ${artifact.displayName}`);
|
|
5065
5323
|
log.info(`downloading ${artifact.downloadUrl}`);
|
|
5066
5324
|
const dl = await downloadFile(artifact.downloadUrl, dest, (b, t) => progress.update(b, t));
|
|
5067
5325
|
progress.done(dl.bytes, null);
|
|
5068
|
-
await
|
|
5326
|
+
const actual = artifact.checksum?.kind === "sha512" ? await hashFile(dest, "sha512") : dl.sha256;
|
|
5327
|
+
const fallbackUrl = applied ? checksumSidecarFallback(resolved.downloadUrl, resolved.checksum?.url, artifact.downloadUrl) : void 0;
|
|
5328
|
+
await verifyChecksum(artifact, actual, { strict: applied, fallbackUrl });
|
|
5069
5329
|
const tmp = tmpExtractDir(paths.tmp());
|
|
5070
5330
|
const bak = `${finalDir}.bak`;
|
|
5071
5331
|
let finalTmp = tmp;
|
|
@@ -5074,28 +5334,28 @@ async function installCommand(type, specInput, opts) {
|
|
|
5074
5334
|
await extractArchive(dest, artifact.archive, tmp, platform);
|
|
5075
5335
|
const normalized = normalizeExtracted(tmp, platform, type);
|
|
5076
5336
|
finalTmp = normalized.root;
|
|
5077
|
-
|
|
5078
|
-
if (
|
|
5337
|
+
fs11.rmSync(bak, { recursive: true, force: true });
|
|
5338
|
+
if (fs11.existsSync(finalDir)) fs11.renameSync(finalDir, bak);
|
|
5079
5339
|
try {
|
|
5080
5340
|
await renameWithRetry(normalized.root, finalDir);
|
|
5081
5341
|
} catch (err) {
|
|
5082
|
-
if (
|
|
5342
|
+
if (fs11.existsSync(bak) && !fs11.existsSync(finalDir)) {
|
|
5083
5343
|
try {
|
|
5084
|
-
|
|
5344
|
+
fs11.renameSync(bak, finalDir);
|
|
5085
5345
|
} catch {
|
|
5086
5346
|
}
|
|
5087
5347
|
}
|
|
5088
5348
|
throw err;
|
|
5089
5349
|
}
|
|
5090
|
-
|
|
5350
|
+
fs11.rmSync(bak, { recursive: true, force: true });
|
|
5091
5351
|
} catch (err) {
|
|
5092
|
-
|
|
5093
|
-
|
|
5352
|
+
fs11.rmSync(finalTmp, { recursive: true, force: true });
|
|
5353
|
+
fs11.rmSync(tmp, { recursive: true, force: true });
|
|
5094
5354
|
throw err;
|
|
5095
5355
|
} finally {
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5356
|
+
fs11.rmSync(dest, { force: true });
|
|
5357
|
+
fs11.rmSync(paths.tmp(), { recursive: true, force: true });
|
|
5358
|
+
fs11.mkdirSync(paths.tmp(), { recursive: true });
|
|
5099
5359
|
}
|
|
5100
5360
|
log.ok(`installed ${artifact.displayName} \u2192 ${finalDir}`);
|
|
5101
5361
|
log.info(`switch to it: ${cmdPath(type)} use ${hintVersion}`);
|
|
@@ -5108,34 +5368,34 @@ import { promisify as promisify2 } from "util";
|
|
|
5108
5368
|
import path15 from "path";
|
|
5109
5369
|
|
|
5110
5370
|
// src/core/registry.ts
|
|
5111
|
-
import
|
|
5371
|
+
import fs13 from "fs";
|
|
5112
5372
|
import path11 from "path";
|
|
5113
5373
|
|
|
5114
5374
|
// src/fs/link.ts
|
|
5115
|
-
import
|
|
5375
|
+
import fs12 from "fs";
|
|
5116
5376
|
import path10 from "path";
|
|
5117
5377
|
function setCurrent(type, target, platform) {
|
|
5118
5378
|
const link = paths.current(type);
|
|
5119
5379
|
if (platform.os === "windows") {
|
|
5120
5380
|
try {
|
|
5121
|
-
|
|
5381
|
+
fs12.rmSync(link, { force: true });
|
|
5122
5382
|
} catch {
|
|
5123
|
-
|
|
5383
|
+
fs12.rmSync(link, { recursive: true, force: true });
|
|
5124
5384
|
}
|
|
5125
|
-
|
|
5385
|
+
fs12.symlinkSync(target, link, "junction");
|
|
5126
5386
|
return;
|
|
5127
5387
|
}
|
|
5128
5388
|
const tmp = `${link}.tmp-${process.pid}`;
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5389
|
+
fs12.rmSync(tmp, { force: true });
|
|
5390
|
+
fs12.symlinkSync(target, tmp);
|
|
5391
|
+
fs12.renameSync(tmp, link);
|
|
5132
5392
|
}
|
|
5133
5393
|
function readCurrent(type) {
|
|
5134
5394
|
const link = paths.current(type);
|
|
5135
5395
|
try {
|
|
5136
|
-
const st =
|
|
5396
|
+
const st = fs12.lstatSync(link);
|
|
5137
5397
|
if (!st.isSymbolicLink()) return null;
|
|
5138
|
-
const raw =
|
|
5398
|
+
const raw = fs12.readlinkSync(link);
|
|
5139
5399
|
return path10.resolve(path10.dirname(link), raw);
|
|
5140
5400
|
} catch {
|
|
5141
5401
|
return null;
|
|
@@ -5144,9 +5404,9 @@ function readCurrent(type) {
|
|
|
5144
5404
|
function clearCurrent(type) {
|
|
5145
5405
|
const link = paths.current(type);
|
|
5146
5406
|
try {
|
|
5147
|
-
|
|
5407
|
+
fs12.rmSync(link, { force: true });
|
|
5148
5408
|
} catch {
|
|
5149
|
-
|
|
5409
|
+
fs12.rmSync(link, { recursive: true, force: true });
|
|
5150
5410
|
}
|
|
5151
5411
|
}
|
|
5152
5412
|
|
|
@@ -5154,13 +5414,13 @@ function clearCurrent(type) {
|
|
|
5154
5414
|
function listInstalled(type) {
|
|
5155
5415
|
const spec = getSdkType(type);
|
|
5156
5416
|
const root = paths.sdks(type);
|
|
5157
|
-
if (!
|
|
5417
|
+
if (!fs13.existsSync(root)) return [];
|
|
5158
5418
|
const result = [];
|
|
5159
|
-
for (const name of
|
|
5419
|
+
for (const name of fs13.readdirSync(root)) {
|
|
5160
5420
|
const version = spec.parseDirName(name);
|
|
5161
5421
|
if (!version) continue;
|
|
5162
5422
|
const dirPath = path11.join(root, name);
|
|
5163
|
-
if (!
|
|
5423
|
+
if (!fs13.statSync(dirPath).isDirectory()) continue;
|
|
5164
5424
|
result.push({ type, version, dirPath, home: spec.locateHome(dirPath) });
|
|
5165
5425
|
}
|
|
5166
5426
|
result.sort((a, b) => spec.compareVersions(a.version, b.version));
|
|
@@ -5232,7 +5492,7 @@ function detectRcFile(platform) {
|
|
|
5232
5492
|
}
|
|
5233
5493
|
|
|
5234
5494
|
// src/shell/rc.ts
|
|
5235
|
-
import
|
|
5495
|
+
import fs14 from "fs";
|
|
5236
5496
|
import os3 from "os";
|
|
5237
5497
|
import path13 from "path";
|
|
5238
5498
|
function rcBegin(type) {
|
|
@@ -5270,8 +5530,8 @@ ${rcBlock(type)}
|
|
|
5270
5530
|
`;
|
|
5271
5531
|
}
|
|
5272
5532
|
function upsertRcFile(file, type) {
|
|
5273
|
-
const content =
|
|
5274
|
-
|
|
5533
|
+
const content = fs14.existsSync(file) ? fs14.readFileSync(file, "utf8") : "";
|
|
5534
|
+
fs14.writeFileSync(file, upsertRcContent(content, type));
|
|
5275
5535
|
}
|
|
5276
5536
|
function escapeRegex(s) {
|
|
5277
5537
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -5374,6 +5634,9 @@ async function useCommand(type, specInput, opts) {
|
|
|
5374
5634
|
console.log(rcBlock(type));
|
|
5375
5635
|
}
|
|
5376
5636
|
}
|
|
5637
|
+
if (spec.requiresJdk && !envGet("JAVA_HOME")) {
|
|
5638
|
+
log.warn(`${spec.label} needs a JDK. Run: ${CLI_BIN} java use <version>`);
|
|
5639
|
+
}
|
|
5377
5640
|
await showSdkVersion(path15.join(installed.home, spec.binRelPath(platform)), type);
|
|
5378
5641
|
}
|
|
5379
5642
|
|
|
@@ -5454,7 +5717,7 @@ function currentCommand(types = SDK_TYPES) {
|
|
|
5454
5717
|
}
|
|
5455
5718
|
|
|
5456
5719
|
// src/cli/uninstall.ts
|
|
5457
|
-
import
|
|
5720
|
+
import fs15 from "fs";
|
|
5458
5721
|
async function uninstallCommand(type, specInput, opts) {
|
|
5459
5722
|
const spec = getSdkType(type);
|
|
5460
5723
|
const installed = findInstalled(type, specInput, opts.vendor);
|
|
@@ -5464,7 +5727,7 @@ async function uninstallCommand(type, specInput, opts) {
|
|
|
5464
5727
|
log.warn(`uninstalled the current ${spec.label}; ${spec.envVar} is now dangling`);
|
|
5465
5728
|
log.info(`select another: ${cmdPath(type)} use <version>`);
|
|
5466
5729
|
}
|
|
5467
|
-
|
|
5730
|
+
fs15.rmSync(installed.dirPath, { recursive: true, force: true });
|
|
5468
5731
|
});
|
|
5469
5732
|
log.ok(`removed ${installed.version.vendor}-${spec.formatVersion(installed.version)}`);
|
|
5470
5733
|
}
|
|
@@ -5474,7 +5737,8 @@ var MIRRORABLE_BY_TYPE = {
|
|
|
5474
5737
|
java: ["temurin"],
|
|
5475
5738
|
go: ["golang"],
|
|
5476
5739
|
flutter: ["flutter"],
|
|
5477
|
-
node: ["nodejs"]
|
|
5740
|
+
node: ["nodejs"],
|
|
5741
|
+
maven: ["maven"]
|
|
5478
5742
|
};
|
|
5479
5743
|
var MIRROR_SITE_PRESETS = [
|
|
5480
5744
|
{
|
|
@@ -5502,14 +5766,16 @@ var MIRROR_SITE_PRESETS = [
|
|
|
5502
5766
|
list: true,
|
|
5503
5767
|
vendors: {
|
|
5504
5768
|
golang: "https://mirrors.aliyun.com/golang",
|
|
5505
|
-
nodejs: "https://mirrors.aliyun.com/nodejs-release"
|
|
5769
|
+
nodejs: "https://mirrors.aliyun.com/nodejs-release",
|
|
5770
|
+
maven: "https://maven.aliyun.com/repository/central"
|
|
5506
5771
|
}
|
|
5507
5772
|
},
|
|
5508
5773
|
{
|
|
5509
5774
|
name: "huawei",
|
|
5510
5775
|
list: true,
|
|
5511
5776
|
vendors: {
|
|
5512
|
-
nodejs: "https://repo.huaweicloud.com/nodejs"
|
|
5777
|
+
nodejs: "https://repo.huaweicloud.com/nodejs",
|
|
5778
|
+
maven: "https://repo.huaweicloud.com/repository/maven"
|
|
5513
5779
|
}
|
|
5514
5780
|
},
|
|
5515
5781
|
{
|
|
@@ -5758,7 +6024,7 @@ function mirrorCommand(type, action, arg1, arg2) {
|
|
|
5758
6024
|
|
|
5759
6025
|
// src/cli/upgrade.ts
|
|
5760
6026
|
import { spawn } from "child_process";
|
|
5761
|
-
import
|
|
6027
|
+
import fs16 from "fs";
|
|
5762
6028
|
import path16 from "path";
|
|
5763
6029
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5764
6030
|
var RELEASE_REPO = "QInJ1995/sdkvm";
|
|
@@ -5794,12 +6060,12 @@ function checksumFor(sumsText, fileName) {
|
|
|
5794
6060
|
}
|
|
5795
6061
|
async function prepareCliPackage(archiveFile, home = sdkvmHome()) {
|
|
5796
6062
|
const staging = path16.join(home, "cli.next");
|
|
5797
|
-
|
|
5798
|
-
|
|
6063
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
6064
|
+
fs16.mkdirSync(home, { recursive: true });
|
|
5799
6065
|
await extractArchive(archiveFile, "tar.gz", staging, detectPlatform());
|
|
5800
6066
|
const unpacked = path16.join(staging, "package");
|
|
5801
|
-
if (!
|
|
5802
|
-
|
|
6067
|
+
if (!fs16.existsSync(path16.join(unpacked, "package.json"))) {
|
|
6068
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5803
6069
|
throw new SdkvmError("Release archive is missing package/package.json", { hint: archiveFile });
|
|
5804
6070
|
}
|
|
5805
6071
|
return unpacked;
|
|
@@ -5809,22 +6075,22 @@ async function replaceCliPackage(archiveFile, home = sdkvmHome()) {
|
|
|
5809
6075
|
const bak = path16.join(home, "cli.bak");
|
|
5810
6076
|
const cli = path16.join(home, "cli");
|
|
5811
6077
|
const unpacked = await prepareCliPackage(archiveFile, home);
|
|
5812
|
-
|
|
5813
|
-
if (
|
|
6078
|
+
fs16.rmSync(bak, { recursive: true, force: true });
|
|
6079
|
+
if (fs16.existsSync(cli)) fs16.renameSync(cli, bak);
|
|
5814
6080
|
try {
|
|
5815
|
-
|
|
6081
|
+
fs16.renameSync(unpacked, cli);
|
|
5816
6082
|
} catch (err) {
|
|
5817
|
-
if (
|
|
6083
|
+
if (fs16.existsSync(bak) && !fs16.existsSync(cli)) {
|
|
5818
6084
|
try {
|
|
5819
|
-
|
|
6085
|
+
fs16.renameSync(bak, cli);
|
|
5820
6086
|
} catch {
|
|
5821
6087
|
}
|
|
5822
6088
|
}
|
|
5823
|
-
|
|
6089
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5824
6090
|
throw err;
|
|
5825
6091
|
}
|
|
5826
|
-
|
|
5827
|
-
|
|
6092
|
+
fs16.rmSync(bak, { recursive: true, force: true });
|
|
6093
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5828
6094
|
}
|
|
5829
6095
|
function windowsUpgradeScript(home) {
|
|
5830
6096
|
return [
|
|
@@ -5847,7 +6113,7 @@ function windowsUpgradeScript(home) {
|
|
|
5847
6113
|
}
|
|
5848
6114
|
function scheduleWindowsCliReplace(home) {
|
|
5849
6115
|
const script = path16.join(home, "upgrade-apply.cmd");
|
|
5850
|
-
|
|
6116
|
+
fs16.writeFileSync(script, windowsUpgradeScript(home), "utf8");
|
|
5851
6117
|
const child = spawn("cmd.exe", ["/c", script], {
|
|
5852
6118
|
detached: true,
|
|
5853
6119
|
stdio: "ignore",
|
|
@@ -5869,7 +6135,7 @@ async function upgradeCommand() {
|
|
|
5869
6135
|
if (!expected) {
|
|
5870
6136
|
throw new SdkvmError(`No checksum for ${RELEASE_ASSET}`, { hint: sumsUrl });
|
|
5871
6137
|
}
|
|
5872
|
-
|
|
6138
|
+
fs16.mkdirSync(paths.cache(), { recursive: true });
|
|
5873
6139
|
const dest = path16.join(paths.cache(), RELEASE_ASSET);
|
|
5874
6140
|
try {
|
|
5875
6141
|
const downloaded = await downloadFile(assetUrl, dest);
|
|
@@ -5894,8 +6160,8 @@ async function upgradeCommand() {
|
|
|
5894
6160
|
`upgraded CLI ${before} \u2192 ${after} in ${path16.join(home, "cli")}; runtime and installed SDKs were left in place`
|
|
5895
6161
|
);
|
|
5896
6162
|
} finally {
|
|
5897
|
-
|
|
5898
|
-
|
|
6163
|
+
fs16.rmSync(dest, { force: true });
|
|
6164
|
+
fs16.rmSync(`${dest}.part`, { force: true });
|
|
5899
6165
|
}
|
|
5900
6166
|
});
|
|
5901
6167
|
}
|
|
@@ -6095,17 +6361,29 @@ async function nrmTest(name, opts = {}) {
|
|
|
6095
6361
|
|
|
6096
6362
|
// src/index.ts
|
|
6097
6363
|
var program2 = new Command();
|
|
6098
|
-
program2.name("sdkvm").description("SDK version manager \u2014 install & switch JDKs (Temurin / Zulu / Corretto), Go toolchains, Flutter SDKs,
|
|
6364
|
+
program2.name("sdkvm").description("SDK version manager \u2014 install & switch JDKs (Temurin / Zulu / Corretto), Go toolchains, Flutter SDKs, Node.js runtimes, and Apache Maven").version(getVersion());
|
|
6365
|
+
var INSTALL_HELP = {
|
|
6366
|
+
java: "21 | lts | 21.0.5 | 21.0.5+11 | temurin-21",
|
|
6367
|
+
go: "1.24 | 1.24.5 | latest | golang-1.24",
|
|
6368
|
+
flutter: "3.47 | 3.47.5 | 3.49.0-0.1.pre | latest | flutter-3.47",
|
|
6369
|
+
node: "22 | 22.20.0 | lts | latest | nodejs-22.20.0",
|
|
6370
|
+
maven: "3 | 3.9 | 3.9.9 | 4.0.0-rc-4 | latest | maven-3.9"
|
|
6371
|
+
};
|
|
6372
|
+
var VERSION_EXAMPLE = {
|
|
6373
|
+
java: "21 / temurin-21.0.5+11",
|
|
6374
|
+
go: "1.24 / golang-1.24.5",
|
|
6375
|
+
flutter: "3.47 / flutter-3.47.5",
|
|
6376
|
+
node: "22 / nodejs-22.20.0",
|
|
6377
|
+
maven: "3.9 / maven-3.9.9"
|
|
6378
|
+
};
|
|
6099
6379
|
function registerSdkCommands(cmd, type) {
|
|
6100
6380
|
const s = getSdkType(type);
|
|
6101
|
-
const isJava = type === "java";
|
|
6102
|
-
const installHelp = isJava ? "21 | lts | 21.0.5 | 21.0.5+11 | temurin-21" : type === "go" ? "1.24 | 1.24.5 | latest | golang-1.24" : type === "flutter" ? "3.47 | 3.47.5 | 3.49.0-0.1.pre | latest | flutter-3.47" : "22 | 22.20.0 | lts | latest | nodejs-22.20.0";
|
|
6103
6381
|
const vendorIds = s.vendors.map((v) => v.id).join(" | ");
|
|
6104
|
-
cmd.command("install").description(`install a ${s.label}: ${
|
|
6105
|
-
cmd.command("use").description(`switch the current ${s.label} (updates ${s.envVar} / PATH)`).argument("<version>", `installed version, e.g. ${
|
|
6382
|
+
cmd.command("install").description(`install a ${s.label}: ${INSTALL_HELP[type]}`).argument("<version>", "version spec (optional vendor- prefix)").option("--vendor <id>", `vendor: ${vendorIds}`).option("--force", "reinstall even if already installed").action((v, o) => installCommand(type, v, o));
|
|
6383
|
+
cmd.command("use").description(`switch the current ${s.label} (updates ${s.envVar} / PATH)`).argument("<version>", `installed version, e.g. ${VERSION_EXAMPLE[type]}`).option("--vendor <id>", "restrict matching to a vendor").action((v, o) => useCommand(type, v, o));
|
|
6106
6384
|
cmd.command("ls").alias("list").description(`list installed ${s.label}s (\u2192 marks current); -r lists installable versions`).option("-r, --remote", "list installable versions from all vendors").option("--vendor <id>", "filter --remote output to one vendor").action((o) => lsCommand(type, o));
|
|
6107
6385
|
cmd.command("current").description(`show the current ${s.label}`).action(() => currentCommand([type]));
|
|
6108
|
-
cmd.command("uninstall").description(`remove an installed ${s.label}`).argument("<version>", `installed version, e.g. ${
|
|
6386
|
+
cmd.command("uninstall").description(`remove an installed ${s.label}`).argument("<version>", `installed version, e.g. ${VERSION_EXAMPLE[type]}`).option("--vendor <id>", "restrict matching to a vendor").action((v, o) => uninstallCommand(type, v, o));
|
|
6109
6387
|
cmd.command("mirror").description("show, set, or switch download mirror sites for this SDK").argument("[action]", "ls | use | current | show | set | unset").argument("[nameOrVendor]", "site name, vendor id, or URL").argument("[url]", "mirror root URL (for set)").action(
|
|
6110
6388
|
(a, v, u) => mirrorCommand(type, a, v, u)
|
|
6111
6389
|
);
|
|
@@ -6123,6 +6401,9 @@ flutterCmd.action(() => flutterCmd.help());
|
|
|
6123
6401
|
var nodeCmd = program2.command("node").description("Node.js subcommands");
|
|
6124
6402
|
registerSdkCommands(nodeCmd, "node");
|
|
6125
6403
|
nodeCmd.action(() => nodeCmd.help());
|
|
6404
|
+
var mavenCmd = program2.command("maven").description("Apache Maven subcommands");
|
|
6405
|
+
registerSdkCommands(mavenCmd, "maven");
|
|
6406
|
+
mavenCmd.action(() => mavenCmd.help());
|
|
6126
6407
|
program2.commands.find((c) => c.name() === "current")?.action(() => currentCommand());
|
|
6127
6408
|
program2.command("version").description("print sdkvm CLI version").action(versionCommand);
|
|
6128
6409
|
program2.command("upgrade").description("upgrade the sdkvm CLI (script install replaces ~/.sdkvm/cli; npm install prints npm update -g)").action(upgradeCommand);
|