writeGeneratedSources function

Future<bool> writeGeneratedSources({
  1. required GeneratedSources sources,
  2. required String outputPath,
  3. bool check = false,
})

Writes both outputs, or checks exact source equality without writing.

Returns false for missing or changed files when check is true. Schema validation and formatter failures propagate without changing either file. Output paths must match those used for generation so relative model imports remain valid. Symbolic links and aliases of the input or sibling output are rejected. Both contents are staged before replacing either destination; replacement of each file is atomic, not a transaction across both files.

Implementation

Future<bool> writeGeneratedSources({
  required GeneratedSources sources,
  required String outputPath,
  bool check = false,
}) async {
  final output = p.normalize(p.absolute(outputPath));
  if (output != sources._outputPath) {
    throw const FormatException(
      'Write to the output path used for generation.',
    );
  }
  await _validateOutputPaths(sources._schemaPath, output);
  final files = {
    output: sources.database,
    snapshotPath(output): sources.snapshot,
  };
  if (check) {
    for (final entry in files.entries) {
      final file = File(entry.key);
      if (!await file.exists() || await file.readAsString() != entry.value) {
        return false;
      }
    }
    return true;
  }
  final staged = <({File file, String target, Directory directory})>[];
  try {
    for (final entry in files.entries) {
      final parent = Directory(p.dirname(entry.key));
      await parent.create(recursive: true);
      final directory = await parent.createTemp('.orm-generate-');
      final file = File(p.join(directory.path, p.basename(entry.key)));
      staged.add((file: file, target: entry.key, directory: directory));
      await file.writeAsString(entry.value, flush: true);
    }
    await _validateOutputPaths(sources._schemaPath, output);
    for (final entry in staged) {
      await entry.file.rename(entry.target);
    }
  } finally {
    for (final entry in staged) {
      await entry.directory.delete(recursive: true);
    }
  }
  return true;
}