Use `package:config` WIP
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index 6290bac..369668e 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -6,6 +6,7 @@
import 'dart:io';
+import 'package:config/config.dart' as pkg_config;
import 'package:ffigen/src/code_generator.dart';
import 'package:logging/logging.dart';
import 'package:package_config/package_config_types.dart';
@@ -22,11 +23,9 @@
/// Handles validation, extraction of confiurations from yaml file.
class Config {
/// Input filename.
- String? get filename => _filename;
String? _filename;
/// Package config.
- PackageConfig? get packageConfig => _packageConfig;
PackageConfig? _packageConfig;
/// Location for llvm/lib folder.
@@ -177,17 +176,32 @@
/// Create config from Yaml map.
factory Config.fromYaml(YamlMap map,
{String? filename, PackageConfig? packageConfig}) {
+ final config = pkg_config.Config(
+ fileParsed: map.cast(),
+ fileSourceUri: Uri(path: filename),
+ );
+
+ return Config.fromConfig(
+ config,
+ filename: filename,
+ packageConfig: packageConfig,
+ );
+ }
+
+ /// Create config from Yaml map.
+ factory Config.fromConfig(pkg_config.Config config,
+ {String? filename, PackageConfig? packageConfig}) {
final configspecs = Config._(filename, packageConfig);
- _logger.finest('Config Map: $map');
+ _logger.finest('Config: $config');
final specs = configspecs._getSpecs();
- final result = configspecs._checkConfigs(map, specs);
+ final result = configspecs._checkConfigs(config, specs);
if (!result) {
throw FormatException('Invalid configurations provided.');
}
- configspecs._extract(map, specs);
+ configspecs._extract(config, specs);
return configspecs;
}
@@ -212,12 +226,14 @@
}
/// Validates Yaml according to given specs.
- bool _checkConfigs(YamlMap map, Map<List<String>, Specification> specs) {
+ bool _checkConfigs(
+ pkg_config.Config config, Map<List<String>, Specification> specs) {
var result = true;
for (final key in specs.keys) {
final spec = specs[key];
- if (checkKeyInYaml(key, map)) {
- result = result && spec!.validator(key, getKeyValueFromYaml(key, map));
+ final value = config.getFileValue<Object>(key.join('.'));
+ if (value != null) {
+ result = result && spec!.validator(key, value);
} else if (spec!.requirement == Requirement.yes) {
_logger.severe("Key '$key' is required.");
result = false;
@@ -226,7 +242,10 @@
}
}
// Warn about unknown keys.
- warnUnknownKeys(specs.keys.toList(), map);
+ // warnUnknownKeys(specs.keys.toList(), map);
+ // TODO(dacoharkes): Should the config allow access to the list of keys?
+ // Should that access be uniform across env/cli/file? Environment is not
+ // going to be empty.
return result;
}
@@ -234,23 +253,22 @@
/// Extracts variables from Yaml according to given specs.
///
/// Validation must be done beforehand, using [_checkConfigs].
- void _extract(YamlMap map, Map<List<String>, Specification> specs) {
+ void _extract(
+ pkg_config.Config config, Map<List<String>, Specification> specs) {
for (final key in specs.keys) {
- final spec = specs[key];
- if (checkKeyInYaml(key, map)) {
- spec!.extractedResult(spec.extractor(getKeyValueFromYaml(key, map)));
- } else {
- spec!.extractedResult(spec.defaultValue?.call());
- }
+ final spec = specs[key]!;
+ final value = spec.extractor(config) ?? spec.defaultValue?.call();
+ spec.extractedResult(value);
}
}
- /// Returns map of various specifications avaialble for our tool.
+ /// Returns map of various specifications available for our tool.
///
/// Key: Name, Value: [Specification]
Map<List<String>, Specification> _getSpecs() {
return <List<String>, Specification>{
[strings.llvmPath]: Specification<String>(
+ key: [strings.llvmPath],
requirement: Requirement.no,
validator: llvmPathValidator,
extractor: llvmPathExtractor,
@@ -260,16 +278,18 @@
},
),
[strings.output]: Specification<OutputConfig>(
+ key: [strings.output],
requirement: Requirement.yes,
validator: outputValidator,
extractor: (dynamic value) =>
- outputExtractor(value, filename, packageConfig),
+ outputExtractor(value, _filename, _packageConfig),
extractedResult: (dynamic result) {
_output = (result as OutputConfig).output;
_symbolFile = result.symbolFile;
},
),
[strings.language]: Specification<Language>(
+ key: [strings.language],
requirement: Requirement.no,
validator: languageValidator,
extractor: languageExtractor,
@@ -277,12 +297,14 @@
extractedResult: (dynamic result) => _language = result as Language,
),
[strings.headers]: Specification<Headers>(
+ key: [strings.headers],
requirement: Requirement.yes,
validator: headersValidator,
- extractor: (dynamic value) => headersExtractor(value, filename),
+ extractor: (dynamic value) => headersExtractor(value, _filename),
extractedResult: (dynamic result) => _headers = result as Headers,
),
[strings.compilerOpts]: Specification<List<String>>(
+ key: [strings.compilerOpts],
requirement: Requirement.no,
validator: compilerOptsValidator,
extractor: compilerOptsExtractor,
@@ -291,6 +313,7 @@
_compilerOpts = result as List<String>,
),
[strings.compilerOptsAuto]: Specification<CompilerOptsAuto>(
+ key: [strings.compilerOptsAuto],
requirement: Requirement.no,
validator: compilerOptsAutoValidator,
extractor: compilerOptsAutoExtractor,
@@ -298,8 +321,10 @@
extractedResult: (dynamic result) {
_compilerOpts
.addAll((result as CompilerOptsAuto).extractCompilerOpts());
- }),
+ },
+ ),
[strings.functions]: Specification<Declaration>(
+ key: [strings.functions],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -309,6 +334,7 @@
},
),
[strings.structs]: Specification<Declaration>(
+ key: [strings.structs],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -318,6 +344,7 @@
},
),
[strings.unions]: Specification<Declaration>(
+ key: [strings.unions],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -327,6 +354,7 @@
},
),
[strings.enums]: Specification<Declaration>(
+ key: [strings.enums],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -336,6 +364,7 @@
},
),
[strings.unnamedEnums]: Specification<Declaration>(
+ key: [strings.unnamedEnums],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -344,6 +373,7 @@
_unnamedEnumConstants = result as Declaration,
),
[strings.globals]: Specification<Declaration>(
+ key: [strings.globals],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -353,6 +383,7 @@
},
),
[strings.macros]: Specification<Declaration>(
+ key: [strings.macros],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -362,6 +393,7 @@
},
),
[strings.typedefs]: Specification<Declaration>(
+ key: [strings.typedefs],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -371,6 +403,7 @@
},
),
[strings.objcInterfaces]: Specification<Declaration>(
+ key: [strings.objcInterfaces],
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -381,6 +414,7 @@
),
[strings.objcInterfaces, strings.objcModule]:
Specification<Map<String, String>>(
+ key: [strings.objcInterfaces, strings.objcModule],
requirement: Requirement.no,
validator: stringStringMapValidator,
extractor: stringStringMapExtractor,
@@ -389,6 +423,7 @@
ObjCModulePrefixer(result as Map<String, String>),
),
[strings.libraryImports]: Specification<Map<String, LibraryImport>>(
+ key: [strings.libraryImports],
validator: libraryImportsValidator,
extractor: libraryImportsExtractor,
defaultValue: () => <String, LibraryImport>{},
@@ -398,9 +433,10 @@
),
[strings.import, strings.symbolFilesImport]:
Specification<Map<String, ImportedType>>(
+ key: [strings.import, strings.symbolFilesImport],
validator: symbolFileImportValidator,
extractor: (value) => symbolFileImportExtractor(
- value, _libraryImports, filename, packageConfig),
+ value, _libraryImports, _filename, _packageConfig),
defaultValue: () => <String, ImportedType>{},
extractedResult: (dynamic result) {
_usrTypeMappings = result as Map<String, ImportedType>;
@@ -408,6 +444,7 @@
),
[strings.typeMap, strings.typeMapTypedefs]:
Specification<Map<String, List<String>>>(
+ key: [strings.typeMap, strings.typeMapTypedefs],
validator: typeMapValidator,
extractor: typeMapExtractor,
defaultValue: () => <String, List<String>>{},
@@ -418,6 +455,7 @@
),
[strings.typeMap, strings.typeMapStructs]:
Specification<Map<String, List<String>>>(
+ key: [strings.typeMap, strings.typeMapStructs],
validator: typeMapValidator,
extractor: typeMapExtractor,
defaultValue: () => <String, List<String>>{},
@@ -428,6 +466,7 @@
),
[strings.typeMap, strings.typeMapUnions]:
Specification<Map<String, List<String>>>(
+ key: [strings.typeMap, strings.typeMapUnions],
validator: typeMapValidator,
extractor: typeMapExtractor,
defaultValue: () => <String, List<String>>{},
@@ -438,6 +477,7 @@
),
[strings.typeMap, strings.typeMapNativeTypes]:
Specification<Map<String, List<String>>>(
+ key: [strings.typeMap, strings.typeMapNativeTypes],
validator: typeMapValidator,
extractor: typeMapExtractor,
defaultValue: () => <String, List<String>>{},
@@ -447,29 +487,36 @@
},
),
[strings.excludeAllByDefault]: Specification<bool>(
+ key: [strings.excludeAllByDefault],
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
+ extractor2: booleanExtractor2,
defaultValue: () => false,
extractedResult: (dynamic result) =>
_excludeAllByDefault = result as bool,
),
[strings.sort]: Specification<bool>(
+ key: [strings.sort],
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
+ extractor2: booleanExtractor2,
defaultValue: () => false,
extractedResult: (dynamic result) => _sort = result as bool,
),
[strings.useSupportedTypedefs]: Specification<bool>(
+ key: [strings.useSupportedTypedefs],
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
+ extractor2: booleanExtractor2,
defaultValue: () => true,
extractedResult: (dynamic result) =>
_useSupportedTypedefs = result as bool,
),
[strings.comments]: Specification<CommentType>(
+ key: [strings.comments],
requirement: Requirement.no,
validator: commentValidator,
extractor: commentExtractor,
@@ -479,6 +526,7 @@
),
[strings.structs, strings.dependencyOnly]:
Specification<CompoundDependencies>(
+ key: [strings.structs, strings.dependencyOnly],
requirement: Requirement.no,
validator: dependencyOnlyValidator,
extractor: dependencyOnlyExtractor,
@@ -488,6 +536,7 @@
),
[strings.unions, strings.dependencyOnly]:
Specification<CompoundDependencies>(
+ key: [strings.unions, strings.dependencyOnly],
requirement: Requirement.no,
validator: dependencyOnlyValidator,
extractor: dependencyOnlyExtractor,
@@ -497,6 +546,7 @@
),
[strings.structs, strings.structPack]:
Specification<StructPackingOverride>(
+ key: [strings.structs, strings.structPack],
requirement: Requirement.no,
validator: structPackingOverrideValidator,
extractor: structPackingOverrideExtractor,
@@ -505,6 +555,7 @@
_structPackingOverride = result as StructPackingOverride,
),
[strings.name]: Specification<String>(
+ key: [strings.name],
requirement: Requirement.prefer,
validator: dartClassNameValidator,
extractor: stringExtractor,
@@ -512,6 +563,7 @@
extractedResult: (dynamic result) => _wrapperName = result as String,
),
[strings.description]: Specification<String?>(
+ key: [strings.description],
requirement: Requirement.prefer,
validator: nonEmptyStringValidator,
extractor: stringExtractor,
@@ -520,20 +572,24 @@
_wrapperDocComment = result as String?,
),
[strings.preamble]: Specification<String?>(
+ key: [strings.preamble],
requirement: Requirement.no,
validator: nonEmptyStringValidator,
extractor: stringExtractor,
extractedResult: (dynamic result) => _preamble = result as String?,
),
[strings.useDartHandle]: Specification<bool>(
+ key: [strings.useDartHandle],
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
+ extractor2: booleanExtractor2,
defaultValue: () => true,
extractedResult: (dynamic result) => _useDartHandle = result as bool,
),
[strings.functions, strings.exposeFunctionTypedefs]:
Specification<Includer>(
+ key: [strings.functions, strings.exposeFunctionTypedefs],
requirement: Requirement.no,
validator: exposeFunctionTypeValidator,
extractor: exposeFunctionTypeExtractor,
@@ -542,6 +598,7 @@
_exposeFunctionTypedefs = result as Includer,
),
[strings.functions, strings.leafFunctions]: Specification<Includer>(
+ key: [strings.functions, strings.leafFunctions],
requirement: Requirement.no,
validator: leafFunctionValidator,
extractor: leafFunctionExtractor,
@@ -550,6 +607,7 @@
_leafFunctions = result as Includer,
),
[strings.ffiNative]: Specification<FfiNativeConfig>(
+ key: [strings.ffiNative],
requirement: Requirement.no,
validator: ffiNativeValidator,
extractor: ffiNativeExtractor,
diff --git a/lib/src/config_provider/config_types.dart b/lib/src/config_provider/config_types.dart
index 8521bdb..a6b8f83 100644
--- a/lib/src/config_provider/config_types.dart
+++ b/lib/src/config_provider/config_types.dart
@@ -5,6 +5,7 @@
/// Contains all the neccesary classes required by config.
import 'dart:io';
+import 'package:config/config.dart' as pkg_config;
import 'package:quiver/pattern.dart' as quiver;
import 'path_finder.dart';
@@ -67,17 +68,21 @@
///
/// [E] is the return type of the extractedResult.
class Specification<E> {
+ final List<String> key;
final bool Function(List<String> name, dynamic value) validator;
- final E Function(dynamic map) extractor;
+ final E Function(pkg_config.Config config) extractor;
+ final E? Function(pkg_config.Config config, List<String> key)? extractor2;
final E Function()? defaultValue;
final Requirement requirement;
final void Function(dynamic result) extractedResult;
Specification({
+ required this.key,
required this.extractedResult,
required this.validator,
required this.extractor,
+ this.extractor2,
this.defaultValue,
this.requirement = Requirement.no,
});
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 9b03ebb..426a531 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -4,6 +4,7 @@
import 'dart:io';
+import 'package:config/config.dart' as pkg_config;
import 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/code_generator/utils.dart';
import 'package:file/local.dart';
@@ -113,6 +114,9 @@
}
}
+bool? booleanExtractor2(pkg_config.Config config, List<String> key) =>
+ config.getBool(key.join('.'));
+
bool booleanExtractor(dynamic value) => value as bool;
bool booleanValidator(List<String> name, dynamic value) =>
diff --git a/lib/src/executables/ffigen.dart b/lib/src/executables/ffigen.dart
index c37cb4f..473a815 100644
--- a/lib/src/executables/ffigen.dart
+++ b/lib/src/executables/ffigen.dart
@@ -7,6 +7,7 @@
import 'package:args/args.dart';
import 'package:cli_util/cli_logging.dart' show Ansi;
+import 'package:config/config.dart' as pkg_config;
import 'package:ffigen/ffigen.dart';
import 'package:logging/logging.dart';
import 'package:package_config/package_config.dart';
@@ -75,9 +76,16 @@
// Parse config from yaml.
if (result.wasParsed(conf)) {
- config = getConfigFromCustomYaml(result[conf] as String, packageConfig);
+ config = getConfigFromCustomYaml(
+ result[conf] as String,
+ packageConfig,
+ result['defines'] as List<String>,
+ );
} else {
- config = getConfigFromPubspec(packageConfig);
+ config = getConfigFromPubspec(
+ packageConfig,
+ result['defines'] as List<String>,
+ );
}
// Add compiler options from command line.
@@ -91,7 +99,10 @@
}
/// Extracts configuration from pubspec file.
-Config getConfigFromPubspec(PackageConfig? packageConfig) {
+Config getConfigFromPubspec(
+ PackageConfig? packageConfig,
+ List<String> cliDefines,
+) {
final pubspecFile = File(pubspecName);
if (!pubspecFile.existsSync()) {
@@ -110,12 +121,24 @@
_logger.severe("Couldn't find an entry for '$configKey' in $pubspecName.");
exit(1);
}
- return Config.fromYaml(bindingsConfigMap,
+
+ final config = pkg_config.Config(
+ cliDefines: cliDefines,
+ environment: Platform.environment,
+ fileParsed: bindingsConfigMap.cast(),
+ fileSourceUri: pubspecFile.uri,
+ );
+
+ return Config.fromConfig(config,
filename: pubspecFile.path, packageConfig: packageConfig);
}
/// Extracts configuration from a custom yaml file.
-Config getConfigFromCustomYaml(String yamlPath, PackageConfig? packageConfig) {
+Config getConfigFromCustomYaml(
+ String yamlPath,
+ PackageConfig? packageConfig,
+ List<String> cliDefines,
+) {
final yamlFile = File(yamlPath);
if (!yamlFile.existsSync()) {
@@ -123,7 +146,14 @@
exit(1);
}
- return Config.fromFile(yamlFile, packageConfig: packageConfig);
+ final config = pkg_config.Config(
+ cliDefines: cliDefines,
+ environment: Platform.environment,
+ fileContents: yamlFile.readAsStringSync(),
+ fileSourceUri: yamlFile.uri,
+ );
+
+ return Config.fromConfig(config, packageConfig: packageConfig);
}
/// Parses the cmd line arguments.
@@ -158,6 +188,15 @@
compilerOpts,
help: 'Compiler options for clang. (E.g --$compilerOpts "-I/headers -W")',
);
+ parser.addMultiOption(
+ 'define',
+ abbr: 'D',
+ help: '''Define or override a config property from command line.
+The same option can be passed multiple times.
+Keys should only contain lower-case alphanumeric characters, underscores,
+and '.'s''',
+ );
+
ArgResults results;
try {
diff --git a/pubspec.yaml b/pubspec.yaml
index 96c6027..3f31570 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,6 +2,9 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+# DO NOT MERGE: prototype.
+publish_to: none
+
name: ffigen
version: 7.2.7
description: Generator for FFI bindings, using LibClang to parse C header files.
@@ -22,6 +25,10 @@
file: ^6.0.0
package_config: ^2.1.0
yaml_edit: ^2.0.3
+ config:
+ git:
+ url: https://github.com/dcharkes/config.git
+ ref: c9a6a3fb1050e2429289f0a98d5b5f97d5b988da
dev_dependencies:
lints: ^2.0.1