Blame view

node_modules/shelljs/src/mv.js 3.45 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  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 files.
  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 && 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, 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) && fs.statSync(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;