1.1.0-alpha

This commit is contained in:
Tobe O 2017-09-25 09:50:56 -04:00
parent a116cb4515
commit 6da8204411
5 changed files with 60 additions and 48 deletions

View file

@ -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`).

View file

@ -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<String, String> 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<String, String> env) async {
Map<String, dynamic> 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<String, String> env) async {
}
}
_applyEnv(var v, Map<String, String> env) {
_applyEnv(var v, Map<String, String> 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<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}));
.fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, app));
} else
return v;
}
@ -88,21 +89,21 @@ _applyEnv(var v, Map<String, String> 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));

View file

@ -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);

View file

@ -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 <thosakwe@gmail.com>
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:

View file

@ -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);