From d19bea4f65e1c0a385b9a40681815b1f02a24538 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Mon, 17 Apr 2023 16:23:45 -0700 Subject: [PATCH] build: Move code around. --- index.ts | 204 ++------------------------------------------------- src/cargo.ts | 69 +++++++++++++++++ src/rust.ts | 143 +++++++++++++++++++++++++++++++++--- 3 files changed, 209 insertions(+), 207 deletions(-) diff --git a/index.ts b/index.ts index 16160fb..1337150 100644 --- a/index.ts +++ b/index.ts @@ -1,206 +1,20 @@ -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; -} - -const DEFAULT_TOOLCHAIN: Toolchain = { - channel: 'stable', - components: [], - profile: 'minimal', - targets: [], -}; - -function parseConfig(configPath: string): Partial { - 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]); -} +import { CARGO_HOME, installBins, restoreCache } from './src/cargo'; +import { installToolchain } from './src/rust'; 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'); + core.info('Adding ~/.cargo/bin to PATH'); + + core.addPath(path.join(CARGO_HOME, 'bin')); + try { - await installToolchain(detectToolchain()); + await installToolchain(); await installBins(); // Restore cache after the toolchain has been installed, @@ -211,10 +25,6 @@ async function run() { throw error; } - - core.info('Adding ~/.cargo/bin to PATH'); - - core.addPath(path.join(CARGO_HOME, 'bin')); } void run(); diff --git a/src/cargo.ts b/src/cargo.ts index 1f50784..eec4764 100644 --- a/src/cargo.ts +++ b/src/cargo.ts @@ -7,12 +7,81 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; import * as glob from '@actions/glob'; import * as io from '@actions/io'; +import * as tc from '@actions/tool-cache'; import { RUST_HASH, RUST_VERSION } from './rust'; export const CARGO_HOME = process.env.CARGO_HOME ?? path.join(os.homedir(), '.cargo'); export const CACHE_ENABLED = core.getBooleanInput('cache') || cache.isFeatureAvailable(); +export 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); + } +} + +export 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]); +} + export function getCachePaths(): string[] { return [ // ~/.cargo/registry diff --git a/src/rust.ts b/src/rust.ts index 02ddf7f..a2a2459 100644 --- a/src/rust.ts +++ b/src/rust.ts @@ -1,10 +1,31 @@ /* eslint-disable import/no-mutable-exports */ +import fs from 'fs'; +import path from 'path'; import * as core from '@actions/core'; import * as exec from '@actions/exec'; +import TOML from '@ltd/j-toml'; -export let RUST_VERSION = ''; -export let RUST_HASH = ''; +interface Toolchain { + channel: string; + components: string[]; + targets: string[]; + profile: string; +} + +interface ToolchainConfig { + toolchain: Partial; +} + +const DEFAULT_TOOLCHAIN: Toolchain = { + channel: 'stable', + components: [], + profile: 'minimal', + targets: [], +}; + +export let RUST_VERSION = core.getState('rust-version'); +export let RUST_HASH = core.getState('rust-hash'); export async function extractRustVersion(toolchain: string) { let out = ''; @@ -17,19 +38,121 @@ export async function extractRustVersion(toolchain: string) { }, }); + const extract = (key: string, line: string) => { + const value = line.split(':')[1].trim(); + + core.setOutput(key, value); + core.saveState(key, value); + + return value; + }; + out.split('\n').forEach((line) => { if (line.startsWith('commit-hash')) { - const value = line.split(':')[1].trim(); - - core.setOutput('rust-hash', value); - RUST_HASH = value; + RUST_HASH = extract('rust-hash', line); // version } else if (line.startsWith('release')) { - const value = line.split(':')[1].trim(); - - core.setOutput('rust-version', value); - RUST_VERSION = value; + RUST_VERSION = extract('rust-version', line); } }); } + +export function parseConfig(configPath: string): Partial { + 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 +export 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; +} + +export async function installToolchain() { + const toolchain = detectToolchain(); + + 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); +}