diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..687b11ce --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# 1.0.5 +* Now using `package:merge_map` to merge configurations. Resolves +[#5](https://github.com/angel-dart/configuration/issues/5). +* You can now specify a custom `envPath`. \ No newline at end of file diff --git a/README.md b/README.md index b588af7e..163bb883 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,30 @@ main() async { The former will allow you to search in a directory other than `config`, and the latter lets you override `$ANGEL_ENV` by specifying a specific configuration name to look for (i.e. `production`). +This package uses +[`package:merge_map`](https://github.com/thosakwe/merge_map) +internally, so existing configurations can be deeply merged. + +Example: + +```yaml +# default.yaml +foo: + bar: baz + quux: hello + +# production.yaml +foo: + quux: goodbye + yellow: submarine + +# Propagates to: +foo: + bar: baz + quux: goodbye + yellow: submarine +``` + **In the Browser** You can easily load configuration values within your client-side app, diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..518eb901 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true \ No newline at end of file diff --git a/lib/angel_configuration.dart b/lib/angel_configuration.dart index 6e451095..4ac626ed 100644 --- a/lib/angel_configuration.dart +++ b/lib/angel_configuration.dart @@ -3,6 +3,7 @@ library angel_configuration; import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:dotenv/dotenv.dart' as dotenv; +import 'package:merge_map/merge_map.dart'; import 'package:yaml/yaml.dart'; final RegExp _equ = new RegExp(r'=$'); @@ -42,9 +43,20 @@ _loadYamlFile(Angel app, File yamlFile, Map env) async { 'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.'); return; } + + Map out = {}; + for (String key in config.keys) { - app.properties[key] = _applyEnv(config[key], env ?? {}); + out[key] = _applyEnv(config[key], env ?? {}); } + + app.properties.addAll(mergeMap( + [ + app.properties, + out, + ], + acceptNull: true, + )); } } @@ -71,12 +83,20 @@ _applyEnv(var v, Map env) { } /// Dynamically loads application configuration from configuration files. +/// +/// 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. AngelConfigurer loadConfigurationFile( - {String directoryPath: "./config", String overrideEnvironmentName}) { + {String directoryPath: "./config", + String overrideEnvironmentName, + String envPath}) { return (Angel app) async { Directory sourceDirectory = new Directory(directoryPath); var env = dotenv.env; - var envFile = new File.fromUri(sourceDirectory.uri.resolve('.env')); + var envFile = + new File.fromUri(sourceDirectory.uri.resolve(envPath ?? '.env')); if (await envFile.exists()) { try { diff --git a/pubspec.yaml b/pubspec.yaml index d46edc7f..1e5a975c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,14 +1,16 @@ name: angel_configuration description: Automatic YAML configuration loader for Angel. -version: 1.0.4 +version: 1.0.5 author: Tobe O homepage: https://github.com/angel-dart/angel_configuration +environment: + sdk: ">=1.19.0" dependencies: analyzer: ">=0.28.1 <1.0.0" - angel_framework: ">=1.0.0-dev < 2.0.0" - angel_route: ">=1.0.0-dev < 2.0.0" - barback: ">=0.15.2 < 0.16.0" - dotenv: ">=0.1.3 <0.2.0" - yaml: ">= 2.1.8 < 2.2.0" + angel_framework: ^1.0.0-dev + barback: ^0.15.2 + dotenv: ^0.1.0 + merge_map: ^1.0.0 + yaml: ^2.0.0 dev_dependencies: - test: ">= 0.12.13 < 0.13.0" + test: ^0.12.0 diff --git a/test/all_test.dart b/test/all_test.dart index cdef5909..5fa3c816 100644 --- a/test/all_test.dart +++ b/test/all_test.dart @@ -6,8 +6,7 @@ import 'transformer.dart' as transformer; main() async { // Note: Set ANGEL_ENV to 'development' var app = new Angel(); - await app.configure( - loadConfigurationFile(directoryPath: './test/config')); + await app.configure(loadConfigurationFile(directoryPath: './test/config')); test('can load based on ANGEL_ENV', () async { expect(app.properties['hello'], equals('world')); @@ -35,7 +34,11 @@ main() async { expect(app.properties['foo']['version'], equals('baz')); }); - + test('merges configuration', () async { + await app.configure(loadConfigurationFile( + directoryPath: './test/config', overrideEnvironmentName: 'override')); + expect(app.properties['merge'], {'map': true, 'hello': 'goodbye'}); + }); group("transformer", transformer.main); } diff --git a/test/config/default.yaml b/test/config/default.yaml index 11f67070..2a7d3954 100644 --- a/test/config/default.yaml +++ b/test/config/default.yaml @@ -2,4 +2,7 @@ set_via: default artist: $JUSTIN angel: framework: $ANGEL_FRAMEWORK -must_be_null: $NONEXISTENT_KEY_FOO_BAR_BAZ_QUUX \ No newline at end of file +must_be_null: $NONEXISTENT_KEY_FOO_BAR_BAZ_QUUX +merge: + map: true + hello: world \ No newline at end of file diff --git a/test/config/override.yaml b/test/config/override.yaml index e0ac5ffa..fb07c149 100644 --- a/test/config/override.yaml +++ b/test/config/override.yaml @@ -1,3 +1,5 @@ hello: goodbye foo: - version: baz \ No newline at end of file + version: baz +merge: + hello: goodbye \ No newline at end of file