checkBridgeFreshness function
Regenerate projectPath's bridges into a scratch tree and compare them with
what the package has committed.
The scratch tree lives under the package's own .dart_tool/, which is
gitignored and per-package, and is removed afterwards. A unique
subdirectory per call keeps two concurrent checks of one package apart.
Implementation
Future<BridgeFreshness> checkBridgeFreshness(String projectPath) async {
final packageRoot = p.normalize(p.absolute(projectPath));
final config = BuildConfigLoader.loadFromTomBuildYaml(packageRoot);
if (config == null) {
throw ArgumentError('No d4rtgen configuration found in $packageRoot');
}
// `generateBridges` runs `dart pub get` for a package without a package
// config. That is a subprocess, which no `dart:io` overlay can redirect, and
// it would rewrite `pubspec.lock` in place. An unresolved package is refused.
final packageConfig = File(
p.join(packageRoot, '.dart_tool', 'package_config.json'),
);
if (!packageConfig.existsSync()) {
return BridgeFreshness(
checked: const [],
stale: const [],
errors: [
'$packageRoot is not resolved (no .dart_tool/package_config.json). '
'Run `dart pub get` first; the check does not run it, because '
'that would write to the package.',
],
);
}
final preview = await previewGeneration(
packageRoot: packageRoot,
purpose: 'freshness',
generate: () => generateBridges(config: config, projectPath: packageRoot),
);
final writes = {for (final w in preview.writes) w.path: w.change};
final checked = <String>[];
final stale = <StaleBridge>[];
for (final reportedPath in preview.result.outputFiles) {
final relative = p.relative(
p.normalize(p.absolute(reportedPath)),
from: packageRoot,
);
checked.add(relative);
// The generator reports destinations in the package; the overlay sent the
// writes to the scratch tree. A reported file the preview did not see was
// written some other way — possibly in place — so nothing can be
// concluded, and the package itself should be inspected.
final change = writes[relative];
if (change == null) {
return BridgeFreshness(
checked: checked,
stale: stale,
errors: [
'The generator reported $relative, but it is not in the scratch '
'tree. The write was not redirected, so the package itself may '
'have been modified — inspect it before trusting any result.',
],
);
}
switch (change) {
case PreviewedChange.created:
stale.add(StaleBridge(relative, StaleReason.notCommitted));
case PreviewedChange.changed:
stale.add(StaleBridge(relative, StaleReason.differs));
case PreviewedChange.unchanged:
break;
}
}
return BridgeFreshness(
checked: checked,
stale: stale,
errors: preview.result.errors,
);
}