var fs = require('fs'); var path = require('path'); var common = require('./common'); var cp = require('./cp'); var rm = require('./rm'); common.register('mv', _mv, { cmdOptions: { 'f': '!no_force', 'n': 'no_force', }, }); //@ //@ ### mv([options ,] source [, source ...], dest') //@ ### mv([options ,] source_array, dest') //@ Available options: //@ //@ + `-f`: force (default behavior) //@ + `-n`: no-clobber //@ //@ Examples: //@ //@ ```javascript //@ mv('-n', 'file', 'dir/'); //@ mv('file1', 'file2', 'dir/'); //@ mv(['file1', 'file2'], 'dir/'); // same as above //@ ``` //@ //@ Moves files. function _mv(options, sources, dest) { // Get sources, dest if (arguments.length < 3) { common.error('missing and/or '); } else if (arguments.length > 3) { sources = [].slice.call(arguments, 1, arguments.length - 1); dest = arguments[arguments.length - 1]; } else if (typeof sources === 'string') { sources = [sources]; } else { // TODO(nate): figure out if we actually need this line common.error('invalid arguments'); } var exists = fs.existsSync(dest); var stats = exists && fs.statSync(dest); // Dest is not existing dir, but multiple sources given if ((!exists || !stats.isDirectory()) && sources.length > 1) { common.error('dest is not a directory (too many sources)'); } // Dest is an existing file, but no -f given if (exists && stats.isFile() && options.no_force) { common.error('dest file already exists: ' + dest); } sources.forEach(function (src) { if (!fs.existsSync(src)) { common.error('no such file or directory: ' + src, { continue: true }); return; // skip file } // If here, src exists // When copying to '/path/dir': // thisDest = '/path/dir/file1' var thisDest = dest; if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) { thisDest = path.normalize(dest + '/' + path.basename(src)); } if (fs.existsSync(thisDest) && options.no_force) { common.error('dest file already exists: ' + thisDest, { continue: true }); return; // skip file } if (path.resolve(src) === path.dirname(path.resolve(thisDest))) { common.error('cannot move to self: ' + src, { continue: true }); return; // skip file } try { fs.renameSync(src, thisDest); } catch (e) { /* istanbul ignore next */ if (e.code === 'EXDEV') { // If we're trying to `mv` to an external partition, we'll actually need // to perform a copy and then clean up the original file. If either the // copy or the rm fails with an exception, we should allow this // exception to pass up to the top level. cp('-r', src, thisDest); rm('-rf', src); } } }); // forEach(src) return ''; } // mv module.exports = _mv;