120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import * as plugins from '../plugins.js';
|
|
|
|
export class ToolchainManager {
|
|
public static TOOLCHAIN_DIR = '/tmp/tsrust_toolchain';
|
|
public static RUSTUP_HOME = '/tmp/tsrust_toolchain/rustup';
|
|
public static CARGO_HOME = '/tmp/tsrust_toolchain/cargo';
|
|
public static BIN_DIR = '/tmp/tsrust_toolchain/cargo/bin';
|
|
|
|
private shell: plugins.smartshell.Smartshell;
|
|
|
|
constructor() {
|
|
this.shell = new plugins.smartshell.Smartshell({
|
|
executor: 'bash',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns the Rust host triple for the current platform.
|
|
*/
|
|
public getHostTriple(): string {
|
|
const platform = os.platform();
|
|
const arch = os.arch();
|
|
|
|
if (platform === 'linux' && arch === 'x64') return 'x86_64-unknown-linux-gnu';
|
|
if (platform === 'linux' && arch === 'arm64') return 'aarch64-unknown-linux-gnu';
|
|
if (platform === 'darwin' && arch === 'x64') return 'x86_64-apple-darwin';
|
|
if (platform === 'darwin' && arch === 'arm64') return 'aarch64-apple-darwin';
|
|
|
|
throw new Error(
|
|
`Unsupported platform: ${platform}/${arch}. Please install Rust manually via https://rustup.rs/`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Checks if the bundled toolchain is already installed at TOOLCHAIN_DIR.
|
|
*/
|
|
public async isInstalled(): Promise<boolean> {
|
|
const cargoPath = path.join(ToolchainManager.BIN_DIR, 'cargo');
|
|
try {
|
|
const stat = await fs.promises.stat(cargoPath);
|
|
return stat.isFile();
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Downloads rustup-init and installs a minimal Rust toolchain to TOOLCHAIN_DIR.
|
|
*/
|
|
public async install(): Promise<void> {
|
|
const triple = this.getHostTriple();
|
|
const rustupInitUrl = `https://static.rust-lang.org/rustup/dist/${triple}/rustup-init`;
|
|
const rustupInitPath = path.join(ToolchainManager.TOOLCHAIN_DIR, 'rustup-init');
|
|
|
|
// Ensure toolchain directory exists
|
|
await fs.promises.mkdir(ToolchainManager.TOOLCHAIN_DIR, { recursive: true });
|
|
|
|
console.log(`Downloading rustup-init for ${triple}...`);
|
|
const downloadResult = await this.shell.exec(
|
|
`curl -sSf -o ${rustupInitPath} ${rustupInitUrl} && chmod +x ${rustupInitPath}`
|
|
);
|
|
if (downloadResult.exitCode !== 0) {
|
|
throw new Error(`Failed to download rustup-init: ${downloadResult.stdout}`);
|
|
}
|
|
|
|
console.log('Installing minimal Rust toolchain to /tmp/tsrust_toolchain/...');
|
|
const installCmd = [
|
|
`RUSTUP_HOME="${ToolchainManager.RUSTUP_HOME}"`,
|
|
`CARGO_HOME="${ToolchainManager.CARGO_HOME}"`,
|
|
rustupInitPath,
|
|
'-y',
|
|
'--default-toolchain stable',
|
|
'--profile minimal',
|
|
'--no-modify-path',
|
|
].join(' ');
|
|
|
|
const installResult = await this.shell.exec(installCmd);
|
|
if (installResult.exitCode !== 0) {
|
|
throw new Error(`Failed to install Rust toolchain: ${installResult.stdout}`);
|
|
}
|
|
|
|
// Verify installation
|
|
const verifyResult = await this.shell.execSilent(
|
|
`${this.getEnvPrefix()}cargo --version`
|
|
);
|
|
if (verifyResult.exitCode !== 0) {
|
|
throw new Error('Rust toolchain installation verification failed.');
|
|
}
|
|
console.log(`Installed: ${verifyResult.stdout.trim()}`);
|
|
|
|
// Clean up rustup-init binary
|
|
await fs.promises.unlink(rustupInitPath).catch(() => {});
|
|
}
|
|
|
|
/**
|
|
* Ensures the bundled toolchain is installed. Downloads if not present.
|
|
*/
|
|
public async ensureInstalled(): Promise<void> {
|
|
if (await this.isInstalled()) {
|
|
console.log('Using bundled Rust toolchain from /tmp/tsrust_toolchain/');
|
|
return;
|
|
}
|
|
await this.install();
|
|
}
|
|
|
|
/**
|
|
* Returns a shell prefix string that sets RUSTUP_HOME, CARGO_HOME, and PATH
|
|
* to point at the bundled toolchain. Prepend this to any shell command.
|
|
*/
|
|
public getEnvPrefix(): string {
|
|
return (
|
|
`export RUSTUP_HOME="${ToolchainManager.RUSTUP_HOME}" CARGO_HOME="${ToolchainManager.CARGO_HOME}" && ` +
|
|
`export PATH="${ToolchainManager.BIN_DIR}:$PATH" && `
|
|
);
|
|
}
|
|
}
|