Add 'packages/configuration/' from commit 'a7902feaa0a360848777b1e7b7c20d9ff848d19b'
git-subtree-dir: packages/configuration git-subtree-mainline:c77d25f6d0
git-subtree-split:a7902feaa0
This commit is contained in:
commit
bda70d18e3
15 changed files with 446 additions and 0 deletions
79
packages/configuration/.gitignore
vendored
Normal file
79
packages/configuration/.gitignore
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/vcs.xml
|
||||
.idea/jsLibraryMappings.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
.idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Dart template
|
||||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.buildlog
|
||||
.packages
|
||||
.project
|
||||
.pub/
|
||||
build/
|
||||
**/packages/
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
*.dart.js
|
||||
*.part.js
|
||||
*.js.deps
|
||||
*.js.map
|
||||
*.info.json
|
||||
|
||||
# Directory created by dartdoc
|
||||
doc/api/
|
||||
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
pubspec.lock
|
||||
|
||||
.dart_tool
|
3
packages/configuration/.travis.yml
Normal file
3
packages/configuration/.travis.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
language: dart
|
||||
dart:
|
||||
- stable
|
18
packages/configuration/CHANGELOG.md
Normal file
18
packages/configuration/CHANGELOG.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# 2.1.0
|
||||
* Add `loadStandaloneConfiguration`.
|
||||
|
||||
# 2.0.0
|
||||
* Use Angel 2.
|
||||
|
||||
# 1.2.0-rc.0
|
||||
* Removed the `Configuration` class.
|
||||
* Removed the `ConfigurationTransformer` class.
|
||||
* Use `Map` casting to prevent runtime cast errors.
|
||||
|
||||
# 1.1.0 (Retroactive changelog)
|
||||
* Use `package:file`.
|
||||
|
||||
# 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`.
|
21
packages/configuration/LICENSE
Normal file
21
packages/configuration/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 angel-dart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
74
packages/configuration/README.md
Normal file
74
packages/configuration/README.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
# 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)
|
||||
|
||||
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.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. :)
|
||||
|
||||
# Installation
|
||||
In `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
angel_configuration: ^2.0.0
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
**Example Configuration**
|
||||
```yaml
|
||||
# Define normal YAML objects
|
||||
some_key: foo
|
||||
this_is_a_map:
|
||||
a_string: "string"
|
||||
another_string: "string"
|
||||
|
||||
```
|
||||
|
||||
You can also load configuration from the environment:
|
||||
```yaml
|
||||
# Loaded from the environment
|
||||
system_path: $PATH
|
||||
```
|
||||
|
||||
If a `.env` file is present in your configuration directory, then it will be loaded before
|
||||
applying YAML configuration.
|
||||
|
||||
**Server-side**
|
||||
Call `configuration()`. The loaded configuration will be available in your application's
|
||||
`configuration` map.
|
||||
|
||||
`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`).
|
||||
|
||||
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
|
||||
```
|
3
packages/configuration/analysis_options.yaml
Normal file
3
packages/configuration/analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: true
|
9
packages/configuration/example/main.dart
Normal file
9
packages/configuration/example/main.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
import 'package:angel_configuration/angel_configuration.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:file/local.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var fs = const LocalFileSystem();
|
||||
await app.configure(configuration(fs));
|
||||
}
|
136
packages/configuration/lib/angel_configuration.dart
Normal file
136
packages/configuration/lib/angel_configuration.dart
Normal file
|
@ -0,0 +1,136 @@
|
|||
library angel_configuration;
|
||||
|
||||
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';
|
||||
|
||||
_loadYamlFile(Map map, File yamlFile, Map<String, String> env,
|
||||
void warn(String msg)) async {
|
||||
if (await yamlFile.exists()) {
|
||||
var config = loadYaml(await yamlFile.readAsString());
|
||||
|
||||
if (config is! Map) {
|
||||
warn(
|
||||
'The configuration at "${yamlFile.absolute.path}" is not a Map. Refusing to load it.');
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, dynamic> out = {};
|
||||
|
||||
for (String key in config.keys) {
|
||||
out[key] = _applyEnv(config[key], env ?? {}, warn);
|
||||
}
|
||||
|
||||
map.addAll(mergeMap(
|
||||
[
|
||||
map,
|
||||
out,
|
||||
],
|
||||
acceptNull: true,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
_applyEnv(var v, Map<String, String> env, void warn(String msg)) {
|
||||
if (v is String) {
|
||||
if (v.startsWith(r'$') && v.length > 1) {
|
||||
var key = v.substring(1);
|
||||
if (env.containsKey(key))
|
||||
return env[key];
|
||||
else {
|
||||
warn(
|
||||
'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 ?? {}, warn)).toList();
|
||||
} else if (v is Map) {
|
||||
return v.keys
|
||||
.fold<Map>({}, (out, k) => out..[k] = _applyEnv(v[k], env ?? {}, warn));
|
||||
} else
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Loads [configuration], and returns a [Map].
|
||||
///
|
||||
/// You can override [onWarning]; otherwise, configuration errors will throw.
|
||||
Future<Map> loadStandaloneConfiguration(FileSystem fileSystem,
|
||||
{String directoryPath: "./config",
|
||||
String overrideEnvironmentName,
|
||||
String envPath,
|
||||
void onWarning(String message)}) async {
|
||||
Directory sourceDirectory = fileSystem.directory(directoryPath);
|
||||
var env = dotenv.env;
|
||||
var envFile = sourceDirectory.childFile(envPath ?? '.env');
|
||||
|
||||
if (await envFile.exists()) {
|
||||
dotenv.load(envFile.absolute.uri.toFilePath());
|
||||
}
|
||||
|
||||
String environmentName = env['ANGEL_ENV'] ?? 'development';
|
||||
|
||||
if (overrideEnvironmentName != null) {
|
||||
environmentName = overrideEnvironmentName;
|
||||
}
|
||||
|
||||
onWarning ??= (String message) => throw new StateError(message);
|
||||
var out = {};
|
||||
|
||||
var defaultYaml = sourceDirectory.childFile('default.yaml');
|
||||
await _loadYamlFile(out, defaultYaml, env, onWarning);
|
||||
|
||||
String configFilePath = "$environmentName.yaml";
|
||||
var configFile = sourceDirectory.childFile(configFilePath);
|
||||
|
||||
await _loadYamlFile(out, configFile, env, onWarning);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/// 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 configuration(FileSystem fileSystem,
|
||||
{String directoryPath: "./config",
|
||||
String overrideEnvironmentName,
|
||||
String envPath}) {
|
||||
return (Angel app) async {
|
||||
Directory sourceDirectory = fileSystem.directory(directoryPath);
|
||||
var env = dotenv.env;
|
||||
var envFile = sourceDirectory.childFile(envPath ?? '.env');
|
||||
|
||||
if (await envFile.exists()) {
|
||||
try {
|
||||
dotenv.load(envFile.absolute.uri.toFilePath());
|
||||
} catch (_) {
|
||||
app.logger?.warning(
|
||||
'WARNING: Found an environment configuration at ${envFile.absolute.path}, but it was invalidly formatted. Refusing to load it.');
|
||||
}
|
||||
}
|
||||
|
||||
String environmentName = env['ANGEL_ENV'] ?? 'development';
|
||||
|
||||
if (overrideEnvironmentName != null) {
|
||||
environmentName = overrideEnvironmentName;
|
||||
}
|
||||
|
||||
void warn(String message) {
|
||||
app.logger?.warning('WARNING: $message');
|
||||
}
|
||||
|
||||
var defaultYaml = sourceDirectory.childFile('default.yaml');
|
||||
await _loadYamlFile(app.configuration, defaultYaml, env, warn);
|
||||
|
||||
String configFilePath = "$environmentName.yaml";
|
||||
var configFile = sourceDirectory.childFile(configFilePath);
|
||||
|
||||
await _loadYamlFile(app.configuration, configFile, env, warn);
|
||||
};
|
||||
}
|
1
packages/configuration/lib/browser.dart
Normal file
1
packages/configuration/lib/browser.dart
Normal file
|
@ -0,0 +1 @@
|
|||
external dynamic config(String key);
|
16
packages/configuration/pubspec.yaml
Normal file
16
packages/configuration/pubspec.yaml
Normal file
|
@ -0,0 +1,16 @@
|
|||
name: angel_configuration
|
||||
description: Automatic YAML application configuration loader for Angel, with .env support.
|
||||
version: 2.1.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_configuration
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
dotenv: ^1.0.0
|
||||
file: ^5.0.0
|
||||
merge_map: ^1.0.0
|
||||
yaml: ^2.0.0
|
||||
dev_dependencies:
|
||||
io: ^0.3.2
|
||||
test: ^1.0.0
|
68
packages/configuration/test/all_test.dart
Normal file
68
packages/configuration/test/all_test.dart
Normal file
|
@ -0,0 +1,68 @@
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_configuration/angel_configuration.dart';
|
||||
import 'package:file/local.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
main() async {
|
||||
// Note: Set ANGEL_ENV to 'development'
|
||||
var app = new Angel();
|
||||
var fileSystem = const LocalFileSystem();
|
||||
|
||||
await app.configure(configuration(
|
||||
fileSystem,
|
||||
directoryPath: './test/config',
|
||||
));
|
||||
|
||||
test('standalone', () async {
|
||||
var config = await loadStandaloneConfiguration(
|
||||
fileSystem,
|
||||
directoryPath: './test/config',
|
||||
onWarning: (msg) {
|
||||
print(yellow.wrap('STANDALONE WARNING: $msg'));
|
||||
},
|
||||
);
|
||||
print('Standalone: $config');
|
||||
expect(config, {
|
||||
"angel": {"framework": "cool"},
|
||||
"must_be_null": null,
|
||||
"artist": "Timberlake",
|
||||
"merge": {"map": true, "hello": "world"},
|
||||
"set_via": "default",
|
||||
"hello": "world",
|
||||
"foo": {"version": "bar"}
|
||||
});
|
||||
});
|
||||
|
||||
test('can load based on ANGEL_ENV', () async {
|
||||
expect(app.configuration['hello'], equals('world'));
|
||||
expect(app.configuration['foo']['version'], equals('bar'));
|
||||
});
|
||||
|
||||
test('will load default.yaml if exists', () {
|
||||
expect(app.configuration["set_via"], equals("default"));
|
||||
});
|
||||
|
||||
test('will load .env if exists', () {
|
||||
expect(app.configuration['artist'], 'Timberlake');
|
||||
expect(app.configuration['angel'], {'framework': 'cool'});
|
||||
});
|
||||
|
||||
test('non-existent environment defaults to 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(configuration(fileSystem,
|
||||
directoryPath: './test/config', overrideEnvironmentName: 'override'));
|
||||
expect(app.configuration['hello'], equals('goodbye'));
|
||||
expect(app.configuration['foo']['version'], equals('baz'));
|
||||
});
|
||||
|
||||
test('merges configuration', () async {
|
||||
await app.configure(configuration(fileSystem,
|
||||
directoryPath: './test/config', overrideEnvironmentName: 'override'));
|
||||
expect(app.configuration['merge'], {'map': true, 'hello': 'goodbye'});
|
||||
});
|
||||
}
|
2
packages/configuration/test/config/.env
Normal file
2
packages/configuration/test/config/.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
ANGEL_FRAMEWORK=cool
|
||||
JUSTIN=Timberlake
|
8
packages/configuration/test/config/default.yaml
Normal file
8
packages/configuration/test/config/default.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
set_via: default
|
||||
artist: $JUSTIN
|
||||
angel:
|
||||
framework: $ANGEL_FRAMEWORK
|
||||
must_be_null: $NONEXISTENT_KEY_FOO_BAR_BAZ_QUUX
|
||||
merge:
|
||||
map: true
|
||||
hello: world
|
3
packages/configuration/test/config/development.yaml
Normal file
3
packages/configuration/test/config/development.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
hello: world
|
||||
foo:
|
||||
version: bar
|
5
packages/configuration/test/config/override.yaml
Normal file
5
packages/configuration/test/config/override.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
hello: goodbye
|
||||
foo:
|
||||
version: baz
|
||||
merge:
|
||||
hello: goodbye
|
Loading…
Reference in a new issue