UNPKG

3.95 kBPlain TextView Raw
1import fsExtra from "fs-extra";
2import isEqual from "lodash/isEqual";
3import path from "path";
4
5import {
6 SOLC_INPUT_FILENAME,
7 SOLC_OUTPUT_FILENAME,
8} from "../../internal/constants";
9import { glob } from "../../internal/util/glob";
10import { getPackageJson } from "../../internal/util/packageInfo";
11import { ProjectPaths, SolcConfig } from "../../types";
12
13// Checks the earliest date of modification for compiled files against the latest date for source files (including libraries).
14// Furthermore, cache is invalidated if Buidler's version changes, or a different solc version is set in the buidler config.
15export async function areArtifactsCached(
16 sourceTimestamps: number[],
17 newSolcConfig: SolcConfig,
18 paths: ProjectPaths
19): Promise<boolean> {
20 const oldConfig = await getLastUsedConfig(paths.cache);
21
22 if (
23 oldConfig === undefined ||
24 !compareSolcConfigs(oldConfig.solc, newSolcConfig) ||
25 !(await compareBuidlerVersion(oldConfig.buidlerVersion))
26 ) {
27 return false;
28 }
29
30 const maxSourceDate = getMaxSourceDate(sourceTimestamps);
31 const minArtifactDate = await getMinArtifactDate(paths.artifacts);
32
33 if (
34 !(await fsExtra.pathExists(path.join(paths.cache, SOLC_INPUT_FILENAME)))
35 ) {
36 return false;
37 }
38
39 if (
40 !(await fsExtra.pathExists(path.join(paths.cache, SOLC_OUTPUT_FILENAME)))
41 ) {
42 return false;
43 }
44
45 const lastConfigTimestamp = await getLastUsedConfigTimestamp(paths.cache);
46 if (
47 lastConfigTimestamp !== undefined &&
48 lastConfigTimestamp > maxSourceDate
49 ) {
50 return true;
51 }
52
53 return maxSourceDate < minArtifactDate;
54}
55
56async function getModificationDatesInDir(dir: string): Promise<number[]> {
57 const pattern = path.join(dir, "**", "*");
58 const files = await glob(pattern);
59
60 return Promise.all(
61 files.map(async (file) => (await fsExtra.stat(file)).ctimeMs)
62 );
63}
64
65function getMaxSourceDate(sourceTimestamps: number[]): number {
66 return Math.max(...sourceTimestamps);
67}
68
69async function getMinArtifactDate(artifactsPath: string): Promise<number> {
70 const timestamps = await getModificationDatesInDir(artifactsPath);
71
72 if (timestamps.length === 0) {
73 return 0;
74 }
75
76 return Math.min(...timestamps);
77}
78
79const LAST_CONFIG_USED_FILENAME = "last-solc-config.json";
80
81function getPathToCachedLastConfigPath(cachePath: string) {
82 const pathToLastConfigUsed = path.join(cachePath, LAST_CONFIG_USED_FILENAME);
83
84 return pathToLastConfigUsed;
85}
86
87async function getLastUsedConfig(
88 cachePath: string
89): Promise<{ solc: SolcConfig; buidlerVersion: string } | undefined> {
90 const pathToConfig = getPathToCachedLastConfigPath(cachePath);
91
92 if (!(await fsExtra.pathExists(pathToConfig))) {
93 return undefined;
94 }
95
96 return module.require(pathToConfig);
97}
98
99async function getLastUsedConfigTimestamp(
100 cachePath: string
101): Promise<number | undefined> {
102 const pathToConfig = getPathToCachedLastConfigPath(cachePath);
103
104 if (!(await fsExtra.pathExists(pathToConfig))) {
105 return undefined;
106 }
107
108 return (await fsExtra.stat(pathToConfig)).ctimeMs;
109}
110
111export async function cacheBuidlerConfig(
112 paths: ProjectPaths,
113 config: SolcConfig
114) {
115 const pathToLastConfigUsed = getPathToCachedLastConfigPath(paths.cache);
116 const newJson = {
117 solc: config,
118 buidlerVersion: await getCurrentBuidlerVersion(),
119 };
120
121 await fsExtra.ensureDir(path.dirname(pathToLastConfigUsed));
122
123 return fsExtra.writeFile(
124 pathToLastConfigUsed,
125 JSON.stringify(newJson, undefined, 2),
126 "utf-8"
127 );
128}
129
130function compareSolcConfigs(
131 oldConfig: SolcConfig,
132 newConfig: SolcConfig
133): boolean {
134 return isEqual(oldConfig, newConfig);
135}
136
137async function getCurrentBuidlerVersion(): Promise<string> {
138 const packageJson = await getPackageJson();
139
140 return packageJson.version;
141}
142
143async function compareBuidlerVersion(
144 lastBuidlerVersion: string
145): Promise<boolean> {
146 const currentVersion = await getCurrentBuidlerVersion();
147
148 return lastBuidlerVersion === currentVersion;
149}