Skip to content

Commit d53f295

Browse files
refactoring
1 parent 9a060b0 commit d53f295

File tree

6 files changed

+60
-21
lines changed

6 files changed

+60
-21
lines changed

src/DotNetEnv/Env.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,24 @@ private static IEnumerable<KeyValuePair<string, string>> LoadContents(string con
8484
? CreateDictionaryOption.TakeLast
8585
: CreateDictionaryOption.TakeFirst;
8686

87-
var previousValueDictionary = actualValues?.ToDotEnvDictionary(dictionaryOption);
88-
var actualValueProvider = previousValueDictionary == null
87+
var actualValueProvider = actualValues == null
8988
? (IValueProvider)new EnvironmentValueProvider()
9089
: new ChainedValueProvider(options.ClobberExistingVars,
91-
new EnvironmentValueProvider(), new DictionaryValueProvider(previousValueDictionary));
90+
new EnvironmentValueProvider(),
91+
new KeyValuePairValueProvider(options.ClobberExistingVars, actualValues.ToList()));
9292

93-
var pairs = Parsers.ParseDotenvFile(contents, options.ClobberExistingVars, actualValueProvider);
93+
var parsedValues = Parsers.ParseDotenvFile(contents, options.ClobberExistingVars, actualValueProvider);
9494

95-
var unClobberedPairs = (options.ClobberExistingVars
96-
? pairs
97-
: pairs.Where(p => !actualValueProvider.TryGetValue(p.Key, out _)))
98-
.ToArray();
95+
var unClobberedDictionary = (options.ClobberExistingVars
96+
? parsedValues
97+
: parsedValues.Where(p => !actualValueProvider.TryGetValue(p.Key, out _)))
98+
.ToDotEnvDictionary(dictionaryOption);
9999

100100
if (options.SetEnvVars)
101-
foreach (var pair in unClobberedPairs)
101+
foreach (var pair in unClobberedDictionary)
102102
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
103103

104-
return unClobberedPairs.ToDotEnvDictionary(dictionaryOption);
104+
return unClobberedDictionary;
105105
}
106106

107107
public static string GetString(string key, string fallback = default(string)) =>

src/DotNetEnv/Parsers.cs

+8-7
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ internal static class Parsers
2222
/// <summary>
2323
/// Contains already parsed variables while parsing.
2424
/// </summary>
25-
private static readonly ConcurrentDictionary<string, string> ParsedValuesDictionary =
26-
new ConcurrentDictionary<string, string>();
25+
private static readonly IList<KeyValuePair<string, string>> ParsedValues =
26+
new List<KeyValuePair<string, string>>();
2727

2828
// helpful blog I discovered only after digging through all the Sprache source myself:
2929
// https://justinpealing.me.uk/post/2020-03-11-sprache1-chars/
@@ -328,19 +328,20 @@ from _lt in LineTerminator
328328
public static IEnumerable<KeyValuePair<string, string>> ParseDotenvFile(string contents,
329329
bool clobberExistingVariables = true, IValueProvider actualValueProvider = null)
330330
{
331-
ParsedValuesDictionary.Clear();
331+
ParsedValues.Clear();
332332
CurrentValueProvider = new ChainedValueProvider(clobberExistingVariables,
333-
actualValueProvider, new DictionaryValueProvider(ParsedValuesDictionary));
333+
actualValueProvider ?? ValueProvider.Empty,
334+
new KeyValuePairValueProvider(clobberExistingVariables, ParsedValues));
334335

335-
return Assignment.Select(UpdateMyDictionary).Or(Empty)
336+
return Assignment.Select(UpdateParsedValues).Or(Empty)
336337
.Many()
337338
.AtEnd()
338339
.Parse(contents)
339340
.Where(kvp => kvp.Key != null);
340341

341-
KeyValuePair<string, string> UpdateMyDictionary(KeyValuePair<string, string> pair)
342+
KeyValuePair<string, string> UpdateParsedValues(KeyValuePair<string, string> pair)
342343
{
343-
ParsedValuesDictionary[pair.Key] = pair.Value;
344+
ParsedValues.Add(pair);
344345
return pair;
345346
}
346347
}

src/DotNetEnv/ValueProvider.cs

+33
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,21 @@ public virtual string GetValue(string key) => TryGetValue(key, out var value)
1717
: throw new KeyNotFoundException();
1818

1919
public abstract bool TryGetValue(string key, out string value);
20+
21+
public static readonly IValueProvider Empty = new EmptyValueProvider();
2022
}
23+
24+
internal class EmptyValueProvider : IValueProvider
25+
{
26+
public string GetValue(string key) => null;
27+
28+
public bool TryGetValue(string key, out string value)
29+
{
30+
value = null;
31+
return false;
32+
}
33+
}
34+
2135
internal class EnvironmentValueProvider : ValueProvider
2236
{
2337
public override bool TryGetValue(string key, out string value)
@@ -37,6 +51,25 @@ public DictionaryValueProvider(IDictionary<string, string> dictionary)
3751
public override bool TryGetValue(string key, out string value) => _keyValuePairs.TryGetValue(key, out value);
3852
}
3953

