From 6da82044115e4d0ebf619dd824232954940e3461 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Mon, 25 Sep 2017 09:50:56 -0400 Subject: [PATCH] 1.1.0-alpha --- README.md | 19 +++++++++------- lib/angel_configuration.dart | 43 ++++++++++++++++++------------------ lib/transformer.dart | 9 +++++--- pubspec.yaml | 5 +++-- test/all_test.dart | 32 ++++++++++++++++----------- 5 files changed, 60 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 163bb883..213338d9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Angel Configuration +# configuration [![Pub](https://img.shields.io/pub/v/angel_configuration.svg)](https://pub.dartlang.org/packages/angel_configuration) [![build status](https://travis-ci.org/angel-dart/configuration.svg)](https://travis-ci.org/angel-dart/configuration) @@ -7,7 +7,7 @@ Automatic YAML configuration loader for Angel. # About Any web app needs different configuration for development and production. This plugin will search -for a `config/default.yaml` file. If it is found, configuration from it is loaded into `app.properties`. +for a `config/default.yaml` file. If it is found, configuration from it is loaded into `app.configuration`. Then, it will look for a `config/$ANGEL_ENV` file. (i.e. config/development.yaml). If this found, all of its configuration be loaded, and will override anything loaded from the `default.yaml` file. This allows for your app to work under different conditions without you re-coding anything. :) @@ -42,12 +42,12 @@ If a `.env` file is present in your configuration directory, then it will be loa applying YAML configuration. **Server-side** -Call `loadConfigurationFile()`. The loaded properties will be available in your application's -`properties` map, which means you can access them like normal instance members. +Call `configuration()`. The loaded configuration will be available in your application's +`configuration` map, which means you can access them like normal instance members. ```dart main() { - print(app.foo == app.properties['foo']); // true + print(app.foo == app.configuration['foo']); // true } ``` @@ -58,10 +58,13 @@ the same way: import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_configuration/angel_configuration.dart'; +import 'package:file/local.dart'; main() async { - Angel angel = new Angel(); - angel.configure(loadConfigurationFile()); // It's that easy! + var app = new Angel(); + var fileSystem = const LocalFileSystem(); + + await app.configure(configuration(fileSystem)); // It's that easy! app.get('/foo', (Configuration config) { return config.some_key; @@ -69,7 +72,7 @@ main() async { } ``` -`loadConfigurationFile` also accepts a `sourceDirectory` or `overrideEnvironmentName` parameter. +`configuration` also accepts a `sourceDirectory` or `overrideEnvironmentName` parameter. 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`). diff --git a/lib/angel_configuration.dart b/lib/angel_configuration.dart index 4ac626ed..7ab73796 100644 --- a/lib/angel_configuration.dart +++ b/lib/angel_configuration.dart @@ -1,8 +1,8 @@ library angel_configuration; -import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:dotenv/dotenv.dart' as dotenv; +import 'package:file/file.dart'; import 'package:merge_map/merge_map.dart'; import 'package:yaml/yaml.dart'; @@ -16,18 +16,18 @@ class Configuration { final Angel app; Configuration(this.app); - operator [](key) => app.properties[key]; - operator []=(key, value) => app.properties[key] = value; + operator [](key) => app.configuration[key]; + operator []=(key, value) => app.configuration[key] = value; noSuchMethod(Invocation invocation) { if (invocation.memberName != null) { String name = _sym.firstMatch(invocation.memberName.toString()).group(1); if (invocation.isMethod) { - return Function.apply(app.properties[name], + return Function.apply(app.configuration[name], invocation.positionalArguments, invocation.namedArguments); } else if (invocation.isGetter) { - return app.properties[name]; + return app.configuration[name]; } } @@ -38,8 +38,9 @@ class Configuration { _loadYamlFile(Angel app, File yamlFile, Map env) async { if (await yamlFile.exists()) { var config = loadYaml(await yamlFile.readAsString()); + if (config is! Map) { - stderr.writeln( + app.logger?.warning( 'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.'); return; } @@ -47,12 +48,12 @@ _loadYamlFile(Angel app, File yamlFile, Map env) async { Map out = {}; for (String key in config.keys) { - out[key] = _applyEnv(config[key], env ?? {}); + out[key] = _applyEnv(config[key], env ?? {}, app); } - app.properties.addAll(mergeMap( + app.configuration.addAll(mergeMap( [ - app.properties, + app.configuration, out, ], acceptNull: true, @@ -60,24 +61,24 @@ _loadYamlFile(Angel app, File yamlFile, Map env) async { } } -_applyEnv(var v, Map env) { +_applyEnv(var v, Map env, Angel app) { 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( + app.logger?.warning( '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(); + return v.map((x) => _applyEnv(x, env ?? {}, app)).toList(); } else if (v is Map) { return v.keys - .fold({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {})); + .fold({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, app)); } else return v; } @@ -88,21 +89,21 @@ _applyEnv(var v, Map env) { /// load from a [overrideEnvironmentName]. /// /// You can also specify a custom [envPath] to load system configuration from. -AngelConfigurer loadConfigurationFile( +AngelConfigurer configuration( + FileSystem fileSystem, {String directoryPath: "./config", String overrideEnvironmentName, String envPath}) { return (Angel app) async { - Directory sourceDirectory = new Directory(directoryPath); + Directory sourceDirectory = fileSystem.directory(directoryPath); var env = dotenv.env; - var envFile = - new File.fromUri(sourceDirectory.uri.resolve(envPath ?? '.env')); + var envFile = sourceDirectory.childFile(envPath ?? '.env'); if (await envFile.exists()) { try { dotenv.load(envFile.absolute.uri.toFilePath()); } catch (_) { - stderr.writeln( + app.logger?.warning( 'WARNING: Found an environment configuration at ${envFile.absolute.path}, but it was invalidly formatted. Refusing to load it.'); } } @@ -113,13 +114,11 @@ AngelConfigurer loadConfigurationFile( environmentName = overrideEnvironmentName; } - File defaultYaml = - new File.fromUri(sourceDirectory.absolute.uri.resolve("default.yaml")); + var defaultYaml = sourceDirectory.childFile('default.yaml'); await _loadYamlFile(app, defaultYaml, env); String configFilePath = "$environmentName.yaml"; - File configFile = - new File.fromUri(sourceDirectory.absolute.uri.resolve(configFilePath)); + var configFile = sourceDirectory.childFile(configFilePath); await _loadYamlFile(app, configFile, env); app.container.singleton(new Configuration(app)); diff --git a/lib/transformer.dart b/lib/transformer.dart index 0bc591e8..1527ebe1 100644 --- a/lib/transformer.dart +++ b/lib/transformer.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:barback/barback.dart'; import 'package:analyzer/analyzer.dart'; import 'package:angel_framework/angel_framework.dart'; +import 'package:file/local.dart'; import 'angel_configuration.dart'; class ConfigurationTransformer extends Transformer { @@ -17,9 +18,11 @@ class ConfigurationTransformer extends Transformer { try { var app = new Angel(); - await app.configure(loadConfigurationFile( - directoryPath: _settings.configuration["dir"] ?? "./config", - overrideEnvironmentName: _settings.configuration["env"])); + await app.configure(configuration( + const LocalFileSystem(), + directoryPath: _settings.configuration["dir"] ?? "./config", + overrideEnvironmentName: _settings.configuration["env"], + )); var text = await transform.primaryInput.readAsString(); var compilationUnit = parseCompilationUnit(text); diff --git a/pubspec.yaml b/pubspec.yaml index 1e5a975c..fa3c7116 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,15 +1,16 @@ name: angel_configuration description: Automatic YAML configuration loader for Angel. -version: 1.0.5 +version: 1.1.0-alpha 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 + angel_framework: ^1.1.0-alpha barback: ^0.15.2 dotenv: ^0.1.0 + file: ^2.0.0 merge_map: ^1.0.0 yaml: ^2.0.0 dev_dependencies: diff --git a/test/all_test.dart b/test/all_test.dart index 5fa3c816..af6fd698 100644 --- a/test/all_test.dart +++ b/test/all_test.dart @@ -1,43 +1,49 @@ import 'package:angel_framework/angel_framework.dart'; import 'package:angel_configuration/angel_configuration.dart'; +import 'package:file/local.dart'; import 'package:test/test.dart'; import 'transformer.dart' as transformer; main() async { // Note: Set ANGEL_ENV to 'development' var app = new Angel(); - await app.configure(loadConfigurationFile(directoryPath: './test/config')); + var fileSystem = const LocalFileSystem(); + + await app.configure(configuration( + fileSystem, + directoryPath: './test/config', + )); test('can load based on ANGEL_ENV', () async { - expect(app.properties['hello'], equals('world')); - expect(app.properties['foo']['version'], equals('bar')); + expect(app.configuration['hello'], equals('world')); + expect(app.configuration['foo']['version'], equals('bar')); }); test('will load default.yaml if exists', () { - expect(app.properties["set_via"], equals("default")); + expect(app.configuration["set_via"], equals("default")); }); test('will load .env if exists', () { - expect(app.properties['artist'], 'Timberlake'); - expect(app.properties['angel'], {'framework': 'cool'}); + expect(app.configuration['artist'], 'Timberlake'); + expect(app.configuration['angel'], {'framework': 'cool'}); }); test('non-existent environment defaults to null', () { - expect(app.properties.keys, contains('must_be_null')); - expect(app.properties['must_be_null'], null); + expect(app.configuration.keys, contains('must_be_null')); + expect(app.configuration['must_be_null'], null); }); test('can override ANGEL_ENV', () async { - await app.configure(loadConfigurationFile( + await app.configure(configuration(fileSystem, directoryPath: './test/config', overrideEnvironmentName: 'override')); - expect(app.properties['hello'], equals('goodbye')); - expect(app.properties['foo']['version'], equals('baz')); + expect(app.configuration['hello'], equals('goodbye')); + expect(app.configuration['foo']['version'], equals('baz')); }); test('merges configuration', () async { - await app.configure(loadConfigurationFile( + await app.configure(configuration(fileSystem, directoryPath: './test/config', overrideEnvironmentName: 'override')); - expect(app.properties['merge'], {'map': true, 'hello': 'goodbye'}); + expect(app.configuration['merge'], {'map': true, 'hello': 'goodbye'}); }); group("transformer", transformer.main);