1 | var path = require('path');
|
2 | var fs = require('fs');
|
3 | var common = require('./common');
|
4 | var glob = require('glob');
|
5 |
|
6 | var globPatternRecursive = path.sep + '**';
|
7 |
|
8 | common.register('ls', _ls, {
|
9 | cmdOptions: {
|
10 | 'R': 'recursive',
|
11 | 'A': 'all',
|
12 | 'L': 'link',
|
13 | 'a': 'all_deprecated',
|
14 | 'd': 'directory',
|
15 | 'l': 'long',
|
16 | },
|
17 | });
|
18 |
|
19 | //@
|
20 | //@ ### ls([options,] [path, ...])
|
21 | //@ ### ls([options,] path_array)
|
22 | //@
|
23 | //@ Available options:
|
24 | //@
|
25 | //@ + `-R`: recursive
|
26 | //@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`)
|
27 | //@ + `-L`: follow symlinks
|
28 | //@ + `-d`: list directories themselves, not their contents
|
29 | //@ + `-l`: list objects representing each file, each with fields containing `ls
|
30 | //@ -l` output fields. See
|
31 | //@ [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
|
32 | //@ for more info
|
33 | //@
|
34 | //@ Examples:
|
35 | //@
|
36 | //@ ```javascript
|
37 | //@ ls('projs/*.js');
|
38 | //@ ls('-R', '/users/me', '/tmp');
|
39 | //@ ls('-R', ['/users/me', '/tmp']); // same as above
|
40 | //@ ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...}
|
41 | //@ ```
|
42 | //@
|
43 | //@ Returns array of files in the given `path`, or files in
|
44 | //@ the current directory if no `path` is provided.
|
45 | function _ls(options, paths) {
|
46 | if (options.all_deprecated) {
|
47 | // We won't support the -a option as it's hard to image why it's useful
|
48 | // (it includes '.' and '..' in addition to '.*' files)
|
49 | // For backwards compatibility we'll dump a deprecated message and proceed as before
|
50 | common.log('ls: Option -a is deprecated. Use -A instead');
|
51 | options.all = true;
|
52 | }
|
53 |
|
54 | if (!paths) {
|
55 | paths = ['.'];
|
56 | } else {
|
57 | paths = [].slice.call(arguments, 1);
|
58 | }
|
59 |
|
60 | var list = [];
|
61 |
|
62 | function pushFile(abs, relName, stat) {
|
63 | if (process.platform === 'win32') {
|
64 | relName = relName.replace(/\\/g, '/');
|
65 | }
|
66 | if (options.long) {
|
67 | stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs));
|
68 | list.push(addLsAttributes(relName, stat));
|
69 | } else {
|
70 | // list.push(path.relative(rel || '.', file));
|
71 | list.push(relName);
|
72 | }
|
73 | }
|
74 |
|
75 | paths.forEach(function (p) {
|
76 | var stat;
|
77 |
|
78 | try {
|
79 | stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p);
|
80 | // follow links to directories by default
|
81 | if (stat.isSymbolicLink()) {
|
82 | /* istanbul ignore next */
|
83 | // workaround for https://github.com/shelljs/shelljs/issues/795
|
84 | // codecov seems to have a bug that miscalculate this block as uncovered.
|
85 | // but according to nyc report this block does get covered.
|
86 | try {
|
87 | var _stat = common.statFollowLinks(p);
|
88 | if (_stat.isDirectory()) {
|
89 | stat = _stat;
|
90 | }
|
91 | } catch (_) {} // bad symlink, treat it like a file
|
92 | }
|
93 | } catch (e) {
|
94 | common.error('no such file or directory: ' + p, 2, { continue: true });
|
95 | return;
|
96 | }
|
97 |
|
98 | // If the stat succeeded
|
99 | if (stat.isDirectory() && !options.directory) {
|
100 | if (options.recursive) {
|
101 | // use glob, because it's simple
|
102 | glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link })
|
103 | .forEach(function (item) {
|
104 | // Glob pattern returns the directory itself and needs to be filtered out.
|
105 | if (path.relative(p, item)) {
|
106 | pushFile(item, path.relative(p, item));
|
107 | }
|
108 | });
|
109 | } else if (options.all) {
|
110 | // use fs.readdirSync, because it's fast
|
111 | fs.readdirSync(p).forEach(function (item) {
|
112 | pushFile(path.join(p, item), item);
|
113 | });
|
114 | } else {
|
115 | // use fs.readdirSync and then filter out secret files
|
116 | fs.readdirSync(p).forEach(function (item) {
|
117 | if (item[0] !== '.') {
|
118 | pushFile(path.join(p, item), item);
|
119 | }
|
120 | });
|
121 | }
|
122 | } else {
|
123 | pushFile(p, p, stat);
|
124 | }
|
125 | });
|
126 |
|
127 | // Add methods, to make this more compatible with ShellStrings
|
128 | return list;
|
129 | }
|
130 |
|
131 | function addLsAttributes(pathName, stats) {
|
132 | // Note: this object will contain more information than .toString() returns
|
133 | stats.name = pathName;
|
134 | stats.toString = function () {
|
135 | // Return a string resembling unix's `ls -l` format
|
136 | return [this.mode, this.nlink, this.uid, this.gid, this.size, this.mtime, this.name].join(' ');
|
137 | };
|
138 | return stats;
|
139 | }
|
140 |
|
141 | module.exports = _ls;
|