"use strict"; const state = require('./state'); const logger = require('../logger'); const fs = require('../fs'); const util = require('../util'); const { join } = require('path'); const Table = require('cli-table3'); const dayjs = require('dayjs'); const relativeTime = require('dayjs/plugin/relativeTime'); const chalk = require('chalk'); const _ = require('lodash'); const getFolderSize = require('./get-folder-size'); const Bluebird = require('bluebird'); dayjs.extend(relativeTime); // output colors for the table const colors = { titles: chalk.white, dates: chalk.cyan, values: chalk.green, size: chalk.gray }; const logCachePath = () => { logger.always(state.getCacheDir()); return undefined; }; const clear = () => { return fs.removeAsync(state.getCacheDir()); }; const prune = () => { const cacheDir = state.getCacheDir(); const checkedInBinaryVersion = util.pkgVersion(); let deletedBinary = false; return fs.readdirAsync(cacheDir).then(versions => { return Bluebird.all(versions.map(version => { if (version !== checkedInBinaryVersion) { deletedBinary = true; const versionDir = join(cacheDir, version); return fs.removeAsync(versionDir); } })); }).then(() => { if (deletedBinary) { logger.always(`Deleted all binary caches except for the ${checkedInBinaryVersion} binary cache.`); } else { logger.always(`No binary caches found to prune.`); } }).catch({ code: 'ENOENT' }, () => { logger.always(`No Cypress cache was found at ${cacheDir}. Nothing to prune.`); }); }; 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 = 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 }); binaries.forEach(binary => { const versionString = colors.values(binary.version); const lastUsed = binary.accessed ? colors.dates(binary.accessed) : 'unknown'; const row = [versionString, lastUsed]; if (showSize) { const size = colors.size(fileSizeInMB(binary.size)); row.push(size); } return table.push(row); }); logger.always(table.toString()); }); }; const getCachedVersions = showSize => { const cacheDir = state.getCacheDir(); return fs.readdirAsync(cacheDir).filter(util.isSemver).map(version => { return { version, folderPath: join(cacheDir, version) }; }).mapSeries(binary => { // last access time on the folder is different from last access time // on the Cypress binary const binaryDir = state.getBinaryDir(binary.version); const executable = state.getPathToExecutable(binaryDir); return fs.statAsync(executable).then(stat => { const lastAccessedTime = _.get(stat, 'atime'); if (!lastAccessedTime) { // the test runner has never been opened // or could be a test simulating missing timestamp return binary; } const accessed = dayjs(lastAccessedTime).fromNow(); binary.accessed = accessed; return binary; }, e => { // could not find the binary or gets its stats return binary; }); }).mapSeries(binary => { if (showSize) { const binaryDir = state.getBinaryDir(binary.version); return getFolderSize(binaryDir).then(size => { return { ...binary, size }; }); } return binary; }); }; module.exports = { path: logCachePath, clear, prune, list, getCachedVersions };