fix: fall back to wget when curl is unavailable (#521)

This commit is contained in:
Taku Kodama 2026-06-18 04:26:03 +10:00 committed by GitHub
parent 5f61b63aff
commit 884d428693
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 179 additions and 34 deletions

View file

@ -2,4 +2,4 @@
npm ci
npm run all
git add dist
git add -f dist

100
dist/index.js generated vendored
View file

@ -38,6 +38,7 @@ import require$$1$3 from 'node:console';
import require$$1$4 from 'node:dns';
import require$$5$4, { StringDecoder } from 'string_decoder';
import * as child from 'child_process';
import { spawn } from 'child_process';
import { setTimeout as setTimeout$1 } from 'timers';
import * as stream from 'stream';
import { Readable } from 'stream';
@ -49,6 +50,7 @@ import process$1 from 'node:process';
import https$1 from 'node:https';
import require$$1$5 from 'tty';
import fs$1 from 'node:fs';
import { pipeline } from 'stream/promises';
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
@ -89246,6 +89248,7 @@ const DEFAULT_CACHE_KEY_TEMPLATE = '{{cache_key_prefix}}-{{platform}}{{#if versi
const ROOT_MISE_LOCK_FILE_PATTERNS = [/^\.?mise(?:\.[^.]+)?\.lock$/];
const CONFIG_DIR_MISE_LOCK_FILE_PATTERNS = [/^mise(?:\.[^.]+)?\.lock$/];
const CONFIG_MISE_LOCK_FILE_PATTERNS = [/^config(?:\.[^.]+)?\.lock$/];
let cachedDownloadTool;
async function run() {
try {
await setToolVersions();
@ -89267,7 +89270,7 @@ async function run() {
// a third-party cache without explicit consent.
//
// Note: `setupMise` fetches the mise binary itself with
// `curl`, which doesn't go through mise's HTTP layer —
// `curl` or `wget`, which doesn't go through mise's HTTP layer —
// the wings rewriter only kicks in once the resulting
// mise binary runs `mise install` and friends. Ordering
// here is irrelevant for binary acceleration; we just
@ -89501,19 +89504,13 @@ async function setupMise(version, fetchFromGitHub = false) {
break;
}
case '.tar.zst':
await exec('sh', [
'-c',
`curl -fsSL ${url} | tar --zstd -xf - -C ${os.tmpdir()} && mv ${os.tmpdir()}/mise/bin/mise ${miseBinPath}`
]);
await installFromTarUrl(url, ['--zstd', '-xf', '-'], miseBinPath);
break;
case '.tar.gz':
await exec('sh', [
'-c',
`curl -fsSL ${url} | tar -xzf - -C ${os.tmpdir()} && mv ${os.tmpdir()}/mise/bin/mise ${miseBinPath}`
]);
await installFromTarUrl(url, ['-xzf', '-'], miseBinPath);
break;
default:
await exec('sh', ['-c', `curl -fsSL ${url} > ${miseBinPath}`]);
await downloadToFile(url, miseBinPath);
await exec('chmod', ['+x', miseBinPath]);
break;
}
@ -89551,7 +89548,7 @@ async function withExtractedZip(url, archiveName, fn) {
try {
const archivePath = path$1.join(tempDir, archiveName);
const extractDir = path$1.join(tempDir, 'extract');
await exec('curl', ['-fsSL', url, '--output', archivePath]);
await downloadToFile(url, archivePath);
await exec('unzip', [archivePath, '-d', extractDir]);
await fn(extractDir);
}
@ -89587,6 +89584,81 @@ async function ensureWindowsMiseShim(miseBinPath, miseShimPath, version) {
warning(`Failed to install mise-shim.exe: ${errorMessage(err)}. Continuing because mise can fall back to file shim mode on Windows.`);
}
}
async function getDownloadTool() {
if (cachedDownloadTool)
return cachedDownloadTool;
if (await which('curl')) {
cachedDownloadTool = 'curl';
}
else if (await which('wget')) {
cachedDownloadTool = 'wget';
}
else {
throw new Error('Neither curl nor wget is available to download mise');
}
info(`Using ${cachedDownloadTool} to download mise`);
return cachedDownloadTool;
}
async function downloadToFile(url, filePath) {
const tool = await getDownloadTool();
if (tool === 'curl') {
await exec('curl', ['-fsSL', url, '--output', filePath]);
}
else {
await exec('wget', ['-qO', filePath, url]);
}
}
async function downloadText(url) {
const tool = await getDownloadTool();
if (tool === 'curl') {
const rsp = await getExecOutput('curl', ['-fsSL', url]);
return rsp.stdout.trim();
}
const rsp = await getExecOutput('wget', ['-qO-', url]);
return rsp.stdout.trim();
}
async function installFromTarUrl(url, tarArgs, miseBinPath) {
const tmpdir = os.tmpdir();
const tool = await getDownloadTool();
const downloader = spawn(tool, tool === 'curl' ? ['-fsSL', url] : ['-qO-', url], { stdio: ['ignore', 'pipe', 'inherit'] });
const tar = spawn('tar', [...tarArgs, '-C', tmpdir], {
stdio: ['pipe', 'inherit', 'inherit']
});
if (!downloader.stdout) {
throw new Error(`Failed to start ${tool} download stream`);
}
const downloadExit = new Promise((resolve, reject) => {
downloader.on('error', reject);
downloader.on('close', code => {
if (code === 0)
resolve();
else
reject(new Error(`${tool} exited with code ${code}`));
});
});
const tarExit = new Promise((resolve, reject) => {
tar.on('error', reject);
tar.on('close', code => {
if (code === 0)
resolve();
else
reject(new Error(`tar exited with code ${code}`));
});
});
try {
await pipeline(downloader.stdout, tar.stdin);
await Promise.all([downloadExit, tarExit]);
}
catch (err) {
downloader.kill();
tar.kill();
downloadExit.catch(() => { });
tarExit.catch(() => { });
throw err;
}
const extractedMisePath = path$1.join(tmpdir, 'mise', 'bin', 'mise');
await exec('mv', [extractedMisePath, miseBinPath]);
}
async function getInstalledMiseVersion(miseBinPath) {
const versionOutput = await getExecOutput(miseBinPath, ['version', '--json'], { silent: true });
const versionJson = JSON.parse(versionOutput.stdout);
@ -89605,11 +89677,7 @@ async function zstdInstalled() {
}
}
async function latestMiseVersion() {
const rsp = await getExecOutput('curl', [
'-fsSL',
'https://mise.jdx.dev/VERSION'
]);
return rsp.stdout.trim();
return downloadText('https://mise.jdx.dev/VERSION');
}
async function setToolVersions() {
const toolVersions = getInput('tool_versions');

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,8 @@ import * as crypto from 'crypto'
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import { spawn } from 'child_process'
import { pipeline } from 'stream/promises'
import * as Handlebars from 'handlebars'
// Configuration file patterns for cache key generation
@ -46,6 +48,9 @@ const ROOT_MISE_LOCK_FILE_PATTERNS = [/^\.?mise(?:\.[^.]+)?\.lock$/]
const CONFIG_DIR_MISE_LOCK_FILE_PATTERNS = [/^mise(?:\.[^.]+)?\.lock$/]
const CONFIG_MISE_LOCK_FILE_PATTERNS = [/^config(?:\.[^.]+)?\.lock$/]
type DownloadTool = 'curl' | 'wget'
let cachedDownloadTool: DownloadTool | undefined
async function run(): Promise<void> {
try {
await setToolVersions()
@ -68,7 +73,7 @@ async function run(): Promise<void> {
// a third-party cache without explicit consent.
//
// Note: `setupMise` fetches the mise binary itself with
// `curl`, which doesn't go through mise's HTTP layer —
// `curl` or `wget`, which doesn't go through mise's HTTP layer —
// the wings rewriter only kicks in once the resulting
// mise binary runs `mise install` and friends. Ordering
// here is irrelevant for binary acceleration; we just
@ -341,19 +346,13 @@ async function setupMise(
break
}
case '.tar.zst':
await exec.exec('sh', [
'-c',
`curl -fsSL ${url} | tar --zstd -xf - -C ${os.tmpdir()} && mv ${os.tmpdir()}/mise/bin/mise ${miseBinPath}`
])
await installFromTarUrl(url, ['--zstd', '-xf', '-'], miseBinPath)
break
case '.tar.gz':
await exec.exec('sh', [
'-c',
`curl -fsSL ${url} | tar -xzf - -C ${os.tmpdir()} && mv ${os.tmpdir()}/mise/bin/mise ${miseBinPath}`
])
await installFromTarUrl(url, ['-xzf', '-'], miseBinPath)
break
default:
await exec.exec('sh', ['-c', `curl -fsSL ${url} > ${miseBinPath}`])
await downloadToFile(url, miseBinPath)
await exec.exec('chmod', ['+x', miseBinPath])
break
}
@ -402,7 +401,7 @@ async function withExtractedZip(
const archivePath = path.join(tempDir, archiveName)
const extractDir = path.join(tempDir, 'extract')
await exec.exec('curl', ['-fsSL', url, '--output', archivePath])
await downloadToFile(url, archivePath)
await exec.exec('unzip', [archivePath, '-d', extractDir])
await fn(extractDir)
} finally {
@ -456,6 +455,88 @@ async function ensureWindowsMiseShim(
}
}
async function getDownloadTool(): Promise<DownloadTool> {
if (cachedDownloadTool) return cachedDownloadTool
if (await io.which('curl')) {
cachedDownloadTool = 'curl'
} else if (await io.which('wget')) {
cachedDownloadTool = 'wget'
} else {
throw new Error('Neither curl nor wget is available to download mise')
}
core.info(`Using ${cachedDownloadTool} to download mise`)
return cachedDownloadTool
}
async function downloadToFile(url: string, filePath: string): Promise<void> {
const tool = await getDownloadTool()
if (tool === 'curl') {
await exec.exec('curl', ['-fsSL', url, '--output', filePath])
} else {
await exec.exec('wget', ['-qO', filePath, url])
}
}
async function downloadText(url: string): Promise<string> {
const tool = await getDownloadTool()
if (tool === 'curl') {
const rsp = await exec.getExecOutput('curl', ['-fsSL', url])
return rsp.stdout.trim()
}
const rsp = await exec.getExecOutput('wget', ['-qO-', url])
return rsp.stdout.trim()
}
async function installFromTarUrl(
url: string,
tarArgs: string[],
miseBinPath: string
): Promise<void> {
const tmpdir = os.tmpdir()
const tool = await getDownloadTool()
const downloader = spawn(
tool,
tool === 'curl' ? ['-fsSL', url] : ['-qO-', url],
{ stdio: ['ignore', 'pipe', 'inherit'] }
)
const tar = spawn('tar', [...tarArgs, '-C', tmpdir], {
stdio: ['pipe', 'inherit', 'inherit']
})
if (!downloader.stdout) {
throw new Error(`Failed to start ${tool} download stream`)
}
const downloadExit = new Promise<void>((resolve, reject) => {
downloader.on('error', reject)
downloader.on('close', code => {
if (code === 0) resolve()
else reject(new Error(`${tool} exited with code ${code}`))
})
})
const tarExit = new Promise<void>((resolve, reject) => {
tar.on('error', reject)
tar.on('close', code => {
if (code === 0) resolve()
else reject(new Error(`tar exited with code ${code}`))
})
})
try {
await pipeline(downloader.stdout, tar.stdin!)
await Promise.all([downloadExit, tarExit])
} catch (err) {
downloader.kill()
tar.kill()
downloadExit.catch(() => {})
tarExit.catch(() => {})
throw err
}
const extractedMisePath = path.join(tmpdir, 'mise', 'bin', 'mise')
await exec.exec('mv', [extractedMisePath, miseBinPath])
}
async function getInstalledMiseVersion(miseBinPath: string): Promise<string> {
const versionOutput = await exec.getExecOutput(
miseBinPath,
@ -480,11 +561,7 @@ async function zstdInstalled(): Promise<boolean> {
}
async function latestMiseVersion(): Promise<string> {
const rsp = await exec.getExecOutput('curl', [
'-fsSL',
'https://mise.jdx.dev/VERSION'
])
return rsp.stdout.trim()
return downloadText('https://mise.jdx.dev/VERSION')
}
async function setToolVersions(): Promise<void> {