import { promisify } from 'util'; import { dirname } from 'path'; import { createWriteStream, rename } from 'fs'; import mkdirp = require('mkdirp'); import pump = require('pump'); import rimraf from 'rimraf'; import { CliTerseError } from '@alwaysai/alwayscli'; import { RandomString } from './random-string'; import { PLEASE_REPORT_THIS_ERROR_MESSAGE } from '../constants'; import { logger } from './logger'; import { stringifyError } from './stringify-error'; import { Readable } from 'node:stream'; import { fetchFilestream } from './fetch'; async function writeToFile(path: string, readable: Readable) { mkdirp.sync(dirname(path)); const tmpFilePath = `${path}.${RandomString()}.tmp`; try { await new Promise((resolve, reject) => { const writeable = createWriteStream(tmpFilePath); pump(readable, writeable, (err) => { if (err) { reject(err); } else { resolve(); } }); }); await promisify(rename)(tmpFilePath, path); } catch (exception) { try { await rimraf(tmpFilePath); } catch (err) { logger.warn('Failed to delete %s! %s', tmpFilePath, stringifyError(err)); } throw exception; } } export async function downloadToFile(props: { url: string; path: string }) { const { url, path } = props; logger.debug(`Downloading package from ${url}`); try { const filestream = await fetchFilestream(url); await writeToFile(path, filestream); } catch (e) { throw new CliTerseError( `Failed to download ${url}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}` ); } }