Skip to content

Instantly share code, notes, and snippets.

@aaronstgeorge-wf
Last active October 14, 2019 18:55
Show Gist options
  • Save aaronstgeorge-wf/bbb60b8b1ce201fe67dcb7cd71497614 to your computer and use it in GitHub Desktop.
Save aaronstgeorge-wf/bbb60b8b1ce201fe67dcb7cd71497614 to your computer and use it in GitHub Desktop.
Small tool to print a mapping between module file "primary source" and dart files that are part of that module
import 'dart:convert';
import 'dart:core';
import 'dart:io';
main() {
final packageName = Directory.current.path.split('/').last;
final generated = new Directory('.dart_tool/build/generated/$packageName');
// The build system's documentation reads "[e]mit .module assets which contain
// a filtered view of the package level meta-module specific to a single
// module. These are emitted for the 'primary source' of each module, as well
// as each library which is an entrypoint." which does not appear to be
// completely correct. It does seem that these are emitted for every 'primary
// source' i.e. root of the dependency tree but these do not appear to be
// emitted for every entry point.
// https://github.com/dart-lang/build/blob/master/build_modules/README.md#module-creation
final moduleFilesInLib = new RegExp(r'.*lib.*\.module$');
final moduleFiles = generated
.listSync(recursive: true)
.where((e) => moduleFilesInLib.hasMatch(e.path))
.fold(new List<File>(), addFiles);
final moduleToFiles =
<String /* module name */, Set<String> /* filenames in module */ >{};
for (final file in moduleFiles) {
final module = json.decode(file.readAsStringSync());
// 'p' is the json key for primarySource
// https://github.com/dart-lang/build/blob/68b3d29a624754959d65aefcc509a918cca11746/build_modules/lib/src/modules.dart#L64
final primarySource = primarySourceToKey(module['p']);
Set<String> files = new Set<String>.from([primarySource]);
// According to the docs sources should not necessarily contain all the dart
// files that are compiled as part of this module, but it always seems to,
// including cases where there does not appear to be import cycles.
// https://github.com/dart-lang/build/blob/68b3d29a624754959d65aefcc509a918cca11746/build_modules/lib/src/modules.dart#L88
for (String source in module['s'].map(primarySourceToKey)) {
files.add(source);
}
moduleToFiles[primarySource] = files;
}
// Invariant check: no two files should be compiled as part of the same module
for (final i in moduleToFiles.keys) {
for (final j in moduleToFiles.keys) {
if (i != j) {
final intersect = moduleToFiles[i]
.intersection(moduleToFiles[j])
.where((String s) => s.startsWith('text'))
.toList();
if (intersect.isNotEmpty) {
print('invariant violation, two modules contain the same dart file');
exit(1);
}
}
}
}
final dartFileInLib = new RegExp(r'^\.\/lib.*dart$');
final expectedDartFiles = new Directory('.')
.listSync(recursive: true)
.fold(new List<String>(), (List<String> value, FileSystemEntity entity) {
if (entity is File && dartFileInLib.hasMatch(entity.path)) {
value.add(entity.path.replaceFirst('./', ''));
}
return value;
});
final notFound = <String>[];
for (final file in expectedDartFiles) {
final containingModule = search(moduleToFiles, file);
if (containingModule == null) {
notFound.add(file);
}
}
if (notFound.isNotEmpty) {
print(
'The following ${notFound.length} dart files were not found $notFound to be part of a module file');
}
for (final k in moduleToFiles.keys) {
print('module $k contains ${moduleToFiles[k].length} files');
}
}
List<File> addFiles(List<File> files, FileSystemEntity entity) {
if (entity is File) {
files.add(entity);
}
return files;
}
/// Find which module file is compiled in.
String search(Map<String, Set<String>> moduleToFile, String fileName) {
for (final k in moduleToFile.keys) {
if (moduleToFile[k]
.map((s) => s.split('|')[1])
.toList()
.contains(fileName)) {
return k;
}
}
return null;
}
String primarySourceToKey(p) {
return '${p[0]}|${p[1]}';
}
@aaronstgeorge-wf
Copy link
Author

aaronstgeorge-wf commented Oct 14, 2019

Good to know! Thanks for taking a look!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment