aboutsummaryrefslogtreecommitdiff
path: root/node_modules/shelljs/src/cp.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/shelljs/src/cp.js')
-rw-r--r--node_modules/shelljs/src/cp.js278
1 files changed, 278 insertions, 0 deletions
diff --git a/node_modules/shelljs/src/cp.js b/node_modules/shelljs/src/cp.js
new file mode 100644
index 000000000..04c4e57ef
--- /dev/null
+++ b/node_modules/shelljs/src/cp.js
@@ -0,0 +1,278 @@
+var fs = require('fs');
+var path = require('path');
+var common = require('./common');
+var os = require('os');
+
+common.register('cp', _cp, {
+ cmdOptions: {
+ 'f': '!no_force',
+ 'n': 'no_force',
+ 'u': 'update',
+ 'R': 'recursive',
+ 'r': 'recursive',
+ 'L': 'followsymlink',
+ 'P': 'noFollowsymlink',
+ },
+ wrapOutput: false,
+});
+
+// Buffered file copy, synchronous
+// (Using readFileSync() + writeFileSync() could easily cause a memory overflow
+// with large files)
+function copyFileSync(srcFile, destFile, options) {
+ if (!fs.existsSync(srcFile)) {
+ common.error('copyFileSync: no such file or directory: ' + srcFile);
+ }
+
+ // Check the mtimes of the files if the '-u' flag is provided
+ try {
+ if (options.update && fs.statSync(srcFile).mtime < fs.statSync(destFile).mtime) {
+ return;
+ }
+ } catch (e) {
+ // If we're here, destFile probably doesn't exist, so just do a normal copy
+ }
+
+ if (fs.lstatSync(srcFile).isSymbolicLink() && !options.followsymlink) {
+ try {
+ fs.lstatSync(destFile);
+ common.unlinkSync(destFile); // re-link it
+ } catch (e) {
+ // it doesn't exist, so no work needs to be done
+ }
+
+ var symlinkFull = fs.readlinkSync(srcFile);
+ fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+ } else {
+ var BUF_LENGTH = 64 * 1024;
+ var buf = new Buffer(BUF_LENGTH);
+ var bytesRead = BUF_LENGTH;
+ var pos = 0;
+ var fdr = null;
+ var fdw = null;
+
+ try {
+ fdr = fs.openSync(srcFile, 'r');
+ } catch (e) {
+ /* istanbul ignore next */
+ common.error('copyFileSync: could not read src file (' + srcFile + ')');
+ }
+
+ try {
+ fdw = fs.openSync(destFile, 'w');
+ } catch (e) {
+ /* istanbul ignore next */
+ common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile);
+ }
+
+ while (bytesRead === BUF_LENGTH) {
+ bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
+ fs.writeSync(fdw, buf, 0, bytesRead);
+ pos += bytesRead;
+ }
+
+ fs.closeSync(fdr);
+ fs.closeSync(fdw);
+
+ fs.chmodSync(destFile, fs.statSync(srcFile).mode);
+ }
+}
+
+// Recursively copies 'sourceDir' into 'destDir'
+// Adapted from https://github.com/ryanmcgrath/wrench-js
+//
+// Copyright (c) 2010 Ryan McGrath
+// Copyright (c) 2012 Artur Adib
+//
+// Licensed under the MIT License
+// http://www.opensource.org/licenses/mit-license.php
+function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) {
+ if (!opts) opts = {};
+
+ // Ensure there is not a run away recursive copy
+ if (currentDepth >= common.config.maxdepth) return;
+ currentDepth++;
+
+ // Create the directory where all our junk is moving to; read the mode of the
+ // source directory and mirror it
+ try {
+ var checkDir = fs.statSync(sourceDir);
+ fs.mkdirSync(destDir, checkDir.mode);
+ } catch (e) {
+ // if the directory already exists, that's okay
+ if (e.code !== 'EEXIST') throw e;
+ }
+
+ var files = fs.readdirSync(sourceDir);
+
+ for (var i = 0; i < files.length; i++) {
+ var srcFile = sourceDir + '/' + files[i];
+ var destFile = destDir + '/' + files[i];
+ var srcFileStat = fs.lstatSync(srcFile);
+
+ var symlinkFull;
+ if (opts.followsymlink) {
+ if (cpcheckcycle(sourceDir, srcFile)) {
+ // Cycle link found.
+ console.error('Cycle link found.');
+ symlinkFull = fs.readlinkSync(srcFile);
+ fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+ continue;
+ }
+ }
+ if (srcFileStat.isDirectory()) {
+ /* recursion this thing right on back. */
+ cpdirSyncRecursive(srcFile, destFile, currentDepth, opts);
+ } else if (srcFileStat.isSymbolicLink() && !opts.followsymlink) {
+ symlinkFull = fs.readlinkSync(srcFile);
+ try {
+ fs.lstatSync(destFile);
+ common.unlinkSync(destFile); // re-link it
+ } catch (e) {
+ // it doesn't exist, so no work needs to be done
+ }
+ fs.symlinkSync(symlinkFull, destFile, os.platform() === 'win32' ? 'junction' : null);
+ } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) {
+ srcFileStat = fs.statSync(srcFile);
+ if (srcFileStat.isDirectory()) {
+ cpdirSyncRecursive(srcFile, destFile, currentDepth, opts);
+ } else {
+ copyFileSync(srcFile, destFile, opts);
+ }
+ } else {
+ /* At this point, we've hit a file actually worth copying... so copy it on over. */
+ if (fs.existsSync(destFile) && opts.no_force) {
+ common.log('skipping existing file: ' + files[i]);
+ } else {
+ copyFileSync(srcFile, destFile, opts);
+ }
+ }
+ } // for files
+} // cpdirSyncRecursive
+
+function cpcheckcycle(sourceDir, srcFile) {
+ var srcFileStat = fs.lstatSync(srcFile);
+ if (srcFileStat.isSymbolicLink()) {
+ // Do cycle check. For example:
+ // $ mkdir -p 1/2/3/4
+ // $ cd 1/2/3/4
+ // $ ln -s ../../3 link
+ // $ cd ../../../..
+ // $ cp -RL 1 copy
+ var cyclecheck = fs.statSync(srcFile);
+ if (cyclecheck.isDirectory()) {
+ var sourcerealpath = fs.realpathSync(sourceDir);
+ var symlinkrealpath = fs.realpathSync(srcFile);
+ var re = new RegExp(symlinkrealpath);
+ if (re.test(sourcerealpath)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//@
+//@ ### cp([options,] source [, source ...], dest)
+//@ ### cp([options,] source_array, dest)
+//@ Available options:
+//@
+//@ + `-f`: force (default behavior)
+//@ + `-n`: no-clobber
+//@ + `-u`: only copy if source is newer than dest
+//@ + `-r`, `-R`: recursive
+//@ + `-L`: follow symlinks
+//@ + `-P`: don't follow symlinks
+//@
+//@ Examples:
+//@
+//@ ```javascript
+//@ cp('file1', 'dir1');
+//@ cp('-R', 'path/to/dir/', '~/newCopy/');
+//@ cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp');
+//@ cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above
+//@ ```
+//@
+//@ Copies files.
+function _cp(options, sources, dest) {
+ // If we're missing -R, it actually implies -L (unless -P is explicit)
+ if (options.followsymlink) {
+ options.noFollowsymlink = false;
+ }
+ if (!options.recursive && !options.noFollowsymlink) {
+ options.followsymlink = true;
+ }
+
+ // Get sources, dest
+ if (arguments.length < 3) {
+ common.error('missing <source> and/or <dest>');
+ } else {
+ sources = [].slice.call(arguments, 1, arguments.length - 1);
+ dest = arguments[arguments.length - 1];
+ }
+
+ var destExists = fs.existsSync(dest);
+ var destStat = destExists && fs.statSync(dest);
+
+ // Dest is not existing dir, but multiple sources given
+ if ((!destExists || !destStat.isDirectory()) && sources.length > 1) {
+ common.error('dest is not a directory (too many sources)');
+ }
+
+ // Dest is an existing file, but -n is given
+ if (destExists && destStat.isFile() && options.no_force) {
+ return new common.ShellString('', '', 0);
+ }
+
+ sources.forEach(function (src) {
+ if (!fs.existsSync(src)) {
+ common.error('no such file or directory: ' + src, { continue: true });
+ return; // skip file
+ }
+ var srcStat = fs.statSync(src);
+ if (!options.noFollowsymlink && srcStat.isDirectory()) {
+ if (!options.recursive) {
+ // Non-Recursive
+ common.error("omitting directory '" + src + "'", { continue: true });
+ } else {
+ // Recursive
+ // 'cp /a/source dest' should create 'source' in 'dest'
+ var newDest = (destStat && destStat.isDirectory()) ?
+ path.join(dest, path.basename(src)) :
+ dest;
+
+ try {
+ fs.statSync(path.dirname(dest));
+ cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink });
+ } catch (e) {
+ /* istanbul ignore next */
+ common.error("cannot create directory '" + dest + "': No such file or directory");
+ }
+ }
+ } else {
+ // If here, src is a file
+
+ // When copying to '/path/dir':
+ // thisDest = '/path/dir/file1'
+ var thisDest = dest;
+ if (destStat && destStat.isDirectory()) {
+ thisDest = path.normalize(dest + '/' + path.basename(src));
+ }
+
+ if (fs.existsSync(thisDest) && options.no_force) {
+ return; // skip file
+ }
+
+ if (path.relative(src, thisDest) === '') {
+ // a file cannot be copied to itself, but we want to continue copying other files
+ common.error("'" + thisDest + "' and '" + src + "' are the same file", { continue: true });
+ return;
+ }
+
+ copyFileSync(src, thisDest, options);
+ }
+ }); // forEach(src)
+
+ return new common.ShellString('', common.state.error, common.state.errorCode);
+}
+module.exports = _cp;