119 lines
3.5 KiB
Plaintext
119 lines
3.5 KiB
Plaintext
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',
|
|
},
|
|
});
|
|
|
|
// Checks if cureent file was created recently
|
|
function checkRecentCreated(sources, index) {
|
|
var lookedSource = sources[index];
|
|
return sources.slice(0, index).some(function (src) {
|
|
return path.basename(src) === path.basename(lookedSource);
|
|
});
|
|
}
|
|
|
|
//@
|
|
//@ ### 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 `source` file(s) to `dest`.
|
|
function _mv(options, sources, dest) {
|
|
// Get sources, dest
|
|
if (arguments.length < 3) {
|
|
common.error('missing <source> and/or <dest>');
|
|
} 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 && common.statFollowLinks(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, srcIndex) {
|
|
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) && common.statFollowLinks(dest).isDirectory()) {
|
|
thisDest = path.normalize(dest + '/' + path.basename(src));
|
|
}
|
|
|
|
var thisDestExists = fs.existsSync(thisDest);
|
|
|
|
if (thisDestExists && checkRecentCreated(sources, srcIndex)) {
|
|
// cannot overwrite file created recently in current execution, but we want to continue copying other files
|
|
if (!options.no_force) {
|
|
common.error("will not overwrite just-created '" + thisDest + "' with '" + src + "'", { continue: true });
|
|
}
|
|
return;
|
|
}
|
|
|
|
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;
|