generate method

Future<bool> generate({
  1. bool recompile = false,
  2. bool skipIfFresh = false,
})

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;
}