@atomist/automation-client
Version:
Atomist API for software low-level client
209 lines • 8.32 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs-extra");
const gs = require("glob-stream");
const fpath = require("path");
const stream = require("stream");
const file_1 = require("../../internal/util/file");
const logger_1 = require("../../internal/util/logger");
const RepoId_1 = require("../../operations/common/RepoId");
const InMemoryProject_1 = require("../mem/InMemoryProject");
const AbstractProject_1 = require("../support/AbstractProject");
const projectUtils_1 = require("../support/projectUtils");
const LocalProject_1 = require("./LocalProject");
const NodeFsLocalFile_1 = require("./NodeFsLocalFile");
class NodeFsLocalProject extends AbstractProject_1.AbstractProject {
/**
* Note: this does not validate existence of the target
* directory, so using it except in tests should be avoided
* @param {RepoRef} ident identification of the repo
* @param {string} baseDir
* @param cleanup function that will release locks, delete temp directories etc
*/
constructor(ident, baseDir, cleanup = () => Promise.resolve()) {
super(typeof ident === "string" ? new RepoId_1.SimpleRepoId(undefined, ident) : ident);
this.cleanup = cleanup;
// TODO not sure why app-root-path can return something weird and this coercion is necessary
this.baseDir = "" + baseDir;
}
/**
* Create a project from an existing directory. The directory must exist
* @param {RepoRef} id
* @param {string} baseDir
* @param cleanup
* @return {Promise<LocalProject>}
*/
static fromExistingDirectory(id, baseDir, cleanup = () => Promise.resolve()) {
return fs.stat(baseDir).then(stat => {
if (!stat.isDirectory()) {
throw new Error(`No such directory: [${baseDir}] when trying to create LocalProject`);
}
else {
return new NodeFsLocalProject(id, baseDir, cleanup);
}
});
}
/**
* Copy the contents of the other project to this project
* @param {Project} other
* @param {string} baseDir
* @param newName new name of the project. Defaults to name of old project
* @param cleanup
* @returns {LocalProject}
*/
static copy(other, baseDir, cleanup = () => Promise.resolve()) {
return fs.ensureDir(baseDir)
.then(() => {
if (LocalProject_1.isLocalProject(other)) {
return fs.copy(other.baseDir, baseDir)
.then(() => new NodeFsLocalProject(other.id, baseDir, cleanup));
}
else {
// We don't know what kind of project the other one is,
// so we are going to need to copy the files one at a time
const p = new NodeFsLocalProject(other.id, baseDir, cleanup);
return projectUtils_1.copyFiles(other, p)
.then(() => {
// Add empty directories if necessary
let prom = Promise.resolve(p);
if (InMemoryProject_1.isInMemoryProject(other)) {
other.addedDirectoryPaths.forEach(path => {
prom = prom.then(() => p.addDirectory(path));
});
}
return prom;
});
}
});
}
release() {
return this.cleanup();
}
addFileSync(path, content) {
const realName = this.baseDir + "/" + path;
const dir = fpath.dirname(realName);
if (!fs.existsSync(dir)) {
fs.mkdirsSync(dir);
}
fs.writeFileSync(realName, content);
}
addFile(path, content) {
const realName = this.baseDir + "/" + path;
const dir = fpath.dirname(realName);
return fs.pathExists(dir).then(exists => exists ? Promise.resolve() : fs.mkdirs(dir))
.then(() => fs.writeFile(realName, content))
.then(() => this);
}
addDirectory(path) {
const realName = this.baseDir + "/" + path;
return fs.mkdirp(realName)
.then(() => this);
}
deleteDirectory(path) {
return fs.remove(this.toRealPath(path))
.then(_ => this)
.catch(err => {
logger_1.logger.warn("Unable to delete directory '%s': %s", path, err);
return this;
});
}
deleteDirectorySync(path) {
const localPath = this.toRealPath(path);
try {
file_1.deleteFolderRecursive(localPath);
fs.unlinkSync(localPath);
}
catch (e) {
logger_1.logger.warn("Ignoring directory deletion error: " + e);
}
}
deleteFileSync(path) {
try {
fs.unlinkSync(this.toRealPath(path));
}
catch (e) {
logger_1.logger.warn("Ignoring file deletion error: " + e);
}
}
deleteFile(path) {
return fs.unlink(this.toRealPath(path)).then(_ => this);
}
makeExecutable(path) {
return fs.stat(this.toRealPath(path))
.then(stats => {
logger_1.logger.debug("Starting mode: " + stats.mode);
// tslint:disable-next-line:no-bitwise
const newMode = stats.mode | fs.constants.S_IXUSR;
logger_1.logger.debug("Setting mode to: " + newMode);
return fs.chmod(this.toRealPath(path), newMode);
})
.then(() => this);
}
makeExecutableSync(path) {
throw new Error("makeExecutableSync not implemented.");
}
directoryExistsSync(path) {
throw new Error("directoryExistsSync not implemented.");
}
fileExistsSync(path) {
return fs.existsSync(this.baseDir + "/" + path);
}
findFile(path) {
return fs.pathExists(this.baseDir + "/" + path)
.then(exists => exists ?
Promise.resolve(new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path)) :
Promise.reject(fileNotFound(path)));
}
getFile(path) {
return __awaiter(this, void 0, void 0, function* () {
const exists = yield fs.pathExists(this.baseDir + "/" + path);
return exists ? new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path) :
undefined;
});
}
findFileSync(path) {
if (!this.fileExistsSync(path)) {
return undefined;
}
return new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path);
}
streamFilesRaw(globPatterns, opts) {
// Fight arrow function "this" issue
const baseDir = this.baseDir;
const toFileTransform = new stream.Transform({ objectMode: true });
toFileTransform._transform = function (chunk, encoding, done) {
const f = new NodeFsLocalFile_1.NodeFsLocalFile(baseDir, pathWithinArchive(baseDir, chunk.path));
this.push(f);
done();
};
const optsToUse = Object.assign({
// We can override these defaults...
nodir: true, allowEmpty: true }, opts, {
// ...but we force this one
cwd: this.baseDir });
return gs(globPatterns, optsToUse)
.pipe(toFileTransform);
}
toRealPath(path) {
return this.baseDir + "/" + path;
}
}
exports.NodeFsLocalProject = NodeFsLocalProject;
function pathWithinArchive(baseDir, rawPath) {
return rawPath.substr(baseDir.length);
}
// construct a useful exception
function fileNotFound(path) {
const error = new Error(`File not found at ${path}`);
error.code = "ENOENT";
return error;
}
//# sourceMappingURL=NodeFsLocalProject.js.map