-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathcache.ts
More file actions
114 lines (103 loc) · 3.24 KB
/
cache.ts
File metadata and controls
114 lines (103 loc) · 3.24 KB
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
import fs from "fs";
import os from "os";
import path from "path";
import { getDocker, getImageByTag } from "./docker";
// Local cache specs. Path = $cachePath
type CacheMap = Map<string, string>;
/**
* Get cache path in common location
*/
function getCachePath(): string {
return path.join(
os.homedir(),
".config",
"dappnodesdk",
"docker-build-cache.json"
);
}
/**
* Read and parse local cache file
*/
export function loadCache(cachePath?: string): CacheMap {
if (!cachePath) cachePath = getCachePath();
try {
const cacheString = fs.readFileSync(cachePath, "utf8");
try {
return new Map(Object.entries(JSON.parse(cacheString)));
} catch (e) {
console.error(`Error parsing cache ${cachePath}`, e);
return new Map();
}
} catch (e) {
if (e.code === "ENOENT") return new Map();
else throw e;
}
}
/**
* Add entry to local cache
*/
export function writeToCache(
{ key, value }: { key: string; value: string },
cachePath?: string
): void {
if (!cachePath) cachePath = getCachePath();
const cache = loadCache(cachePath);
cache.set(key, value);
writeCache(cache, cachePath);
}
/**
* Stringify and write cacheMap to local cache file
*/
export function writeCache(cache: CacheMap, cachePath?: string): void {
if (!cachePath) cachePath = getCachePath();
const cacheObj: { [key: string]: string } = {};
for (const [key, value] of cache) cacheObj[key] = value;
const cacheString = JSON.stringify(cacheObj, null, 2);
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
fs.writeFileSync(cachePath, cacheString);
}
/**
* Returns a single deterministic cache key from an array of image tags
* @param imageTags
* @returns "dappmanager.dnp.dappnode.eth:0.2.24/sha256:0d31e5521ef6e92a0efb6110024da8a3517daac4b1e4bbbccaf063ce96641b1b"
*/
export async function getCacheKey(imageTags: string[]): Promise<string> {
return (
await Promise.all(
imageTags.sort().map(async imageTag => {
const image = await getImageByTag(getDocker(), imageTag);
const info = await image.inspect();
// info.Id = "sha256:2dbd79fff9541ba91c6ce5867840ecee8d5e335bc2465dadb39a3419e7039f96"
return [imageTag, info.Id].join("/");
})
)
).join(";");
}
/**
* Prune local cache by removing entries of images that are no longer in disk
* @param cachePath
*/
export async function pruneCache(cachePath?: string): Promise<void> {
if (!cachePath) cachePath = getCachePath();
if (fs.existsSync(cachePath)) {
const cache = loadCache(cachePath);
const images = await getDocker().listImages();
// imageIds = ["sha256:2dbd79fff9541ba91c6ce5867840ecee8d5e335bc2465dadb39a3419e7039f96"]
const imageIds = images.map(image => image.Id);
const prunedCache = _pruneCache(cache, imageIds);
writeCache(prunedCache, cachePath);
}
}
/**
* Pure function version of pruneCache to ease testing
* @param cache
* @param imageIds ["6b74b6ba423e, "4a67065ab84a"]
*/
export function _pruneCache(cache: CacheMap, imageIds: string[]): CacheMap {
for (const [cacheImageId] of cache) {
// Remove entry if no image ID is included in the cache key digest
if (imageIds.every(imageId => !cacheImageId.includes(imageId)))
cache.delete(cacheImageId);
}
return cache;
}