load static method

Manifest load(
  1. String root
)

Loads the manifest from root (default: current directory).

Implementation

static Manifest load(String root) {
  final file = File('$root/$kManifestFileName');
  if (!file.existsSync()) {
    throw FileSystemException('no $kManifestFileName in $root — run '
        '"dart run flutter_bench_contract:contract init" first');
  }
  final dynamic doc;
  try {
    doc = loadYaml(file.readAsStringSync());
  } catch (e) {
    throw FormatException('cannot parse $kManifestFileName: $e');
  }
  if (doc is! YamlMap) {
    throw FormatException('$kManifestFileName: expected a YAML map');
  }
  String str(String key, {String fallback = ''}) =>
      (doc[key] as String?) ?? fallback;
  List<String> list(String key) =>
      [for (final s in (doc[key] as List? ?? const [])) s as String];

  // Multi-library shape: `libraries: {name: {driver, driverClass, ref?}}`.
  // When present it fully replaces the single-library fields (which may be
  // absent); the consumer runs each entry against the same scenario list.
  final librariesDoc = doc['libraries'];
  final libraries = <LibraryEntry>[];
  if (librariesDoc != null) {
    if (librariesDoc is! YamlMap) {
      throw FormatException('$kManifestFileName: libraries must be a map '
          '{name: {driver, driverClass, ref?}}');
    }
    for (final entry in librariesDoc.entries) {
      final name = entry.key as String;
      final spec = entry.value;
      if (spec is! YamlMap || spec['driver'] is! String ||
          spec['driverClass'] is! String) {
        throw FormatException('$kManifestFileName: libraries.$name needs '
            'driver + driverClass');
      }
      libraries.add(LibraryEntry(
        name: name,
        driver: spec['driver'] as String,
        driverClass: spec['driverClass'] as String,
        ref: spec['ref'] as String?,
      ));
    }
  }

  // Consumer-owned scenarios: keys are short names, the metric id is
  // `custom.<key>`; a key colliding with a contract scenario id is
  // shadowing and rejected (a package scenario cannot be redefined).
  final customScenarios = <CustomScenario>[];
  final customDoc = doc['customScenarios'];
  if (customDoc != null) {
    if (customDoc is! YamlMap) {
      throw FormatException('$kManifestFileName: customScenarios must be a '
          'map {name: {target, ref?, runs?}}');
    }
    for (final entry in customDoc.entries) {
      final name = entry.key as String;
      if (name.isEmpty || name.startsWith('custom.')) {
        throw FormatException('$kManifestFileName: customScenarios key '
            '"$name" must be a short name — the id is custom.<name>');
      }
      if (kContractScenarioIds.contains(name)) {
        throw FormatException('$kManifestFileName: customScenarios key '
            '"$name" shadows the contract scenario — package scenarios '
            'cannot be redefined');
      }
      final spec = entry.value;
      if (spec is! YamlMap || spec['target'] is! String ||
          (spec['target'] as String).isEmpty) {
        throw FormatException('$kManifestFileName: customScenarios.$name '
            'needs a non-empty target: (the test file path)');
      }
      final ref = spec['ref'] as String? ?? 'custom';
      if (ref.isEmpty) {
        throw FormatException('$kManifestFileName: customScenarios.$name '
            'ref must not be empty');
      }
      final runs = spec['runs'] is int ? spec['runs'] as int : 1;
      if (runs < 1) {
        throw FormatException('$kManifestFileName: customScenarios.$name '
            'runs must be >= 1');
      }
      customScenarios.add(CustomScenario(
        id: 'custom.$name',
        name: name,
        target: spec['target'] as String,
        ref: ref,
        runs: runs,
      ));
    }
  }

  // The contract `scenarios:` list holds only contract ids — a `custom.*`
  // entry there is a shape error (custom scenarios live under
  // `customScenarios:` and are not per-library).
  final scenarios = list('scenarios');
  for (final id in scenarios) {
    if (id.startsWith('custom.')) {
      throw FormatException('$kManifestFileName: scenario "$id" belongs '
          'under customScenarios:, not scenarios:');
    }
  }

  return Manifest(
    library: str('library'),
    driver: str('driver'),
    driverClass: str('driverClass'),
    contractDir: str('contractDir', fallback: 'bench/contract'),
    scenarios: scenarios,
    idleClasses: list('idleClasses'),
    libraries: libraries,
    customScenarios: customScenarios,
    template: doc['template'] is int ? doc['template'] as int : kTemplateVersion,
    size: SizeConfig.fromYaml(doc['size']),
    card: _cardFromYaml(doc['card']),
    readme: _readmeFromYaml(doc['readme']),
  );
}