@n-seiji/nuthatch 0.1.7 → 0.2.0
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.ja.md +21 -21
- package/README.md +21 -21
- package/dist/{clean-n2f9z8n3.js → clean-dkrfmz85.js} +24 -25
- package/dist/cli-26d2drt6.js +30 -0
- package/dist/{cli-2bhb9p0x.js → cli-77yanq37.js} +3 -1
- package/dist/{cli-ygt2w4e1.js → cli-9y31xrsx.js} +20 -28
- package/dist/cli-a56b2ar0.js +20 -0
- package/dist/{cli-g72ra4e5.js → cli-b0tk5wcx.js} +1 -19
- package/dist/{cli-pqd2qe7v.js → cli-btqjpf1q.js} +1 -1
- package/dist/{cli-71jgs14h.js → cli-fhta3tr8.js} +15 -1
- package/dist/{cli-7jg5qqs9.js → cli-fqz7emfm.js} +12 -12
- package/dist/{cli-3ya15je0.js → cli-mfz1rx2x.js} +6 -33
- package/dist/{cli-qrxgkskr.js → cli-ph0gp56k.js} +6 -21
- package/dist/{cli-pick-w9qk71fy.js → cli-pick-wdtja21m.js} +60 -151
- package/dist/{cli-23z98dw1.js → cli-r39xsdym.js} +17 -30
- package/dist/cli-s5qcjcwk.js +25 -0
- package/dist/{cli-update-7exha1em.js → cli-update-kepe7h0z.js} +82 -334
- package/dist/{cli-rcw5adqd.js → cli-wcnyhk4w.js} +1 -1
- package/dist/cli.js +52 -54
- package/dist/{init-s0dafa83.js → init-2x8g9295.js} +1 -10
- package/dist/{jump-nvdkeega.js → jump-tnpgxcsz.js} +5 -5
- package/dist/{ls-kvz4wmc9.js → ls-ky84e8ep.js} +3 -3
- package/dist/{render-ls-6r3vv7y0.js → render-ls-x4hpnsvy.js} +16 -27
- package/dist/rm-0g8cxees.js +7 -0
- package/dist/root-czmzc98y.js +7 -0
- package/package.json +3 -4
- package/dist/rm-231qjgd8.js +0 -7
- package/dist/root-mmyazwc3.js +0 -7
- package/shell/init.zsh +0 -53
|
@@ -2,16 +2,11 @@ import {
|
|
|
2
2
|
isRunningAsCompiledBinary,
|
|
3
3
|
wantsJson,
|
|
4
4
|
reportFatalError,
|
|
5
|
-
firstExecutable,
|
|
6
5
|
VERSION
|
|
7
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-mfz1rx2x.js";
|
|
8
7
|
import {
|
|
9
|
-
parentDir,
|
|
10
|
-
baseName,
|
|
11
|
-
absoluteCandidates,
|
|
12
|
-
splitPathEnv,
|
|
13
8
|
messageOf
|
|
14
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-ph0gp56k.js";
|
|
15
10
|
import {
|
|
16
11
|
reportResult
|
|
17
12
|
} from "./cli-dbzx9nzg.js";
|
|
@@ -21,43 +16,67 @@ import {
|
|
|
21
16
|
EXIT_SAFE_REJECTION,
|
|
22
17
|
ok,
|
|
23
18
|
fail
|
|
24
|
-
} from "./cli-
|
|
19
|
+
} from "./cli-77yanq37.js";
|
|
20
|
+
import {
|
|
21
|
+
parentDir
|
|
22
|
+
} from "./cli-s5qcjcwk.js";
|
|
25
23
|
|
|
26
|
-
// src/domain/install-
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
markers: ["/aquaproj-aqua/", "/aqua/pkgs/"],
|
|
42
|
-
manager: "aqua",
|
|
43
|
-
update: "aqua",
|
|
44
|
-
ownsNpmPrefix: false
|
|
45
|
-
},
|
|
46
|
-
{ markers: ["/.proto/tools/"], manager: "proto", update: "proto", ownsNpmPrefix: false }
|
|
24
|
+
// src/domain/install-method.ts
|
|
25
|
+
var RELEASE_ASSETS = new Map([
|
|
26
|
+
["darwin-arm64", "hop-darwin-arm64"],
|
|
27
|
+
["darwin-x64", "hop-darwin-x64"],
|
|
28
|
+
["linux-x64", "hop-linux-x64"]
|
|
29
|
+
]);
|
|
30
|
+
var MANAGED_TREES = [
|
|
31
|
+
"/Cellar/",
|
|
32
|
+
"/Caskroom/",
|
|
33
|
+
"/nix/store/",
|
|
34
|
+
"/aquaproj-aqua/",
|
|
35
|
+
"/aqua/pkgs/",
|
|
36
|
+
"/.proto/",
|
|
37
|
+
"/installs/"
|
|
47
38
|
];
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
var MISE_TREE = "/mise/installs/";
|
|
40
|
+
var NODE_MODULES = "/node_modules/";
|
|
41
|
+
var detectInstallMethod = (facts) => {
|
|
42
|
+
const path = facts.compiled ? facts.executablePath : facts.scriptPath;
|
|
43
|
+
if (path === null) {
|
|
44
|
+
return { kind: "other" };
|
|
45
|
+
}
|
|
46
|
+
if (path.includes(MISE_TREE)) {
|
|
47
|
+
return { kind: "mise" };
|
|
48
|
+
}
|
|
49
|
+
if (!facts.compiled) {
|
|
50
|
+
return { kind: path.includes(NODE_MODULES) ? "package-manager" : "other" };
|
|
51
|
+
}
|
|
52
|
+
const assetName = RELEASE_ASSETS.get(`${facts.platform}-${facts.arch}`);
|
|
53
|
+
if (assetName === undefined || MANAGED_TREES.some((tree) => path.includes(tree))) {
|
|
54
|
+
return { kind: "other" };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
kind: "standalone",
|
|
58
|
+
binaryPath: path,
|
|
59
|
+
installDir: parentDir(path),
|
|
60
|
+
assetName
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
var suggestedCommand = (kind) => {
|
|
64
|
+
if (kind === "mise") {
|
|
65
|
+
return ["mise", "upgrade"];
|
|
66
|
+
}
|
|
67
|
+
return kind === "package-manager" ? ["npm", "i", "-g", "@n-seiji/nuthatch@latest"] : null;
|
|
68
|
+
};
|
|
69
|
+
var updateHint = (kind) => {
|
|
70
|
+
const command = suggestedCommand(kind)?.join(" ");
|
|
71
|
+
if (kind === "mise") {
|
|
72
|
+
return `Update with mise: ${command}`;
|
|
73
|
+
}
|
|
74
|
+
return kind === "package-manager" ? `Update with your package manager, e.g. ${command}` : "Update hop with the tool you installed it with.";
|
|
51
75
|
};
|
|
52
|
-
var managerRootReason = (binaryPath) => reasonWithin(binaryPath, MANAGER_ROOTS);
|
|
53
|
-
var managerNpmPrefixReason = (prefix) => reasonWithin(prefix, MANAGER_ROOTS.filter(({ ownsNpmPrefix }) => ownsNpmPrefix));
|
|
54
76
|
|
|
55
77
|
// src/domain/self-update.ts
|
|
56
|
-
var NPM_PACKAGE = "@n-seiji/nuthatch";
|
|
57
|
-
var NPM_PACKAGE_LATEST = `${NPM_PACKAGE}@latest`;
|
|
58
78
|
var GITHUB_REPO = "n-seiji/nuthatch";
|
|
59
79
|
var GITHUB_LATEST_RELEASE_URL = `https://api.github.com/repos/${GITHUB_REPO}/releases/latest`;
|
|
60
|
-
var NPM_LATEST_URL = `https://registry.npmjs.org/${NPM_PACKAGE.replace("/", "%2F")}/latest`;
|
|
61
80
|
var releaseAssetUrl = (version, assetName) => `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${assetName}`;
|
|
62
81
|
var VERSION_PATTERN = /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/u;
|
|
63
82
|
var TAG_PATTERN = /^v(?<version>\d+\.\d+\.\d+)$/u;
|
|
@@ -74,10 +93,6 @@ var compareVersions = (a, b) => {
|
|
|
74
93
|
const [bMajor, bMinor, bPatch] = parseVersion(b);
|
|
75
94
|
return aMajor - bMajor || aMinor - bMinor || aPatch - bPatch;
|
|
76
95
|
};
|
|
77
|
-
var requireVersion = (text) => {
|
|
78
|
-
parseVersion(text);
|
|
79
|
-
return text;
|
|
80
|
-
};
|
|
81
96
|
var versionFromTag = (tag) => {
|
|
82
97
|
const version = TAG_PATTERN.exec(tag)?.groups?.version;
|
|
83
98
|
if (version === undefined) {
|
|
@@ -96,165 +111,8 @@ var parseChecksumFile = (text, assetName) => {
|
|
|
96
111
|
}
|
|
97
112
|
return { ok: true, digest: digest.toLowerCase() };
|
|
98
113
|
};
|
|
99
|
-
var pathExecutableCandidates = (name, pathEnv, preferredDir = null) => absoluteCandidates([...preferredDir === null ? [] : [preferredDir], ...splitPathEnv(pathEnv)], name);
|
|
100
114
|
var isWriteDenied = (error) => error instanceof Error && ("code" in error) && (error.code === "EACCES" || error.code === "EPERM" || error.code === "EROFS");
|
|
101
115
|
|
|
102
|
-
// src/domain/install-script.ts
|
|
103
|
-
var NPX_MARKER = "/_npx/";
|
|
104
|
-
var BUNX_MARKER = "/bunx-";
|
|
105
|
-
var BUN_GLOBAL_MARKER = "/.bun/install/global/node_modules/";
|
|
106
|
-
var NPM_GLOBAL_MARKER = `/lib/node_modules/${NPM_PACKAGE}/`;
|
|
107
|
-
var NODE_MODULES_MARKER = `/node_modules/${NPM_PACKAGE}/`;
|
|
108
|
-
var PNPM_GLOBAL_MARKER = "/pnpm/global/";
|
|
109
|
-
var YARN_GLOBAL_MARKER = "/yarn/global/";
|
|
110
|
-
var unsupported = (reason) => ({ kind: "unsupported", reason });
|
|
111
|
-
var npmGlobalPrefixOf = (scriptPath) => {
|
|
112
|
-
const index = scriptPath.lastIndexOf(NPM_GLOBAL_MARKER);
|
|
113
|
-
return index > 0 ? scriptPath.slice(0, index) : null;
|
|
114
|
-
};
|
|
115
|
-
var otherNodeModulesReason = (scriptPath) => {
|
|
116
|
-
if (scriptPath.includes(PNPM_GLOBAL_MARKER)) {
|
|
117
|
-
return `installed globally with pnpm, which hop does not drive; run "pnpm add -g ${NPM_PACKAGE_LATEST}" yourself`;
|
|
118
|
-
}
|
|
119
|
-
if (scriptPath.includes(YARN_GLOBAL_MARKER)) {
|
|
120
|
-
return `installed globally with yarn, which hop does not drive; run "yarn global add ${NPM_PACKAGE_LATEST}" yourself`;
|
|
121
|
-
}
|
|
122
|
-
return "installed as a project dependency (a local node_modules); update it in that project";
|
|
123
|
-
};
|
|
124
|
-
var detectScriptInstall = (scriptPath, npmGlobalPrefix) => {
|
|
125
|
-
if (scriptPath.includes(NPX_MARKER)) {
|
|
126
|
-
return unsupported("running through npx, which already fetches the published version on every run");
|
|
127
|
-
}
|
|
128
|
-
if (scriptPath.includes(BUNX_MARKER)) {
|
|
129
|
-
return unsupported("running through bunx, which already fetches the published version on every run");
|
|
130
|
-
}
|
|
131
|
-
if (scriptPath.includes(BUN_GLOBAL_MARKER)) {
|
|
132
|
-
return { kind: "bun" };
|
|
133
|
-
}
|
|
134
|
-
if (npmGlobalPrefix !== null) {
|
|
135
|
-
const managedBy = managerNpmPrefixReason(npmGlobalPrefix);
|
|
136
|
-
return managedBy === null ? { kind: "npm", prefix: npmGlobalPrefix } : unsupported(managedBy);
|
|
137
|
-
}
|
|
138
|
-
if (scriptPath.includes(NODE_MODULES_MARKER)) {
|
|
139
|
-
return unsupported(otherNodeModulesReason(scriptPath));
|
|
140
|
-
}
|
|
141
|
-
return unsupported("running from a source checkout; update it with git (git pull)");
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
// src/domain/mise-tool.ts
|
|
145
|
-
var MISE_WALK_LIMIT = 8;
|
|
146
|
-
var HOP_BACKEND_PATTERN = /^[a-z0-9_-]+:@?n-seiji\/nuthatch$/iu;
|
|
147
|
-
var HOP_TOOL_DIR_PATTERN = /(?:^|-)n-seiji-nuthatch$/iu;
|
|
148
|
-
var parseMiseBackendToml = (text) => {
|
|
149
|
-
const match = /^\s*full\s*=\s*"(?<tool>[^"]+)"\s*$/mu.exec(text);
|
|
150
|
-
return match?.groups?.tool ?? null;
|
|
151
|
-
};
|
|
152
|
-
var parseLegacyMiseBackend = (text) => {
|
|
153
|
-
const lines = text.split(`
|
|
154
|
-
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
155
|
-
return lines.at(-1) ?? null;
|
|
156
|
-
};
|
|
157
|
-
var withoutToolOptions = (backend) => backend.replace(/\[[^\]]*\]$/u, "");
|
|
158
|
-
var isHopBackend = (backend) => HOP_BACKEND_PATTERN.test(backend);
|
|
159
|
-
var isHopToolDirName = (name) => HOP_TOOL_DIR_PATTERN.test(name);
|
|
160
|
-
var ancestorDirs = (path, limit) => {
|
|
161
|
-
const dirs = [];
|
|
162
|
-
let dir = parentDir(path);
|
|
163
|
-
while (dirs.length < limit && dir !== "/" && dir !== ".") {
|
|
164
|
-
dirs.push(dir);
|
|
165
|
-
dir = parentDir(dir);
|
|
166
|
-
}
|
|
167
|
-
return dirs;
|
|
168
|
-
};
|
|
169
|
-
var miseToolDir = (path) => ancestorDirs(path, MISE_WALK_LIMIT).find((dir) => baseName(parentDir(dir)) === "installs") ?? null;
|
|
170
|
-
|
|
171
|
-
// src/domain/install-method.ts
|
|
172
|
-
var RELEASE_ASSETS = new Map([
|
|
173
|
-
["darwin-arm64", "hop-darwin-arm64"],
|
|
174
|
-
["darwin-x64", "hop-darwin-x64"],
|
|
175
|
-
["linux-x64", "hop-linux-x64"]
|
|
176
|
-
]);
|
|
177
|
-
var releaseAssetName = (platform, arch) => RELEASE_ASSETS.get(`${platform}-${arch}`) ?? null;
|
|
178
|
-
var GITHUB_BACKEND_PREFIXES = ["github:", "ubi:", "aqua:"];
|
|
179
|
-
var NPM_BACKEND_PREFIX = "npm:";
|
|
180
|
-
var unsupported2 = (reason) => ({
|
|
181
|
-
kind: "unsupported",
|
|
182
|
-
reason
|
|
183
|
-
});
|
|
184
|
-
var miseChannel = (tool) => {
|
|
185
|
-
if (tool.startsWith(NPM_BACKEND_PREFIX)) {
|
|
186
|
-
return "npm";
|
|
187
|
-
}
|
|
188
|
-
return GITHUB_BACKEND_PREFIXES.some((prefix) => tool.startsWith(prefix)) ? "github" : null;
|
|
189
|
-
};
|
|
190
|
-
var insideVersionManager = (dir, marker) => unsupported2(`installed under a version manager's install dir (${dir}) ${marker}; update it with the tool that installed it`);
|
|
191
|
-
var detectUnmarkedToolDir = (dir, compiled) => {
|
|
192
|
-
if (isHopToolDirName(baseName(dir))) {
|
|
193
|
-
return unsupported2(`installed by mise, but its backend is unknown (no readable marker in ${dir}); run "mise upgrade" yourself`);
|
|
194
|
-
}
|
|
195
|
-
return compiled ? insideVersionManager(dir, "without a readable mise marker") : null;
|
|
196
|
-
};
|
|
197
|
-
var detectMise = ({ mise, compiled }) => {
|
|
198
|
-
if (mise === null) {
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
if (mise.backend === null) {
|
|
202
|
-
return detectUnmarkedToolDir(mise.dir, compiled);
|
|
203
|
-
}
|
|
204
|
-
const tool = withoutToolOptions(mise.backend);
|
|
205
|
-
if (!isHopBackend(tool)) {
|
|
206
|
-
return compiled ? insideVersionManager(mise.dir, `whose marker names "${tool}", not hop`) : null;
|
|
207
|
-
}
|
|
208
|
-
const channel = miseChannel(tool);
|
|
209
|
-
return channel === null ? unsupported2(`mise installed hop through "${tool}", which is neither a GitHub nor an npm backend; run "mise upgrade ${tool}" yourself`) : { kind: "mise", tool, channel };
|
|
210
|
-
};
|
|
211
|
-
var detectStandalone = (facts) => {
|
|
212
|
-
const { executablePath, platform, arch } = facts;
|
|
213
|
-
if (executablePath === null) {
|
|
214
|
-
return unsupported2("cannot tell where the hop binary is installed");
|
|
215
|
-
}
|
|
216
|
-
const managedBy = managerRootReason(executablePath);
|
|
217
|
-
if (managedBy !== null) {
|
|
218
|
-
return unsupported2(managedBy);
|
|
219
|
-
}
|
|
220
|
-
const assetName = releaseAssetName(platform, arch);
|
|
221
|
-
if (assetName === null) {
|
|
222
|
-
return unsupported2(`there is no prebuilt binary for ${platform}-${arch}; install with npm instead (npm i -g ${NPM_PACKAGE})`);
|
|
223
|
-
}
|
|
224
|
-
return {
|
|
225
|
-
kind: "standalone",
|
|
226
|
-
binaryPath: executablePath,
|
|
227
|
-
installDir: parentDir(executablePath),
|
|
228
|
-
assetName
|
|
229
|
-
};
|
|
230
|
-
};
|
|
231
|
-
var detectInstallMethod = (facts) => {
|
|
232
|
-
const mise = detectMise(facts);
|
|
233
|
-
if (mise !== null) {
|
|
234
|
-
return mise;
|
|
235
|
-
}
|
|
236
|
-
return facts.compiled ? detectStandalone(facts) : detectScriptInstall(facts.scriptPath ?? "", facts.npmGlobalPrefix);
|
|
237
|
-
};
|
|
238
|
-
var latestChannel = (method) => {
|
|
239
|
-
if (method.kind === "mise") {
|
|
240
|
-
return method.channel;
|
|
241
|
-
}
|
|
242
|
-
return method.kind === "standalone" ? "github" : "npm";
|
|
243
|
-
};
|
|
244
|
-
var upgradeCommand = (method) => {
|
|
245
|
-
if (method.kind === "mise") {
|
|
246
|
-
return ["mise", "upgrade", method.tool];
|
|
247
|
-
}
|
|
248
|
-
return method.kind === "npm" ? ["npm", "install", "-g", "--prefix", method.prefix, NPM_PACKAGE_LATEST] : ["bun", "add", "-g", NPM_PACKAGE_LATEST];
|
|
249
|
-
};
|
|
250
|
-
var miseDryRunCommand = (method) => [
|
|
251
|
-
"mise",
|
|
252
|
-
"upgrade",
|
|
253
|
-
"--dry-run-code",
|
|
254
|
-
method.tool
|
|
255
|
-
];
|
|
256
|
-
var preferredProgramDir = (method) => method.kind === "npm" ? `${method.prefix}/bin` : null;
|
|
257
|
-
|
|
258
116
|
// src/commands/self-update-attempt.ts
|
|
259
117
|
var attempt = async (run) => {
|
|
260
118
|
try {
|
|
@@ -264,48 +122,6 @@ var attempt = async (run) => {
|
|
|
264
122
|
}
|
|
265
123
|
};
|
|
266
124
|
|
|
267
|
-
// src/commands/self-update-delegated.ts
|
|
268
|
-
var MISE_WOULD_NOT_UPGRADE = 0;
|
|
269
|
-
var runLogged = (port, term, executable, [, ...args]) => {
|
|
270
|
-
const command = [executable, ...args];
|
|
271
|
-
term.logStderr(`Running: ${command.join(" ")}`);
|
|
272
|
-
return attempt(() => port.runCommand(command));
|
|
273
|
-
};
|
|
274
|
-
var miseNothingToUpgradeWarning = ({ tool }, { current, latest }) => [
|
|
275
|
-
`mise has nothing to upgrade for ${tool}, so hop stays at ${current} although ${latest} is the latest release.`,
|
|
276
|
-
"Likely causes: the version is pinned in your global mise config, a minimum_release_age setting holds the release back,",
|
|
277
|
-
`or ${tool} is not in your global mise config (hop runs mise from your home directory, so a project's mise.toml does not count).`,
|
|
278
|
-
`Run "mise upgrade --dry-run ${tool}" from your home directory to see what mise decides.`
|
|
279
|
-
].join(" ");
|
|
280
|
-
var runDelegated = async (port, term, method, base) => {
|
|
281
|
-
const argv = upgradeCommand(method);
|
|
282
|
-
const [program] = argv;
|
|
283
|
-
const command = argv.join(" ");
|
|
284
|
-
const executable = await port.resolveExecutable(program, preferredProgramDir(method));
|
|
285
|
-
if (executable === null) {
|
|
286
|
-
return fail(EXIT_GENERAL_ERROR, `Cannot find "${program}" on PATH. Run it yourself: ${command}`);
|
|
287
|
-
}
|
|
288
|
-
if (method.kind === "mise") {
|
|
289
|
-
const question = miseDryRunCommand(method);
|
|
290
|
-
const answer = await runLogged(port, term, executable, question);
|
|
291
|
-
if (!answer.ok) {
|
|
292
|
-
return fail(EXIT_GENERAL_ERROR, `Failed to run ${question.join(" ")}: ${messageOf(answer.error)}`);
|
|
293
|
-
}
|
|
294
|
-
if (answer.value === MISE_WOULD_NOT_UPGRADE) {
|
|
295
|
-
return ok({ data: base, warnings: [miseNothingToUpgradeWarning(method, base)] });
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
const run = await runLogged(port, term, executable, argv);
|
|
299
|
-
if (!run.ok) {
|
|
300
|
-
return fail(EXIT_GENERAL_ERROR, `Failed to run ${command}: ${messageOf(run.error)}`);
|
|
301
|
-
}
|
|
302
|
-
if (run.value !== 0) {
|
|
303
|
-
return fail(EXIT_GENERAL_ERROR, `${command} exited with code ${run.value}.`);
|
|
304
|
-
}
|
|
305
|
-
term.logStderr(`${command} finished; run "hop --version" to see which version you have now.`);
|
|
306
|
-
return ok({ data: { ...base, action: "delegated", command: [...argv] } });
|
|
307
|
-
};
|
|
308
|
-
|
|
309
125
|
// src/commands/self-update-standalone.ts
|
|
310
126
|
var checksumRejection = (port, assetName, checksumText, bytes) => {
|
|
311
127
|
const expected = parseChecksumFile(checksumText, assetName);
|
|
@@ -349,24 +165,18 @@ var replaceStandalone = async (port, term, method, base) => {
|
|
|
349
165
|
};
|
|
350
166
|
|
|
351
167
|
// src/commands/self-update.ts
|
|
352
|
-
var fetchLatest = (port, method) => latestChannel(method) === "npm" ? port.latestNpmVersion() : port.latestGithubVersion();
|
|
353
|
-
var checkCommand = (method) => method.kind === "standalone" ? null : [...upgradeCommand(method)];
|
|
354
|
-
var describeCheck = (method, base) => {
|
|
355
|
-
const how = method.kind === "standalone" ? `replaces ${method.binaryPath}` : `runs: ${upgradeCommand(method).join(" ")}`;
|
|
356
|
-
return `Update available: ${base.current} -> ${base.latest}. "hop --update" ${how}.`;
|
|
357
|
-
};
|
|
358
168
|
var selfUpdate = async (port, term, options) => {
|
|
359
169
|
const facts = await attempt(() => port.installFacts());
|
|
360
170
|
if (!facts.ok) {
|
|
361
171
|
return fail(EXIT_GENERAL_ERROR, `Cannot update hop: could not tell how it was installed (${messageOf(facts.error)}).`);
|
|
362
172
|
}
|
|
363
173
|
const method = detectInstallMethod(facts.value);
|
|
364
|
-
if (method.kind
|
|
365
|
-
return fail(EXIT_GENERAL_ERROR,
|
|
174
|
+
if (method.kind !== "standalone" && !options.check) {
|
|
175
|
+
return fail(EXIT_GENERAL_ERROR, updateHint(method.kind));
|
|
366
176
|
}
|
|
367
177
|
term.logStderr("Checking for the latest release...");
|
|
368
178
|
const release = await attempt(async () => {
|
|
369
|
-
const latest = await
|
|
179
|
+
const latest = await port.latestGithubVersion();
|
|
370
180
|
return {
|
|
371
181
|
latest,
|
|
372
182
|
updateAvailable: compareVersions(latest, options.currentVersion) > 0
|
|
@@ -387,94 +197,43 @@ var selfUpdate = async (port, term, options) => {
|
|
|
387
197
|
term.logStderr(`hop ${base.current} is up to date (latest release: ${base.latest}).`);
|
|
388
198
|
return ok({ data: base });
|
|
389
199
|
}
|
|
200
|
+
const available = `Update available: ${base.current} -> ${base.latest}.`;
|
|
201
|
+
if (method.kind !== "standalone") {
|
|
202
|
+
term.logStderr(`${available} ${updateHint(method.kind)}`);
|
|
203
|
+
const command = suggestedCommand(method.kind);
|
|
204
|
+
return ok({
|
|
205
|
+
data: { ...base, command: command === null ? null : [...command] }
|
|
206
|
+
});
|
|
207
|
+
}
|
|
390
208
|
if (options.check) {
|
|
391
|
-
term.logStderr(
|
|
392
|
-
return ok({ data:
|
|
209
|
+
term.logStderr(`${available} "hop --update" replaces ${method.binaryPath}.`);
|
|
210
|
+
return ok({ data: base });
|
|
393
211
|
}
|
|
394
|
-
return
|
|
212
|
+
return replaceStandalone(port, term, method, base);
|
|
395
213
|
};
|
|
396
214
|
|
|
397
215
|
// src/infra/install-facts.ts
|
|
398
|
-
import {
|
|
399
|
-
|
|
400
|
-
var MISE_BACKEND_TOML = ".mise.backend.toml";
|
|
401
|
-
var MISE_BACKEND_LEGACY = ".mise.backend";
|
|
402
|
-
var realpathOrNull = async (path) => {
|
|
216
|
+
import { realpath } from "node:fs/promises";
|
|
217
|
+
var realpathOrSelf = async (path) => {
|
|
403
218
|
try {
|
|
404
219
|
return await realpath(path);
|
|
405
220
|
} catch {
|
|
406
|
-
return
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
var realpathOrSelf = async (path) => await realpathOrNull(path) ?? path;
|
|
410
|
-
var readTextOrNull = async (path) => {
|
|
411
|
-
try {
|
|
412
|
-
return await readFile(path, "utf8");
|
|
413
|
-
} catch {
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
var readMiseBackend = async (dir) => {
|
|
418
|
-
const toml = await readTextOrNull(join(dir, MISE_BACKEND_TOML));
|
|
419
|
-
const fromToml = toml === null ? null : parseMiseBackendToml(toml);
|
|
420
|
-
if (fromToml !== null) {
|
|
421
|
-
return fromToml;
|
|
422
|
-
}
|
|
423
|
-
const legacy = await readTextOrNull(join(dir, MISE_BACKEND_LEGACY));
|
|
424
|
-
return legacy === null ? null : parseLegacyMiseBackend(legacy);
|
|
425
|
-
};
|
|
426
|
-
var findMiseTool = async (path) => {
|
|
427
|
-
const dir = path === null ? null : miseToolDir(path);
|
|
428
|
-
return dir === null ? null : { dir, backend: await readMiseBackend(dir) };
|
|
429
|
-
};
|
|
430
|
-
var verifiedNpmPrefix = async (scriptPath) => {
|
|
431
|
-
const prefix = scriptPath === null ? null : npmGlobalPrefixOf(scriptPath);
|
|
432
|
-
if (prefix === null) {
|
|
433
|
-
return null;
|
|
221
|
+
return path;
|
|
434
222
|
}
|
|
435
|
-
return await realpathOrNull(join(prefix, "bin", "hop")) === scriptPath ? prefix : null;
|
|
436
223
|
};
|
|
437
|
-
var readInstallFacts = async (source) => {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
scriptPath,
|
|
444
|
-
mise: await findMiseTool(executablePath ?? scriptPath),
|
|
445
|
-
npmGlobalPrefix: await verifiedNpmPrefix(scriptPath),
|
|
446
|
-
platform: source.platform,
|
|
447
|
-
arch: source.arch
|
|
448
|
-
};
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
// src/infra/package-manager.ts
|
|
452
|
-
import { spawn } from "node:child_process";
|
|
453
|
-
import { homedir } from "node:os";
|
|
454
|
-
import { basename } from "node:path";
|
|
455
|
-
var STDERR_FD = 2;
|
|
456
|
-
var resolveExecutable = (name, pathEnv, preferredDir = null) => firstExecutable(pathExecutableCandidates(name, pathEnv, preferredDir));
|
|
457
|
-
var runCommand = (argv) => new Promise((resolve, reject) => {
|
|
458
|
-
const [program, ...args] = argv;
|
|
459
|
-
const child = spawn(program, args, {
|
|
460
|
-
cwd: homedir(),
|
|
461
|
-
stdio: ["inherit", STDERR_FD, STDERR_FD]
|
|
462
|
-
});
|
|
463
|
-
child.once("error", reject);
|
|
464
|
-
child.once("close", (code, signal) => {
|
|
465
|
-
if (code === null) {
|
|
466
|
-
reject(new Error(`${basename(program)} was killed by signal ${signal ?? "unknown"}`));
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
resolve(code);
|
|
470
|
-
});
|
|
224
|
+
var readInstallFacts = async (source) => ({
|
|
225
|
+
compiled: source.compiled,
|
|
226
|
+
executablePath: source.compiled ? await realpathOrSelf(source.execPath) : null,
|
|
227
|
+
scriptPath: source.compiled || source.argv1 === undefined ? null : await realpathOrSelf(source.argv1),
|
|
228
|
+
platform: source.platform,
|
|
229
|
+
arch: source.arch
|
|
471
230
|
});
|
|
472
231
|
|
|
473
232
|
// src/infra/release-binary.ts
|
|
474
233
|
import { createHash, randomBytes } from "node:crypto";
|
|
475
234
|
import { constants } from "node:fs";
|
|
476
235
|
import { access, open, realpath as realpath2, rename, rm } from "node:fs/promises";
|
|
477
|
-
import { basename
|
|
236
|
+
import { basename, dirname, join } from "node:path";
|
|
478
237
|
var EXECUTABLE_MODE = 493;
|
|
479
238
|
var TEMP_SUFFIX_BYTES = 6;
|
|
480
239
|
var sha256Hex = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
@@ -496,7 +255,7 @@ var writeDurably = async (path, bytes) => {
|
|
|
496
255
|
var replaceExecutable = async (path, bytes) => {
|
|
497
256
|
const target = await realpath2(path);
|
|
498
257
|
const suffix = randomBytes(TEMP_SUFFIX_BYTES).toString("hex");
|
|
499
|
-
const temp =
|
|
258
|
+
const temp = join(dirname(target), `.${basename(target)}.update-${suffix}`);
|
|
500
259
|
try {
|
|
501
260
|
await writeDurably(temp, bytes);
|
|
502
261
|
await rename(temp, target);
|
|
@@ -737,7 +496,6 @@ var GITHUB_API_ORIGIN = "https://api.github.com/";
|
|
|
737
496
|
var HTTP_FORBIDDEN = 403;
|
|
738
497
|
var HTTP_TOO_MANY_REQUESTS = 429;
|
|
739
498
|
var GithubLatestSchema = object({ tag_name: string() });
|
|
740
|
-
var NpmLatestSchema = object({ version: string() });
|
|
741
499
|
var DECODER = new TextDecoder;
|
|
742
500
|
var send = async (fetcher, url, { headers, timeoutMs }) => {
|
|
743
501
|
try {
|
|
@@ -806,14 +564,6 @@ var createReleaseHttp = (userAgent, fetcher = fetch) => ({
|
|
|
806
564
|
});
|
|
807
565
|
return versionFromTag(release.tag_name);
|
|
808
566
|
},
|
|
809
|
-
async latestNpmVersion() {
|
|
810
|
-
const latest = await getJson(fetcher, NPM_LATEST_URL, NpmLatestSchema, {
|
|
811
|
-
headers: { Accept: "application/json", "User-Agent": userAgent },
|
|
812
|
-
timeoutMs: METADATA_TIMEOUT_MS,
|
|
813
|
-
maxBytes: METADATA_MAX_BYTES
|
|
814
|
-
});
|
|
815
|
-
return requireVersion(latest.version);
|
|
816
|
-
},
|
|
817
567
|
async downloadReleaseAsset(version, assetName) {
|
|
818
568
|
return await getBytes(fetcher, releaseAssetUrl(version, assetName), {
|
|
819
569
|
headers: { Accept: "application/octet-stream", "User-Agent": userAgent },
|
|
@@ -846,9 +596,7 @@ var createSelfUpdatePort = ({
|
|
|
846
596
|
...createReleaseHttp(`hop/${version}`),
|
|
847
597
|
sha256Hex,
|
|
848
598
|
assertWritableDir,
|
|
849
|
-
replaceExecutable
|
|
850
|
-
resolveExecutable: (name, preferredDir) => resolveExecutable(name, process.env.PATH, preferredDir),
|
|
851
|
-
runCommand
|
|
599
|
+
replaceExecutable
|
|
852
600
|
});
|
|
853
601
|
|
|
854
602
|
// src/cli-update.ts
|