Skip to content

Commit b313db5

Browse files
committed
Align seqcli's environment override handling with Seq's
1 parent 3dfdf3a commit b313db5

File tree

13 files changed

+325
-133
lines changed

13 files changed

+325
-133
lines changed

src/SeqCli/Cli/Commands/ConfigCommand.cs

Lines changed: 13 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,25 @@ protected override Task<int> Run()
4444

4545
try
4646
{
47-
var config = SeqCliConfig.Read();
48-
47+
var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
48+
4949
if (_key != null)
5050
{
5151
if (_clear)
5252
{
5353
verb = "clear";
54-
Clear(config, _key);
55-
SeqCliConfig.Write(config);
54+
KeyValueSettings.Clear(config, _key);
55+
SeqCliConfig.Write(config, RuntimeConfigurationLoader.DefaultConfigFilename);
5656
}
5757
else if (_value != null)
5858
{
5959
verb = "update";
60-
Set(config, _key, _value);
61-
SeqCliConfig.Write(config);
60+
KeyValueSettings.Set(config, _key, _value);
61+
SeqCliConfig.Write(config, RuntimeConfigurationLoader.DefaultConfigFilename);
6262
}
6363
else
6464
{
65+
verb = "print";
6566
Print(config, _key);
6667
}
6768
}
@@ -78,114 +79,23 @@ protected override Task<int> Run()
7879
return Task.FromResult(1);
7980
}
8081
}
81-
82+
8283
static void Print(SeqCliConfig config, string key)
8384
{
8485
if (config == null) throw new ArgumentNullException(nameof(config));
8586
if (key == null) throw new ArgumentNullException(nameof(key));
8687

87-
var pr = ReadPairs(config).SingleOrDefault(p => p.Key == key);
88-
if (pr.Key == null)
89-
throw new ArgumentException($"Option {key} not found.");
90-
91-
Console.WriteLine(Format(pr.Value));
92-
}
93-
94-
static void Set(SeqCliConfig config, string key, string? value)
95-
{
96-
if (config == null) throw new ArgumentNullException(nameof(config));
97-
if (key == null) throw new ArgumentNullException(nameof(key));
98-
99-
var steps = key.Split('.');
100-
if (steps.Length != 2)
101-
throw new ArgumentException("The format of the key is incorrect; run the command without any arguments to view all keys.");
102-
103-
var first = config.GetType().GetTypeInfo().DeclaredProperties
104-
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic)
105-
.SingleOrDefault(p => Camelize(p.Name) == steps[0]);
106-
107-
if (first == null)
108-
throw new ArgumentException("The key could not be found; run the command without any arguments to view all keys.");
109-
110-
if (first.PropertyType == typeof(Dictionary<string, SeqCliConnectionConfig>))
111-
throw new NotSupportedException("Use `seqcli profile create` to configure connection profiles.");
112-
113-
var second = first.PropertyType.GetTypeInfo().DeclaredProperties
114-
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic)
115-
.SingleOrDefault(p => Camelize(p.Name) == steps[1]);
116-
117-
if (second == null)
118-
throw new ArgumentException("The key could not be found; run the command without any arguments to view all keys.");
88+
if (!KeyValueSettings.TryGetValue(config, key, out var value, out _))
89+
throw new ArgumentException($"Option {key} not found");
11990

120-
if (!second.CanWrite || !second.SetMethod!.IsPublic)
121-
throw new ArgumentException("The value is not writeable.");
122-
123-
var targetValue = Convert.ChangeType(value, second.PropertyType, CultureInfo.InvariantCulture);
124-
var configItem = first.GetValue(config);
125-
second.SetValue(configItem, targetValue);
126-
}
127-
128-
static void Clear(SeqCliConfig config, string key)
129-
{
130-
Set(config, key, null);
91+
Console.WriteLine(value);
13192
}
13293

13394
static void List(SeqCliConfig config)
13495
{
135-
foreach (var (key, value) in ReadPairs(config))
136-
{
137-
Console.WriteLine($"{key}:");
138-
Console.WriteLine($" {Format(value)}");
139-
}
140-
}
141-
142-
static IEnumerable<KeyValuePair<string, object?>> ReadPairs(object config)
143-
{
144-
foreach (var property in config.GetType().GetTypeInfo().DeclaredProperties
145-
.Where(p => p.CanRead && p.GetMethod!.IsPublic && !p.GetMethod.IsStatic && !p.Name.StartsWith("Encoded"))
146-
.OrderBy(p => p.Name))
96+
foreach (var (key, value, _) in KeyValueSettings.Inspect(config))
14797
{
148-
var propertyName = Camelize(property.Name);
149-
var propertyValue = property.GetValue(config);
150-
151-
if (propertyValue is IDictionary dict)
152-
{
153-
foreach (var elementKey in dict.Keys)
154-
{
155-
foreach (var elementPair in ReadPairs(dict[elementKey]!))
156-
{
157-
yield return new KeyValuePair<string, object?>(
158-
$"{propertyName}[{elementKey}].{elementPair.Key}",
159-
elementPair.Value);
160-
}
161-
}
162-
}
163-
else if (propertyValue?.GetType().Namespace?.StartsWith("SeqCli.Config") ?? false)
164-
{
165-
foreach (var childPair in ReadPairs(propertyValue))
166-
{
167-
var name = propertyName + "." + childPair.Key;
168-
yield return new KeyValuePair<string, object?>(name, childPair.Value);
169-
}
170-
}
171-
else
172-
{
173-
yield return new KeyValuePair<string, object?>(propertyName, propertyValue);
174-
}
98+
Console.WriteLine($"{key}={value}");
17599
}
176100
}
177-
178-
static string Camelize(string s)
179-
{
180-
if (s.Length < 2)
181-
throw new NotSupportedException("No camel-case support for short names");
182-
return char.ToLowerInvariant(s[0]) + s.Substring(1);
183-
}
184-
185-
static string Format(object? value)
186-
{
187-
return value is IFormattable formattable
188-
? formattable.ToString(null, CultureInfo.InvariantCulture)
189-
: value?.ToString() ?? "";
190-
}
191101
}

