platform/lib/angel_configuration.dart

128 lines
3.8 KiB
Dart
Raw Normal View History

2016-04-22 01:17:31 +00:00
library angel_configuration;
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
2017-06-14 18:48:13 +00:00
import 'package:dotenv/dotenv.dart' as dotenv;
2017-08-16 00:29:13 +00:00
import 'package:merge_map/merge_map.dart';
2016-04-22 01:17:31 +00:00
import 'package:yaml/yaml.dart';
2016-11-23 20:51:20 +00:00
final RegExp _equ = new RegExp(r'=$');
final RegExp _sym = new RegExp(r'Symbol\("([^"]+)"\)');
2017-06-14 18:48:13 +00:00
/// A proxy object that encapsulates a server's configuration.
2016-11-23 23:40:42 +00:00
@proxy
2016-11-23 20:51:20 +00:00
class Configuration {
2017-06-14 18:48:13 +00:00
/// The [Angel] instance that loaded this configuration.
2016-11-23 20:51:20 +00:00
final Angel app;
Configuration(this.app);
operator [](key) => app.properties[key];
operator []=(key, value) => app.properties[key] = value;
noSuchMethod(Invocation invocation) {
if (invocation.memberName != null) {
String name = _sym.firstMatch(invocation.memberName.toString()).group(1);
if (invocation.isMethod) {
2017-06-14 18:48:13 +00:00
return Function.apply(app.properties[name],
invocation.positionalArguments, invocation.namedArguments);
2016-11-23 20:51:20 +00:00
} else if (invocation.isGetter) {
return app.properties[name];
}
}
super.noSuchMethod(invocation);
}
}
2017-06-14 18:48:13 +00:00
_loadYamlFile(Angel app, File yamlFile, Map<String, String> env) async {
2016-05-02 23:35:21 +00:00
if (await yamlFile.exists()) {
2017-06-14 18:48:13 +00:00
var config = loadYaml(await yamlFile.readAsString());
if (config is! Map) {
stderr.writeln(
'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.');
return;
}
2017-08-16 00:29:13 +00:00
Map<String, dynamic> out = {};
2016-04-22 01:17:31 +00:00
for (String key in config.keys) {
2017-08-16 00:29:13 +00:00
out[key] = _applyEnv(config[key], env ?? {});
2016-04-22 01:17:31 +00:00
}
2017-08-16 00:29:13 +00:00
app.properties.addAll(mergeMap(
[
app.properties,
out,
],
acceptNull: true,
));
2016-04-22 01:17:31 +00:00
}
}
2017-06-14 18:48:13 +00:00
_applyEnv(var v, Map<String, String> env) {
if (v is String) {
if (v.startsWith(r'$') && v.length > 1) {
var key = v.substring(1);
if (env.containsKey(key))
return env[key];
else {
stderr.writeln(
'Your configuration calls for loading the value of "$key" from the system environment, but it is not defined. Defaulting to `null`.');
return null;
}
} else
return v;
} else if (v is Iterable) {
return v.map((x) => _applyEnv(x, env ?? {})).toList();
} else if (v is Map) {
return v.keys
.fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}));
} else
return v;
}
/// Dynamically loads application configuration from configuration files.
2017-08-16 00:29:13 +00:00
///
/// You can modify which [directoryPath] to search in, or explicitly
/// load from a [overrideEnvironmentName].
///
/// You can also specify a custom [envPath] to load system configuration from.
2017-06-14 18:48:13 +00:00
AngelConfigurer loadConfigurationFile(
2017-08-16 00:29:13 +00:00
{String directoryPath: "./config",
String overrideEnvironmentName,
String envPath}) {
2016-05-02 23:35:21 +00:00
return (Angel app) async {
2016-04-22 01:17:31 +00:00
Directory sourceDirectory = new Directory(directoryPath);
2017-06-14 18:48:13 +00:00
var env = dotenv.env;
2017-08-16 00:29:13 +00:00
var envFile =
new File.fromUri(sourceDirectory.uri.resolve(envPath ?? '.env'));
2017-06-14 18:48:13 +00:00
if (await envFile.exists()) {
try {
dotenv.load(envFile.absolute.uri.toFilePath());
} catch (_) {
stderr.writeln(
'WARNING: Found an environment configuration at ${envFile.absolute.path}, but it was invalidly formatted. Refusing to load it.');
}
}
String environmentName = env['ANGEL_ENV'] ?? 'development';
2016-04-22 01:17:31 +00:00
if (overrideEnvironmentName != null) {
environmentName = overrideEnvironmentName;
}
2017-06-14 18:48:13 +00:00
File defaultYaml =
new File.fromUri(sourceDirectory.absolute.uri.resolve("default.yaml"));
await _loadYamlFile(app, defaultYaml, env);
2016-04-22 01:17:31 +00:00
String configFilePath = "$environmentName.yaml";
2017-06-14 18:48:13 +00:00
File configFile =
new File.fromUri(sourceDirectory.absolute.uri.resolve(configFilePath));
2016-04-22 01:17:31 +00:00
2017-06-14 18:48:13 +00:00
await _loadYamlFile(app, configFile, env);
2016-11-28 02:03:05 +00:00
app.container.singleton(new Configuration(app));
2016-04-22 01:17:31 +00:00
};
2017-06-14 18:48:13 +00:00
}