123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import fs from 'node:fs/promises'
- import { spawn } from 'node:child_process'
- import { envVars } from './config'
- import { downloadFile } from './download'
- export async function fileExistsAsync(filePath: string): Promise<boolean> {
- try {
- await fs.access(filePath)
- return true
- }
- catch {
- return false
- }
- }
- export async function removeDir(dir: string): Promise<void> {
- await fs.rm(dir, { recursive: true, force: true })
- }
- export async function createDir(dirPath: string): Promise<void> {
- await fs.mkdir(dirPath, { recursive: true })
- }
- export async function runCommand(
- command: string,
- args: string[] = [],
- options: {
- task?: { output?: string }
- env?: NodeJS.ProcessEnv
- disableOutput?: boolean
- maxOutputLines?: number
- } = { disableOutput: false },
- ): Promise<void> {
- if (!options.env) options.env = envVars
- const maxOutputLines = options.maxOutputLines ?? 10
- return new Promise((resolve, reject) => {
- const finalEnv = { ...envVars, ...(options.env || {}) }
- let outputLines: string[] = [`$ ${command} ${args.join(' ')}`]
- let remainingData = ''
- const child = spawn(command, args, { env: finalEnv, shell: true })
- const updateOutput = (data: Buffer) => {
- const text = data.toString()
- const fullText = remainingData + text
- const lines = fullText.split('\n')
- if (!fullText.endsWith('\n')) {
- remainingData = lines.pop() ?? ''
- }
- else {
- remainingData = ''
- }
- outputLines.push(...lines)
- if (outputLines.length > maxOutputLines) {
- outputLines = outputLines.slice(outputLines.length - maxOutputLines)
- }
- if (options.task) {
- options.task.output = outputLines.join('\n')
- }
- }
- if (!options.disableOutput) {
- child.stdout.on('data', updateOutput)
- child.stderr.on('data', updateOutput)
- }
- child.on('error', reject)
- child.on('close', (code) => {
- if (remainingData) {
- outputLines.push(remainingData)
- }
- if (outputLines.length > maxOutputLines) {
- outputLines = outputLines.slice(outputLines.length - maxOutputLines)
- }
- if (options.task) {
- options.task.output = outputLines.join('\n')
- }
- if (code === 0) {
- resolve()
- }
- else {
- reject(
- new Error(
- `Command "${command} ${args.join(' ')}" exited with code ${code}\nOutput:\n${outputLines.join('\n')}\nENV: ${JSON.stringify(options.env)}`,
- ),
- )
- }
- })
- })
- }
- export async function extractArchive(
- archiveName: string,
- extractCommand: string[],
- options: { task?: { output?: string } } = {},
- ) {
- // TODO: extract zip using library
- await runCommand('bash', ['-c', `"${extractCommand.join(' && ')}"`], options)
- }
- export async function ensureDownloadedAndExtracted(
- filePath: string,
- downloadUrl: string,
- archiveName: string,
- extractCommand: string[],
- options: { task?: { output?: string } } = {},
- ): Promise<void> {
- if (!(await fileExistsAsync(filePath))) {
- await downloadFile(options.task, downloadUrl, archiveName)
- await extractArchive(archiveName, extractCommand, options)
- }
- }
|