UNPKG

@plugjs/plug

Version:
92 lines 4.28 kB
import { assert } from "../asserts.js"; import { Files } from "../files.js"; import { chmod, copyFile, fsConstants, mkdir } from "../fs.js"; import { $p } from "../logging.js"; import { assertAbsolutePath, getAbsoluteParent, resolveAbsolutePath } from "../paths.js"; import { install } from "../pipe.js"; /* ========================================================================== * * INSTALLATION / IMPLEMENTATION * * ========================================================================== */ /** Copy the curent {@link Files} to a different directory */ install('copy', class Copy { _directory; _options; constructor(_directory, _options = {}) { this._directory = _directory; this._options = _options; } async pipe(files, context) { /* Destructure our options with some defaults and compute write flags */ const { mode, dirMode, overwrite = 'fail', rename = (s) => s } = this._options; const flags = overwrite === 'overwrite' ? 0 : fsConstants.COPYFILE_EXCL; const dmode = parseMode(dirMode); const fmode = parseMode(mode); /* Our files builder for all written files */ const directory = context.resolve(this._directory); const builder = Files.builder(directory); /* Iterate through all the mappings of the source files */ for (const [relative, absolute] of files.pathMappings()) { /* The target absolute is the (possibly) renamed relative source file * relocated to the the target directory */ const target = resolveAbsolutePath(builder.directory, rename(relative)); /* We never copy a file onto itself, but not fail either */ if (target === absolute) { context.log.warn('Cowardly refusing to copy same file', $p(absolute)); continue; } /* Create the parent directory, recursively */ const directory = getAbsoluteParent(target); const firstParent = await mkdir(directory, { recursive: true }); /* Set the mode for all created directories */ if (firstParent && (dmode !== undefined)) { assertAbsolutePath(firstParent); for (let dir = directory;; dir = getAbsoluteParent(dir)) { context.log.trace(`Setting mode ${stringifyMode(dmode)} for directory`, $p(dir)); await chmod(dir, dmode); if (dir === firstParent) break; } } context.log.trace(`Copying "${$p(absolute)}" to "${$p(target)}"`); try { /* Actually _copy_ the file */ await copyFile(absolute, target, flags); /* Set the mode, if we need to */ if (fmode !== undefined) { context.log.trace(`Setting mode ${stringifyMode(fmode)} for file`, $p(target)); await chmod(target, fmode); } /* Record this file */ builder.add(target); } catch (error) { /* Just log that we skipped the file if we have to */ if ((error.code === 'EEXIST') && (overwrite === 'skip')) { context.log.warn(`Not overwriting existing file ${$p(target)}`); } else { throw error; } } } const result = builder.build(); context.log.info('Copied', result.length, 'files to', $p(builder.directory)); return result; } }); /* ========================================================================== * * INTERNALS * * ========================================================================== */ function parseMode(mode) { if (mode === undefined) return undefined; if (typeof mode === 'number') return mode; const parsed = parseInt(mode, 8); assert(!isNaN(parsed), `Invalid mode "${mode}"`); return parsed; } function stringifyMode(mode) { return mode.toString(8).padStart(4, '0'); } //# sourceMappingURL=copy.js.map