From aa4772c4cf2bc2451e4617cfca7658ea44156e90 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Tue, 6 Oct 2020 00:31:59 +0900 Subject: [PATCH] feat: Print folder sizes with cypress cache list command. (#8590) --- cli/__snapshots__/cache_spec.js | 10 ++++++++ cli/__snapshots__/cli_spec.js | 6 +++++ cli/lib/cli.js | 8 ++++++ cli/lib/tasks/cache.js | 43 ++++++++++++++++++++++++++++---- cli/lib/tasks/get-folder-size.js | 36 ++++++++++++++++++++++++++ cli/test/html/show-size.html | 27 ++++++++++++++++++++ cli/test/lib/tasks/cache_spec.js | 23 ++++++++++++++++- 7 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 cli/lib/tasks/get-folder-size.js create mode 100644 cli/test/html/show-size.html diff --git a/cli/__snapshots__/cache_spec.js b/cli/__snapshots__/cache_spec.js index f900b9e5d5..91ca939277 100644 --- a/cli/__snapshots__/cache_spec.js +++ b/cli/__snapshots__/cache_spec.js @@ -55,3 +55,13 @@ exports['cache list with warn log level'] = ` │ 2.3.4 │ unknown │ └─────────┴───────────┘ ` + +exports['lib/tasks/cache .list shows sizes 1'] = ` +┌─────────┬──────────────┬───────┐ +│ version │ last used │ size │ +├─────────┼──────────────┼───────┤ +│ 1.2.3 │ 3 months ago │ 0.2MB │ +├─────────┼──────────────┼───────┤ +│ 2.3.4 │ unknown │ 0.2MB │ +└─────────┴──────────────┴───────┘ +` diff --git a/cli/__snapshots__/cli_spec.js b/cli/__snapshots__/cli_spec.js index 1a928151f9..2b0309700d 100644 --- a/cli/__snapshots__/cli_spec.js +++ b/cli/__snapshots__/cli_spec.js @@ -112,6 +112,8 @@ exports['cli unknown option shows help for cache command - unknown option --foo list list cached binary versions path print the path to the binary cache clear delete all cached binaries + --size Used with the list command to show the sizes of the cached + folders -h, --help output usage information ------- stderr: @@ -142,6 +144,8 @@ exports['cli unknown option shows help for cache command - unknown sub-command f list list cached binary versions path print the path to the binary cache clear delete all cached binaries + --size Used with the list command to show the sizes of the cached + folders -h, --help output usage information ------- stderr: @@ -170,6 +174,8 @@ exports['cli unknown option shows help for cache command - no sub-command 1'] = list list cached binary versions path print the path to the binary cache clear delete all cached binaries + --size Used with the list command to show the sizes of the cached + folders -h, --help output usage information ------- stderr: diff --git a/cli/lib/cli.js b/cli/lib/cli.js index 2d675dd78a..42bfc050be 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -102,6 +102,7 @@ const descriptions = { cacheClear: 'delete all cached binaries', cacheList: 'list cached binary versions', cachePath: 'print the path to the binary cache', + cacheSize: 'Used with the list command to show the sizes of the cached folders', ciBuildId: 'the unique identifier for a run on your CI provider. typically a "BUILD_ID" env var. this value is automatically detected for most CI providers', config: 'sets configuration values. separate multiple values with a comma. overrides any value in cypress.json.', configFile: 'path to JSON file where configuration values are set. defaults to "cypress.json". pass "false" to disable.', @@ -386,6 +387,7 @@ module.exports = { .option('list', text('cacheList')) .option('path', text('cachePath')) .option('clear', text('cacheClear')) + .option('--size', text('cacheSize')) .action(function (opts, args) { if (!args || !args.length) { this.outputHelp() @@ -398,6 +400,12 @@ module.exports = { unknownOption.call(this, `cache ${command}`, 'command') } + if (command === 'list') { + cache.list(opts.size) + + return + } + cache[command]() }) diff --git a/cli/lib/tasks/cache.js b/cli/lib/tasks/cache.js index 54c7fac971..928a566449 100644 --- a/cli/lib/tasks/cache.js +++ b/cli/lib/tasks/cache.js @@ -7,12 +7,14 @@ const Table = require('cli-table3') const moment = require('moment') const chalk = require('chalk') const _ = require('lodash') +const getFolderSize = require('./get-folder-size') // output colors for the table const colors = { titles: chalk.white, dates: chalk.cyan, values: chalk.green, + size: chalk.gray, } const logCachePath = () => { @@ -25,29 +27,46 @@ const clear = () => { return fs.removeAsync(state.getCacheDir()) } +const fileSizeInMB = (size) => { + return `${(size / 1024 / 1024).toFixed(1)}MB` +} + /** * Collects all cached versions, finds when each was used * and prints a table with results to the terminal */ -const list = () => { - return getCachedVersions() +const list = (showSize) => { + return getCachedVersions(showSize) .then((binaries) => { + const head = [colors.titles('version'), colors.titles('last used')] + + if (showSize) { + head.push(colors.titles('size')) + } + const table = new Table({ - head: [colors.titles('version'), colors.titles('last used')], + head, }) binaries.forEach((binary) => { const versionString = colors.values(binary.version) const lastUsed = binary.accessed ? colors.dates(binary.accessed) : 'unknown' + const row = [versionString, lastUsed] - return table.push([versionString, lastUsed]) + if (showSize) { + const size = colors.size(fileSizeInMB(binary.size)) + + row.push(size) + } + + return table.push(row) }) logger.always(table.toString()) }) } -const getCachedVersions = () => { +const getCachedVersions = (showSize) => { const cacheDir = state.getCacheDir() return fs @@ -84,6 +103,20 @@ const getCachedVersions = () => { return binary }) }) + .mapSeries((binary) => { + if (showSize) { + const binaryDir = state.getBinaryDir(binary.version) + + return getFolderSize(binaryDir).then((size) => { + return { + ...binary, + size, + } + }) + } + + return binary + }) } module.exports = { diff --git a/cli/lib/tasks/get-folder-size.js b/cli/lib/tasks/get-folder-size.js new file mode 100644 index 0000000000..0d5c12e04b --- /dev/null +++ b/cli/lib/tasks/get-folder-size.js @@ -0,0 +1,36 @@ +const fs = require('../fs') +const { join } = require('path') +const Bluebird = require('bluebird') + +/** + * Get the size of a folder or a file. + * + * This function returns the actual file size of the folder (size), not the allocated space on disk (size on disk). + * For more details between the difference, check this link: + * https://www.howtogeek.com/180369/why-is-there-a-big-difference-between-size-and-size-on-disk/ + * + * @param {string} path path to the file or the folder. + */ +async function getSize (path) { + const stat = await fs.lstat(path) + + if (stat.isDirectory()) { + const list = await fs.readdir(path) + + return Bluebird.resolve(list).reduce(async (prev, curr) => { + const currPath = join(path, curr) + + const s = await fs.lstat(currPath) + + if (s.isDirectory()) { + return prev + await getSize(currPath) + } + + return prev + s.size + }, 0) + } + + return stat.size +} + +module.exports = getSize diff --git a/cli/test/html/show-size.html b/cli/test/html/show-size.html new file mode 100644 index 0000000000..e6f29a92a3 --- /dev/null +++ b/cli/test/html/show-size.html @@ -0,0 +1,27 @@ + + + + + + +
┌─────────┬──────────────┬───────┐
+│ versionlast usedsize  │
+├─────────┼──────────────┼───────┤
+│ 1.2.33 months ago0.2MB │
+├─────────┼──────────────┼───────┤
+│ 2.3.4   │ unknown      │ 0.2MB │
+└─────────┴──────────────┴───────┘
+
\ No newline at end of file diff --git a/cli/test/lib/tasks/cache_spec.js b/cli/test/lib/tasks/cache_spec.js index 5cfa9f11a8..2efc44e9bb 100644 --- a/cli/test/lib/tasks/cache_spec.js +++ b/cli/test/lib/tasks/cache_spec.js @@ -20,7 +20,12 @@ describe('lib/tasks/cache', () => { mockfs({ '/.cache/Cypress': { '1.2.3': { - 'Cypress': {}, + 'Cypress': { + 'file1': Buffer.from(new Array(32 * 1024).fill(1)), + 'dir': { + 'file2': Buffer.from(new Array(128 * 1042).fill(2)), + }, + }, }, '2.3.4': { 'Cypress.app': {}, @@ -204,5 +209,21 @@ describe('lib/tasks/cache', () => { await cache.list() await snapshotWithHtml('second-binary-never-used.html') }) + + it('shows sizes', async function () { + sinon.stub(state, 'getPathToExecutable').returns('/.cache/Cypress/1.2.3/app/cypress') + + const statAsync = sinon.stub(fs, 'statAsync') + + statAsync.onFirstCall().resolves({ + atime: moment().subtract(3, 'month').valueOf(), + }) + + // the second binary has never been accessed + statAsync.onSecondCall().resolves() + + await cache.list(true) + await snapshotWithHtml('show-size.html') + }) }) })