Skip to content

Commit 7a65dac

Browse files
authored
chore: cache custom generators (#311)
1 parent 7a7164a commit 7a65dac

File tree

4 files changed

+104
-24
lines changed

4 files changed

+104
-24
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ build
2020
pom.xml
2121

2222
dist
23+
.cache
2324

2425
.openapi-generator
2526

scripts/buildSpecs.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import fsp from 'fs/promises';
22

3-
import { hashElement } from 'folder-hash';
43
import yaml from 'js-yaml';
54

6-
import { exists, run, toAbsolutePath } from './common';
5+
import { checkForCache, exists, run, toAbsolutePath } from './common';
76
import { createSpinner } from './oraLog';
87
import type { Spec } from './pre-gen/setHostsOptions';
98

@@ -53,30 +52,22 @@ async function buildSpec(
5352
let hash = '';
5453

5554
if (useCache) {
56-
const spinner = createSpinner(
57-
`checking cache for '${client}'`,
55+
const { cacheExists, hash: newCache } = await checkForCache(
56+
{
57+
job: `'${client}' specs`,
58+
folder: toAbsolutePath('specs/'),
59+
generatedFiles: [`bundled/${client}.yml`],
60+
filesToCache: [client, 'common'],
61+
cacheFile,
62+
},
5863
verbose
59-
).start();
60-
// check if file and cache exist
61-
if (await exists(toAbsolutePath(`specs/bundled/${client}.yml`))) {
62-
// compare with stored cache
63-
const specHash = (await hashElement(toAbsolutePath(`specs/${client}`)))
64-
.hash;
65-
const commonHash = (await hashElement(toAbsolutePath(`specs/common`)))
66-
.hash;
67-
hash = `${specHash}-${commonHash}`;
68-
if (await exists(cacheFile)) {
69-
const storedHash = (await fsp.readFile(cacheFile)).toString();
70-
if (storedHash === hash) {
71-
spinner.succeed(
72-
`skipped building ${client} spec because the files did not change`
73-
);
74-
return;
75-
}
76-
}
64+
);
65+
66+
if (cacheExists) {
67+
return;
7768
}
7869

79-
spinner.info(`cache not found for ${client}' spec`);
70+
hash = newCache;
8071
}
8172

8273
const spinner = createSpinner(`building ${client} spec`, verbose).start();

scripts/common.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import fsp from 'fs/promises';
22
import path from 'path';
33

44
import execa from 'execa'; // https://github.com/sindresorhus/execa/tree/v5.1.1
5+
import { hashElement } from 'folder-hash';
56

67
import openapitools from '../openapitools.json';
78

89
import { createSpinner } from './oraLog';
9-
import type { Generator, RunOptions } from './types';
10+
import type {
11+
CheckForCache,
12+
CheckForCacheOptions,
13+
Generator,
14+
RunOptions,
15+
} from './types';
1016

1117
export const CI = Boolean(process.env.CI);
1218
export const DOCKER = Boolean(process.env.DOCKER);
@@ -194,11 +200,80 @@ export async function gitCommit({
194200
);
195201
}
196202

203+
export async function checkForCache(
204+
{
205+
job,
206+
folder,
207+
generatedFiles,
208+
filesToCache,
209+
cacheFile,
210+
}: CheckForCacheOptions,
211+
verbose: boolean
212+
): Promise<CheckForCache> {
213+
const spinner = createSpinner(`checking cache for ${job}`, verbose).start();
214+
const cache: CheckForCache = {
215+
cacheExists: false,
216+
hash: '',
217+
};
218+
const generatedFilesExists = (
219+
await Promise.all(
220+
generatedFiles.map((generatedFile) =>
221+
exists(`${folder}/${generatedFile}`)
222+
)
223+
)
224+
).every((exist) => exist);
225+
226+
for (const fileToCache of filesToCache) {
227+
const fileHash = (await hashElement(`${folder}/${fileToCache}`)).hash;
228+
229+
cache.hash = `${cache.hash}-${fileHash}`;
230+
}
231+
232+
// We only skip if both the cache and the generated file exists
233+
if (generatedFilesExists && (await exists(cacheFile))) {
234+
const storedHash = (await fsp.readFile(cacheFile)).toString();
235+
if (storedHash === cache.hash) {
236+
spinner.succeed(`job skipped, cache found for ${job}`);
237+
return {
238+
cacheExists: true,
239+
hash: cache.hash,
240+
};
241+
}
242+
}
243+
244+
spinner.info(`cache not found for ${job}`);
245+
246+
return cache;
247+
}
248+
197249
export async function buildCustomGenerators(verbose: boolean): Promise<void> {
250+
const cacheFile = toAbsolutePath('generators/.cache');
251+
const { cacheExists, hash } = await checkForCache(
252+
{
253+
job: 'custom generators',
254+
folder: toAbsolutePath('generators/'),
255+
generatedFiles: ['build'],
256+
filesToCache: ['src', 'build.gradle', 'settings.gradle'],
257+
cacheFile,
258+
},
259+
verbose
260+
);
261+
262+
if (cacheExists) {
263+
return;
264+
}
265+
198266
const spinner = createSpinner('building custom generators', verbose).start();
267+
199268
await run('./gradle/gradlew --no-daemon -p generators assemble', {
200269
verbose,
201270
});
271+
272+
if (hash) {
273+
spinner.text = 'storing custom generators cache';
274+
await fsp.writeFile(cacheFile, hash);
275+
}
276+
202277
spinner.succeed();
203278
}
204279

scripts/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import type config from '../config/clients.config.json';
22

3+
export type CheckForCacheOptions = {
4+
job: string;
5+
folder: string;
6+
generatedFiles: string[];
7+
filesToCache: string[];
8+
cacheFile: string;
9+
};
10+
11+
export type CheckForCache = {
12+
cacheExists: boolean;
13+
hash: string;
14+
};
15+
316
export type Generator = Record<string, any> & {
417
language: string;
518
client: string;

0 commit comments

Comments
 (0)