libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 12015ed6dd0e1e91c9ce400ba332ee0bba9a7e42
parent fb40741be92b179dba8fc416f993c59f1a6850aa
Author: Florian Dold <florian@dold.me>
Date:   Sun, 24 Sep 2023 15:33:10 +0200

basic support for variables in config

Diffstat:
MMakefile | 13+++++++------
Acontrib/libeufin-bank.conf | 17+++++++++++++++++
Dcontrib/libeufin-bank.sample.conf | 13-------------
Mutil/src/main/kotlin/TalerConfig.kt | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mutil/src/test/kotlin/TalerConfigTest.kt | 15+++++++++++++++
5 files changed, 115 insertions(+), 22 deletions(-)

diff --git a/Makefile b/Makefile @@ -12,6 +12,9 @@ define versions_check = then echo WARNING: Project version from Gradle: $(gradle_version) differs from current Git tag: $(git_tag); fi endef +sql_dir=$(prefix)/share/taler/sql/libeufin-bank +config_dir=$(prefix)/share/taler/config.d + .PHONY: dist dist: @$(call versions_check) @@ -37,6 +40,7 @@ deb: exec-arch copy-spa .PHONY: install-bank install-bank: + @install -D contrib/libeufin-bank.conf $(config_dir) @./gradlew -q -Pprefix=$(prefix) bank:installToPrefix; cd .. # To reactivate after the refactoring. @@ -51,12 +55,9 @@ install-cli: .PHONY: install-db-versioning install-db-versioning: - $(eval BANK_DBINIT_SCRIPT := libeufin-bank-dbinit) - @sed "s|__BANK_STATIC_PATCHES_LOCATION__|$(prefix)/share/libeufin/sql/bank|" < contrib/$(BANK_DBINIT_SCRIPT) > build/$(BANK_DBINIT_SCRIPT) - @install -D database-versioning/libeufin-bank*.sql -t $(prefix)/share/libeufin/sql/bank - @install -D database-versioning/versioning.sql -t $(prefix)/share/libeufin/sql/bank - @install -D database-versioning/procedures.sql -t $(prefix)/share/libeufin/sql/bank - @install -D build/$(BANK_DBINIT_SCRIPT) -t $(prefix)/bin + @install -D database-versioning/libeufin-bank*.sql -t $(sql_dir) + @install -D database-versioning/versioning.sql -t $(sql_dir) + @install -D database-versioning/procedures.sql -t $(sql_dir) .PHONY: assemble assemble: diff --git a/contrib/libeufin-bank.conf b/contrib/libeufin-bank.conf @@ -0,0 +1,17 @@ +[libeufin-bank] +CURRENCY = KUDOS +DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:200 +DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:2000 +REGISTRATION_BONUS = KUDOS:100 +REGISTRATION_BONUS_ENABLED = yes +MAX_AUTH_TOKEN_DURATION = 1d + +SERVE = tcp +PORT = 8080 + +[libeufin-bankdb] +CONFIG = postgresql:///libeufinbank + +[libeufin-bankdb-postgres] +# Where are the SQL files to setup our tables? +SQL_DIR = $DATADIR/sql/bank/ diff --git a/contrib/libeufin-bank.sample.conf b/contrib/libeufin-bank.sample.conf @@ -1,13 +0,0 @@ -[libeufin-bank] -CURRENCY = KUDOS -DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:200 -DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:2000 -REGISTRATION_BONUS = KUDOS:100 -REGISTRATION_BONUS_ENABLED = yes -MAX_AUTH_TOKEN_DURATION = 1d - -SERVE = tcp -PORT = 8080 - -[libeufin-bank-db-postgres] -CONFIG = postgresql:///libeufinbank diff --git a/util/src/main/kotlin/TalerConfig.kt b/util/src/main/kotlin/TalerConfig.kt @@ -19,7 +19,6 @@ import java.io.File import java.nio.file.Paths -import java.util.* import kotlin.io.path.Path import kotlin.io.path.listDirectoryEntries @@ -92,12 +91,13 @@ class TalerConfig { } private fun provideSection(name: String): Section { - val existingSec = this.sectionMap[name] + val canonSecName = name.uppercase() + val existingSec = this.sectionMap[canonSecName] if (existingSec != null) { return existingSec } val newSection = Section(entries = mutableMapOf()) - this.sectionMap[name] = newSection + this.sectionMap[canonSecName] = newSection return newSection } @@ -151,6 +151,25 @@ class TalerConfig { throw TalerConfigError("expected yes/no in configuration section $section option $option but got $v") } + private fun setSystemDefault(section: String, option: String, value: String) { + // FIXME: The value should be marked as a system default for diagnostics pretty printing + val sec = provideSection(section) + sec.entries[option.uppercase()] = Entry(value = value) + } + + fun putValueString(section: String, option: String, value: String) { + val sec = provideSection(section) + sec.entries[option.uppercase()] = Entry(value = value) + } + + fun lookupValuePath(section: String, option: String): String? { + val entry = lookupEntry(section, option) + if (entry == null) { + return null + } + return pathsub(entry.value) + } + /** * Create a string representation of the loaded configuration. */ @@ -187,9 +206,63 @@ class TalerConfig { fun loadDefaults() { val installDir = getTalerInstallPath() val baseConfigDir = Paths.get(installDir, "share/taler/config.d").toString() + setSystemDefault("PATHS", "PREFIX", "${installDir}/") + setSystemDefault("PATHS", "BINDIR", "${installDir}/bin/") + setSystemDefault("PATHS", "LIBEXECDIR", "${installDir}/taler/libexec/") + setSystemDefault("PATHS", "DOCDIR", "${installDir}/share/doc/taler/") + setSystemDefault("PATHS", "ICONDIR", "${installDir}/share/icons/") + setSystemDefault("PATHS", "LOCALEDIR", "${installDir}/share/locale/") + setSystemDefault("PATHS", "LIBDIR", "${installDir}/lib/taler/") + setSystemDefault("PATHS", "DATADIR", "${installDir}/share/taler/") loadDefaultsFromDir(baseConfigDir) } + fun variableLookup(x: String, recursionDepth: Int = 0): String? { + val pathRes = this.lookupValueString("PATHS", x) + if (pathRes != null) { + return pathsub(pathRes, recursionDepth + 1) + } + val envVal = System.getenv(x) + if (envVal != null) { + return envVal + } + return null + } + + fun pathsub(x: String, recursionDepth: Int = 0): String { + if (recursionDepth > 128) { + throw TalerConfigError("recursion limit in path substitution exceeded") + } + val result = StringBuilder() + var l = 0 + val s = x + while (l < s.length) { + if (s[l] != '$') { + // normal character + result.append(s[l]) + l++; + continue + } + if (l + 1 < s.length && s[l + 1] == '{') { + // ${var} + throw NotImplementedError("bracketed variables not yet supported") + } else { + // $var + var varEnd = l + 1 + while (varEnd < s.length && (s[varEnd].isLetterOrDigit() || s[varEnd] == '_')) { + varEnd++ + } + val varName = s.substring(l + 1, varEnd) + val res = variableLookup(varName) + if (res != null) { + result.append(res) + } + l = varEnd + } + } + return result.toString() + } + companion object { /** * Load configuration values from the file system. diff --git a/util/src/test/kotlin/TalerConfigTest.kt b/util/src/test/kotlin/TalerConfigTest.kt @@ -42,4 +42,19 @@ class TalerConfigTest { println(TalerConfig.getTalerInstallPath()) } + + @Test + fun substitution() { + val conf = TalerConfig() + conf.putValueString("PATHS", "DATADIR", "mydir") + conf.putValueString("foo", "bar", "baz") + conf.putValueString("foo", "bar2", "baz") + + assertEquals("baz", conf.lookupValueString("foo", "bar")) + assertEquals("baz", conf.lookupValuePath("foo", "bar")) + + conf.putValueString("foo", "dir1", "foo/\$DATADIR/bar") + + assertEquals("foo/mydir/bar", conf.lookupValuePath("foo", "dir1")) + } }