Blame view

node_modules/shelljs/src/ls.js 4.24 KB
ce4c83ff   wxy   初始提交
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  var path = require('path');
  var fs = require('fs');
  var common = require('./common');
  var glob = require('glob');
  
  var globPatternRecursive = path.sep + '**';
  
  common.register('ls', _ls, {
    cmdOptions: {
      'R': 'recursive',
      'A': 'all',
      'L': 'link',
      'a': 'all_deprecated',
      'd': 'directory',
      'l': 'long',
    },
  });
  
  //@
  //@ ### ls([options,] [path, ...])
  //@ ### ls([options,] path_array)
  //@
  //@ Available options:
  //@
  //@ + `-R`: recursive
  //@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`)
  //@ + `-L`: follow symlinks
  //@ + `-d`: list directories themselves, not their contents
  //@ + `-l`: list objects representing each file, each with fields containing `ls
  //@         -l` output fields. See
  //@         [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
  //@         for more info
  //@
  //@ Examples:
  //@
  //@ ```javascript
  //@ ls('projs/*.js');
  //@ ls('-R', '/users/me', '/tmp');
  //@ ls('-R', ['/users/me', '/tmp']); // same as above
  //@ ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...}
  //@ ```
  //@
  //@ Returns array of files in the given `path`, or files in
  //@ the current directory if no `path` is  provided.
  function _ls(options, paths) {
    if (options.all_deprecated) {
      // We won't support the -a option as it's hard to image why it's useful
      // (it includes '.' and '..' in addition to '.*' files)
      // For backwards compatibility we'll dump a deprecated message and proceed as before
      common.log('ls: Option -a is deprecated. Use -A instead');
      options.all = true;
    }
  
    if (!paths) {
      paths = ['.'];
    } else {
      paths = [].slice.call(arguments, 1);
    }
  
    var list = [];
  
    function pushFile(abs, relName, stat) {
      if (process.platform === 'win32') {
        relName = relName.replace(/\\/g, '/');
      }
      if (options.long) {
        stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs));
        list.push(addLsAttributes(relName, stat));
      } else {
        // list.push(path.relative(rel || '.', file));
        list.push(relName);
      }
    }
  
    paths.forEach(function (p) {
      var stat;
  
      try {
        stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p);
        // follow links to directories by default
        if (stat.isSymbolicLink()) {
          /* istanbul ignore next */
          // workaround for https://github.com/shelljs/shelljs/issues/795
          // codecov seems to have a bug that miscalculate this block as uncovered.
          // but according to nyc report this block does get covered.
          try {
            var _stat = common.statFollowLinks(p);
            if (_stat.isDirectory()) {
              stat = _stat;
            }
          } catch (_) {} // bad symlink, treat it like a file
        }
      } catch (e) {
        common.error('no such file or directory: ' + p, 2, { continue: true });
        return;
      }
  
      // If the stat succeeded
      if (stat.isDirectory() && !options.directory) {
        if (options.recursive) {
          // use glob, because it's simple
          glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link })
            .forEach(function (item) {
              // Glob pattern returns the directory itself and needs to be filtered out.
              if (path.relative(p, item)) {
                pushFile(item, path.relative(p, item));
              }
            });
        } else if (options.all) {
          // use fs.readdirSync, because it's fast
          fs.readdirSync(p).forEach(function (item) {
            pushFile(path.join(p, item), item);
          });
        } else {
          // use fs.readdirSync and then filter out secret files
          fs.readdirSync(p).forEach(function (item) {
            if (item[0] !== '.') {
              pushFile(path.join(p, item), item);
            }
          });
        }
      } else {
        pushFile(p, p, stat);
      }
    });
  
    // Add methods, to make this more compatible with ShellStrings
    return list;
  }
  
  function addLsAttributes(pathName, stats) {
    // Note: this object will contain more information than .toString() returns
    stats.name = pathName;
    stats.toString = function () {
      // Return a string resembling unix's `ls -l` format
      return [this.mode, this.nlink, this.uid, this.gid, this.size, this.mtime, this.name].join(' ');
    };
    return stats;
  }
  
  module.exports = _ls;