cypress 15.1.0 → 15.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cypress +3 -1
- package/dist/VerboseRenderer.js +61 -0
- package/dist/cli.js +544 -0
- package/dist/cypress.js +104 -0
- package/dist/errors.js +391 -0
- package/dist/exec/info.js +103 -0
- package/dist/exec/open.js +103 -0
- package/dist/exec/run.js +177 -0
- package/dist/exec/shared.js +55 -0
- package/dist/exec/spawn.js +301 -0
- package/dist/exec/versions.js +67 -0
- package/dist/exec/xvfb.js +118 -0
- package/dist/index.js +52 -0
- package/dist/index.mjs +9 -0
- package/dist/logger.js +55 -0
- package/dist/tasks/cache.js +144 -0
- package/dist/tasks/download.js +304 -0
- package/dist/tasks/get-folder-size.js +44 -0
- package/dist/tasks/install.js +326 -0
- package/dist/tasks/state.js +184 -0
- package/dist/tasks/unzip.js +192 -0
- package/dist/tasks/verify.js +303 -0
- package/dist/util.js +452 -0
- package/package.json +10 -13
- package/types/cypress-automation.d.ts +2 -1
- package/types/cypress.d.ts +1 -0
- package/index.js +0 -27
- package/index.mjs +0 -17
- package/lib/VerboseRenderer.js +0 -58
- package/lib/cli.js +0 -411
- package/lib/cypress.js +0 -98
- package/lib/errors.js +0 -392
- package/lib/exec/info.js +0 -92
- package/lib/exec/open.js +0 -90
- package/lib/exec/run.js +0 -176
- package/lib/exec/shared.js +0 -62
- package/lib/exec/spawn.js +0 -247
- package/lib/exec/versions.js +0 -53
- package/lib/exec/xvfb.js +0 -93
- package/lib/fs.js +0 -4
- package/lib/logger.js +0 -50
- package/lib/tasks/cache.js +0 -132
- package/lib/tasks/download.js +0 -324
- package/lib/tasks/get-folder-size.js +0 -33
- package/lib/tasks/install.js +0 -368
- package/lib/tasks/state.js +0 -185
- package/lib/tasks/unzip.js +0 -200
- package/lib/tasks/verify.js +0 -300
- package/lib/util.js +0 -448
package/lib/tasks/cache.js
DELETED
@@ -1,132 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
const state = require('./state');
|
4
|
-
const logger = require('../logger');
|
5
|
-
const fs = require('../fs');
|
6
|
-
const util = require('../util');
|
7
|
-
const {
|
8
|
-
join
|
9
|
-
} = require('path');
|
10
|
-
const Table = require('cli-table3');
|
11
|
-
const dayjs = require('dayjs');
|
12
|
-
const relativeTime = require('dayjs/plugin/relativeTime');
|
13
|
-
const chalk = require('chalk');
|
14
|
-
const _ = require('lodash');
|
15
|
-
const getFolderSize = require('./get-folder-size');
|
16
|
-
const Bluebird = require('bluebird');
|
17
|
-
dayjs.extend(relativeTime);
|
18
|
-
|
19
|
-
// output colors for the table
|
20
|
-
const colors = {
|
21
|
-
titles: chalk.white,
|
22
|
-
dates: chalk.cyan,
|
23
|
-
values: chalk.green,
|
24
|
-
size: chalk.gray
|
25
|
-
};
|
26
|
-
const logCachePath = () => {
|
27
|
-
logger.always(state.getCacheDir());
|
28
|
-
return undefined;
|
29
|
-
};
|
30
|
-
const clear = () => {
|
31
|
-
return fs.removeAsync(state.getCacheDir());
|
32
|
-
};
|
33
|
-
const prune = () => {
|
34
|
-
const cacheDir = state.getCacheDir();
|
35
|
-
const checkedInBinaryVersion = util.pkgVersion();
|
36
|
-
let deletedBinary = false;
|
37
|
-
return fs.readdirAsync(cacheDir).then(versions => {
|
38
|
-
return Bluebird.all(versions.map(version => {
|
39
|
-
if (version !== checkedInBinaryVersion) {
|
40
|
-
deletedBinary = true;
|
41
|
-
const versionDir = join(cacheDir, version);
|
42
|
-
return fs.removeAsync(versionDir);
|
43
|
-
}
|
44
|
-
}));
|
45
|
-
}).then(() => {
|
46
|
-
if (deletedBinary) {
|
47
|
-
logger.always(`Deleted all binary caches except for the ${checkedInBinaryVersion} binary cache.`);
|
48
|
-
} else {
|
49
|
-
logger.always(`No binary caches found to prune.`);
|
50
|
-
}
|
51
|
-
}).catch({
|
52
|
-
code: 'ENOENT'
|
53
|
-
}, () => {
|
54
|
-
logger.always(`No Cypress cache was found at ${cacheDir}. Nothing to prune.`);
|
55
|
-
});
|
56
|
-
};
|
57
|
-
const fileSizeInMB = size => {
|
58
|
-
return `${(size / 1024 / 1024).toFixed(1)}MB`;
|
59
|
-
};
|
60
|
-
|
61
|
-
/**
|
62
|
-
* Collects all cached versions, finds when each was used
|
63
|
-
* and prints a table with results to the terminal
|
64
|
-
*/
|
65
|
-
const list = showSize => {
|
66
|
-
return getCachedVersions(showSize).then(binaries => {
|
67
|
-
const head = [colors.titles('version'), colors.titles('last used')];
|
68
|
-
if (showSize) {
|
69
|
-
head.push(colors.titles('size'));
|
70
|
-
}
|
71
|
-
const table = new Table({
|
72
|
-
head
|
73
|
-
});
|
74
|
-
binaries.forEach(binary => {
|
75
|
-
const versionString = colors.values(binary.version);
|
76
|
-
const lastUsed = binary.accessed ? colors.dates(binary.accessed) : 'unknown';
|
77
|
-
const row = [versionString, lastUsed];
|
78
|
-
if (showSize) {
|
79
|
-
const size = colors.size(fileSizeInMB(binary.size));
|
80
|
-
row.push(size);
|
81
|
-
}
|
82
|
-
return table.push(row);
|
83
|
-
});
|
84
|
-
logger.always(table.toString());
|
85
|
-
});
|
86
|
-
};
|
87
|
-
const getCachedVersions = showSize => {
|
88
|
-
const cacheDir = state.getCacheDir();
|
89
|
-
return fs.readdirAsync(cacheDir).filter(util.isSemver).map(version => {
|
90
|
-
return {
|
91
|
-
version,
|
92
|
-
folderPath: join(cacheDir, version)
|
93
|
-
};
|
94
|
-
}).mapSeries(binary => {
|
95
|
-
// last access time on the folder is different from last access time
|
96
|
-
// on the Cypress binary
|
97
|
-
const binaryDir = state.getBinaryDir(binary.version);
|
98
|
-
const executable = state.getPathToExecutable(binaryDir);
|
99
|
-
return fs.statAsync(executable).then(stat => {
|
100
|
-
const lastAccessedTime = _.get(stat, 'atime');
|
101
|
-
if (!lastAccessedTime) {
|
102
|
-
// the test runner has never been opened
|
103
|
-
// or could be a test simulating missing timestamp
|
104
|
-
return binary;
|
105
|
-
}
|
106
|
-
const accessed = dayjs(lastAccessedTime).fromNow();
|
107
|
-
binary.accessed = accessed;
|
108
|
-
return binary;
|
109
|
-
}, e => {
|
110
|
-
// could not find the binary or gets its stats
|
111
|
-
return binary;
|
112
|
-
});
|
113
|
-
}).mapSeries(binary => {
|
114
|
-
if (showSize) {
|
115
|
-
const binaryDir = state.getBinaryDir(binary.version);
|
116
|
-
return getFolderSize(binaryDir).then(size => {
|
117
|
-
return {
|
118
|
-
...binary,
|
119
|
-
size
|
120
|
-
};
|
121
|
-
});
|
122
|
-
}
|
123
|
-
return binary;
|
124
|
-
});
|
125
|
-
};
|
126
|
-
module.exports = {
|
127
|
-
path: logCachePath,
|
128
|
-
clear,
|
129
|
-
prune,
|
130
|
-
list,
|
131
|
-
getCachedVersions
|
132
|
-
};
|
package/lib/tasks/download.js
DELETED
@@ -1,324 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
const la = require('lazy-ass');
|
4
|
-
const is = require('check-more-types');
|
5
|
-
const os = require('os');
|
6
|
-
const url = require('url');
|
7
|
-
const path = require('path');
|
8
|
-
const debug = require('debug')('cypress:cli');
|
9
|
-
const request = require('@cypress/request');
|
10
|
-
const Promise = require('bluebird');
|
11
|
-
const requestProgress = require('request-progress');
|
12
|
-
const {
|
13
|
-
stripIndent
|
14
|
-
} = require('common-tags');
|
15
|
-
const getProxyForUrl = require('proxy-from-env').getProxyForUrl;
|
16
|
-
const {
|
17
|
-
throwFormErrorText,
|
18
|
-
errors
|
19
|
-
} = require('../errors');
|
20
|
-
const fs = require('../fs');
|
21
|
-
const util = require('../util');
|
22
|
-
const defaultBaseUrl = 'https://download.cypress.io/';
|
23
|
-
const defaultMaxRedirects = 10;
|
24
|
-
const getProxyForUrlWithNpmConfig = url => {
|
25
|
-
return getProxyForUrl(url) || process.env.npm_config_https_proxy || process.env.npm_config_proxy || null;
|
26
|
-
};
|
27
|
-
const getBaseUrl = () => {
|
28
|
-
if (util.getEnv('CYPRESS_DOWNLOAD_MIRROR')) {
|
29
|
-
let baseUrl = util.getEnv('CYPRESS_DOWNLOAD_MIRROR');
|
30
|
-
if (!baseUrl.endsWith('/')) {
|
31
|
-
baseUrl += '/';
|
32
|
-
}
|
33
|
-
return baseUrl;
|
34
|
-
}
|
35
|
-
return defaultBaseUrl;
|
36
|
-
};
|
37
|
-
const getCA = () => {
|
38
|
-
return new Promise(resolve => {
|
39
|
-
if (process.env.npm_config_cafile) {
|
40
|
-
fs.readFile(process.env.npm_config_cafile, 'utf8').then(cafileContent => {
|
41
|
-
resolve(cafileContent);
|
42
|
-
}).catch(() => {
|
43
|
-
resolve();
|
44
|
-
});
|
45
|
-
} else if (process.env.npm_config_ca) {
|
46
|
-
resolve(process.env.npm_config_ca);
|
47
|
-
} else {
|
48
|
-
resolve();
|
49
|
-
}
|
50
|
-
});
|
51
|
-
};
|
52
|
-
const prepend = (arch, urlPath, version) => {
|
53
|
-
const endpoint = url.resolve(getBaseUrl(), urlPath);
|
54
|
-
const platform = os.platform();
|
55
|
-
const pathTemplate = util.getEnv('CYPRESS_DOWNLOAD_PATH_TEMPLATE', true);
|
56
|
-
if (platform === 'win32' && arch === 'arm64') {
|
57
|
-
debug(`detected platform ${platform} architecture ${arch} combination`);
|
58
|
-
arch = 'x64';
|
59
|
-
debug(`overriding to download ${platform}-${arch} instead`);
|
60
|
-
}
|
61
|
-
return pathTemplate ? pathTemplate.replace(/\\?\$\{endpoint\}/g, endpoint).replace(/\\?\$\{platform\}/g, platform).replace(/\\?\$\{arch\}/g, arch).replace(/\\?\$\{version\}/g, version) : `${endpoint}?platform=${platform}&arch=${arch}`;
|
62
|
-
};
|
63
|
-
const getUrl = (arch, version) => {
|
64
|
-
if (is.url(version)) {
|
65
|
-
debug('version is already an url', version);
|
66
|
-
return version;
|
67
|
-
}
|
68
|
-
const urlPath = version ? `desktop/${version}` : 'desktop';
|
69
|
-
return prepend(arch, urlPath, version);
|
70
|
-
};
|
71
|
-
const statusMessage = err => {
|
72
|
-
return err.statusCode ? [err.statusCode, err.statusMessage].join(' - ') : err.toString();
|
73
|
-
};
|
74
|
-
const prettyDownloadErr = (err, url) => {
|
75
|
-
const msg = stripIndent`
|
76
|
-
URL: ${url}
|
77
|
-
${statusMessage(err)}
|
78
|
-
`;
|
79
|
-
debug(msg);
|
80
|
-
return throwFormErrorText(errors.failedDownload)(msg);
|
81
|
-
};
|
82
|
-
|
83
|
-
/**
|
84
|
-
* Checks checksum and file size for the given file. Allows both
|
85
|
-
* values or just one of them to be checked.
|
86
|
-
*/
|
87
|
-
const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
88
|
-
if (expectedSize && expectedChecksum) {
|
89
|
-
debug('verifying checksum and file size');
|
90
|
-
return Promise.join(util.getFileChecksum(filename), util.getFileSize(filename), (checksum, filesize) => {
|
91
|
-
if (checksum === expectedChecksum && filesize === expectedSize) {
|
92
|
-
debug('downloaded file has the expected checksum and size ✅');
|
93
|
-
return;
|
94
|
-
}
|
95
|
-
debug('raising error: checksum or file size mismatch');
|
96
|
-
const text = stripIndent`
|
97
|
-
Corrupted download
|
98
|
-
|
99
|
-
Expected downloaded file to have checksum: ${expectedChecksum}
|
100
|
-
Computed checksum: ${checksum}
|
101
|
-
|
102
|
-
Expected downloaded file to have size: ${expectedSize}
|
103
|
-
Computed size: ${filesize}
|
104
|
-
`;
|
105
|
-
debug(text);
|
106
|
-
throw new Error(text);
|
107
|
-
});
|
108
|
-
}
|
109
|
-
if (expectedChecksum) {
|
110
|
-
debug('only checking expected file checksum %d', expectedChecksum);
|
111
|
-
return util.getFileChecksum(filename).then(checksum => {
|
112
|
-
if (checksum === expectedChecksum) {
|
113
|
-
debug('downloaded file has the expected checksum ✅');
|
114
|
-
return;
|
115
|
-
}
|
116
|
-
debug('raising error: file checksum mismatch');
|
117
|
-
const text = stripIndent`
|
118
|
-
Corrupted download
|
119
|
-
|
120
|
-
Expected downloaded file to have checksum: ${expectedChecksum}
|
121
|
-
Computed checksum: ${checksum}
|
122
|
-
`;
|
123
|
-
throw new Error(text);
|
124
|
-
});
|
125
|
-
}
|
126
|
-
if (expectedSize) {
|
127
|
-
// maybe we don't have a checksum, but at least CDN returns content length
|
128
|
-
// which we can check against the file size
|
129
|
-
debug('only checking expected file size %d', expectedSize);
|
130
|
-
return util.getFileSize(filename).then(filesize => {
|
131
|
-
if (filesize === expectedSize) {
|
132
|
-
debug('downloaded file has the expected size ✅');
|
133
|
-
return;
|
134
|
-
}
|
135
|
-
debug('raising error: file size mismatch');
|
136
|
-
const text = stripIndent`
|
137
|
-
Corrupted download
|
138
|
-
|
139
|
-
Expected downloaded file to have size: ${expectedSize}
|
140
|
-
Computed size: ${filesize}
|
141
|
-
`;
|
142
|
-
throw new Error(text);
|
143
|
-
});
|
144
|
-
}
|
145
|
-
debug('downloaded file lacks checksum or size to verify');
|
146
|
-
return Promise.resolve();
|
147
|
-
};
|
148
|
-
|
149
|
-
// downloads from given url
|
150
|
-
// return an object with
|
151
|
-
// {filename: ..., downloaded: true}
|
152
|
-
const downloadFromUrl = ({
|
153
|
-
url,
|
154
|
-
downloadDestination,
|
155
|
-
progress,
|
156
|
-
ca,
|
157
|
-
version,
|
158
|
-
redirectTTL = defaultMaxRedirects
|
159
|
-
}) => {
|
160
|
-
if (redirectTTL <= 0) {
|
161
|
-
return Promise.reject(new Error(stripIndent`
|
162
|
-
Failed downloading the Cypress binary.
|
163
|
-
There were too many redirects. The default allowance is ${defaultMaxRedirects}.
|
164
|
-
Maybe you got stuck in a redirect loop?
|
165
|
-
`));
|
166
|
-
}
|
167
|
-
return new Promise((resolve, reject) => {
|
168
|
-
const proxy = getProxyForUrlWithNpmConfig(url);
|
169
|
-
debug('Downloading package', {
|
170
|
-
url,
|
171
|
-
proxy,
|
172
|
-
downloadDestination
|
173
|
-
});
|
174
|
-
if (ca) {
|
175
|
-
debug('using custom CA details from npm config');
|
176
|
-
}
|
177
|
-
const reqOptions = {
|
178
|
-
uri: url,
|
179
|
-
...(proxy ? {
|
180
|
-
proxy
|
181
|
-
} : {}),
|
182
|
-
...(ca ? {
|
183
|
-
agentOptions: {
|
184
|
-
ca
|
185
|
-
}
|
186
|
-
} : {}),
|
187
|
-
method: 'GET',
|
188
|
-
followRedirect: false
|
189
|
-
};
|
190
|
-
const req = request(reqOptions);
|
191
|
-
|
192
|
-
// closure
|
193
|
-
let started = null;
|
194
|
-
let expectedSize;
|
195
|
-
let expectedChecksum;
|
196
|
-
requestProgress(req, {
|
197
|
-
throttle: progress.throttle
|
198
|
-
}).on('response', response => {
|
199
|
-
// we have computed checksum and filesize during test runner binary build
|
200
|
-
// and have set it on the S3 object as user meta data, available via
|
201
|
-
// these custom headers "x-amz-meta-..."
|
202
|
-
// see https://github.com/cypress-io/cypress/pull/4092
|
203
|
-
expectedSize = response.headers['x-amz-meta-size'] || response.headers['content-length'];
|
204
|
-
expectedChecksum = response.headers['x-amz-meta-checksum'];
|
205
|
-
if (expectedChecksum) {
|
206
|
-
debug('expected checksum %s', expectedChecksum);
|
207
|
-
}
|
208
|
-
if (expectedSize) {
|
209
|
-
// convert from string (all Amazon custom headers are strings)
|
210
|
-
expectedSize = Number(expectedSize);
|
211
|
-
debug('expected file size %d', expectedSize);
|
212
|
-
}
|
213
|
-
|
214
|
-
// start counting now once we've gotten
|
215
|
-
// response headers
|
216
|
-
started = new Date();
|
217
|
-
if (/^3/.test(response.statusCode)) {
|
218
|
-
const redirectVersion = response.headers['x-version'];
|
219
|
-
const redirectUrl = response.headers.location;
|
220
|
-
debug('redirect version:', redirectVersion);
|
221
|
-
debug('redirect url:', redirectUrl);
|
222
|
-
downloadFromUrl({
|
223
|
-
url: redirectUrl,
|
224
|
-
progress,
|
225
|
-
ca,
|
226
|
-
downloadDestination,
|
227
|
-
version: redirectVersion,
|
228
|
-
redirectTTL: redirectTTL - 1
|
229
|
-
}).then(resolve).catch(reject);
|
230
|
-
|
231
|
-
// if our status code does not start with 200
|
232
|
-
} else if (!/^2/.test(response.statusCode)) {
|
233
|
-
debug('response code %d', response.statusCode);
|
234
|
-
const err = new Error(stripIndent`
|
235
|
-
Failed downloading the Cypress binary.
|
236
|
-
Response code: ${response.statusCode}
|
237
|
-
Response message: ${response.statusMessage}
|
238
|
-
`);
|
239
|
-
reject(err);
|
240
|
-
// status codes here are all 2xx
|
241
|
-
} else {
|
242
|
-
// We only enable this pipe connection when we know we've got a successful return
|
243
|
-
// and handle the completion with verify and resolve
|
244
|
-
// there was a possible race condition between end of request and close of writeStream
|
245
|
-
// that is made ordered with this Promise.all
|
246
|
-
Promise.all([new Promise(r => {
|
247
|
-
return response.pipe(fs.createWriteStream(downloadDestination).on('close', r));
|
248
|
-
}), new Promise(r => response.on('end', r))]).then(() => {
|
249
|
-
debug('downloading finished');
|
250
|
-
verifyDownloadedFile(downloadDestination, expectedSize, expectedChecksum).then(() => debug('verified')).then(() => resolve(version)).catch(reject);
|
251
|
-
});
|
252
|
-
}
|
253
|
-
}).on('error', e => {
|
254
|
-
if (e.code === 'ECONNRESET') return; // sometimes proxies give ECONNRESET but we don't care
|
255
|
-
|
256
|
-
reject(e);
|
257
|
-
}).on('progress', state => {
|
258
|
-
// total time we've elapsed
|
259
|
-
// starting on our first progress notification
|
260
|
-
const elapsed = new Date() - started;
|
261
|
-
|
262
|
-
// request-progress sends a value between 0 and 1
|
263
|
-
const percentage = util.convertPercentToPercentage(state.percent);
|
264
|
-
const eta = util.calculateEta(percentage, elapsed);
|
265
|
-
|
266
|
-
// send up our percent and seconds remaining
|
267
|
-
progress.onProgress(percentage, util.secsRemaining(eta));
|
268
|
-
});
|
269
|
-
});
|
270
|
-
};
|
271
|
-
|
272
|
-
/**
|
273
|
-
* Download Cypress.zip from external versionUrl to local file.
|
274
|
-
* @param [string] version Could be "3.3.0" or full URL
|
275
|
-
* @param [string] downloadDestination Local filename to save as
|
276
|
-
*/
|
277
|
-
const start = async opts => {
|
278
|
-
let {
|
279
|
-
version,
|
280
|
-
downloadDestination,
|
281
|
-
progress,
|
282
|
-
redirectTTL
|
283
|
-
} = opts;
|
284
|
-
if (!downloadDestination) {
|
285
|
-
la(is.unemptyString(downloadDestination), 'missing download dir', opts);
|
286
|
-
}
|
287
|
-
if (!progress) {
|
288
|
-
progress = {
|
289
|
-
onProgress: () => {
|
290
|
-
return {};
|
291
|
-
}
|
292
|
-
};
|
293
|
-
}
|
294
|
-
const arch = await util.getRealArch();
|
295
|
-
const versionUrl = getUrl(arch, version);
|
296
|
-
progress.throttle = 100;
|
297
|
-
debug('needed Cypress version: %s', version);
|
298
|
-
debug('source url %s', versionUrl);
|
299
|
-
debug(`downloading cypress.zip to "${downloadDestination}"`);
|
300
|
-
|
301
|
-
// ensure download dir exists
|
302
|
-
return fs.ensureDirAsync(path.dirname(downloadDestination)).then(() => {
|
303
|
-
return getCA();
|
304
|
-
}).then(ca => {
|
305
|
-
return downloadFromUrl({
|
306
|
-
url: versionUrl,
|
307
|
-
downloadDestination,
|
308
|
-
progress,
|
309
|
-
ca,
|
310
|
-
version,
|
311
|
-
...(redirectTTL ? {
|
312
|
-
redirectTTL
|
313
|
-
} : {})
|
314
|
-
});
|
315
|
-
}).catch(err => {
|
316
|
-
return prettyDownloadErr(err, versionUrl);
|
317
|
-
});
|
318
|
-
};
|
319
|
-
module.exports = {
|
320
|
-
start,
|
321
|
-
getUrl,
|
322
|
-
getProxyForUrlWithNpmConfig,
|
323
|
-
getCA
|
324
|
-
};
|
@@ -1,33 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
const fs = require('../fs');
|
4
|
-
const {
|
5
|
-
join
|
6
|
-
} = require('path');
|
7
|
-
const Bluebird = require('bluebird');
|
8
|
-
|
9
|
-
/**
|
10
|
-
* Get the size of a folder or a file.
|
11
|
-
*
|
12
|
-
* This function returns the actual file size of the folder (size), not the allocated space on disk (size on disk).
|
13
|
-
* For more details between the difference, check this link:
|
14
|
-
* https://www.howtogeek.com/180369/why-is-there-a-big-difference-between-size-and-size-on-disk/
|
15
|
-
*
|
16
|
-
* @param {string} path path to the file or the folder.
|
17
|
-
*/
|
18
|
-
async function getSize(path) {
|
19
|
-
const stat = await fs.lstat(path);
|
20
|
-
if (stat.isDirectory()) {
|
21
|
-
const list = await fs.readdir(path);
|
22
|
-
return Bluebird.resolve(list).reduce(async (prev, curr) => {
|
23
|
-
const currPath = join(path, curr);
|
24
|
-
const s = await fs.lstat(currPath);
|
25
|
-
if (s.isDirectory()) {
|
26
|
-
return prev + (await getSize(currPath));
|
27
|
-
}
|
28
|
-
return prev + s.size;
|
29
|
-
}, 0);
|
30
|
-
}
|
31
|
-
return stat.size;
|
32
|
-
}
|
33
|
-
module.exports = getSize;
|