mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-04-28 11:40:25 +00:00
Co-authored-by: a7m-1st <Ahmed.jimi.awelkeir500@gmail.com> Co-authored-by: eigent-ai <camel@eigent.ai> Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com> Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
224 lines
7 KiB
JavaScript
224 lines
7 KiB
JavaScript
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
|
|
/* global console, process */
|
|
import AdmZip from 'adm-zip';
|
|
import fs from 'fs';
|
|
import os from 'os';
|
|
import path from 'path';
|
|
import { downloadWithRedirects } from './download.js';
|
|
|
|
// Base URL for downloading bun binaries
|
|
const BUN_RELEASE_BASE_URL = 'https://github.com/oven-sh/bun/releases/download';
|
|
const DEFAULT_BUN_VERSION = '1.2.9'; // Default fallback version
|
|
|
|
// Mapping of platform+arch to binary package name
|
|
const BUN_PACKAGES = {
|
|
'darwin-arm64': 'bun-darwin-aarch64.zip',
|
|
'darwin-x64': 'bun-darwin-x64.zip',
|
|
'win32-x64': 'bun-windows-x64.zip',
|
|
'win32-x64-baseline': 'bun-windows-x64-baseline.zip',
|
|
'linux-x64': 'bun-linux-x64.zip',
|
|
'linux-x64-baseline': 'bun-linux-x64-baseline.zip',
|
|
'linux-arm64': 'bun-linux-aarch64.zip',
|
|
// MUSL variants
|
|
'linux-musl-x64': 'bun-linux-x64-musl.zip',
|
|
'linux-musl-x64-baseline': 'bun-linux-x64-musl-baseline.zip',
|
|
'linux-musl-arm64': 'bun-linux-aarch64-musl.zip',
|
|
};
|
|
|
|
/**
|
|
* Downloads and extracts the bun binary for the specified platform and architecture
|
|
* @param {string} platform Platform to download for (e.g., 'darwin', 'win32', 'linux')
|
|
* @param {string} arch Architecture to download for (e.g., 'x64', 'arm64')
|
|
* @param {string} version Version of bun to download
|
|
* @param {boolean} isMusl Whether to use MUSL variant for Linux
|
|
* @param {boolean} isBaseline Whether to use baseline variant
|
|
*/
|
|
async function downloadBunBinary(
|
|
bun_download_url,
|
|
platform,
|
|
arch,
|
|
version = DEFAULT_BUN_VERSION,
|
|
isMusl = false,
|
|
isBaseline = false
|
|
) {
|
|
let platformKey = isMusl ? `${platform}-musl-${arch}` : `${platform}-${arch}`;
|
|
if (isBaseline) {
|
|
platformKey += '-baseline';
|
|
}
|
|
const packageName = BUN_PACKAGES[platformKey];
|
|
|
|
if (!packageName) {
|
|
console.error(`No binary available for ${platformKey}`);
|
|
return false;
|
|
}
|
|
|
|
// Create output directory structure
|
|
const binDir = path.join(os.homedir(), '.eigent', 'bin');
|
|
// Ensure directories exist
|
|
fs.mkdirSync(binDir, { recursive: true });
|
|
|
|
// Download URL for the specific binary
|
|
const downloadUrl = `${bun_download_url}/bun-v${version}/${packageName}`;
|
|
const tempdir = os.tmpdir();
|
|
// Create a temporary file for the downloaded binary
|
|
// Use unique temp filename to avoid race conditions when multiple processes install simultaneously
|
|
const uniqueSuffix = `${process.pid}-${Date.now()}`;
|
|
const tempFilename = path.join(tempdir, `${uniqueSuffix}-${packageName}`);
|
|
|
|
try {
|
|
console.log(`Downloading bun ${version} for ${platformKey}...`);
|
|
console.log(`URL: ${downloadUrl}`);
|
|
if (fs.existsSync(tempFilename)) fs.unlinkSync(tempFilename);
|
|
// Use the new download function
|
|
await downloadWithRedirects(downloadUrl, tempFilename);
|
|
|
|
// Extract the zip file using adm-zip
|
|
console.log(`Extracting ${packageName} to ${binDir}...`);
|
|
const zip = new AdmZip(tempFilename);
|
|
|
|
// Get all entries and find the bun binary
|
|
const entries = zip.getEntries();
|
|
let bunFound = false;
|
|
|
|
for (const entry of entries) {
|
|
const entryName = entry.entryName;
|
|
// Look for the bun binary (could be in root or in a subdirectory)
|
|
if (
|
|
entryName === 'bun' ||
|
|
entryName === 'bun.exe' ||
|
|
entryName.endsWith('/bun') ||
|
|
entryName.endsWith('/bun.exe') ||
|
|
entryName.endsWith('\\bun') ||
|
|
entryName.endsWith('\\bun.exe')
|
|
) {
|
|
// Extract just the binary name
|
|
const fileName = path.basename(entryName);
|
|
const destPath = path.join(binDir, fileName);
|
|
|
|
// Extract the specific file
|
|
zip.extractEntryTo(entry, binDir, false, true);
|
|
|
|
// Set executable permissions for non-Windows platforms
|
|
if (platform !== 'win32' && fileName === 'bun') {
|
|
try {
|
|
fs.chmodSync(destPath, '755');
|
|
} catch (error) {
|
|
console.warn(
|
|
`Warning: Failed to set executable permissions: ${error.message}`
|
|
);
|
|
}
|
|
}
|
|
|
|
bunFound = true;
|
|
}
|
|
}
|
|
|
|
if (!bunFound) {
|
|
throw new Error('bun binary not found in archive');
|
|
}
|
|
|
|
// Clean up
|
|
fs.unlinkSync(tempFilename);
|
|
|
|
console.log(`Successfully installed bun ${version} for ${platformKey}`);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Error installing bun for ${platformKey}: ${error.message}`);
|
|
// Clean up temporary file if it exists
|
|
if (fs.existsSync(tempFilename)) {
|
|
fs.unlinkSync(tempFilename);
|
|
}
|
|
|
|
// Check if binDir is empty and remove it if so
|
|
try {
|
|
const files = fs.readdirSync(binDir);
|
|
if (files.length === 0) {
|
|
fs.rmSync(binDir, { recursive: true });
|
|
console.log(`Removed empty directory: ${binDir}`);
|
|
}
|
|
} catch (cleanupError) {
|
|
console.warn(
|
|
`Warning: Failed to clean up directory: ${cleanupError.message}`
|
|
);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Detects current platform and architecture
|
|
*/
|
|
function detectPlatformAndArch() {
|
|
const platform = os.platform();
|
|
const arch = os.arch();
|
|
const isMusl = platform === 'linux' && detectIsMusl();
|
|
const isBaseline = platform === 'win32';
|
|
|
|
return { platform, arch, isMusl, isBaseline };
|
|
}
|
|
|
|
/**
|
|
* Attempts to detect if running on MUSL libc
|
|
*/
|
|
function detectIsMusl() {
|
|
try {
|
|
// Simple check for Alpine Linux which uses MUSL
|
|
const output = fs.readFileSync('/etc/os-release', 'utf8');
|
|
return output.toLowerCase().includes('alpine');
|
|
} catch (error) {
|
|
console.error(`Error detecting MUSL: ${error}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main function to install bun
|
|
*/
|
|
async function installBun() {
|
|
// Get the latest version if no specific version is provided
|
|
const version = DEFAULT_BUN_VERSION;
|
|
console.log(`Using bun version: ${version}`);
|
|
|
|
const { platform, arch, isMusl, isBaseline } = detectPlatformAndArch();
|
|
|
|
console.log(
|
|
`Installing bun ${version} for ${platform}-${arch}${isMusl ? ' (MUSL)' : ''}${isBaseline ? ' (baseline)' : ''}...`
|
|
);
|
|
|
|
const isInstalled = await downloadBunBinary(
|
|
BUN_RELEASE_BASE_URL,
|
|
platform,
|
|
arch,
|
|
version,
|
|
isMusl,
|
|
isBaseline
|
|
);
|
|
if (!isInstalled) {
|
|
throw new Error(`Failed to download bun ${version} from default source`);
|
|
}
|
|
}
|
|
|
|
// Run the installation
|
|
installBun()
|
|
.then(() => {
|
|
console.log('Installation successful');
|
|
process.exit(0);
|
|
})
|
|
.catch((error) => {
|
|
console.error('Installation failed:', error);
|
|
process.exit(1);
|
|
});
|