mirror of
https://github.com/moonrepo/setup-rust.git
synced 2025-04-20 09:38:43 +00:00
220 lines
5.2 KiB
TypeScript
220 lines
5.2 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import * as core from '@actions/core';
|
|
import * as exec from '@actions/exec';
|
|
import * as tc from '@actions/tool-cache';
|
|
import TOML from '@ltd/j-toml';
|
|
import { CACHE_ENABLED, CARGO_HOME, restoreCache } from './src/cargo';
|
|
import { extractRustVersion } from './src/rust';
|
|
|
|
interface Toolchain {
|
|
channel: string;
|
|
components: string[];
|
|
targets: string[];
|
|
profile: string;
|
|
}
|
|
|
|
interface ToolchainConfig {
|
|
toolchain: Partial<Toolchain>;
|
|
}
|
|
|
|
const DEFAULT_TOOLCHAIN: Toolchain = {
|
|
channel: 'stable',
|
|
components: [],
|
|
profile: 'minimal',
|
|
targets: [],
|
|
};
|
|
|
|
function parseConfig(configPath: string): Partial<Toolchain> {
|
|
const contents = fs.readFileSync(configPath, 'utf8').trim();
|
|
|
|
if (!contents.includes('[toolchain]')) {
|
|
core.debug('No [toolchain] section found, assuming legacy format');
|
|
|
|
return { channel: contents };
|
|
}
|
|
|
|
const config = TOML.parse(contents) as unknown as ToolchainConfig;
|
|
|
|
if (config.toolchain.channel) {
|
|
core.debug('Found channel in [toolchain] section');
|
|
|
|
return { channel: config.toolchain.channel };
|
|
}
|
|
|
|
core.debug('No channel found in [toolchain] section');
|
|
|
|
return {};
|
|
}
|
|
|
|
// https://rust-lang.github.io/rustup/overrides.html
|
|
function detectToolchain(): Toolchain {
|
|
core.info('Detecting toolchain');
|
|
|
|
const toolchain = { ...DEFAULT_TOOLCHAIN };
|
|
|
|
if (process.env.RUSTUP_TOOLCHAIN) {
|
|
core.info('Using toolchain from RUSTUP_TOOLCHAIN environment variable');
|
|
|
|
Object.assign(toolchain, {
|
|
channel: process.env.RUSTUP_TOOLCHAIN,
|
|
});
|
|
} else {
|
|
core.info('Loading rust-toolchain.toml or rust-toolchain file');
|
|
|
|
for (const configName of ['rust-toolchain.toml', 'rust-toolchain']) {
|
|
const configPath = path.join(process.cwd(), configName);
|
|
|
|
if (fs.existsSync(configPath)) {
|
|
core.debug(`Found ${configName}, parsing TOML`);
|
|
|
|
Object.assign(toolchain, parseConfig(configPath));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
core.info('Inheriting toolchain settings from inputs');
|
|
|
|
(Object.keys(DEFAULT_TOOLCHAIN) as (keyof typeof DEFAULT_TOOLCHAIN)[]).forEach((key) => {
|
|
const input = core.getInput(key);
|
|
|
|
if (input) {
|
|
core.debug(`Found input for ${key}: ${input}`);
|
|
|
|
if (key === 'components' || key === 'targets') {
|
|
input.split(',').forEach((part) => {
|
|
toolchain[key].push(part.trim());
|
|
});
|
|
} else {
|
|
toolchain[key] = input;
|
|
}
|
|
}
|
|
});
|
|
|
|
return toolchain;
|
|
}
|
|
|
|
async function installToolchain(toolchain: Toolchain) {
|
|
core.info('Installing toolchain with rustup');
|
|
|
|
const args = ['toolchain', 'install', toolchain.channel, '--profile', toolchain.profile];
|
|
|
|
toolchain.targets.forEach((target) => {
|
|
args.push('--target', target);
|
|
});
|
|
|
|
toolchain.components.forEach((component) => {
|
|
args.push('--component', component);
|
|
});
|
|
|
|
if (toolchain.channel === 'nightly' && toolchain.components.length > 0) {
|
|
args.push('--allow-downgrade');
|
|
}
|
|
|
|
args.push('--no-self-update');
|
|
|
|
await exec.exec('rustup', args);
|
|
await exec.exec('rustup', ['default', toolchain.channel]);
|
|
|
|
core.info('Logging installed toolchain versions');
|
|
|
|
await extractRustVersion(toolchain.channel);
|
|
}
|
|
|
|
async function downloadAndInstallBinstall(binDir: string) {
|
|
core.info('cargo-binstall does not exist, attempting to install');
|
|
|
|
let arch;
|
|
let file;
|
|
|
|
switch (process.arch) {
|
|
case 'x64':
|
|
arch = 'x86_64';
|
|
break;
|
|
case 'arm64':
|
|
arch = 'aarch64';
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported architecture: ${process.arch}`);
|
|
}
|
|
|
|
switch (process.platform) {
|
|
case 'linux':
|
|
file = `${arch}-unknown-linux-gnu.tgz`;
|
|
break;
|
|
case 'darwin':
|
|
file = `${arch}-apple-darwin.zip`;
|
|
break;
|
|
case 'win32':
|
|
file = `${arch}-pc-windows-msvc.zip`;
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
}
|
|
|
|
const url = `https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-${file}`;
|
|
const dlPath = await tc.downloadTool(url);
|
|
|
|
if (url.endsWith('.zip')) {
|
|
await tc.extractZip(dlPath, binDir);
|
|
} else if (url.endsWith('.tgz')) {
|
|
await tc.extractTar(dlPath, binDir);
|
|
}
|
|
}
|
|
|
|
async function installBins() {
|
|
const bins = core
|
|
.getInput('bins')
|
|
.split(',')
|
|
.map((bin) => bin.trim())
|
|
.filter(Boolean)
|
|
.map((bin) => (bin.startsWith('cargo-') ? bin : `cargo-${bin}`));
|
|
|
|
if (CACHE_ENABLED) {
|
|
bins.push('cargo-cache');
|
|
}
|
|
|
|
if (bins.length === 0) {
|
|
return;
|
|
}
|
|
|
|
core.info('Installing additional binaries');
|
|
|
|
const binDir = path.join(CARGO_HOME, 'bin');
|
|
|
|
if (!fs.existsSync(path.join(binDir, 'cargo-binstall'))) {
|
|
await downloadAndInstallBinstall(binDir);
|
|
}
|
|
|
|
await exec.exec('cargo', ['binstall', '--no-confirm', '--log-level', 'info', ...bins]);
|
|
}
|
|
|
|
async function run() {
|
|
core.info('Setting cargo environment variables');
|
|
|
|
// Disable incremental compilation
|
|
core.exportVariable('CARGO_INCREMENTAL', '0');
|
|
|
|
// Always enable colored output
|
|
core.exportVariable('CARGO_TERM_COLOR', 'always');
|
|
|
|
try {
|
|
await installToolchain(detectToolchain());
|
|
await installBins();
|
|
|
|
// Restore cache after the toolchain has been installed,
|
|
// as we use the rust version and commit hashes in the cache key!
|
|
await restoreCache();
|
|
} catch (error: unknown) {
|
|
core.setFailed((error as Error).message);
|
|
|
|
throw error;
|
|
}
|
|
|
|
core.info('Adding ~/.cargo/bin to PATH');
|
|
|
|
core.addPath(path.join(CARGO_HOME, 'bin'));
|
|
}
|
|
|
|
void run();
|