packages/cli: refactor build-cache to have a reusable withCache function

This commit is contained in:
Patrik Oldsberg
2020-04-07 00:00:14 +02:00
parent af882489e2
commit 98dea870e6
2 changed files with 46 additions and 20 deletions
+23 -13
View File
@@ -17,24 +17,21 @@
import { Command } from 'commander';
import { run } from 'helpers/run';
import { Cache } from './cache';
import { parseOptions } from './options';
import { parseOptions, Options } from './options';
function print(msg: string) {
process.stdout.write(`[build-cache] ${msg}\n`);
}
/*
* The build-cache command is used to make builds a no-op if there are no changes to the package.
* It supports both local development where the output directory remains intact, as well as CI
* where the output directory is stored in a separate cache dir.
*/
export default async (cmd: Command, args: string[]) => {
const options = await parseOptions(cmd);
// Wrap a build function with a cache, which won't call the build function on cache hit
export async function withCache(
options: Options,
buildFunc: () => Promise<void>,
): Promise<void> {
const key = await Cache.readInputKey(options.inputs);
if (!key) {
print('input directory is dirty, skipping cache');
await run(args[0], args.slice(1));
await buildFunc();
return;
}
@@ -52,9 +49,22 @@ export default async (cmd: Command, args: string[]) => {
}
print('cache miss, need to build');
await buildFunc();
await run(args[0], args.slice(1));
print('caching build output');
await cacheResult.archive(options.output, options.maxCacheEntries);
}
/*
* The build-cache command is used to make builds a no-op if there are no changes to the package.
* It supports both local development where the output directory remains intact, as well as CI
* where the output directory is stored in a separate cache dir.
*/
export default async (cmd: Command, args: string[]) => {
const options = await parseOptions(cmd);
await withCache(options, async () => {
await run(args[0], args.slice(1));
});
};
export * from './options';
@@ -18,6 +18,7 @@ import { resolve as resolvePath } from 'path';
import { Command } from 'commander';
import { paths } from 'helpers/paths';
const DEFAULT_CACHE_DIR = '<repoRoot>/node_modules/.cache/backstage-builds';
const DEFAULT_MAX_ENTRIES = 10;
export type Options = {
@@ -27,19 +28,34 @@ export type Options = {
maxCacheEntries: number;
};
export async function parseOptions(cmd: Command): Promise<Options> {
const argTransformer = (arg: string) =>
resolvePath(arg.replace(/<repoRoot>/g, paths.targetRoot).replace(/'/g, ''));
function transformPath(path: string): string {
return resolvePath(
path.replace(/<repoRoot>/g, paths.targetRoot).replace(/'/g, ''),
);
}
const inputs = cmd.input.map(argTransformer) as string[];
export async function parseOptions(cmd: Command): Promise<Options> {
const inputs = cmd.input.map(transformPath) as string[];
if (inputs.length === 0) {
inputs.push(argTransformer('.'));
inputs.push(transformPath('.'));
}
const output = argTransformer(cmd.output);
const cacheDir = argTransformer(
const output = transformPath(cmd.output);
const cacheDir = transformPath(
process.env.BACKSTAGE_CACHE_DIR || cmd.cacheDir,
);
const maxCacheEntries =
Number(process.env.BACKSTAGE_CACHE_MAX_ENTRIES) || DEFAULT_MAX_ENTRIES;
return { inputs, output, cacheDir, maxCacheEntries };
}
export function getDefaultCacheOptions(): Options {
return {
inputs: [transformPath('.')],
output: transformPath('dist'),
cacheDir: transformPath(
process.env.BACKSTAGE_CACHE_DIR || DEFAULT_CACHE_DIR,
),
maxCacheEntries:
Number(process.env.BACKSTAGE_CACHE_MAX_ENTRIES) || DEFAULT_MAX_ENTRIES,
};
}