@atomist/automation-client
Version:
Atomist API for software low-level client
272 lines • 10.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fg = require("fast-glob");
const fs = require("fs-extra");
const fpath = require("path");
const stream = require("stream");
const RepoId_1 = require("../../operations/common/RepoId");
const logger_1 = require("../../util/logger");
const InMemoryProject_1 = require("../mem/InMemoryProject");
const AbstractProject_1 = require("../support/AbstractProject");
const projectUtils_1 = require("../util/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(), shouldCache = false) {
super(typeof ident === "string" ? new RepoId_1.SimpleRepoId(undefined, ident) : ident, shouldCache);
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 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) {
this.invalidateCache();
const realName = this.toRealPath(path);
fs.outputFileSync(realName, content);
}
addFile(path, content) {
return __awaiter(this, void 0, void 0, function* () {
this.invalidateCache();
const realName = this.toRealPath(path);
yield fs.outputFile(realName, content);
return this;
});
}
addDirectory(path) {
return __awaiter(this, void 0, void 0, function* () {
this.invalidateCache();
const realName = this.toRealPath(path);
yield fs.ensureDir(realName);
return this;
});
}
deleteDirectory(path) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield fs.remove(this.toRealPath(path));
this.invalidateCache();
}
catch (e) {
logger_1.logger.debug("Unable to delete directory '%s': %s", path, e.message);
}
return this;
});
}
deleteDirectorySync(path) {
const localPath = this.toRealPath(path);
try {
fs.removeSync(localPath);
this.invalidateCache();
}
catch (e) {
logger_1.logger.debug("Unable to delete directory '%s': %s", path, e.message);
}
}
deleteFileSync(path) {
try {
fs.unlinkSync(this.toRealPath(path));
this.invalidateCache();
}
catch (e) {
logger_1.logger.debug("Unable to delete file '%s': %s", path, e.message);
}
}
deleteFile(path) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield fs.unlink(this.toRealPath(path));
this.invalidateCache();
}
catch (e) {
logger_1.logger.debug("Unable to delete file '%s': %s", path, e.message);
}
return this;
});
}
makeExecutable(path) {
return __awaiter(this, void 0, void 0, function* () {
const stat = yield fs.stat(this.toRealPath(path));
// tslint:disable-next-line:no-bitwise
const newMode = stat.mode | fs.constants.S_IXUSR | fs.constants.S_IXGRP | fs.constants.S_IXOTH;
yield fs.chmod(this.toRealPath(path), newMode);
return this;
});
}
makeExecutableSync(path) {
const stat = fs.statSync(this.toRealPath(path));
// tslint:disable-next-line:no-bitwise
const newMode = stat.mode | fs.constants.S_IXUSR | fs.constants.S_IXGRP | fs.constants.S_IXOTH;
fs.chmodSync(this.toRealPath(path), newMode);
}
directoryExistsSync(path) {
try {
const stat = fs.statSync(this.toRealPath(path));
return stat.isDirectory();
}
catch (e) {
return false;
}
}
hasDirectory(path) {
return __awaiter(this, void 0, void 0, function* () {
try {
const stat = yield fs.stat(this.toRealPath(path));
return stat.isDirectory();
}
catch (e) {
return false;
}
});
}
fileExistsSync(path) {
try {
const stat = fs.statSync(this.toRealPath(path));
return stat.isFile();
}
catch (e) {
return false;
}
}
findFile(path) {
return __awaiter(this, void 0, void 0, function* () {
let stat;
try {
stat = yield fs.stat(this.toRealPath(path));
}
catch (e) {
throw fileNotFound(path);
}
if (!stat.isFile()) {
throw new Error(`Path ${path} is not a regular file`);
}
return new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path);
});
}
getFile(path) {
return __awaiter(this, void 0, void 0, function* () {
try {
const stat = yield fs.stat(this.toRealPath(path));
return stat.isFile() ? new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path) : undefined;
}
catch (e) {
return undefined;
}
});
}
findFileSync(path) {
try {
const stat = fs.statSync(this.toRealPath(path));
return stat.isFile() ? new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path) : undefined;
}
catch (e) {
return undefined;
}
}
getFilesInternal(globPatterns) {
return __awaiter(this, void 0, void 0, function* () {
const optsToUse = {
onlyFiles: true,
dot: true,
cwd: this.baseDir,
};
const paths = yield fg(globPatterns, optsToUse);
const files = paths.map(path => new NodeFsLocalFile_1.NodeFsLocalFile(this.baseDir, path));
return files;
});
}
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, chunk);
this.push(f);
done();
};
const optsToUse = Object.assign(Object.assign({
// We can override these defaults...
onlyFiles: true }, opts), {
// ...but we force this one
cwd: this.baseDir });
return fg.stream(globPatterns, optsToUse)
.pipe(toFileTransform);
}
toRealPath(path) {
return fpath.join(this.baseDir, path);
}
}
exports.NodeFsLocalProject = NodeFsLocalProject;
// 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