sdkvm 1.0.2 → 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 +153 -122
- package/README.md +154 -123
- package/dist/index.js +385 -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,19 +5034,72 @@ 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;
|
|
4829
|
-
|
|
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
|
+
}
|
|
5045
|
+
function hex64(value) {
|
|
5046
|
+
return hexOf(value, "sha256");
|
|
5047
|
+
}
|
|
5048
|
+
function extractExpectedChecksum(text, kind = "sha256") {
|
|
4830
5049
|
const trimmed = text.trim();
|
|
4831
|
-
if (trimmed.startsWith("{")) {
|
|
5050
|
+
if (kind === "sha256" && trimmed.startsWith("{")) {
|
|
4832
5051
|
try {
|
|
4833
5052
|
const obj = JSON.parse(trimmed);
|
|
4834
|
-
|
|
5053
|
+
const direct = hex64(obj.checksum) ?? hex64(obj.sha256);
|
|
5054
|
+
if (direct) return direct;
|
|
5055
|
+
if (Array.isArray(obj.hashes)) {
|
|
5056
|
+
for (const item of obj.hashes) {
|
|
5057
|
+
if (!item || typeof item !== "object") continue;
|
|
5058
|
+
const hash = item;
|
|
5059
|
+
const alg = typeof hash.alg === "string" ? hash.alg.toLowerCase().replace(/-/g, "") : "";
|
|
5060
|
+
if (alg === "sha256") {
|
|
5061
|
+
const content = hex64(hash.content);
|
|
5062
|
+
if (content) return content;
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
4835
5066
|
} catch {
|
|
4836
5067
|
}
|
|
4837
5068
|
return null;
|
|
4838
5069
|
}
|
|
4839
5070
|
const token = trimmed.split(/\s+/)[0] ?? "";
|
|
4840
|
-
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;
|
|
4841
5103
|
}
|
|
4842
5104
|
async function verifyChecksum(artifact, actual, opts = {}) {
|
|
4843
5105
|
const strict = opts.strict === true;
|
|
@@ -4853,17 +5115,28 @@ async function verifyChecksum(artifact, actual, opts = {}) {
|
|
|
4853
5115
|
}
|
|
4854
5116
|
let expected = info.expected?.toLowerCase() ?? null;
|
|
4855
5117
|
if (!expected && info.url) {
|
|
5118
|
+
const fallback = opts.fallbackUrl && opts.fallbackUrl !== info.url ? opts.fallbackUrl : void 0;
|
|
4856
5119
|
try {
|
|
4857
|
-
expected = extractExpectedChecksum(await httpText(info.url));
|
|
5120
|
+
expected = extractExpectedChecksum(await httpText(info.url), info.kind);
|
|
4858
5121
|
} catch (err) {
|
|
4859
|
-
if (
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
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;
|
|
4864
5131
|
}
|
|
4865
|
-
log.warn(`cannot fetch checksum for ${artifact.displayName},
|
|
4866
|
-
|
|
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;
|
|
4867
5140
|
}
|
|
4868
5141
|
}
|
|
4869
5142
|
if (!expected) {
|
|
@@ -4883,7 +5156,7 @@ async function verifyChecksum(artifact, actual, opts = {}) {
|
|
|
4883
5156
|
}
|
|
4884
5157
|
|
|
4885
5158
|
// src/fs/extract.ts
|
|
4886
|
-
import
|
|
5159
|
+
import fs9 from "fs";
|
|
4887
5160
|
import path7 from "path";
|
|
4888
5161
|
|
|
4889
5162
|
// src/util/spawn.ts
|
|
@@ -4909,9 +5182,9 @@ async function run(cmd, args, opts = {}) {
|
|
|
4909
5182
|
// src/fs/extract.ts
|
|
4910
5183
|
var WIN_TAR = "C:\\Windows\\System32\\tar.exe";
|
|
4911
5184
|
async function extractArchive(archiveFile, archiveType, destDir, platform) {
|
|
4912
|
-
|
|
5185
|
+
fs9.mkdirSync(destDir, { recursive: true });
|
|
4913
5186
|
if (platform.os === "windows") {
|
|
4914
|
-
if (
|
|
5187
|
+
if (fs9.existsSync(WIN_TAR)) {
|
|
4915
5188
|
await run(WIN_TAR, ["-xf", archiveFile, "-C", destDir]);
|
|
4916
5189
|
} else {
|
|
4917
5190
|
await run("powershell.exe", [
|
|
@@ -4934,21 +5207,21 @@ function tmpExtractDir(base) {
|
|
|
4934
5207
|
}
|
|
4935
5208
|
|
|
4936
5209
|
// src/fs/layout.ts
|
|
4937
|
-
import
|
|
5210
|
+
import fs10 from "fs";
|
|
4938
5211
|
import path8 from "path";
|
|
4939
5212
|
function normalizeExtracted(tmpDir, platform, type) {
|
|
4940
5213
|
const spec = getSdkType(type);
|
|
4941
|
-
const entries =
|
|
5214
|
+
const entries = fs10.readdirSync(tmpDir).filter((e) => e !== "._" && !e.startsWith("._"));
|
|
4942
5215
|
const real = entries.filter((e) => e !== ".DS_Store");
|
|
4943
5216
|
let root;
|
|
4944
|
-
if (real.length === 1 &&
|
|
5217
|
+
if (real.length === 1 && fs10.statSync(path8.join(tmpDir, real[0])).isDirectory()) {
|
|
4945
5218
|
root = path8.join(tmpDir, real[0]);
|
|
4946
5219
|
} else {
|
|
4947
5220
|
root = tmpDir;
|
|
4948
5221
|
}
|
|
4949
5222
|
const home = spec.locateHome(root);
|
|
4950
5223
|
const bin = path8.join(home, spec.binRelPath(platform));
|
|
4951
|
-
if (!
|
|
5224
|
+
if (!fs10.existsSync(bin)) {
|
|
4952
5225
|
throw new SdkvmError(`Archive does not look like a valid ${spec.label} (bin not found)`, {
|
|
4953
5226
|
hint: `expected ${bin}`
|
|
4954
5227
|
});
|
|
@@ -5000,7 +5273,7 @@ function createProgress(label2) {
|
|
|
5000
5273
|
async function renameWithRetry(from, to, attempts = 3) {
|
|
5001
5274
|
for (let i = 1; ; i++) {
|
|
5002
5275
|
try {
|
|
5003
|
-
|
|
5276
|
+
fs11.renameSync(from, to);
|
|
5004
5277
|
return;
|
|
5005
5278
|
} catch (err) {
|
|
5006
5279
|
if (i >= attempts) throw err;
|
|
@@ -5034,7 +5307,7 @@ async function installCommand(type, specInput, opts) {
|
|
|
5034
5307
|
const hintVersion = type === "java" || type === "node" ? String(artifact.version.major) : `${artifact.version.major}.${artifact.version.minor}`;
|
|
5035
5308
|
await withLock(async () => {
|
|
5036
5309
|
ensureLayout();
|
|
5037
|
-
if (
|
|
5310
|
+
if (fs11.existsSync(finalDir)) {
|
|
5038
5311
|
if (!opts.force) {
|
|
5039
5312
|
log.warn(`${artifact.displayName} is already installed`);
|
|
5040
5313
|
log.info(`run: ${cmdPath(type)} use ${hintVersion}`);
|
|
@@ -5042,15 +5315,17 @@ async function installCommand(type, specInput, opts) {
|
|
|
5042
5315
|
}
|
|
5043
5316
|
log.warn(`--force: removing existing ${artifact.dirName}`);
|
|
5044
5317
|
}
|
|
5045
|
-
for (const f of
|
|
5046
|
-
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 });
|
|
5047
5320
|
}
|
|
5048
5321
|
const dest = path9.join(paths.cache(), cacheFileName(artifact.downloadUrl));
|
|
5049
5322
|
const progress = createProgress(`\u2193 ${artifact.displayName}`);
|
|
5050
5323
|
log.info(`downloading ${artifact.downloadUrl}`);
|
|
5051
5324
|
const dl = await downloadFile(artifact.downloadUrl, dest, (b, t) => progress.update(b, t));
|
|
5052
5325
|
progress.done(dl.bytes, null);
|
|
5053
|
-
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 });
|
|
5054
5329
|
const tmp = tmpExtractDir(paths.tmp());
|
|
5055
5330
|
const bak = `${finalDir}.bak`;
|
|
5056
5331
|
let finalTmp = tmp;
|
|
@@ -5059,28 +5334,28 @@ async function installCommand(type, specInput, opts) {
|
|
|
5059
5334
|
await extractArchive(dest, artifact.archive, tmp, platform);
|
|
5060
5335
|
const normalized = normalizeExtracted(tmp, platform, type);
|
|
5061
5336
|
finalTmp = normalized.root;
|
|
5062
|
-
|
|
5063
|
-
if (
|
|
5337
|
+
fs11.rmSync(bak, { recursive: true, force: true });
|
|
5338
|
+
if (fs11.existsSync(finalDir)) fs11.renameSync(finalDir, bak);
|
|
5064
5339
|
try {
|
|
5065
5340
|
await renameWithRetry(normalized.root, finalDir);
|
|
5066
5341
|
} catch (err) {
|
|
5067
|
-
if (
|
|
5342
|
+
if (fs11.existsSync(bak) && !fs11.existsSync(finalDir)) {
|
|
5068
5343
|
try {
|
|
5069
|
-
|
|
5344
|
+
fs11.renameSync(bak, finalDir);
|
|
5070
5345
|
} catch {
|
|
5071
5346
|
}
|
|
5072
5347
|
}
|
|
5073
5348
|
throw err;
|
|
5074
5349
|
}
|
|
5075
|
-
|
|
5350
|
+
fs11.rmSync(bak, { recursive: true, force: true });
|
|
5076
5351
|
} catch (err) {
|
|
5077
|
-
|
|
5078
|
-
|
|
5352
|
+
fs11.rmSync(finalTmp, { recursive: true, force: true });
|
|
5353
|
+
fs11.rmSync(tmp, { recursive: true, force: true });
|
|
5079
5354
|
throw err;
|
|
5080
5355
|
} finally {
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5356
|
+
fs11.rmSync(dest, { force: true });
|
|
5357
|
+
fs11.rmSync(paths.tmp(), { recursive: true, force: true });
|
|
5358
|
+
fs11.mkdirSync(paths.tmp(), { recursive: true });
|
|
5084
5359
|
}
|
|
5085
5360
|
log.ok(`installed ${artifact.displayName} \u2192 ${finalDir}`);
|
|
5086
5361
|
log.info(`switch to it: ${cmdPath(type)} use ${hintVersion}`);
|
|
@@ -5093,34 +5368,34 @@ import { promisify as promisify2 } from "util";
|
|
|
5093
5368
|
import path15 from "path";
|
|
5094
5369
|
|
|
5095
5370
|
// src/core/registry.ts
|
|
5096
|
-
import
|
|
5371
|
+
import fs13 from "fs";
|
|
5097
5372
|
import path11 from "path";
|
|
5098
5373
|
|
|
5099
5374
|
// src/fs/link.ts
|
|
5100
|
-
import
|
|
5375
|
+
import fs12 from "fs";
|
|
5101
5376
|
import path10 from "path";
|
|
5102
5377
|
function setCurrent(type, target, platform) {
|
|
5103
5378
|
const link = paths.current(type);
|
|
5104
5379
|
if (platform.os === "windows") {
|
|
5105
5380
|
try {
|
|
5106
|
-
|
|
5381
|
+
fs12.rmSync(link, { force: true });
|
|
5107
5382
|
} catch {
|
|
5108
|
-
|
|
5383
|
+
fs12.rmSync(link, { recursive: true, force: true });
|
|
5109
5384
|
}
|
|
5110
|
-
|
|
5385
|
+
fs12.symlinkSync(target, link, "junction");
|
|
5111
5386
|
return;
|
|
5112
5387
|
}
|
|
5113
5388
|
const tmp = `${link}.tmp-${process.pid}`;
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5389
|
+
fs12.rmSync(tmp, { force: true });
|
|
5390
|
+
fs12.symlinkSync(target, tmp);
|
|
5391
|
+
fs12.renameSync(tmp, link);
|
|
5117
5392
|
}
|
|
5118
5393
|
function readCurrent(type) {
|
|
5119
5394
|
const link = paths.current(type);
|
|
5120
5395
|
try {
|
|
5121
|
-
const st =
|
|
5396
|
+
const st = fs12.lstatSync(link);
|
|
5122
5397
|
if (!st.isSymbolicLink()) return null;
|
|
5123
|
-
const raw =
|
|
5398
|
+
const raw = fs12.readlinkSync(link);
|
|
5124
5399
|
return path10.resolve(path10.dirname(link), raw);
|
|
5125
5400
|
} catch {
|
|
5126
5401
|
return null;
|
|
@@ -5129,9 +5404,9 @@ function readCurrent(type) {
|
|
|
5129
5404
|
function clearCurrent(type) {
|
|
5130
5405
|
const link = paths.current(type);
|
|
5131
5406
|
try {
|
|
5132
|
-
|
|
5407
|
+
fs12.rmSync(link, { force: true });
|
|
5133
5408
|
} catch {
|
|
5134
|
-
|
|
5409
|
+
fs12.rmSync(link, { recursive: true, force: true });
|
|
5135
5410
|
}
|
|
5136
5411
|
}
|
|
5137
5412
|
|
|
@@ -5139,13 +5414,13 @@ function clearCurrent(type) {
|
|
|
5139
5414
|
function listInstalled(type) {
|
|
5140
5415
|
const spec = getSdkType(type);
|
|
5141
5416
|
const root = paths.sdks(type);
|
|
5142
|
-
if (!
|
|
5417
|
+
if (!fs13.existsSync(root)) return [];
|
|
5143
5418
|
const result = [];
|
|
5144
|
-
for (const name of
|
|
5419
|
+
for (const name of fs13.readdirSync(root)) {
|
|
5145
5420
|
const version = spec.parseDirName(name);
|
|
5146
5421
|
if (!version) continue;
|
|
5147
5422
|
const dirPath = path11.join(root, name);
|
|
5148
|
-
if (!
|
|
5423
|
+
if (!fs13.statSync(dirPath).isDirectory()) continue;
|
|
5149
5424
|
result.push({ type, version, dirPath, home: spec.locateHome(dirPath) });
|
|
5150
5425
|
}
|
|
5151
5426
|
result.sort((a, b) => spec.compareVersions(a.version, b.version));
|
|
@@ -5217,7 +5492,7 @@ function detectRcFile(platform) {
|
|
|
5217
5492
|
}
|
|
5218
5493
|
|
|
5219
5494
|
// src/shell/rc.ts
|
|
5220
|
-
import
|
|
5495
|
+
import fs14 from "fs";
|
|
5221
5496
|
import os3 from "os";
|
|
5222
5497
|
import path13 from "path";
|
|
5223
5498
|
function rcBegin(type) {
|
|
@@ -5255,8 +5530,8 @@ ${rcBlock(type)}
|
|
|
5255
5530
|
`;
|
|
5256
5531
|
}
|
|
5257
5532
|
function upsertRcFile(file, type) {
|
|
5258
|
-
const content =
|
|
5259
|
-
|
|
5533
|
+
const content = fs14.existsSync(file) ? fs14.readFileSync(file, "utf8") : "";
|
|
5534
|
+
fs14.writeFileSync(file, upsertRcContent(content, type));
|
|
5260
5535
|
}
|
|
5261
5536
|
function escapeRegex(s) {
|
|
5262
5537
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -5359,6 +5634,9 @@ async function useCommand(type, specInput, opts) {
|
|
|
5359
5634
|
console.log(rcBlock(type));
|
|
5360
5635
|
}
|
|
5361
5636
|
}
|
|
5637
|
+
if (spec.requiresJdk && !envGet("JAVA_HOME")) {
|
|
5638
|
+
log.warn(`${spec.label} needs a JDK. Run: ${CLI_BIN} java use <version>`);
|
|
5639
|
+
}
|
|
5362
5640
|
await showSdkVersion(path15.join(installed.home, spec.binRelPath(platform)), type);
|
|
5363
5641
|
}
|
|
5364
5642
|
|
|
@@ -5439,7 +5717,7 @@ function currentCommand(types = SDK_TYPES) {
|
|
|
5439
5717
|
}
|
|
5440
5718
|
|
|
5441
5719
|
// src/cli/uninstall.ts
|
|
5442
|
-
import
|
|
5720
|
+
import fs15 from "fs";
|
|
5443
5721
|
async function uninstallCommand(type, specInput, opts) {
|
|
5444
5722
|
const spec = getSdkType(type);
|
|
5445
5723
|
const installed = findInstalled(type, specInput, opts.vendor);
|
|
@@ -5449,7 +5727,7 @@ async function uninstallCommand(type, specInput, opts) {
|
|
|
5449
5727
|
log.warn(`uninstalled the current ${spec.label}; ${spec.envVar} is now dangling`);
|
|
5450
5728
|
log.info(`select another: ${cmdPath(type)} use <version>`);
|
|
5451
5729
|
}
|
|
5452
|
-
|
|
5730
|
+
fs15.rmSync(installed.dirPath, { recursive: true, force: true });
|
|
5453
5731
|
});
|
|
5454
5732
|
log.ok(`removed ${installed.version.vendor}-${spec.formatVersion(installed.version)}`);
|
|
5455
5733
|
}
|
|
@@ -5459,7 +5737,8 @@ var MIRRORABLE_BY_TYPE = {
|
|
|
5459
5737
|
java: ["temurin"],
|
|
5460
5738
|
go: ["golang"],
|
|
5461
5739
|
flutter: ["flutter"],
|
|
5462
|
-
node: ["nodejs"]
|
|
5740
|
+
node: ["nodejs"],
|
|
5741
|
+
maven: ["maven"]
|
|
5463
5742
|
};
|
|
5464
5743
|
var MIRROR_SITE_PRESETS = [
|
|
5465
5744
|
{
|
|
@@ -5487,14 +5766,16 @@ var MIRROR_SITE_PRESETS = [
|
|
|
5487
5766
|
list: true,
|
|
5488
5767
|
vendors: {
|
|
5489
5768
|
golang: "https://mirrors.aliyun.com/golang",
|
|
5490
|
-
nodejs: "https://mirrors.aliyun.com/nodejs-release"
|
|
5769
|
+
nodejs: "https://mirrors.aliyun.com/nodejs-release",
|
|
5770
|
+
maven: "https://maven.aliyun.com/repository/central"
|
|
5491
5771
|
}
|
|
5492
5772
|
},
|
|
5493
5773
|
{
|
|
5494
5774
|
name: "huawei",
|
|
5495
5775
|
list: true,
|
|
5496
5776
|
vendors: {
|
|
5497
|
-
nodejs: "https://repo.huaweicloud.com/nodejs"
|
|
5777
|
+
nodejs: "https://repo.huaweicloud.com/nodejs",
|
|
5778
|
+
maven: "https://repo.huaweicloud.com/repository/maven"
|
|
5498
5779
|
}
|
|
5499
5780
|
},
|
|
5500
5781
|
{
|
|
@@ -5743,7 +6024,7 @@ function mirrorCommand(type, action, arg1, arg2) {
|
|
|
5743
6024
|
|
|
5744
6025
|
// src/cli/upgrade.ts
|
|
5745
6026
|
import { spawn } from "child_process";
|
|
5746
|
-
import
|
|
6027
|
+
import fs16 from "fs";
|
|
5747
6028
|
import path16 from "path";
|
|
5748
6029
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5749
6030
|
var RELEASE_REPO = "QInJ1995/sdkvm";
|
|
@@ -5779,12 +6060,12 @@ function checksumFor(sumsText, fileName) {
|
|
|
5779
6060
|
}
|
|
5780
6061
|
async function prepareCliPackage(archiveFile, home = sdkvmHome()) {
|
|
5781
6062
|
const staging = path16.join(home, "cli.next");
|
|
5782
|
-
|
|
5783
|
-
|
|
6063
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
6064
|
+
fs16.mkdirSync(home, { recursive: true });
|
|
5784
6065
|
await extractArchive(archiveFile, "tar.gz", staging, detectPlatform());
|
|
5785
6066
|
const unpacked = path16.join(staging, "package");
|
|
5786
|
-
if (!
|
|
5787
|
-
|
|
6067
|
+
if (!fs16.existsSync(path16.join(unpacked, "package.json"))) {
|
|
6068
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5788
6069
|
throw new SdkvmError("Release archive is missing package/package.json", { hint: archiveFile });
|
|
5789
6070
|
}
|
|
5790
6071
|
return unpacked;
|
|
@@ -5794,22 +6075,22 @@ async function replaceCliPackage(archiveFile, home = sdkvmHome()) {
|
|
|
5794
6075
|
const bak = path16.join(home, "cli.bak");
|
|
5795
6076
|
const cli = path16.join(home, "cli");
|
|
5796
6077
|
const unpacked = await prepareCliPackage(archiveFile, home);
|
|
5797
|
-
|
|
5798
|
-
if (
|
|
6078
|
+
fs16.rmSync(bak, { recursive: true, force: true });
|
|
6079
|
+
if (fs16.existsSync(cli)) fs16.renameSync(cli, bak);
|
|
5799
6080
|
try {
|
|
5800
|
-
|
|
6081
|
+
fs16.renameSync(unpacked, cli);
|
|
5801
6082
|
} catch (err) {
|
|
5802
|
-
if (
|
|
6083
|
+
if (fs16.existsSync(bak) && !fs16.existsSync(cli)) {
|
|
5803
6084
|
try {
|
|
5804
|
-
|
|
6085
|
+
fs16.renameSync(bak, cli);
|
|
5805
6086
|
} catch {
|
|
5806
6087
|
}
|
|
5807
6088
|
}
|
|
5808
|
-
|
|
6089
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5809
6090
|
throw err;
|
|
5810
6091
|
}
|
|
5811
|
-
|
|
5812
|
-
|
|
6092
|
+
fs16.rmSync(bak, { recursive: true, force: true });
|
|
6093
|
+
fs16.rmSync(staging, { recursive: true, force: true });
|
|
5813
6094
|
}
|
|
5814
6095
|
function windowsUpgradeScript(home) {
|
|
5815
6096
|
return [
|
|
@@ -5832,7 +6113,7 @@ function windowsUpgradeScript(home) {
|
|
|
5832
6113
|
}
|
|
5833
6114
|
function scheduleWindowsCliReplace(home) {
|
|
5834
6115
|
const script = path16.join(home, "upgrade-apply.cmd");
|
|
5835
|
-
|
|
6116
|
+
fs16.writeFileSync(script, windowsUpgradeScript(home), "utf8");
|
|
5836
6117
|
const child = spawn("cmd.exe", ["/c", script], {
|
|
5837
6118
|
detached: true,
|
|
5838
6119
|
stdio: "ignore",
|
|
@@ -5854,7 +6135,7 @@ async function upgradeCommand() {
|
|
|
5854
6135
|
if (!expected) {
|
|
5855
6136
|
throw new SdkvmError(`No checksum for ${RELEASE_ASSET}`, { hint: sumsUrl });
|
|
5856
6137
|
}
|
|
5857
|
-
|
|
6138
|
+
fs16.mkdirSync(paths.cache(), { recursive: true });
|
|
5858
6139
|
const dest = path16.join(paths.cache(), RELEASE_ASSET);
|
|
5859
6140
|
try {
|
|
5860
6141
|
const downloaded = await downloadFile(assetUrl, dest);
|
|
@@ -5879,8 +6160,8 @@ async function upgradeCommand() {
|
|
|
5879
6160
|
`upgraded CLI ${before} \u2192 ${after} in ${path16.join(home, "cli")}; runtime and installed SDKs were left in place`
|
|
5880
6161
|
);
|
|
5881
6162
|
} finally {
|
|
5882
|
-
|
|
5883
|
-
|
|
6163
|
+
fs16.rmSync(dest, { force: true });
|
|
6164
|
+
fs16.rmSync(`${dest}.part`, { force: true });
|
|
5884
6165
|
}
|
|
5885
6166
|
});
|
|
5886
6167
|
}
|
|
@@ -6080,17 +6361,29 @@ async function nrmTest(name, opts = {}) {
|
|
|
6080
6361
|
|
|
6081
6362
|
// src/index.ts
|
|
6082
6363
|
var program2 = new Command();
|
|
6083
|
-
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
|
+
};
|
|
6084
6379
|
function registerSdkCommands(cmd, type) {
|
|
6085
6380
|
const s = getSdkType(type);
|
|
6086
|
-
const isJava = type === "java";
|
|
6087
|
-
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";
|
|
6088
6381
|
const vendorIds = s.vendors.map((v) => v.id).join(" | ");
|
|
6089
|
-
cmd.command("install").description(`install a ${s.label}: ${
|
|
6090
|
-
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));
|
|
6091
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));
|
|
6092
6385
|
cmd.command("current").description(`show the current ${s.label}`).action(() => currentCommand([type]));
|
|
6093
|
-
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));
|
|
6094
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(
|
|
6095
6388
|
(a, v, u) => mirrorCommand(type, a, v, u)
|
|
6096
6389
|
);
|
|
@@ -6108,6 +6401,9 @@ flutterCmd.action(() => flutterCmd.help());
|
|
|
6108
6401
|
var nodeCmd = program2.command("node").description("Node.js subcommands");
|
|
6109
6402
|
registerSdkCommands(nodeCmd, "node");
|
|
6110
6403
|
nodeCmd.action(() => nodeCmd.help());
|
|
6404
|
+
var mavenCmd = program2.command("maven").description("Apache Maven subcommands");
|
|
6405
|
+
registerSdkCommands(mavenCmd, "maven");
|
|
6406
|
+
mavenCmd.action(() => mavenCmd.help());
|
|
6111
6407
|
program2.commands.find((c) => c.name() === "current")?.action(() => currentCommand());
|
|
6112
6408
|
program2.command("version").description("print sdkvm CLI version").action(versionCommand);
|
|
6113
6409
|
program2.command("upgrade").description("upgrade the sdkvm CLI (script install replaces ~/.sdkvm/cli; npm install prints npm update -g)").action(upgradeCommand);
|