UNPKG

setup-cpp

Version:

Install all the tools required for building and testing C++/C projects.

197 lines (168 loc) 5.61 kB
import { basename, dirname, join } from "path" import { grantUserWriteAccess } from "admina" import { info, warning } from "ci-log" import { execa } from "execa" import { mkdirp, move, readdir, remove, stat } from "fs-extra" import { untildifyUser } from "untildify-user" import which from "which" import { setupSevenZip } from "../../sevenzip/sevenzip.js" import { setupTar } from "../../tar/tar.js" export { extractTar, extractXar } from "@actions/tool-cache" export enum ArchiveType { Tar = 0, TarGz = 1, TarXz = 2, Zip = 3, SevenZip = 4, } export function getArchiveType(file: string): ArchiveType { const ext = file.split(".").pop() if (ext === "tar") { return ArchiveType.Tar } if (ext === "gz" || ext === "tgz") { return ArchiveType.TarGz } if (ext === "xz" || ext === "txz") { return ArchiveType.TarXz } if (ext === "zip") { return ArchiveType.Zip } if (ext === "7z" || ext === "exe") { return ArchiveType.SevenZip } // default to 7z warning(`Unknown archive type: ${ext}. Defaulting to 7z`) return ArchiveType.SevenZip } export function getExtractFunction(archiveType: ArchiveType) { switch (archiveType) { case ArchiveType.Tar: case ArchiveType.TarGz: case ArchiveType.TarXz: return process.platform === "win32" ? extract7Zip : extractTarByExe case ArchiveType.Zip: return extractZip default: return extract7Zip } } let sevenZip: string | undefined /// Extract 7z using 7z export async function extract7Zip(file: string, dest: string, stripComponents: boolean = false) { const name = basename(file) if (/.*\.tar\..+$/.test(name)) { await extractTarXzBy7zip(file, name, dest, stripComponents) } else { // extract the 7z file directly await run7zip(file, dest) } return dest } async function extractTarXzBy7zip(file: string, name: string, dest: string, stripComponents: boolean) { if (!/.*\.tar\..+$/.test(name)) { throw new Error(`Invalid tar file: ${name}`) } // extract the compression first const tarDir = join(dirname(file), "sevenzip-temp") await run7zip(file, tarDir) // extract the tar const tarName = name.slice(0, -3) const tarFile = join(tarDir, tarName) await run7zip(tarFile, tarDir) await remove(tarFile) // move the extracted files to the destination info(`Moving ${tarDir} to ${dest}`) const tarDirFiles = await readdir(tarDir) await Promise.all( tarDirFiles.map(async (tarDirFile) => { await move(join(tarDir, tarDirFile), join(dest, tarDirFile), { overwrite: true }) }), ) await remove(tarDir) if (stripComponents) { await stripPathComponents(dest) } } async function stripPathComponents(dest: string) { info(`Stripping path components from ${dest}`) // get all subfolders in the folder const toStrip = await readdir(dest) if (toStrip.length !== 1) { throw new Error(`Expected 1 folder in ${dest}, got ${toStrip.length}`) } const subFolder = toStrip[0] const subFolderPath = join(dest, subFolder) const subFolderStat = await stat(subFolderPath) if (!subFolderStat.isDirectory()) { // if the subfolder is not a directory, do nothing warning(`Expected ${subFolderPath} to be a directory, got ${subFolderStat}.`) return } // for each child of the subfolder, move all files to the destination const subFiles = await readdir(subFolderPath) await Promise.all( subFiles.map((subFile) => { return move(join(subFolderPath, subFile), join(dest, subFile), { overwrite: true }) }), ) // remove the subfolder await remove(subFolderPath) } async function run7zip(file: string, dest: string) { info(`7z: extracting ${file} to ${dest}`) await execa(await getSevenZip(), ["x", file, `-o${dest}`, "-y"], { stdio: "inherit" }) await grantUserWriteAccess(dest) } /// install 7z if needed async function getSevenZip() { if (sevenZip === undefined) { if (which.sync("7z", { nothrow: true }) === null) { await setupSevenZip({ version: "" }) } // eslint-disable-next-line require-atomic-updates sevenZip = "7z" } return sevenZip } /// Extract Exe using 7z export function extractExe(file: string, dest: string) { return extract7Zip(file, dest) } /// Extract Zip using unzip or 7z export async function extractZip(file: string, dest: string) { // prefer 7z if available (faster especially on Windows) if (which.sync("7z", { nothrow: true }) !== null) { return extract7Zip(file, dest) } // if unzip is available use it (usually available on posix systems) if (which.sync("unzip", { nothrow: true }) !== null) { await execa("unzip", ["-q", file, "-d", dest], { stdio: "inherit" }) await grantUserWriteAccess(dest) return dest } // fallback to 7z (will install 7z if needed) return extract7Zip(file, dest) } export async function extractTarByExe(file: string, dest: string, stripComponents: number = 0, flags: string[] = []) { await setupTar({ version: "", arch: process.arch, setupDir: untildifyUser("~/tar") }) try { await mkdirp(dest) } catch { // ignore } // TODO windows fails to create symlinks // https://github.com/heroku/heroku-slugs/issues/3 try { await execa("tar", ["xf", file, "-C", dest, `--strip-components=${stripComponents}`, ...flags], { stdio: "inherit", }) } catch (e) { if (process.platform === "win32" && (e as Error).message.includes("Can't create '\\\\?\\C:")) { warning(`Failed to extract symlink ${file} to ${dest}. Ignoring this symlink.`) } } await grantUserWriteAccess(dest) return dest }