54+
internal class KeyValuePairValueProvider : ValueProvider
55+
{
56+
private readonly bool _clobberExisting;
57+
private readonly IList<KeyValuePair<string, string>> _keyValuePairs;
58+
59+
public KeyValuePairValueProvider(bool clobberExisting, IList<KeyValuePair<string, string>> keyValuePairs)
60+
{
61+
_clobberExisting = clobberExisting;
62+
_keyValuePairs = keyValuePairs;
63+
}
64+
65+
public override bool TryGetValue(string key, out string value)
66+
{
67+
value = (_clobberExisting ? _keyValuePairs.Reverse() : _keyValuePairs)
68+
.FirstOrDefault(pair => pair.Key == key).Value;
69+
return value != null;
70+
}
71+
}
72+
4073
internal class ChainedValueProvider : ValueProvider
4174
{
4275
private readonly bool _clobberExisting;

test/DotNetEnv.Tests/.env

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# test env file
2+
NAME=ClobberedToni
23
NAME=Toni #inline comment
34
EMPTY=
45
QUOTE="'"
@@ -8,3 +9,4 @@ CONNECTION=user=test;password=secret
89
PASSWORD=Google#Facebook
910
SSL_CERT="SPECIAL STUFF---\nLONG-BASE64\ignore\"slash"
1011
ENVVAR_TEST=overridden
12+
INTERPOLATED_NAME=$NAME

test/DotNetEnv.Tests/EnvConfigurationTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void AddSourceToBuilderAndLoadMultiWithNoClobber()
9090
.AddDotNetEnvMulti(new[] { "./.env", "./.env2" }, LoadOptions.NoEnvVars().NoClobber())
9191
.Build();
9292

93-
Assert.Equal("Toni", configuration["NAME"]);
93+
Assert.Equal("ClobberedToni", configuration["NAME"]);
9494
Assert.Null(configuration["ENVVAR_TEST"]); // value from EnvironmentVariables is not contained for NoClobber
9595
Assert.Equal("ENV value", configuration["ClobberEnvVarTest"]); // should contain ENVVAR_TEST from EnvironmentVariable
9696
Assert.Equal("https://github.com/tonerdo", configuration["UrlFromVariable"]); // should contain Url from .env

test/DotNetEnv.Tests/EnvTests.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class EnvTests
1515
private static string[] OldEnvVars = new string[]
1616
{
1717
"NAME",
18+
"INTERPOLATED_NAME",
1819
"EMPTY",
1920
"QUOTE",
2021
"URL",
@@ -141,7 +142,7 @@ public void LoadMultiTest()
141142
Assert.Equal("Other", Environment.GetEnvironmentVariable("NAME"));
142143
Environment.SetEnvironmentVariable("NAME", null);
143144
DotNetEnv.Env.NoClobber().LoadMulti(new[] { "./.env", "./.env2" });
144-
Assert.Equal("Toni", Environment.GetEnvironmentVariable("NAME"));
145+
Assert.Equal("ClobberedToni", Environment.GetEnvironmentVariable("NAME"));
145146
Environment.SetEnvironmentVariable("NAME", "Person");
146147
DotNetEnv.Env.NoClobber().LoadMulti(new[] { "./.env", "./.env2" });
147148
Assert.Equal("Person", Environment.GetEnvironmentVariable("NAME"));
@@ -154,7 +155,7 @@ public void LoadMultiTestNoEnvVars()
154155
Assert.Equal("Other", pairs.LastOrDefault(x => x.Key == "NAME").Value);
155156
Environment.SetEnvironmentVariable("NAME", null);
156157
pairs = DotNetEnv.Env.NoEnvVars().NoClobber().LoadMulti(new[] { "./.env", "./.env2" });
157-
Assert.Equal("Toni", pairs.FirstOrDefault(x => x.Key == "NAME").Value);
158+
Assert.Equal("ClobberedToni", pairs.FirstOrDefault(x => x.Key == "NAME").Value);
158159
Environment.SetEnvironmentVariable("NAME", "Person");
159160
pairs = DotNetEnv.Env.NoEnvVars().NoClobber().LoadMulti(new[] { "./.env", "./.env2" });
160161
Assert.Null(pairs.FirstOrDefault(x => x.Key == "NAME").Value); // value from EnvironmentVariables is not contained with NoClobber
@@ -168,13 +169,15 @@ public void LoadNoClobberTest()
168169
Environment.SetEnvironmentVariable("URL", expected);
169170
DotNetEnv.Env.Load(options: new DotNetEnv.LoadOptions(clobberExistingVars: false));
170171
Assert.Equal(expected, Environment.GetEnvironmentVariable("URL"));
171-
Assert.Equal("Toni", Environment.GetEnvironmentVariable("NAME"));
172+
Assert.Equal("ClobberedToni", Environment.GetEnvironmentVariable("NAME"));
173+
Assert.Equal("ClobberedToni", Environment.GetEnvironmentVariable("INTERPOLATED_NAME"));
172174

173175
Environment.SetEnvironmentVariable("NAME", null);
174176
Environment.SetEnvironmentVariable("URL", "i'm going to be overwritten");
175177
DotNetEnv.Env.Load(options: new DotNetEnv.LoadOptions(clobberExistingVars: true));
176178
Assert.Equal("https://github.com/tonerdo", Environment.GetEnvironmentVariable("URL"));
177179
Assert.Equal("Toni", Environment.GetEnvironmentVariable("NAME"));
180+
Assert.Equal("Toni", Environment.GetEnvironmentVariable("INTERPOLATED_NAME"));
178181
}
179182

180183
[Fact]

0 commit comments

Comments
 (0)