123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- const { readdir: _readdir, stat: _stat } = require('graceful-fs');
- const { basename, join } = require('path');
- const _rimraf = require('rimraf');
- const logMessages = require('./util/log-messages');
- const pluginCompat = require('./util/plugin-compat');
- const promisify = require('./util/promisify');
- const readdir = promisify(_readdir);
- const rimraf = promisify(_rimraf);
- const stat = promisify(_stat);
- const directorySize = async dir => {
- const _stat = await stat(dir);
- if (_stat.isFile()) {
- return _stat.size;
- }
- if (_stat.isDirectory()) {
- const names = await readdir(dir);
- let size = 0;
- for (const name of names) {
- size += await directorySize(join(dir, name));
- }
- return size;
- }
- return 0;
- };
- class CacheInfo {
- constructor(id = '') {
- this.id = id;
- this.lastModified = 0;
- this.size = 0;
- }
- static async fromDirectory(dir) {
- const info = new CacheInfo(basename(dir));
- info.lastModified = new Date(
- (await stat(join(dir, 'stamp'))).mtime,
- ).getTime();
- info.size = await directorySize(dir);
- return info;
- }
- static async fromDirectoryChildren(dir) {
- const children = [];
- const names = await readdir(dir);
- for (const name of names) {
- children.push(await CacheInfo.fromDirectory(join(dir, name)));
- }
- return children;
- }
- }
- // Compilers for webpack with multiple parallel configurations might try to
- // delete caches at the same time. Mutex lock the process of pruning to keep
- // from multiple pruning runs from colliding with each other.
- let deleteLock = null;
- class PruneCachesSystem {
- constructor(cacheRoot, options = {}) {
- this.cacheRoot = cacheRoot;
- this.options = Object.assign(
- {
- // Caches younger than `maxAge` are not considered for deletion. They
- // must be at least this (default: 2 days) old in milliseconds.
- maxAge: 2 * 24 * 60 * 60 * 1000,
- // All caches together must be larger than `sizeThreshold` before any
- // caches will be deleted. Together they must be at least this
- // (default: 50 MB) big in bytes.
- sizeThreshold: 50 * 1024 * 1024,
- },
- options,
- );
- }
- apply(compiler) {
- const compilerHooks = pluginCompat.hooks(compiler);
- const deleteOldCaches = async () => {
- while (deleteLock !== null) {
- await deleteLock;
- }
- let resolveLock;
- let infos;
- try {
- deleteLock = new Promise(resolve => {
- resolveLock = resolve;
- });
- infos = await CacheInfo.fromDirectoryChildren(this.cacheRoot);
- // Sort lastModified in descending order. More recently modified at the
- // beginning of the array.
- infos.sort((a, b) => b.lastModified - a.lastModified);
- const totalSize = infos.reduce((carry, info) => carry + info.size, 0);
- const oldInfos = infos.filter(
- info => info.lastModified < Date.now() - this.options.maxAge,
- );
- const oldTotalSize = oldInfos.reduce(
- (carry, info) => carry + info.size,
- 0,
- );
- if (oldInfos.length > 0 && totalSize > this.options.sizeThreshold) {
- const newInfos = infos.filter(
- info => info.lastModified >= Date.now() - this.options.maxAge,
- );
- for (const info of oldInfos) {
- rimraf(join(this.cacheRoot, info.id));
- }
- const newTotalSize = newInfos.reduce(
- (carry, info) => carry + info.size,
- 0,
- );
- logMessages.deleteOldCaches(compiler, {
- infos,
- totalSize,
- newInfos,
- newTotalSize,
- oldInfos,
- oldTotalSize,
- });
- } else {
- logMessages.keepCaches(compiler, {
- infos,
- totalSize,
- });
- }
- } catch (error) {
- if (error.code !== 'ENOENT') {
- throw error;
- }
- } finally {
- if (typeof resolveLock === 'function') {
- deleteLock = null;
- resolveLock();
- }
- }
- };
- compilerHooks.watchRun.tapPromise(
- 'HardSource - PruneCachesSystem',
- deleteOldCaches,
- );
- compilerHooks.run.tapPromise(
- 'HardSource - PruneCachesSystem',
- deleteOldCaches,
- );
- }
- }
- module.exports = PruneCachesSystem;
|