Support ini-like sections in keyvalue config

This commit is contained in:
Mike Bierlee 2022-10-11 21:07:08 +03:00
parent 42e93e64d0
commit 089e42a2bf
3 changed files with 55 additions and 18 deletions

View file

@ -12,14 +12,15 @@
module mirage.java; module mirage.java;
import mirage.config : ConfigDictionary; import mirage.config : ConfigDictionary;
import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments; import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments, SupportSections;
/** /**
* Creates configuration files from Java properties. * Creates configuration files from Java properties.
*/ */
class JavaPropertiesFactory : KeyValueConfigFactory!( class JavaPropertiesFactory : KeyValueConfigFactory!(
SupportHashtagComments.yes, SupportHashtagComments.yes,
SupportSemicolonComments.no SupportSemicolonComments.no,
SupportSections.no
) { ) {
} }

View file

@ -13,14 +13,15 @@ module mirage.keyvalue;
import mirage.config : ConfigFactory, ConfigDictionary, ConfigNode, ValueNode, ObjectNode, ConfigCreationException; import mirage.config : ConfigFactory, ConfigDictionary, ConfigNode, ValueNode, ObjectNode, ConfigCreationException;
import std.string : lineSplitter, strip, startsWith, split, indexOf; import std.string : lineSplitter, strip, startsWith, endsWith, split, indexOf;
import std.array : array; import std.array : array;
import std.exception : enforce; import std.exception : enforce;
import std.conv : to; import std.conv : to;
import std.typecons : Flag; import std.typecons : Flag;
alias SupportHashtagComments = Flag!"supportHashtagComment"; alias SupportHashtagComments = Flag!"SupportHashtagComments";
alias SupportSemicolonComments = Flag!"supportSemicolonComments"; alias SupportSemicolonComments = Flag!"SupportSemicolonComments";
alias SupportSections = Flag!"SupportSections";
/** /**
* A generic reusable key/value config factory that can be configured to parse * A generic reusable key/value config factory that can be configured to parse
@ -28,7 +29,8 @@ alias SupportSemicolonComments = Flag!"supportSemicolonComments";
*/ */
class KeyValueConfigFactory( class KeyValueConfigFactory(
SupportHashtagComments supportHashtagComments = SupportHashtagComments.no, SupportHashtagComments supportHashtagComments = SupportHashtagComments.no,
SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no SupportSemicolonComments supportSemicolonComments = SupportSemicolonComments.no,
SupportSections supportSections = SupportSections.no
) : ConfigFactory { ) : ConfigFactory {
/** /**
* Parse a configuration file following the configured key/value conventions. * Parse a configuration file following the configured key/value conventions.
@ -41,33 +43,41 @@ class KeyValueConfigFactory(
enforce!ConfigCreationException(contents !is null, "Contents cannot be null."); enforce!ConfigCreationException(contents !is null, "Contents cannot be null.");
auto lines = contents.lineSplitter().array; auto lines = contents.lineSplitter().array;
auto properties = new ConfigDictionary(); auto properties = new ConfigDictionary();
auto section = "";
foreach (size_t index, string line; lines) { foreach (size_t index, string line; lines) {
auto normalizedLine = line; auto processedLine = line;
if (supportHashtagComments) { if (supportHashtagComments) {
auto commentPosition = normalizedLine.indexOf('#'); auto commentPosition = processedLine.indexOf('#');
if (commentPosition >= 0) { if (commentPosition >= 0) {
normalizedLine = normalizedLine[0 .. commentPosition]; processedLine = processedLine[0 .. commentPosition];
} }
} }
if (supportSemicolonComments) { if (supportSemicolonComments) {
auto commentPosition = normalizedLine.indexOf(';'); auto commentPosition = processedLine.indexOf(';');
if (commentPosition >= 0) { if (commentPosition >= 0) {
normalizedLine = normalizedLine[0 .. commentPosition]; processedLine = processedLine[0 .. commentPosition];
} }
} }
normalizedLine = normalizedLine.strip; processedLine = processedLine.strip;
if (normalizedLine.length == 0) {
if (supportSections && processedLine.startsWith('[') && processedLine.endsWith(']')) {
section = processedLine[1 .. $ - 1] ~ '.';
continue; continue;
} }
auto parts = normalizedLine.split('='); if (processedLine.length == 0) {
continue;
}
auto parts = processedLine.split('=');
enforce!ConfigCreationException(parts.length <= 2, "Line has too many equals signs and cannot be parsed (L" ~ index enforce!ConfigCreationException(parts.length <= 2, "Line has too many equals signs and cannot be parsed (L" ~ index
.to!string ~ "): " ~ normalizedLine); .to!string ~ "): " ~ processedLine);
enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ normalizedLine); enforce!ConfigCreationException(parts.length == 2, "Missing value assignment (L" ~ index.to!string ~ "): " ~ processedLine);
properties.set(parts[0].strip, parts[1].strip);
properties.set(section ~ parts[0].strip, parts[1].strip);
} }
return properties; return properties;
@ -156,4 +166,29 @@ version (unittest) {
assert(config.get("server") == "localhost"); assert(config.get("server") == "localhost");
assert(config.get("port") == "9876"); assert(config.get("port") == "9876");
} }
@("Support sections when enabled")
unittest {
auto config = new KeyValueConfigFactory!(SupportHashtagComments.no,
SupportSemicolonComments.yes,
SupportSections.yes)().parseConfig("
applicationName = test me!
[server]
host=localhost
port=2873
[server.middleware] ; Stuff that handles the http protocol
protocolServer = netty
[database.driver]
id=PostgresDriver
");
assert(config.get("applicationName") == "test me!");
assert(config.get("server.host") == "localhost");
assert(config.get("server.port") == "2873");
assert(config.get("server.middleware.protocolServer") == "netty");
assert(config.get("database.driver.id") == "PostgresDriver");
}
} }

View file

@ -10,5 +10,6 @@
module mirage; module mirage;
public import mirage.config; public import mirage.config;
public import mirage.json;
public import mirage.java; public import mirage.java;
public import mirage.json;
public import mirage.keyvalue;