This commit is contained in:
Tobe O 2018-12-31 10:41:56 -05:00
parent d9391c05fe
commit 8db7ed7bbb
4 changed files with 79 additions and 13 deletions

View file

@ -1,3 +1,6 @@
# 2.1.0
* Add `loadStandaloneConfiguration`.
# 2.0.0 # 2.0.0
* Use Angel 2. * Use Angel 2.

View file

@ -6,25 +6,26 @@ import 'package:file/file.dart';
import 'package:merge_map/merge_map.dart'; import 'package:merge_map/merge_map.dart';
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
_loadYamlFile(Angel app, File yamlFile, Map<String, String> env) async { _loadYamlFile(Map map, File yamlFile, Map<String, String> env,
void warn(String msg)) async {
if (await yamlFile.exists()) { if (await yamlFile.exists()) {
var config = loadYaml(await yamlFile.readAsString()); var config = loadYaml(await yamlFile.readAsString());
if (config is! Map) { if (config is! Map) {
app.logger?.warning( warn(
'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.'); 'The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.');
return; return;
} }
Map<String, dynamic> out = {}; Map<String, dynamic> out = {};
for (String key in config.keys) { for (String key in config.keys) {
out[key] = _applyEnv(config[key], env ?? {}, app); out[key] = _applyEnv(config[key], env ?? {}, warn);
} }
app.configuration.addAll(mergeMap( map.addAll(mergeMap(
[ [
app.configuration, map,
out, out,
], ],
acceptNull: true, acceptNull: true,
@ -32,28 +33,64 @@ _loadYamlFile(Angel app, File yamlFile, Map<String, String> env) async {
} }
} }
_applyEnv(var v, Map<String, String> env, Angel app) { _applyEnv(var v, Map<String, String> env, void warn(String msg)) {
if (v is String) { if (v is String) {
if (v.startsWith(r'$') && v.length > 1) { if (v.startsWith(r'$') && v.length > 1) {
var key = v.substring(1); var key = v.substring(1);
if (env.containsKey(key)) if (env.containsKey(key))
return env[key]; return env[key];
else { else {
app.logger?.warning( warn(
'Your configuration calls for loading the value of "$key" from the system environment, but it is not defined. Defaulting to `null`.'); 'Your configuration calls for loading the value of "$key" from the system environment, but it is not defined. Defaulting to `null`.');
return null; return null;
} }
} else } else
return v; return v;
} else if (v is Iterable) { } else if (v is Iterable) {
return v.map((x) => _applyEnv(x, env ?? {}, app)).toList(); return v.map((x) => _applyEnv(x, env ?? {}, warn)).toList();
} else if (v is Map) { } else if (v is Map) {
return v.keys return v.keys
.fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, app)); .fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, warn));
} else } else
return v; return v;
} }
/// Loads [configuration], and returns a [Map].
///
/// You can override [onWarning]; otherwise, configuration errors will throw.
Future<Map> loadStandaloneConfiguration(FileSystem fileSystem,
{String directoryPath: "./config",
String overrideEnvironmentName,
String envPath,
void onWarning(String message)}) async {
Directory sourceDirectory = fileSystem.directory(directoryPath);
var env = dotenv.env;
var envFile = sourceDirectory.childFile(envPath ?? '.env');
if (await envFile.exists()) {
dotenv.load(envFile.absolute.uri.toFilePath());
}
String environmentName = env['ANGEL_ENV'] ?? 'development';
if (overrideEnvironmentName != null) {
environmentName = overrideEnvironmentName;
}
onWarning ??= (String message) => throw new StateError(message);
var out = {};
var defaultYaml = sourceDirectory.childFile('default.yaml');
await _loadYamlFile(out, defaultYaml, env, onWarning);
String configFilePath = "$environmentName.yaml";
var configFile = sourceDirectory.childFile(configFilePath);
await _loadYamlFile(out, configFile, env, onWarning);
return out;
}
/// Dynamically loads application configuration from configuration files. /// Dynamically loads application configuration from configuration files.
/// ///
/// You can modify which [directoryPath] to search in, or explicitly /// You can modify which [directoryPath] to search in, or explicitly
@ -84,12 +121,16 @@ AngelConfigurer configuration(FileSystem fileSystem,
environmentName = overrideEnvironmentName; environmentName = overrideEnvironmentName;
} }
void warn(String message) {
app.logger?.warning('WARNING: $message');
}
var defaultYaml = sourceDirectory.childFile('default.yaml'); var defaultYaml = sourceDirectory.childFile('default.yaml');
await _loadYamlFile(app, defaultYaml, env); await _loadYamlFile(app.configuration, defaultYaml, env, warn);
String configFilePath = "$environmentName.yaml"; String configFilePath = "$environmentName.yaml";
var configFile = sourceDirectory.childFile(configFilePath); var configFile = sourceDirectory.childFile(configFilePath);
await _loadYamlFile(app, configFile, env); await _loadYamlFile(app.configuration, configFile, env, warn);
}; };
} }

View file

@ -1,6 +1,6 @@
name: angel_configuration name: angel_configuration
description: Automatic YAML configuration loader for Angel. description: Automatic YAML configuration loader for Angel.
version: 2.0.0 version: 2.1.0
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_configuration homepage: https://github.com/angel-dart/angel_configuration
environment: environment:
@ -12,4 +12,5 @@ dependencies:
merge_map: ^1.0.0 merge_map: ^1.0.0
yaml: ^2.0.0 yaml: ^2.0.0
dev_dependencies: dev_dependencies:
io: ^0.3.2
test: ^1.0.0 test: ^1.0.0

View file

@ -1,6 +1,7 @@
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'package:angel_configuration/angel_configuration.dart'; import 'package:angel_configuration/angel_configuration.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'package:io/ansi.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
main() async { main() async {
@ -13,6 +14,26 @@ main() async {
directoryPath: './test/config', directoryPath: './test/config',
)); ));
test('standalone', () async {
var config = await loadStandaloneConfiguration(
fileSystem,
directoryPath: './test/config',
onWarning: (msg) {
print(yellow.wrap('STANDALONE WARNING: $msg'));
},
);
print('Standalone: $config');
expect(config, {
"angel": {"framework": "cool"},
"must_be_null": null,
"artist": "Timberlake",
"merge": {"map": true, "hello": "world"},
"set_via": "default",
"hello": "world",
"foo": {"version": "bar"}
});
});
test('can load based on ANGEL_ENV', () async { test('can load based on ANGEL_ENV', () async {
expect(app.configuration['hello'], equals('world')); expect(app.configuration['hello'], equals('world'));
expect(app.configuration['foo']['version'], equals('bar')); expect(app.configuration['foo']['version'], equals('bar'));