src/SeqCli/Cli/Commands/Profile/CreateCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ int RunSync()
4848

4949
try
5050
{
51-
var config = SeqCliConfig.Read();
51+
var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
5252
config.Profiles[_name] = new SeqCliConnectionConfig { ServerUrl = _url, ApiKey = _apiKey };
53-
SeqCliConfig.Write(config);
53+
SeqCliConfig.Write(config, RuntimeConfigurationLoader.DefaultConfigFilename);
5454
return 0;
5555
}
5656
catch (Exception ex)

src/SeqCli/Cli/Commands/Profile/ListCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class ListCommand : Command
1111
{
1212
protected override Task<int> Run()
1313
{
14-
var config = SeqCliConfig.Read();
14+
var config = RuntimeConfigurationLoader.Load();
1515

1616
foreach (var profile in config.Profiles.OrderBy(p => p.Key))
1717
{

src/SeqCli/Cli/Commands/Profile/RemoveCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ int RunSync()
3434

3535
try
3636
{
37-
var config = SeqCliConfig.Read();
37+
var config = SeqCliConfig.ReadFromFile(RuntimeConfigurationLoader.DefaultConfigFilename);
3838
if (!config.Profiles.Remove(_name))
3939
{
4040
Log.Error("No profile with name {ProfileName} was found", _name);
4141
return 1;
4242
}
4343

44-
SeqCliConfig.Write(config);
44+
SeqCliConfig.Write(config, RuntimeConfigurationLoader.DefaultConfigFilename);
4545

4646
return 0;
4747
}

src/SeqCli/Cli/Options.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ private static int GetLineEnd (int start, int length, string description)
239239

240240
class OptionValueCollection : IList, IList<string> {
241241

242-
List<string> values = new List<string> ();
242+
List<string> values = new();
243243
OptionContext c;
244244

245245
internal OptionValueCollection (OptionContext c)
@@ -694,7 +694,7 @@ public Converter<string, string> MessageLocalizer {
694694
get {return localizer;}
695695
}
696696

697-
List<ArgumentSource> sources = new List<ArgumentSource> ();
697+
List<ArgumentSource> sources = new();
698698
ReadOnlyCollection<ArgumentSource> roSources;
699699

700700
public ReadOnlyCollection<ArgumentSource> ArgumentSources {
@@ -960,7 +960,7 @@ public List<string> Parse (IEnumerable<string> arguments)
960960
}
961961

962962
class ArgumentEnumerator : IEnumerable<string> {
963-
List<IEnumerator<string>> sources = new List<IEnumerator<string>> ();
963+
List<IEnumerator<string>> sources = new();
964964

965965
public ArgumentEnumerator (IEnumerable<string> arguments)
966966
{
@@ -1015,7 +1015,7 @@ private static bool Unprocessed (ICollection<string> extra, Option def, OptionCo
10151015
return false;
10161016
}
10171017

1018-
private readonly Regex ValueOption = new Regex (
1018+
private readonly Regex ValueOption = new(
10191019
@"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$");
10201020

10211021
protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace SeqCli.Config;
7+
8+
static class EnvironmentOverrides
9+
{
10+
public static void Apply(string prefix, SeqCliConfig config)
11+
{
12+
var environment = Environment.GetEnvironmentVariables();
13+
Apply(prefix, config, environment.Keys.Cast<string>().ToDictionary(k => k, k => (string?)environment[k]));
14+
}
15+
16+
internal static void Apply(string prefix, SeqCliConfig config, Dictionary<string, string?> environment)
17+
{
18+
if (config == null) throw new ArgumentNullException(nameof(config));
19+
if (environment == null) throw new ArgumentNullException(nameof(environment));
20+
21+
config.DisallowExport();
22+
23+
foreach (var (key, _, _) in KeyValueSettings.Inspect(config))
24+
{
25+
var envVar = ToEnvironmentVariableName(prefix, key);
26+
if (environment.TryGetValue(envVar, out var value))
27+
{
28+
KeyValueSettings.Set(config, key, value ?? "");
29+
}
30+
}
31+
}
32+
33+
internal static string ToEnvironmentVariableName(string prefix, string key)
34+
{
35+
return prefix + key.Replace(".", "_").ToUpperInvariant();
36+
}
37+
}

0 commit comments

Comments
 (0)