alwaysai
Version:
The alwaysAI command-line interface (CLI)
53 lines (49 loc) • 1.6 kB
text/typescript
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<void>((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}`
);
}
}