123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.copyPromise = exports.LinkStrategy = void 0;
- const tslib_1 = require("tslib");
- const fs_1 = tslib_1.__importDefault(require("fs"));
- const constants = tslib_1.__importStar(require("../constants"));
- const path_1 = require("../path");
- const defaultTime = new Date(constants.SAFE_TIME * 1000);
- var LinkStrategy;
- (function (LinkStrategy) {
- LinkStrategy["Allow"] = "allow";
- LinkStrategy["ReadOnly"] = "readOnly";
- })(LinkStrategy = exports.LinkStrategy || (exports.LinkStrategy = {}));
- async function copyPromise(destinationFs, destination, sourceFs, source, opts) {
- const normalizedDestination = destinationFs.pathUtils.normalize(destination);
- const normalizedSource = sourceFs.pathUtils.normalize(source);
- const prelayout = [];
- const postlayout = [];
- const { atime, mtime } = opts.stableTime
- ? { atime: defaultTime, mtime: defaultTime }
- : await sourceFs.lstatPromise(normalizedSource);
- await destinationFs.mkdirpPromise(destinationFs.pathUtils.dirname(destination), { utimes: [atime, mtime] });
- const updateTime = typeof destinationFs.lutimesPromise === `function`
- ? destinationFs.lutimesPromise.bind(destinationFs)
- : destinationFs.utimesPromise.bind(destinationFs);
- await copyImpl(prelayout, postlayout, updateTime, destinationFs, normalizedDestination, sourceFs, normalizedSource, { ...opts, didParentExist: true });
- for (const operation of prelayout)
- await operation();
- await Promise.all(postlayout.map(operation => {
- return operation();
- }));
- }
- exports.copyPromise = copyPromise;
- async function copyImpl(prelayout, postlayout, updateTime, destinationFs, destination, sourceFs, source, opts) {
- var _a, _b;
- const destinationStat = opts.didParentExist ? await maybeLStat(destinationFs, destination) : null;
- const sourceStat = await sourceFs.lstatPromise(source);
- const { atime, mtime } = opts.stableTime
- ? { atime: defaultTime, mtime: defaultTime }
- : sourceStat;
- let updated;
- switch (true) {
- case sourceStat.isDirectory():
- {
- updated = await copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
- }
- break;
- case sourceStat.isFile():
- {
- updated = await copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
- }
- break;
- case sourceStat.isSymbolicLink():
- {
- updated = await copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts);
- }
- break;
- default:
- {
- throw new Error(`Unsupported file type (${sourceStat.mode})`);
- }
- break;
- }
- if (updated || ((_a = destinationStat === null || destinationStat === void 0 ? void 0 : destinationStat.mtime) === null || _a === void 0 ? void 0 : _a.getTime()) !== mtime.getTime() || ((_b = destinationStat === null || destinationStat === void 0 ? void 0 : destinationStat.atime) === null || _b === void 0 ? void 0 : _b.getTime()) !== atime.getTime()) {
- postlayout.push(() => updateTime(destination, atime, mtime));
- updated = true;
- }
- if (destinationStat === null || (destinationStat.mode & 0o777) !== (sourceStat.mode & 0o777)) {
- postlayout.push(() => destinationFs.chmodPromise(destination, sourceStat.mode & 0o777));
- updated = true;
- }
- return updated;
- }
- async function maybeLStat(baseFs, p) {
- try {
- return await baseFs.lstatPromise(p);
- }
- catch (e) {
- return null;
- }
- }
- async function copyFolder(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
- if (destinationStat !== null && !destinationStat.isDirectory()) {
- if (opts.overwrite) {
- prelayout.push(async () => destinationFs.removePromise(destination));
- destinationStat = null;
- }
- else {
- return false;
- }
- }
- let updated = false;
- if (destinationStat === null) {
- prelayout.push(async () => {
- try {
- await destinationFs.mkdirPromise(destination, { mode: sourceStat.mode });
- }
- catch (err) {
- if (err.code !== `EEXIST`) {
- throw err;
- }
- }
- });
- updated = true;
- }
- const entries = await sourceFs.readdirPromise(source);
- const nextOpts = opts.didParentExist && !destinationStat ? { ...opts, didParentExist: false } : opts;
- if (opts.stableSort) {
- for (const entry of entries.sort()) {
- if (await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts)) {
- updated = true;
- }
- }
- }
- else {
- const entriesUpdateStatus = await Promise.all(entries.map(async (entry) => {
- await copyImpl(prelayout, postlayout, updateTime, destinationFs, destinationFs.pathUtils.join(destination, entry), sourceFs, sourceFs.pathUtils.join(source, entry), nextOpts);
- }));
- if (entriesUpdateStatus.some(status => status)) {
- updated = true;
- }
- }
- return updated;
- }
- const isCloneSupportedCache = new WeakMap();
- function makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy) {
- return async () => {
- await opFs.linkPromise(source, destination);
- if (linkStrategy === LinkStrategy.ReadOnly) {
- // We mutate the stat, otherwise it'll be reset by copyImpl
- sourceStat.mode &= ~0o222;
- await opFs.chmodPromise(destination, sourceStat.mode);
- }
- };
- }
- function makeCloneLinkOperation(opFs, destination, source, sourceStat, linkStrategy) {
- const isCloneSupported = isCloneSupportedCache.get(opFs);
- if (typeof isCloneSupported === `undefined`) {
- return async () => {
- try {
- await opFs.copyFilePromise(source, destination, fs_1.default.constants.COPYFILE_FICLONE_FORCE);
- isCloneSupportedCache.set(opFs, true);
- }
- catch (err) {
- if (err.code === `ENOSYS` || err.code === `ENOTSUP`) {
- isCloneSupportedCache.set(opFs, false);
- await makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy)();
- }
- else {
- throw err;
- }
- }
- };
- }
- else {
- if (isCloneSupported) {
- return async () => opFs.copyFilePromise(source, destination, fs_1.default.constants.COPYFILE_FICLONE_FORCE);
- }
- else {
- return makeLinkOperation(opFs, destination, source, sourceStat, linkStrategy);
- }
- }
- }
- async function copyFile(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
- var _a;
- if (destinationStat !== null) {
- if (opts.overwrite) {
- prelayout.push(async () => destinationFs.removePromise(destination));
- destinationStat = null;
- }
- else {
- return false;
- }
- }
- const linkStrategy = (_a = opts.linkStrategy) !== null && _a !== void 0 ? _a : null;
- const op = destinationFs === sourceFs
- ? linkStrategy !== null
- ? makeCloneLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy)
- : async () => destinationFs.copyFilePromise(source, destination, fs_1.default.constants.COPYFILE_FICLONE)
- : linkStrategy !== null
- ? makeLinkOperation(destinationFs, destination, source, sourceStat, linkStrategy)
- : async () => destinationFs.writeFilePromise(destination, await sourceFs.readFilePromise(source));
- prelayout.push(async () => op());
- return true;
- }
- async function copySymlink(prelayout, postlayout, updateTime, destinationFs, destination, destinationStat, sourceFs, source, sourceStat, opts) {
- if (destinationStat !== null) {
- if (opts.overwrite) {
- prelayout.push(async () => destinationFs.removePromise(destination));
- destinationStat = null;
- }
- else {
- return false;
- }
- }
- prelayout.push(async () => {
- await destinationFs.symlinkPromise((0, path_1.convertPath)(destinationFs.pathUtils, await sourceFs.readlinkPromise(source)), destination);
- });
- return true;
- }
|