builder-util
Version:
Various utilities. Used by [electron-builder](https://github.com/electron-userland/electron-builder).
405 lines (319 loc) • 11.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unlinkIfExists = unlinkIfExists;
exports.copyFile = copyFile;
exports.copyOrLinkFile = copyOrLinkFile;
exports.copyDir = copyDir;
exports.USE_HARD_LINKS = exports.DO_NOT_USE_HARD_LINKS = exports.FileCopier = exports.walk = exports.exists = exports.statOrNull = exports.CONCURRENCY = exports.MAX_FILE_REQUESTS = void 0;
function _bluebirdLst() {
const data = _interopRequireWildcard(require("bluebird-lst"));
_bluebirdLst = function () {
return data;
};
return data;
}
function _fsExtraP() {
const data = require("fs-extra-p");
_fsExtraP = function () {
return data;
};
return data;
}
var path = _interopRequireWildcard(require("path"));
function _statMode() {
const data = _interopRequireDefault(require("stat-mode"));
_statMode = function () {
return data;
};
return data;
}
function _log() {
const data = require("./log");
_log = function () {
return data;
};
return data;
}
function _promise() {
const data = require("./promise");
_promise = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
const MAX_FILE_REQUESTS = 8;
exports.MAX_FILE_REQUESTS = MAX_FILE_REQUESTS;
const CONCURRENCY = {
concurrency: MAX_FILE_REQUESTS
};
exports.CONCURRENCY = CONCURRENCY;
function unlinkIfExists(file) {
return (0, _fsExtraP().unlink)(file).catch(() => {});
}
let statOrNull = (() => {
var _ref = (0, _bluebirdLst().coroutine)(function* (file) {
return (0, _promise().orNullIfFileNotExist)((0, _fsExtraP().stat)(file));
});
return function statOrNull(_x) {
return _ref.apply(this, arguments);
};
})();
exports.statOrNull = statOrNull;
let exists = (() => {
var _ref2 = (0, _bluebirdLst().coroutine)(function* (file) {
try {
yield (0, _fsExtraP().access)(file);
return true;
} catch (e) {
return false;
}
});
return function exists(_x2) {
return _ref2.apply(this, arguments);
};
})();
/**
* Returns list of file paths (system-dependent file separator)
*/
exports.exists = exists;
let walk = (() => {
var _ref3 = (0, _bluebirdLst().coroutine)(function* (initialDirPath, filter, consumer) {
let result = [];
const queue = [initialDirPath];
let addDirToResult = false;
const isIncludeDir = consumer == null ? false : consumer.isIncludeDir === true;
while (queue.length > 0) {
const dirPath = queue.pop();
if (isIncludeDir) {
if (addDirToResult) {
result.push(dirPath);
} else {
addDirToResult = true;
}
}
const childNames = yield (0, _fsExtraP().readdir)(dirPath);
childNames.sort();
let nodeModuleContent = null;
const dirs = []; // our handler is async, but we should add sorted files, so, we add file to result not in the mapper, but after map
const sortedFilePaths = yield _bluebirdLst().default.map(childNames, name => {
if (name === ".DS_Store" || name === ".gitkeep") {
return null;
}
const filePath = dirPath + path.sep + name;
return (0, _fsExtraP().lstat)(filePath).then(stat => {
if (filter != null && !filter(filePath, stat)) {
return null;
}
const consumerResult = consumer == null ? null : consumer.consume(filePath, stat, dirPath, childNames);
if (consumerResult === false) {
return null;
} else if (consumerResult == null || !("then" in consumerResult)) {
if (stat.isDirectory()) {
dirs.push(name);
return null;
} else {
return filePath;
}
} else {
return consumerResult.then(it => {
if (it != null && Array.isArray(it)) {
nodeModuleContent = it;
return null;
} // asarUtil can return modified stat (symlink handling)
if ((it != null && "isDirectory" in it ? it : stat).isDirectory()) {
dirs.push(name);
return null;
} else {
return filePath;
}
});
}
});
}, CONCURRENCY);
for (const child of sortedFilePaths) {
if (child != null) {
result.push(child);
}
}
dirs.sort();
for (const child of dirs) {
queue.push(dirPath + path.sep + child);
}
if (nodeModuleContent != null) {
result = result.concat(nodeModuleContent);
}
}
return result;
});
return function walk(_x3, _x4, _x5) {
return _ref3.apply(this, arguments);
};
})();
exports.walk = walk;
const _isUseHardLink = process.platform !== "win32" && process.env.USE_HARD_LINKS !== "false" && (require("is-ci") || process.env.USE_HARD_LINKS === "true");
function copyFile(src, dest, isEnsureDir = true) {
return (isEnsureDir ? (0, _fsExtraP().ensureDir)(path.dirname(dest)) : Promise.resolve()).then(() => copyOrLinkFile(src, dest, null, false));
}
/**
* Hard links is used if supported and allowed.
* File permission is fixed — allow execute for all if owner can, allow read for all if owner can.
*
* ensureDir is not called, dest parent dir must exists
*/
function copyOrLinkFile(src, dest, stats, isUseHardLink = _isUseHardLink, exDevErrorHandler) {
if (stats != null) {
const originalModeNumber = stats.mode;
const mode = new (_statMode().default)(stats);
if (mode.owner.execute) {
mode.group.execute = true;
mode.others.execute = true;
}
mode.group.read = true;
mode.others.read = true;
if (originalModeNumber !== stats.mode) {
if (_log().log.isDebugEnabled) {
const oldMode = new (_statMode().default)({
mode: originalModeNumber
});
_log().log.debug({
file: dest,
oldMode,
mode
}, "permissions fixed from");
} // https://helgeklein.com/blog/2009/05/hard-links-and-permissions-acls/
// Permissions on all hard links to the same data on disk are always identical. The same applies to attributes.
// That means if you change the permissions/owner/attributes on one hard link, you will immediately see the changes on all other hard links.
if (isUseHardLink) {
isUseHardLink = false;
_log().log.debug({
dest
}, "copied, but not linked, because file permissions need to be fixed");
}
}
}
if (isUseHardLink) {
return (0, _fsExtraP().link)(src, dest).catch(e => {
if (e.code === "EXDEV") {
const isLog = exDevErrorHandler == null ? true : exDevErrorHandler();
if (isLog && _log().log.isDebugEnabled) {
_log().log.debug({
error: e.message
}, "cannot copy using hard link");
}
return doCopyFile(src, dest, stats);
} else {
throw e;
}
});
}
return doCopyFile(src, dest, stats);
}
function doCopyFile(src, dest, stats) {
if (_fsExtraP().copyFile == null) {
return new (_bluebirdLst().default)((resolve, reject) => {
const reader = (0, _fsExtraP().createReadStream)(src);
const writer = (0, _fsExtraP().createWriteStream)(dest, stats == null ? undefined : {
mode: stats.mode
});
reader.on("error", reject);
writer.on("error", reject);
writer.on("open", () => {
reader.pipe(writer);
});
writer.once("close", resolve);
});
} // node 8.5.0+
const promise = (0, _fsExtraP().copyFile)(src, dest);
if (stats == null) {
return promise;
}
return promise.then(() => (0, _fsExtraP().chmod)(dest, stats.mode));
}
class FileCopier {
constructor(isUseHardLinkFunction, transformer) {
this.isUseHardLinkFunction = isUseHardLinkFunction;
this.transformer = transformer;
if (isUseHardLinkFunction === USE_HARD_LINKS) {
this.isUseHardLink = true;
} else {
this.isUseHardLink = _isUseHardLink && isUseHardLinkFunction !== DO_NOT_USE_HARD_LINKS;
}
}
copy(src, dest, stat) {
var _this = this;
return (0, _bluebirdLst().coroutine)(function* () {
if (_this.transformer != null && stat != null && stat.isFile()) {
let data = _this.transformer(src);
if (data != null) {
if (typeof data.then === "function") {
data = yield data;
}
if (data != null) {
yield (0, _fsExtraP().writeFile)(dest, data);
return;
}
}
}
const isUseHardLink = !_this.isUseHardLink || _this.isUseHardLinkFunction == null ? _this.isUseHardLink : _this.isUseHardLinkFunction(dest);
yield copyOrLinkFile(src, dest, stat, isUseHardLink, isUseHardLink ? () => {
// files are copied concurrently, so, we must not check here currentIsUseHardLink — our code can be executed after that other handler will set currentIsUseHardLink to false
if (_this.isUseHardLink) {
_this.isUseHardLink = false;
return true;
} else {
return false;
}
} : null);
})();
}
}
/**
* Empty directories is never created.
* Hard links is used if supported and allowed.
*/
exports.FileCopier = FileCopier;
function copyDir(src, destination, options = {}) {
const fileCopier = new FileCopier(options.isUseHardLink, options.transformer);
if (_log().log.isDebugEnabled) {
_log().log.debug({
src,
destination
}, `copying${fileCopier.isUseHardLink ? " using hard links" : ""}`);
}
const createdSourceDirs = new Set();
const links = [];
return walk(src, options.filter, {
consume: (() => {
var _ref4 = (0, _bluebirdLst().coroutine)(function* (file, stat, parent) {
if (!stat.isFile() && !stat.isSymbolicLink()) {
return;
}
if (!createdSourceDirs.has(parent)) {
yield (0, _fsExtraP().ensureDir)(parent.replace(src, destination));
createdSourceDirs.add(parent);
}
const destFile = file.replace(src, destination);
if (stat.isFile()) {
yield fileCopier.copy(file, destFile, stat);
} else {
links.push({
file: destFile,
link: yield (0, _fsExtraP().readlink)(file)
});
}
});
return function consume(_x6, _x7, _x8) {
return _ref4.apply(this, arguments);
};
})()
}).then(() => _bluebirdLst().default.map(links, it => (0, _fsExtraP().symlink)(it.link, it.file), CONCURRENCY));
}
const DO_NOT_USE_HARD_LINKS = file => false;
exports.DO_NOT_USE_HARD_LINKS = DO_NOT_USE_HARD_LINKS;
const USE_HARD_LINKS = file => true;
exports.USE_HARD_LINKS = USE_HARD_LINKS;
//# sourceMappingURL=fs.js.map