Skip to content

Commit 9947806

Browse files
committed
Allow overriding with other env files
renaming and additional readme revert pubspec.lock changes increment minor version level
1 parent 3688e72 commit 9947806

File tree

6 files changed

+118
-14
lines changed

6 files changed

+118
-14
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ ESCAPED_DOLLAR_SIGN='$1000'
128128
You can merge a map into the environment on load:
129129

130130
```dart
131-
await DotEnv.load(mergeWith: { "FOO": "foo", "BAR": "bar"});
131+
await dotenv.load(mergeWith: { "FOO": "foo", "BAR": "bar"});
132132
```
133133

134134
You can also reference these merged variables within `.env`:
@@ -137,13 +137,33 @@ You can also reference these merged variables within `.env`:
137137
FOOBAR=$FOO$BAR
138138
```
139139

140+
## Merge with other env files:
141+
142+
Useful for defining a base set of values, and overriding a subset based on environment. Env files specified first take precedence.
143+
144+
```env
145+
# .env
146+
TEST_VALUE=base-value
147+
```
148+
149+
```env
150+
# .env-staging
151+
TEST_VALUE=staging-value
152+
```
153+
154+
```dart
155+
await dotenv.load(fileName: ".env", overrideWith: [".env-staging"]);
156+
157+
dotenv.get("TEST_VALUE") // => "staging-value"
158+
```
159+
140160
## Usage with Platform Environment
141161

142162
The Platform.environment map can be merged into the env:
143163

144164
```dart
145165
// For example using Platform.environment that contains a CLIENT_ID entry
146-
await DotEnv.load(mergeWith: Platform.environment);
166+
await dotenv.load(mergeWith: Platform.environment);
147167
print(env["CLIENT_ID"]);
148168
```
149169

lib/src/dotenv.dart

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,50 @@ class DotEnv {
5151

5252
/// Loads environment variables from the env file into a map
5353
/// Merge with any entries defined in [mergeWith]
54-
Future<void> load(
55-
{String fileName = '.env', Parser parser = const Parser(), Map<String, String> mergeWith = const {}}) async {
54+
/// [overrideWith] is a list of other env files whose values will override values
55+
/// read from [fileName]
56+
Future<void> load({
57+
String fileName = '.env',
58+
Parser parser = const Parser(),
59+
Map<String, String> mergeWith = const {},
60+
List<String> overrideWith = const [],
61+
}) async {
5662
clean();
5763
final linesFromFile = await _getEntriesFromFile(fileName);
58-
final linesFromMergeWith = mergeWith.entries.map((entry) => "${entry.key}=${entry.value}").toList();
59-
final allLines = linesFromMergeWith..addAll(linesFromFile);
64+
final linesFromOverrides = await _getLinesFromOverride(overrideWith);
65+
66+
final linesFromMergeWith = mergeWith.entries
67+
.map((entry) => "${entry.key}=${entry.value}")
68+
.toList();
69+
final allLines = linesFromMergeWith
70+
..addAll(linesFromOverrides)
71+
..addAll(linesFromFile);
72+
6073
final envEntries = parser.parse(allLines);
6174
_envMap.addAll(envEntries);
6275
_isInitialized = true;
6376
}
6477

65-
Future<void> testLoad(
66-
{String fileInput = '', Parser parser = const Parser(), Map<String, String> mergeWith = const {}}) async {
78+
Future<void> testLoad({
79+
String fileInput = '',
80+
Parser parser = const Parser(),
81+
Map<String, String> mergeWith = const {},
82+
List<String> overrideWith = const [],
83+
}) async {
6784
clean();
6885
final linesFromFile = fileInput.split('\n');
69-
final linesFromMergeWith = mergeWith.entries.map((entry) => "${entry.key}=${entry.value}").toList();
70-
final allLines = linesFromMergeWith..addAll(linesFromFile);
86+
87+
final linesFromOverrides = overrideWith
88+
.map((String lines) => lines.split("\n"))
89+
.expand((x) => x)
90+
.toList();
91+
92+
final linesFromMergeWith = mergeWith.entries
93+
.map((entry) => "${entry.key}=${entry.value}")
94+
.toList();
95+
final allLines = linesFromMergeWith
96+
..addAll(linesFromOverrides)
97+
..addAll(linesFromFile);
7198
final envEntries = parser.parse(allLines);
7299
_envMap.addAll(envEntries);
73100
_isInitialized = true;
@@ -76,7 +103,8 @@ class DotEnv {
76103
/// True if all supplied variables have nonempty value; false otherwise.
77104
/// Differs from [containsKey](dart:core) by excluding null values.
78105
/// Note [load] should be called first.
79-
bool isEveryDefined(Iterable<String> vars) => vars.every((k) => _envMap[k]?.isNotEmpty ?? false);
106+
bool isEveryDefined(Iterable<String> vars) =>
107+
vars.every((k) => _envMap[k]?.isNotEmpty ?? false);
80108

81109
Future<List<String>> _getEntriesFromFile(String filename) async {
82110
try {
@@ -90,4 +118,16 @@ class DotEnv {
90118
throw FileNotFoundError();
91119
}
92120
}
121+
122+
Future<List<String>> _getLinesFromOverride(List<String> overrideWith) async {
123+
List<String> overrideLines = [];
124+
125+
for (int i = 0; i < overrideWith.length; i++) {
126+
final overrideWithFile = overrideWith[i];
127+
final lines = await _getEntriesFromFile(overrideWithFile);
128+
overrideLines = overrideLines..addAll(lines);
129+
}
130+
131+
return overrideLines;
132+
}
93133
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: flutter_dotenv
2-
version: 5.0.0
2+
version: 5.1.0
33
description: Easily configure any flutter application with global variables using a `.env` file.
44
homepage: https://github.com/java-james/flutter_dotenv
55
environment:

test/.env

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ RETAIN_TRAILING_SQUOTE=retained'
2828
RETAIN_INNER_QUOTES_AS_STRING='{"foo": "bar"}'
2929
TRIM_SPACE_FROM_UNQUOTED= some spaced out string
3030
31-
SPACED_KEY = parsed
31+
SPACED_KEY = parsed
32+
33+
OVERRIDE_VALUE=not-overridden

test/.env-override

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OVERRIDE_VALUE=overridden

test/dotenv_test.dart

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ void main() {
66
group('dotenv', () {
77
setUp(() {
88
print(Directory.current.toString());
9-
dotenv.testLoad(fileInput: File('test/.env').readAsStringSync()); //, mergeWith: Platform.environment
9+
dotenv.testLoad(
10+
fileInput: File('test/.env')
11+
.readAsStringSync()); //, mergeWith: Platform.environment
1012
});
1113
test('able to load .env', () {
1214
expect(dotenv.env['FOO'], 'foo');
@@ -35,6 +37,45 @@ void main() {
3537
expect(dotenv.env['TRIM_SPACE_FROM_UNQUOTED'], 'some spaced out string');
3638
expect(dotenv.env['USERNAME'], '[email protected]');
3739
expect(dotenv.env['SPACED_KEY'], 'parsed');
40+
expect(dotenv.env['OVERRIDE_VALUE'], 'not-overridden');
41+
});
42+
});
43+
44+
group('dotenv with overrides', () {
45+
setUp(() {
46+
print(Directory.current.toString());
47+
dotenv.testLoad(
48+
fileInput: File('test/.env').readAsStringSync(),
49+
overrideWith: [File("test/.env-override").readAsStringSync()],
50+
); //, mergeWith: Platform.environment
51+
});
52+
test('able to load .env', () {
53+
expect(dotenv.env['BAR'], 'bar');
54+
expect(dotenv.env['FOOBAR'], '\$FOOfoobar');
55+
expect(dotenv.env['ESCAPED_DOLLAR_SIGN'], '\$1000');
56+
expect(dotenv.env['ESCAPED_QUOTE'], "'");
57+
expect(dotenv.env['BASIC'], 'basic');
58+
expect(dotenv.env['AFTER_LINE'], 'after_line');
59+
expect(dotenv.env['EMPTY'], '');
60+
expect(dotenv.env['SINGLE_QUOTES'], 'single_quotes');
61+
expect(dotenv.env['SINGLE_QUOTES_SPACED'], ' single quotes ');
62+
expect(dotenv.env['DOUBLE_QUOTES'], 'double_quotes');
63+
expect(dotenv.env['DOUBLE_QUOTES_SPACED'], ' double quotes ');
64+
expect(dotenv.env['EXPAND_NEWLINES'], "expand\nnew\nlines");
65+
expect(dotenv.env['DONT_EXPAND_UNQUOTED'], 'dontexpand\\nnewlines');
66+
expect(dotenv.env['DONT_EXPAND_SQUOTED'], 'dontexpand\\nnewlines');
67+
expect(dotenv.env['COMMENTS'], null);
68+
expect(dotenv.env['EQUAL_SIGNS'], 'equals==');
69+
expect(dotenv.env['RETAIN_INNER_QUOTES'], '{"foo": "bar"}');
70+
expect(dotenv.env['RETAIN_LEADING_DQUOTE'], "\"retained");
71+
expect(dotenv.env['RETAIN_LEADING_SQUOTE'], '\'retained');
72+
expect(dotenv.env['RETAIN_TRAILING_DQUOTE'], 'retained\"');
73+
expect(dotenv.env['RETAIN_TRAILING_SQUOTE'], "retained\'");
74+
expect(dotenv.env['RETAIN_INNER_QUOTES_AS_STRING'], '{"foo": "bar"}');
75+
expect(dotenv.env['TRIM_SPACE_FROM_UNQUOTED'], 'some spaced out string');
76+
expect(dotenv.env['USERNAME'], '[email protected]');
77+
expect(dotenv.env['SPACED_KEY'], 'parsed');
78+
expect(dotenv.env['OVERRIDE_VALUE'], 'overridden');
3879
});
3980
});
4081
}

0 commit comments

Comments
 (0)