保誠-保戶業務員媒合平台
HelenHuang
2022-06-09 9bdb95c9e34cef640534e5e5a1e2225a80442000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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;