1.1.0-alpha
This commit is contained in:
parent
a116cb4515
commit
6da8204411
5 changed files with 60 additions and 48 deletions
19
README.md
19
README.md
|
@ -1,4 +1,4 @@
|
||||||
# Angel Configuration
|
# configuration
|
||||||
|
|
||||||
[](https://pub.dartlang.org/packages/angel_configuration)
|
[](https://pub.dartlang.org/packages/angel_configuration)
|
||||||
[](https://travis-ci.org/angel-dart/configuration)
|
[](https://travis-ci.org/angel-dart/configuration)
|
||||||
|
@ -7,7 +7,7 @@ Automatic YAML configuration loader for Angel.
|
||||||
|
|
||||||
# About
|
# About
|
||||||
Any web app needs different configuration for development and production. This plugin will search
|
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
|
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
|
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. :)
|
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.
|
applying YAML configuration.
|
||||||
|
|
||||||
**Server-side**
|
**Server-side**
|
||||||
Call `loadConfigurationFile()`. The loaded properties will be available in your application's
|
Call `configuration()`. The loaded configuration will be available in your application's
|
||||||
`properties` map, which means you can access them like normal instance members.
|
`configuration` map, which means you can access them like normal instance members.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
main() {
|
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 'dart:io';
|
||||||
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';
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
Angel angel = new Angel();
|
var app = new Angel();
|
||||||
angel.configure(loadConfigurationFile()); // It's that easy!
|
var fileSystem = const LocalFileSystem();
|
||||||
|
|
||||||
|
await app.configure(configuration(fileSystem)); // It's that easy!
|
||||||
|
|
||||||
app.get('/foo', (Configuration config) {
|
app.get('/foo', (Configuration config) {
|
||||||
return config.some_key;
|
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
|
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`).
|
override `$ANGEL_ENV` by specifying a specific configuration name to look for (i.e. `production`).
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
library angel_configuration;
|
library angel_configuration;
|
||||||
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:dotenv/dotenv.dart' as dotenv;
|
import 'package:dotenv/dotenv.dart' as dotenv;
|
||||||
|
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';
|
||||||
|
|
||||||
|
@ -16,18 +16,18 @@ class Configuration {
|
||||||
final Angel app;
|
final Angel app;
|
||||||
Configuration(this.app);
|
Configuration(this.app);
|
||||||
|
|
||||||
operator [](key) => app.properties[key];
|
operator [](key) => app.configuration[key];
|
||||||
operator []=(key, value) => app.properties[key] = value;
|
operator []=(key, value) => app.configuration[key] = value;
|
||||||
|
|
||||||
noSuchMethod(Invocation invocation) {
|
noSuchMethod(Invocation invocation) {
|
||||||
if (invocation.memberName != null) {
|
if (invocation.memberName != null) {
|
||||||
String name = _sym.firstMatch(invocation.memberName.toString()).group(1);
|
String name = _sym.firstMatch(invocation.memberName.toString()).group(1);
|
||||||
|
|
||||||
if (invocation.isMethod) {
|
if (invocation.isMethod) {
|
||||||
return Function.apply(app.properties[name],
|
return Function.apply(app.configuration[name],
|
||||||
invocation.positionalArguments, invocation.namedArguments);
|
invocation.positionalArguments, invocation.namedArguments);
|
||||||
} else if (invocation.isGetter) {
|
} 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 {
|
_loadYamlFile(Angel app, File yamlFile, Map<String, String> env) 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) {
|
||||||
stderr.writeln(
|
app.logger?.warning(
|
||||||
'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.');
|
'WARNING: The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,12 +48,12 @@ _loadYamlFile(Angel app, File yamlFile, Map<String, String> env) async {
|
||||||
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 ?? {});
|
out[key] = _applyEnv(config[key], env ?? {}, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.properties.addAll(mergeMap(
|
app.configuration.addAll(mergeMap(
|
||||||
[
|
[
|
||||||
app.properties,
|
app.configuration,
|
||||||
out,
|
out,
|
||||||
],
|
],
|
||||||
acceptNull: true,
|
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 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 {
|
||||||
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`.');
|
'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 ?? {})).toList();
|
return v.map((x) => _applyEnv(x, env ?? {}, app)).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 ?? {}));
|
.fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, app));
|
||||||
} else
|
} else
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -88,21 +89,21 @@ _applyEnv(var v, Map<String, String> env) {
|
||||||
/// load from a [overrideEnvironmentName].
|
/// load from a [overrideEnvironmentName].
|
||||||
///
|
///
|
||||||
/// You can also specify a custom [envPath] to load system configuration from.
|
/// You can also specify a custom [envPath] to load system configuration from.
|
||||||
AngelConfigurer loadConfigurationFile(
|
AngelConfigurer configuration(
|
||||||
|
FileSystem fileSystem,
|
||||||
{String directoryPath: "./config",
|
{String directoryPath: "./config",
|
||||||
String overrideEnvironmentName,
|
String overrideEnvironmentName,
|
||||||
String envPath}) {
|
String envPath}) {
|
||||||
return (Angel app) async {
|
return (Angel app) async {
|
||||||
Directory sourceDirectory = new Directory(directoryPath);
|
Directory sourceDirectory = fileSystem.directory(directoryPath);
|
||||||
var env = dotenv.env;
|
var env = dotenv.env;
|
||||||
var envFile =
|
var envFile = sourceDirectory.childFile(envPath ?? '.env');
|
||||||
new File.fromUri(sourceDirectory.uri.resolve(envPath ?? '.env'));
|
|
||||||
|
|
||||||
if (await envFile.exists()) {
|
if (await envFile.exists()) {
|
||||||
try {
|
try {
|
||||||
dotenv.load(envFile.absolute.uri.toFilePath());
|
dotenv.load(envFile.absolute.uri.toFilePath());
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
stderr.writeln(
|
app.logger?.warning(
|
||||||
'WARNING: Found an environment configuration at ${envFile.absolute.path}, but it was invalidly formatted. Refusing to load it.');
|
'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;
|
environmentName = overrideEnvironmentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
File defaultYaml =
|
var defaultYaml = sourceDirectory.childFile('default.yaml');
|
||||||
new File.fromUri(sourceDirectory.absolute.uri.resolve("default.yaml"));
|
|
||||||
await _loadYamlFile(app, defaultYaml, env);
|
await _loadYamlFile(app, defaultYaml, env);
|
||||||
|
|
||||||
String configFilePath = "$environmentName.yaml";
|
String configFilePath = "$environmentName.yaml";
|
||||||
File configFile =
|
var configFile = sourceDirectory.childFile(configFilePath);
|
||||||
new File.fromUri(sourceDirectory.absolute.uri.resolve(configFilePath));
|
|
||||||
|
|
||||||
await _loadYamlFile(app, configFile, env);
|
await _loadYamlFile(app, configFile, env);
|
||||||
app.container.singleton(new Configuration(app));
|
app.container.singleton(new Configuration(app));
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
import 'package:analyzer/analyzer.dart';
|
import 'package:analyzer/analyzer.dart';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:file/local.dart';
|
||||||
import 'angel_configuration.dart';
|
import 'angel_configuration.dart';
|
||||||
|
|
||||||
class ConfigurationTransformer extends Transformer {
|
class ConfigurationTransformer extends Transformer {
|
||||||
|
@ -17,9 +18,11 @@ class ConfigurationTransformer extends Transformer {
|
||||||
try {
|
try {
|
||||||
var app = new Angel();
|
var app = new Angel();
|
||||||
|
|
||||||
await app.configure(loadConfigurationFile(
|
await app.configure(configuration(
|
||||||
directoryPath: _settings.configuration["dir"] ?? "./config",
|
const LocalFileSystem(),
|
||||||
overrideEnvironmentName: _settings.configuration["env"]));
|
directoryPath: _settings.configuration["dir"] ?? "./config",
|
||||||
|
overrideEnvironmentName: _settings.configuration["env"],
|
||||||
|
));
|
||||||
|
|
||||||
var text = await transform.primaryInput.readAsString();
|
var text = await transform.primaryInput.readAsString();
|
||||||
var compilationUnit = parseCompilationUnit(text);
|
var compilationUnit = parseCompilationUnit(text);
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
name: angel_configuration
|
name: angel_configuration
|
||||||
description: Automatic YAML configuration loader for Angel.
|
description: Automatic YAML configuration loader for Angel.
|
||||||
version: 1.0.5
|
version: 1.1.0-alpha
|
||||||
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:
|
||||||
sdk: ">=1.19.0"
|
sdk: ">=1.19.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
analyzer: ">=0.28.1 <1.0.0"
|
analyzer: ">=0.28.1 <1.0.0"
|
||||||
angel_framework: ^1.0.0-dev
|
angel_framework: ^1.1.0-alpha
|
||||||
barback: ^0.15.2
|
barback: ^0.15.2
|
||||||
dotenv: ^0.1.0
|
dotenv: ^0.1.0
|
||||||
|
file: ^2.0.0
|
||||||
merge_map: ^1.0.0
|
merge_map: ^1.0.0
|
||||||
yaml: ^2.0.0
|
yaml: ^2.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
@ -1,43 +1,49 @@
|
||||||
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:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'transformer.dart' as transformer;
|
import 'transformer.dart' as transformer;
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
// Note: Set ANGEL_ENV to 'development'
|
// Note: Set ANGEL_ENV to 'development'
|
||||||
var app = new Angel();
|
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 {
|
test('can load based on ANGEL_ENV', () async {
|
||||||
expect(app.properties['hello'], equals('world'));
|
expect(app.configuration['hello'], equals('world'));
|
||||||
expect(app.properties['foo']['version'], equals('bar'));
|
expect(app.configuration['foo']['version'], equals('bar'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('will load default.yaml if exists', () {
|
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', () {
|
test('will load .env if exists', () {
|
||||||
expect(app.properties['artist'], 'Timberlake');
|
expect(app.configuration['artist'], 'Timberlake');
|
||||||
expect(app.properties['angel'], {'framework': 'cool'});
|
expect(app.configuration['angel'], {'framework': 'cool'});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('non-existent environment defaults to null', () {
|
test('non-existent environment defaults to null', () {
|
||||||
expect(app.properties.keys, contains('must_be_null'));
|
expect(app.configuration.keys, contains('must_be_null'));
|
||||||
expect(app.properties['must_be_null'], null);
|
expect(app.configuration['must_be_null'], null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can override ANGEL_ENV', () async {
|
test('can override ANGEL_ENV', () async {
|
||||||
await app.configure(loadConfigurationFile(
|
await app.configure(configuration(fileSystem,
|
||||||
directoryPath: './test/config', overrideEnvironmentName: 'override'));
|
directoryPath: './test/config', overrideEnvironmentName: 'override'));
|
||||||
expect(app.properties['hello'], equals('goodbye'));
|
expect(app.configuration['hello'], equals('goodbye'));
|
||||||
expect(app.properties['foo']['version'], equals('baz'));
|
expect(app.configuration['foo']['version'], equals('baz'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('merges configuration', () async {
|
test('merges configuration', () async {
|
||||||
await app.configure(loadConfigurationFile(
|
await app.configure(configuration(fileSystem,
|
||||||
directoryPath: './test/config', overrideEnvironmentName: 'override'));
|
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);
|
group("transformer", transformer.main);
|
||||||
|
|
Loading…
Reference in a new issue