2017-02-06 13:40:28 -05:00
|
|
|
// Imports
|
|
|
|
import * as cp from 'child_process';
|
|
|
|
import {EventEmitter} from 'events';
|
|
|
|
import * as fs from 'fs';
|
|
|
|
import * as path from 'path';
|
|
|
|
import * as shell from 'shelljs';
|
2017-02-27 14:04:43 -05:00
|
|
|
import {assertNotMissingOrEmpty} from '../common/utils';
|
2017-02-06 13:40:28 -05:00
|
|
|
import {CreatedBuildEvent} from './build-events';
|
|
|
|
import {UploadError} from './upload-error';
|
|
|
|
|
|
|
|
// Classes
|
|
|
|
export class BuildCreator extends EventEmitter {
|
|
|
|
// Constructor
|
|
|
|
constructor(protected buildsDir: string) {
|
|
|
|
super();
|
2017-02-27 14:04:43 -05:00
|
|
|
assertNotMissingOrEmpty('buildsDir', buildsDir);
|
2017-02-06 13:40:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Methods - Public
|
|
|
|
public create(pr: string, sha: string, archivePath: string): Promise<any> {
|
|
|
|
const prDir = path.join(this.buildsDir, pr);
|
|
|
|
const shaDir = path.join(prDir, sha);
|
|
|
|
let dirToRemoveOnError: string;
|
|
|
|
|
|
|
|
return Promise.
|
|
|
|
all([this.exists(prDir), this.exists(shaDir)]).
|
|
|
|
then(([prDirExisted, shaDirExisted]) => {
|
|
|
|
if (shaDirExisted) {
|
|
|
|
throw new UploadError(403, `Request to overwrite existing directory: ${shaDir}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
dirToRemoveOnError = prDirExisted ? shaDir : prDir;
|
|
|
|
|
|
|
|
return Promise.resolve().
|
|
|
|
then(() => shell.mkdir('-p', shaDir)).
|
|
|
|
then(() => this.extractArchive(archivePath, shaDir)).
|
|
|
|
then(() => this.emit(CreatedBuildEvent.type, new CreatedBuildEvent(+pr, sha)));
|
|
|
|
}).
|
|
|
|
catch(err => {
|
|
|
|
if (dirToRemoveOnError) {
|
|
|
|
shell.rm('-rf', dirToRemoveOnError);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(err instanceof UploadError)) {
|
|
|
|
err = new UploadError(500, `Error while uploading to directory: ${shaDir}\n${err}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
throw err;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Methods - Protected
|
|
|
|
protected exists(fileOrDir: string): Promise<boolean> {
|
|
|
|
return new Promise(resolve => fs.access(fileOrDir, err => resolve(!err)));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected extractArchive(inputFile: string, outputDir: string): Promise<void> {
|
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
|
|
const cmd = `tar --extract --gzip --directory "${outputDir}" --file "${inputFile}"`;
|
|
|
|
|
|
|
|
cp.exec(cmd, (err, _stdout, stderr) => {
|
|
|
|
if (err) {
|
|
|
|
return reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stderr) {
|
|
|
|
console.warn(stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
|
|
|
(shell as any).chmod('-R', 'a-w', outputDir);
|
|
|
|
shell.rm('-f', inputFile);
|
|
|
|
resolve();
|
|
|
|
} catch (err) {
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|