generate method
Generates / refreshes the construct kernel.
Returns true when the construct isolate should run (server/client gen).
Returns false when skipIfFresh short-circuits a fully up-to-date
package.
Implementation
Future<bool> generate({
bool recompile = false,
bool skipIfFresh = false,
}) async {
final root = await rootOf(initialDirectory);
logger.detail('Root: ${root.path}');
final constructProgress = logger.progress('Retrieving constructs');
final constructs = await constructHandler.constructDepsFrom(root);
constructProgress.complete('Retrieved constructs');
logger.detail('Constructs Dependencies: ${constructs.length}');
for (final dep in constructs) {
logger.detail('Package: ${dep.packageName}');
for (final construct in dep.constructs) {
logger.detail(' - ${construct.name}');
}
}
final fingerprint = constructSetFingerprint(constructs);
final cacheDir = resolveKernelCacheDir(
fs,
root,
).childDirectory(fingerprint);
final cachedKernel = cacheDir.childFile(kernelFile);
final cachedEntrypoint = cacheDir.childFile(entrypointFile);
if (skipIfFresh && !recompile) {
final outputsFresh = await _packageOutputsAreFresh(root);
// Use local kernel only — a sibling publishing to the shared cache must
// not cause this package to skip regenerating its `.revali` outputs.
final localKernelForSkip = await root.getInternalRevaliFile(kernelFile);
final kernelFresh =
localKernelForSkip.existsSync() &&
!await kernelIsStale(constructs, root);
if (outputsFresh && kernelFresh) {
logger.success('Generated outputs are fresh — skipping generate');
return false;
}
}
final assetsChanged = await checkAssets(constructs, root);
final localKernel = await root.getInternalRevaliFile(kernelFile);
final localEntrypoint = await root.getInternalRevaliFile(entrypointFile);
// Staleness is always against the *local* kernel. A fresh shared cache must
// be installed locally — never treated as "already up to date" in-place.
final localKernelStale = await kernelIsStale(constructs, root);
final cacheIsFresh =
cachedKernel.existsSync() &&
!await _fileNewerThanSources(cachedKernel, constructs, root);
if (!recompile && !assetsChanged) {
if (!localKernelStale && localKernel.existsSync()) {
logger
..detail('Skipping entrypoint generation, using existing kernel')
..success('Constructs entrypoint is up to date');
return true;
}
if (cacheIsFresh) {
await _installCachedKernel(
root: root,
cachedKernel: cachedKernel,
cachedEntrypoint: cachedEntrypoint,
localKernel: localKernel,
localEntrypoint: localEntrypoint,
);
logger.success('Constructs entrypoint restored from shared cache');
return true;
}
}
if (recompile) {
logger.detail('Forcing entrypoint recompile');
}
final entrypointProgress = logger.progress(
'Generating constructs entrypoint',
);
await createEntrypoint(root, constructs: constructs);
entrypointProgress.complete('Generated constructs entrypoint');
// Serialize compile/publish so parallel packages share one ~4s compile.
await _withSharedCacheLock(cacheDir, () async {
// Re-check after lock — another package may have compiled.
if (!recompile &&
cachedKernel.existsSync() &&
!await _fileNewerThanSources(cachedKernel, constructs, root)) {
await _installCachedKernel(
root: root,
cachedKernel: cachedKernel,
cachedEntrypoint: cachedEntrypoint,
localKernel: localKernel,
localEntrypoint: localEntrypoint,
);
logger.success('Constructs entrypoint reused from shared cache');
return;
}
final compileProgress = logger.progress(
'Compiling constructs entrypoint',
);
await compile(root: root);
compileProgress.complete('Compiled constructs entrypoint');
await _publishKernelToCache(
cacheDir: cacheDir,
localKernel: localKernel,
localEntrypoint: localEntrypoint,
);
});
return true;
}