Chore/build npm (#9)
Co-authored-by: DigHuang <114602213+DigHuang@users.noreply.github.com> Co-authored-by: Felix <24791380+vcfgv@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,139 +1,124 @@
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { mkdirSync, rmSync, existsSync, chmodSync, renameSync, writeFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { platform, arch } from 'node:os';
|
||||
#!/usr/bin/env zx
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT_DIR = join(__dirname, '..');
|
||||
import 'zx/globals';
|
||||
|
||||
// Configuration
|
||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||
const UV_VERSION = '0.10.0';
|
||||
const BASE_URL = `https://github.com/astral-sh/uv/releases/download/${UV_VERSION}`;
|
||||
const OUTPUT_BASE = join(ROOT_DIR, 'resources', 'bin');
|
||||
const OUTPUT_BASE = path.join(ROOT_DIR, 'resources', 'bin');
|
||||
|
||||
// Mapping Node platforms/archs to uv release naming
|
||||
const TARGETS = {
|
||||
'darwin-arm64': {
|
||||
filename: 'uv-aarch64-apple-darwin.tar.gz',
|
||||
binName: 'uv',
|
||||
extractCmd: (src, dest) => spawnSync('tar', ['-xzf', src, '-C', dest])
|
||||
},
|
||||
'darwin-x64': {
|
||||
filename: 'uv-x86_64-apple-darwin.tar.gz',
|
||||
binName: 'uv',
|
||||
extractCmd: (src, dest) => spawnSync('tar', ['-xzf', src, '-C', dest])
|
||||
},
|
||||
'win32-x64': {
|
||||
filename: 'uv-x86_64-pc-windows-msvc.zip',
|
||||
binName: 'uv.exe',
|
||||
extractCmd: (src, dest) => {
|
||||
if (platform() === 'win32') {
|
||||
return spawnSync('powershell.exe', ['-Command', `Expand-Archive -Path "${src}" -DestinationPath "${dest}" -Force`]);
|
||||
} else {
|
||||
return spawnSync('unzip', ['-q', '-o', src, '-d', dest]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function downloadFile(url, dest) {
|
||||
console.log(`⬇️ Downloading: ${url}`);
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error(`Failed to download: ${response.statusText}`);
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
writeFileSync(dest, Buffer.from(arrayBuffer));
|
||||
}
|
||||
|
||||
async function setupTarget(id) {
|
||||
const target = TARGETS[id];
|
||||
if (!target) {
|
||||
console.warn(`⚠️ Target ${id} is not supported by this script.`);
|
||||
echo(chalk.yellow`⚠️ Target ${id} is not supported by this script.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const targetDir = join(OUTPUT_BASE, id);
|
||||
const tempDir = join(ROOT_DIR, 'temp_uv_extract');
|
||||
const archivePath = join(ROOT_DIR, target.filename);
|
||||
const targetDir = path.join(OUTPUT_BASE, id);
|
||||
const tempDir = path.join(ROOT_DIR, 'temp_uv_extract');
|
||||
const archivePath = path.join(ROOT_DIR, target.filename);
|
||||
const downloadUrl = `${BASE_URL}/${target.filename}`;
|
||||
|
||||
console.log(`
|
||||
📦 Setting up uv for ${id}...`);
|
||||
echo(chalk.blue`\n📦 Setting up uv for ${id}...`);
|
||||
|
||||
// Cleanup & Prep
|
||||
if (existsSync(targetDir)) rmSync(targetDir, { recursive: true });
|
||||
if (existsSync(tempDir)) rmSync(tempDir, { recursive: true });
|
||||
mkdirSync(targetDir, { recursive: true });
|
||||
mkdirSync(tempDir, { recursive: true });
|
||||
await fs.remove(targetDir);
|
||||
await fs.remove(tempDir);
|
||||
await fs.ensureDir(targetDir);
|
||||
await fs.ensureDir(tempDir);
|
||||
|
||||
try {
|
||||
// Download
|
||||
await downloadFile(`${BASE_URL}/${target.filename}`, archivePath);
|
||||
echo`⬇️ Downloading: ${downloadUrl}`;
|
||||
const response = await fetch(downloadUrl);
|
||||
if (!response.ok) throw new Error(`Failed to download: ${response.statusText}`);
|
||||
const buffer = await response.arrayBuffer();
|
||||
await fs.writeFile(archivePath, Buffer.from(buffer));
|
||||
|
||||
// Extract
|
||||
console.log('📂 Extracting...');
|
||||
target.extractCmd(archivePath, tempDir);
|
||||
echo`📂 Extracting...`;
|
||||
if (target.filename.endsWith('.zip')) {
|
||||
if (os.platform() === 'win32') {
|
||||
// Use .NET Framework for ZIP extraction (more reliable than Expand-Archive)
|
||||
const { execSync } = await import('child_process');
|
||||
const psCommand = `Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory('${archivePath.replace(/'/g, "''")}', '${tempDir.replace(/'/g, "''")}')`;
|
||||
execSync(`powershell.exe -NoProfile -Command "${psCommand}"`, { stdio: 'inherit' });
|
||||
} else {
|
||||
await $`unzip -q -o ${archivePath} -d ${tempDir}`;
|
||||
}
|
||||
} else {
|
||||
await $`tar -xzf ${archivePath} -C ${tempDir}`;
|
||||
}
|
||||
|
||||
// Move binary to final location
|
||||
// Move binary
|
||||
// uv archives usually contain a folder named after the target
|
||||
const folderName = target.filename.replace('.tar.gz', '').replace('.zip', '');
|
||||
const sourceBin = join(tempDir, folderName, target.binName);
|
||||
const destBin = join(targetDir, target.binName);
|
||||
const sourceBin = path.join(tempDir, folderName, target.binName);
|
||||
const destBin = path.join(targetDir, target.binName);
|
||||
|
||||
if (existsSync(sourceBin)) {
|
||||
renameSync(sourceBin, destBin);
|
||||
if (await fs.pathExists(sourceBin)) {
|
||||
await fs.move(sourceBin, destBin, { overwrite: true });
|
||||
} else {
|
||||
// Fallback: search for the binary if folder structure changed
|
||||
console.log('🔍 Binary not found in expected subfolder, searching...');
|
||||
const findResult = spawnSync(platform() === 'win32' ? 'where' : 'find',
|
||||
platform() === 'win32' ? ['/R', tempDir, target.binName] : [tempDir, '-name', target.binName]);
|
||||
|
||||
const foundPath = findResult.stdout.toString().trim().split('\n')[0];
|
||||
if (foundPath && existsSync(foundPath)) {
|
||||
renameSync(foundPath, destBin);
|
||||
echo(chalk.yellow`🔍 Binary not found in expected subfolder, searching...`);
|
||||
const files = await glob(`**/${target.binName}`, { cwd: tempDir, absolute: true });
|
||||
if (files.length > 0) {
|
||||
await fs.move(files[0], destBin, { overwrite: true });
|
||||
} else {
|
||||
throw new Error(`Could not find ${target.binName} in extracted files.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Permission fix
|
||||
if (platform() !== 'win32') {
|
||||
chmodSync(destBin, 0o755);
|
||||
if (os.platform() !== 'win32') {
|
||||
await fs.chmod(destBin, 0o755);
|
||||
}
|
||||
|
||||
console.log(`✅ Success: ${destBin}`);
|
||||
echo(chalk.green`✅ Success: ${destBin}`);
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (existsSync(archivePath)) rmSync(archivePath);
|
||||
if (existsSync(tempDir)) rmSync(tempDir, { recursive: true });
|
||||
await fs.remove(archivePath);
|
||||
await fs.remove(tempDir);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const downloadAll = args.includes('--all');
|
||||
// Main logic
|
||||
const args = process.argv.slice(3); // zx scripts/file.mjs --all -> argv is [node, zx, file, --all] ? or similar.
|
||||
// zx execution: process.argv is [node, script, users_args...]
|
||||
// Let's use minimist which zx includes globally as `argv`
|
||||
const downloadAll = argv.all;
|
||||
|
||||
if (downloadAll) {
|
||||
echo(chalk.cyan`🌐 Downloading uv binaries for ALL supported platforms...`);
|
||||
for (const id of Object.keys(TARGETS)) {
|
||||
await setupTarget(id);
|
||||
}
|
||||
} else {
|
||||
const currentId = `${os.platform()}-${os.arch()}`;
|
||||
echo(chalk.cyan`💻 Detected system: ${currentId}`);
|
||||
|
||||
if (downloadAll) {
|
||||
console.log('🌐 Downloading uv binaries for ALL supported platforms...');
|
||||
for (const id of Object.keys(TARGETS)) {
|
||||
await setupTarget(id);
|
||||
}
|
||||
if (TARGETS[currentId]) {
|
||||
await setupTarget(currentId);
|
||||
} else {
|
||||
const currentId = `${platform()}-${arch()}`;
|
||||
console.log(`💻 Detected system: ${currentId}`);
|
||||
|
||||
if (TARGETS[currentId]) {
|
||||
await setupTarget(currentId);
|
||||
} else {
|
||||
console.error(`❌ Current system ${currentId} is not in the supported download list.`);
|
||||
console.log('Supported targets:', Object.keys(TARGETS).join(', '));
|
||||
process.exit(1);
|
||||
}
|
||||
echo(chalk.red`❌ Current system ${currentId} is not in the supported download list.`);
|
||||
echo(`Supported targets: ${Object.keys(TARGETS).join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n🎉 Done!');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('\n❌ Error:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
echo(chalk.green`\n🎉 Done!`);
|
||||
|
||||
Reference in New Issue
Block a user