// build_runner:build_runner.dart Future<void> main(List<String> args) async { // Use the actual command runner to parse the args and immediately print the // usage information if there is no command provided or the help command was // explicitly invoked. var commandRunner = BuildCommandRunner([], await PackageGraph.forThisPackage()); // ... }
// build_runner_core:src/package_graph/package_graph.dart classPackageGraph{ /// Creates a [PackageGraph] for the package in which you are currently /// running. static Future<PackageGraph> forThisPackage() => // 读取项目的PackageGraph PackageGraph.forPath(p.current);
/// Creates a [PackageGraph] for the package whose top level directory lives /// at [packagePath] (no trailing slash). static Future<PackageGraph> forPath(String packagePath) async { // ... // 读取PackageConfig,Flutter会把项目的包依赖信息放在PackageConfig里 final packageConfig = await findPackageConfig(Directory(packagePath), recurse: false); // ... // 通过PackageConfig解析包依赖 final packageDependencies = _parsePackageDependencies( packageConfig.packages.where((p) => p.name != rootPackageName)); // ... }
/// Read the pubspec for each package in [packages] and finds it's /// dependencies. Map<String, List<String>> _parsePackageDependencies( Iterable<Package> packages) { final dependencies = <String, List<String>>{}; for (final package in packages) { // 针对每个包,读取它的pubspec.yaml final pubspec = _pubspecForPath(package.root.toFilePath()); dependencies[package.name] = _depsFromYaml(pubspec); } return dependencies; }
/// Should point to the top level directory for the package. YamlMap _pubspecForPath(String absolutePath) { var pubspecPath = p.join(absolutePath, 'pubspec.yaml'); var pubspec = File(pubspecPath); if (!pubspec.existsSync()) { // .dart_tool/flutter_gen这个包也被列入了依赖,而这个包里没有pubspec.yaml,所以在这里报了错 throw StateError( 'Unable to generate package graph, no `$pubspecPath` found.'); } return loadYaml(pubspec.readAsStringSync()) as YamlMap; }
classFlutterManifest{ /// Whether a synthetic flutter_gen package should be generated. /// /// This can be provided to the [Pub] interface to inject a new entry /// into the package_config.json file which points to `.dart_tool/flutter_gen`. /// /// This allows generated source code to be imported using a package /// alias. boolget generateSyntheticPackage => _generateSyntheticPackage ??= _computeGenerateSyntheticPackage(); bool _generateSyntheticPackage; bool _computeGenerateSyntheticPackage() { if (!_flutterDescriptor.containsKey('generate')) { returnfalse; } finalObject value = _flutterDescriptor['generate']; if (value is! bool) { returnfalse; } return value asbool; } }
classLocalizationsGenerator{ void writeOutputFiles(Logger logger, { bool isFromYaml = false }) { // First, generate the string contents of all necessary files. _generateCode();
// A pubspec.yaml file is required when using a synthetic package. If it does not // exist, create a blank one. if (_useSyntheticPackage) { final Directory syntheticPackageDirectory = _fs.directory(defaultSyntheticPackagePath); syntheticPackageDirectory.createSync(recursive: true); final File flutterGenPubspec = syntheticPackageDirectory.childFile('pubspec.yaml'); if (!flutterGenPubspec.existsSync()) { flutterGenPubspec.writeAsStringSync(emptyPubspecTemplate); } }
// ... void writeOutputFiles() { // First, generate the string contents of all necessary files. _generateCode();
// Since all validity checks have passed up to this point, // write the contents into the directory. if (!outputDirectory.existsSync()) { outputDirectory.createSync(recursive: true); }
// Ensure that the created directory has read/write permissions. final FileStat fileStat = outputDirectory.statSync(); if (_isNotReadable(fileStat) || _isNotWritable(fileStat)) { throw L10nException( "The 'output-dir' directory, $outputDirectory, doesn't allow reading and writing.\n" 'Please ensure that the user has read and write permissions.' ); }
// Generate the required files for localizations. _languageFileMap.forEach((File file, String contents) { file.writeAsStringSync(contents); if (_inputsAndOutputsListFile != null) { _outputFileList.add(file.absolute.path); } });
baseOutputFile.writeAsStringSync(_generatedLocalizationsFile); if (_inputsAndOutputsListFile != null) { _outputFileList.add(baseOutputFile.absolute.path);
// Generate a JSON file containing the inputs and outputs of the gen_l10n script. if (!_inputsAndOutputsListFile.existsSync()) { _inputsAndOutputsListFile.createSync(recursive: true); }
final FileSystem fileSystem = environment.fileSystem; final File l10nYamlFile = fileSystem.file( fileSystem.path.join(environment.projectDir.path, 'l10n.yaml'));
// If pubspec.yaml has generate:true and if l10n.yaml exists in the // root project directory, check to see if a synthetic package should // be generated for gen_l10n. if (!l10nYamlFile.existsSync()) { return; }
final YamlNode yamlNode = loadYamlNode(l10nYamlFile.readAsStringSync()); if (yamlNode.value != null && yamlNode is! YamlMap) { throwToolExit( 'Expected ${l10nYamlFile.path} to contain a map, instead was $yamlNode' ); }
BuildResult result; // If an l10n.yaml file exists but is empty, attempt to build synthetic // package with default settings. if (yamlNode.value == null) { result = await buildSystem.build( const GenerateLocalizationsTarget(), environment, ); } else { final YamlMap yamlMap = yamlNode as YamlMap; finalObject value = yamlMap['synthetic-package']; if (value is! bool && value != null) { throwToolExit( 'Expected "synthetic-package" to have a bool value, ' 'instead was "$value"' ); }
// Generate gen_l10n synthetic package only if synthetic-package: true or // synthetic-package is null. finalbool isSyntheticL10nPackage = value asbool ?? true; if (!isSyntheticL10nPackage) { return; } }
result = await buildSystem.build( const GenerateLocalizationsTarget(), environment, );
if (result == null || result.hasException) { throwToolExit('Generating synthetic localizations package has failed.'); } }
A Function that throws an exception when called. The function cannot take any arguments. If you want to test that a function expecting arguments throws, wrap it in another zero-argument function that calls the one you want to test.
A Future that completes with an exception. Note that this creates an asynchronous expectation. The call to expect() that includes this will return immediately and execution will continue. Later, when the future completes, the actual expectation will run.
A Function that returns a Future that completes with an exception.
In all three cases, when an exception is thrown, this will test that the exception object matches matcher. If matcher is not an instance of Matcher, it will implicitly be treated as equals(matcher).
Certain matchers, like completion and throwsA, either match or fail asynchronously. When you use expect with these matchers, it ensures that the test doesn’t complete until the matcher has either matched or failed. If you want to wait for the matcher to complete before continuing the test, you can call expectLater instead and await the result.