LoomFlavorSelection.load constructor

LoomFlavorSelection.load(
  1. List<String> arguments, {
  2. required File projectFile,
  3. Map<String, String>? environmentVariables,
})

Loads inline flavor defaults from projectFile and an optional override.

Implementation

factory LoomFlavorSelection.load(
  List<String> arguments, {
  required File projectFile,
  Map<String, String>? environmentVariables,
}) {
  final processEnvironment = environmentVariables ?? Platform.environment;
  final forwarded = [...arguments];
  final environmentOption = _takeOption(forwarded, '--env');
  final flavorOption = _takeOption(forwarded, '--flavor');
  if (environmentOption != null && flavorOption != null) {
    throw const FormatException('Use either --env or --flavor, not both.');
  }
  final explicit = flavorOption ?? environmentOption;
  final document = loadYaml(projectFile.readAsStringSync());
  if (document is! YamlMap || document['runner'] is! YamlMap) {
    throw FormatException('${projectFile.path} has no runner configuration.');
  }
  final runner = document['runner']! as YamlMap;
  final flavors = document['flavors'];
  if (flavors is! YamlMap || flavors.isEmpty) {
    throw FormatException('${projectFile.path} must define flavors.');
  }
  final fallback = runner['default_flavor'];
  final name =
      explicit ??
      processEnvironment['SQLITE_LOOM_FLAVOR'] ??
      processEnvironment['CLIENT'] ??
      processEnvironment['APP_FLAVOR'] ??
      (fallback is String ? fallback : 'development');
  _validateFlavorName(name);
  final inline = flavors[name];
  if (inline is! YamlMap) {
    throw FormatException('SQLite Loom flavor is not defined: $name');
  }
  final values = _stringMap(inline);
  final overrides = runner['flavor_overrides_directory'];
  if (overrides is String && overrides.trim().isNotEmpty) {
    final root = p.normalize(
      p.absolute(projectFile.parent.path, overrides.trim()),
    );
    final override = File(p.join(root, '$name.yaml'));
    if (!p.isWithin(root, p.normalize(p.absolute(override.path)))) {
      throw FormatException('Flavor override escapes its directory: $name');
    }
    if (override.existsSync()) {
      final overrideYaml = loadYaml(override.readAsStringSync());
      if (overrideYaml is! YamlMap) {
        throw FormatException('${override.path} must contain a YAML map.');
      }
      _merge(values, _stringMap(overrideYaml));
    }
  }
  final database = values['database'];
  final safety = values['safety'];
  if (database is! Map || database['path'] is! String) {
    throw FormatException('Flavor $name must define database.path.');
  }
  final configuredEnvironment = values['environment'];
  final configuredDestructive = safety is Map
      ? safety['allow_destructive']
      : null;
  return LoomFlavorSelection(
    name: name,
    databasePath: _environmentValue(
      'SQLITE_LOOM_DATABASE',
      database['path']! as String,
      processEnvironment,
    ),
    environment: _environmentValue(
      'SQLITE_LOOM_ENVIRONMENT',
      configuredEnvironment is String ? configuredEnvironment : name,
      processEnvironment,
    ),
    allowDestructive: _environmentBoolean(
      'SQLITE_LOOM_ALLOW_DESTRUCTIVE',
      configuredDestructive is bool ? configuredDestructive : false,
      processEnvironment,
    ),
    arguments: List.unmodifiable(forwarded),
  );
}