/
audit.ts
111 lines (92 loc) · 3.15 KB
/
audit.ts
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
import * as chokidar from "chokidar";
import * as findUp from "find-up";
import * as path from "path";
import anymatch from "anymatch";
import { logger } from "backfill-logger";
import { outputFolderAsArray } from "backfill-config";
let changedFilesOutsideScope: string[] = [];
let changedFilesInsideScope: string[] = [];
let watcher: chokidar.FSWatcher;
function getGitRepositoryRoot(packageRoot: string) {
const nearestGitFolder = findUp.sync(".git", {
cwd: packageRoot,
type: "directory"
});
if (nearestGitFolder) {
// Return the parent folder of some/path/.git
return path.join(nearestGitFolder, "..");
}
return packageRoot;
}
function addGlobstars(globPatterns: string[]): string[] {
const folders = globPatterns.map(p => path.posix.join("**", p, "**", "*"));
const files = globPatterns.map(p => path.posix.join("**", p));
return [...folders, ...files];
}
export function initializeWatcher(
packageRoot: string,
internalCacheFolder: string,
logFolder: string,
outputFolder: string | string[],
hashGlobs: string[]
) {
// Trying to find the git root and using it as an approximation of code boundary
const repositoryRoot = getGitRepositoryRoot(packageRoot);
// Empty the arrays
changedFilesOutsideScope = [];
changedFilesInsideScope = [];
logger.info("Running in AUDIT mode");
logger.info(`[audit] Watching file changes in: ${repositoryRoot}`);
logger.info(`[audit] Backfill will cache folder: ${outputFolder}`);
// Define globs
const ignoreGlobs = addGlobstars([
".git",
".cache",
logFolder,
internalCacheFolder
]);
const cacheFolderGlob = outputFolderAsArray(outputFolder).map(folder =>
path.posix.join("**", folder, "**")
);
watcher = chokidar
.watch(hashGlobs, {
ignored: ignoreGlobs,
cwd: repositoryRoot,
persistent: true,
ignoreInitial: true,
followSymlinks: false,
usePolling: true
})
.on("all", (event, filePath) => {
const logLine = `${filePath} (${event})`;
logger.silly(`[audit] File change: ${logLine}`);
if (!anymatch(cacheFolderGlob, filePath)) {
changedFilesOutsideScope.push(logLine);
} else {
changedFilesInsideScope.push(logLine);
}
});
}
export const sideEffectWarningString =
"[audit] The following files got changed outside of the scope of the folder to be cached:";
export const sideEffectCallToActionString =
"[audit] You should make sure that these changes are non-essential, as they would not be brought back on a cache-hit.";
export const noSideEffectString =
"[audit] All observed file changes were within the scope of the folder to be cached.";
async function delay(time: number) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
export async function closeWatcher() {
// Wait for one second before closing, giving time for file changes to propagate
await delay(1000);
if (changedFilesOutsideScope.length > 0) {
logger.warn(sideEffectWarningString);
changedFilesOutsideScope.forEach(file => logger.warn(`- ${file}`));
logger.warn(sideEffectCallToActionString);
} else {
logger.info(noSideEffectString);
}
watcher.close();
}