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:
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"))
+ }
}