From 13d37195e8a4e97dcb2ce000fb4abf23632dc504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Wed, 3 Sep 2025 16:11:26 +0200 Subject: [PATCH 1/7] rm --project cmd option --- .../ch/kleis/lcaac/cli/cmd/AssessCommand.kt | 9 +- .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 6 +- .../ch/kleis/lcaac/cli/cmd/TraceCommand.kt | 6 +- .../ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt | 94 ++++++++++--------- .../03-advanced/03-project-file/README.md | 7 -- tutorials/README.md | 2 + tutorials/run.sh | 1 + 7 files changed, 57 insertions(+), 68 deletions(-) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt index bbc6c89c..02c53f7c 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt @@ -1,8 +1,8 @@ package ch.kleis.lcaac.cli.cmd -import ch.kleis.lcaac.cli.csv.assess.AssessCsvProcessor import ch.kleis.lcaac.cli.csv.CsvRequest import ch.kleis.lcaac.cli.csv.CsvRequestReader +import ch.kleis.lcaac.cli.csv.assess.AssessCsvProcessor import ch.kleis.lcaac.cli.csv.assess.AssessCsvResultWriter import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.math.basic.BasicOperations @@ -13,7 +13,6 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.options.associate -import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file @@ -29,10 +28,8 @@ class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary Example: lcaac assess -l model="ABC" -l geo="FR". """.trimIndent()) .associate() - private val getProjectPath = option("-p", "--project").file() - .default(File(defaultLcaacFilename)) - .help("Path to project folder or yaml file.") - val projectPath: File by getProjectPath + + val projectPath = File(defaultLcaacFilename) val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index ac9136c8..c8df4b9a 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -19,7 +19,6 @@ import com.github.ajalt.clikt.core.ProgramResult import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.default import com.github.ajalt.clikt.parameters.arguments.help -import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option @@ -33,10 +32,7 @@ private const val redCross = "\u274C" class TestCommand : CliktCommand(name = "test", help = "Run specified tests") { val name: String by argument().help("Process name").default("") - private val getProjectPath = option("-p", "--project").file() - .default(File(defaultLcaacFilename)) - .help("Path to project folder or yaml file.") - val projectPath: File by getProjectPath + val projectPath = File(defaultLcaacFilename) val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt index 815ac0b6..1f67fc38 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt @@ -13,7 +13,6 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.options.associate -import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file @@ -29,10 +28,7 @@ class TraceCommand : CliktCommand(name = "trace", help = "Trace the contribution Example: lcaac assess -l model="ABC" -l geo="FR". """.trimIndent()) .associate() - private val getProjectPath = option("-p", "--project").file() - .default(File(defaultLcaacFilename)) - .help("Path to project folder or yaml file.") - val projectPath: File by getProjectPath + val projectPath = File(defaultLcaacFilename) val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt index c455f8d6..225f1c1d 100644 --- a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt @@ -8,6 +8,7 @@ import ch.kleis.lcaac.core.math.basic.BasicNumber import ch.kleis.lcaac.core.prelude.Prelude import io.mockk.every import io.mockk.mockk +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.assertThrows import java.io.File import java.nio.file.Path @@ -19,51 +20,54 @@ import kotlin.test.assertEquals class UtilsKtTest { - @Test - fun parseProjectPath_whenSimpleFile() { - // given - val path = mockk() - every { path.isDirectory } returns false - every { path.parentFile } returns null - every { path.path } returns "lcaac.yaml" - - // when - val (workingDir, configFile) = parseProjectPath(path) - - // then - assertEquals(".", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) - } - - @Test - fun parseProjectPath_whenFileWithParentDirectory() { - // given - val path = mockk() - every { path.isDirectory } returns false - every { path.parentFile } returns Paths.get("some", "directory").toFile() - every { path.path } returns "lcaac.yaml" - - // when - val (workingDir, configFile) = parseProjectPath(path) - - // then - assertEquals("some/directory", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) - } - - @Test - fun parseProjectPath_whenDirectory() { - // given - val path = mockk() - every { path.isDirectory } returns true - every { path.path } returns "some/directory" - - // when - val (workingDir, configFile) = parseProjectPath(path) - - // then - assertEquals("some/directory", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) + @Nested + inner class ParseProjectPath { + @Test + fun whenSimpleFile() { + // given + val path = mockk() + every { path.isDirectory } returns false + every { path.parentFile } returns null + every { path.path } returns "lcaac.yaml" + + // when + val (workingDir, configFile) = parseProjectPath(path) + + // then + assertEquals(".", workingDir.path) + assertEquals("lcaac.yaml", configFile.path) + } + + @Test + fun whenFileWithParentDirectory() { + // given + val path = mockk() + every { path.isDirectory } returns false + every { path.parentFile } returns Paths.get("some", "directory").toFile() + every { path.path } returns "lcaac.yaml" + + // when + val (workingDir, configFile) = parseProjectPath(path) + + // then + assertEquals("some/directory", workingDir.path) + assertEquals("lcaac.yaml", configFile.path) + } + + @Test + fun whenDirectory() { + // given + val path = mockk() + every { path.isDirectory } returns true + every { path.path } returns "some/directory" + + // when + val (workingDir, configFile) = parseProjectPath(path) + + // then + assertEquals("some/directory", workingDir.path) + assertEquals("lcaac.yaml", configFile.path) + } } @Test diff --git a/tutorials/03-advanced/03-project-file/README.md b/tutorials/03-advanced/03-project-file/README.md index 6d3c404e..f670e1d6 100644 --- a/tutorials/03-advanced/03-project-file/README.md +++ b/tutorials/03-advanced/03-project-file/README.md @@ -25,10 +25,3 @@ connectors: options: directory: mock ``` - -Here each file specifies a different location for the folder containing the CSV files supporting the datasources. -You can choose which settings to use with the cli option `-p` or `--project`. -```bash -lcaac assess --project lcaac.yaml main -lcaac assess --project lcaac-mock.yaml main -``` diff --git a/tutorials/README.md b/tutorials/README.md index 57d458fb..5a1c5bfa 100644 --- a/tutorials/README.md +++ b/tutorials/README.md @@ -4,7 +4,9 @@ This folder contains multiple code samples covering the main LCAAC language feat Each code sample takes the form a `.lca` file. Use the [cli](../cli/README.md) to interact with the code. Moreover, each code sample contains tests. You can run the tests manually, e.g., + ```bash +#TODO adapt command with new --source parameter lcaac test -p 01-basics/01-getting-started ``` diff --git a/tutorials/run.sh b/tutorials/run.sh index d1704979..d49951f1 100755 --- a/tutorials/run.sh +++ b/tutorials/run.sh @@ -20,6 +20,7 @@ if ! [ -f $LCAAC_PATH/lcaac ]; then fi # Check all lca tests +#TODO adapt command with new --source parameter lcaac test -p $TUTORIALS_PATH/01-basics/01-getting-started lcaac test -p $TUTORIALS_PATH/01-basics/02-biosphere lcaac test -p $TUTORIALS_PATH/01-basics/03-impacts From 860b73aa25ff36ee355c90cad560fec21192774b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Wed, 3 Sep 2025 17:01:42 +0200 Subject: [PATCH 2/7] add config option to CLI --- .../ch/kleis/lcaac/cli/cmd/AssessCommand.kt | 15 +++--- .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 16 +++---- .../ch/kleis/lcaac/cli/cmd/TraceCommand.kt | 15 +++--- .../kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt | 13 +++--- .../ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt | 46 +++++-------------- cli/src/test/resources/validLcaacConfig.yaml | 8 ++++ .../ch/kleis/lcaac/core/config/LcaacConfig.kt | 1 + 7 files changed, 47 insertions(+), 67 deletions(-) create mode 100644 cli/src/test/resources/validLcaacConfig.yaml diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt index 02c53f7c..39071cb8 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt @@ -4,19 +4,19 @@ import ch.kleis.lcaac.cli.csv.CsvRequest import ch.kleis.lcaac.cli.csv.CsvRequestReader import ch.kleis.lcaac.cli.csv.assess.AssessCsvProcessor import ch.kleis.lcaac.cli.csv.assess.AssessCsvResultWriter -import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.math.basic.BasicOperations import ch.kleis.lcaac.grammar.Loader import ch.kleis.lcaac.grammar.LoaderOption -import com.charleskorn.kaml.decodeFromStream import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.options.associate +import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import java.io.File +import kotlin.io.path.Path @Suppress("MemberVisibilityCanBePrivate", "DuplicatedCode") class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary impacts of a process in CSV format") { @@ -29,7 +29,9 @@ class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary """.trimIndent()) .associate() - val projectPath = File(defaultLcaacFilename) + val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) + .default(File(defaultLcaacFilename)) + .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" @@ -52,11 +54,8 @@ class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary ).associate() override fun run() { - val (workingDirectory, lcaacConfigFile) = parseProjectPath(projectPath) - val yamlConfig = if (lcaacConfigFile.exists()) projectPath.inputStream().use { - yaml.decodeFromStream(LcaacConfig.serializer(), it) - } - else LcaacConfig() + val workingDirectory = Path(".").toFile() + val yamlConfig = parseLcaacConfig(configFile) val files = lcaFiles(workingDirectory) val symbolTable = Loader( diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index c8df4b9a..ba8db316 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -1,6 +1,5 @@ package ch.kleis.lcaac.cli.cmd -import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.datasource.ConnectorFactory import ch.kleis.lcaac.core.datasource.DefaultDataSourceOperations import ch.kleis.lcaac.core.datasource.csv.CsvConnectorBuilder @@ -13,17 +12,18 @@ import ch.kleis.lcaac.grammar.CoreTestMapper import ch.kleis.lcaac.grammar.Loader import ch.kleis.lcaac.grammar.LoaderOption import ch.kleis.lcaac.grammar.parser.LcaLangParser -import com.charleskorn.kaml.decodeFromStream import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.ProgramResult import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.default import com.github.ajalt.clikt.parameters.arguments.help +import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import java.io.File +import kotlin.io.path.Path private const val greenTick = "\u2705" private const val redCross = "\u274C" @@ -32,7 +32,9 @@ private const val redCross = "\u274C" class TestCommand : CliktCommand(name = "test", help = "Run specified tests") { val name: String by argument().help("Process name").default("") - val projectPath = File(defaultLcaacFilename) + val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) + .default(File(defaultLcaacFilename)) + .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" @@ -42,12 +44,8 @@ class TestCommand : CliktCommand(name = "test", help = "Run specified tests") { val showSuccess: Boolean by option("--show-success").flag(default = false).help("Show successful assertions") override fun run() { - val (workingDirectory, lcaacConfigFile) = parseProjectPath(projectPath) - - val yamlConfig = if (lcaacConfigFile.exists()) projectPath.inputStream().use { - yaml.decodeFromStream(LcaacConfig.serializer(), it) - } - else LcaacConfig() + val workingDirectory = Path(".").toFile() + val yamlConfig = parseLcaacConfig(configFile) val ops = BasicOperations val files = lcaFiles(workingDirectory) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt index 1f67fc38..51eabb6c 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt @@ -4,19 +4,19 @@ import ch.kleis.lcaac.cli.csv.CsvRequest import ch.kleis.lcaac.cli.csv.CsvRequestReader import ch.kleis.lcaac.cli.csv.trace.TraceCsvProcessor import ch.kleis.lcaac.cli.csv.trace.TraceCsvResultWriter -import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.math.basic.BasicOperations import ch.kleis.lcaac.grammar.Loader import ch.kleis.lcaac.grammar.LoaderOption -import com.charleskorn.kaml.decodeFromStream import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.options.associate +import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import java.io.File +import kotlin.io.path.Path @Suppress("MemberVisibilityCanBePrivate", "DuplicatedCode") class TraceCommand : CliktCommand(name = "trace", help = "Trace the contributions") { @@ -28,7 +28,9 @@ class TraceCommand : CliktCommand(name = "trace", help = "Trace the contribution Example: lcaac assess -l model="ABC" -l geo="FR". """.trimIndent()) .associate() - val projectPath = File(defaultLcaacFilename) + val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) + .default(File(defaultLcaacFilename)) + .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") val file: File? by option("-f", "--file").file(canBeDir = false) .help(""" @@ -51,11 +53,8 @@ class TraceCommand : CliktCommand(name = "trace", help = "Trace the contribution ).associate() override fun run() { - val (workingDirectory, lcaacConfigFile) = parseProjectPath(projectPath) - val yamlConfig = if (lcaacConfigFile.exists()) projectPath.inputStream().use { - yaml.decodeFromStream(LcaacConfig.serializer(), it) - } - else LcaacConfig() + val workingDirectory = Path(".").toFile() + val yamlConfig = parseLcaacConfig(configFile) val files = lcaFiles(workingDirectory) val symbolTable = Loader( diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt index 44568ab2..6a187df6 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt @@ -1,5 +1,6 @@ package ch.kleis.lcaac.cli.cmd +import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.evaluator.reducer.DataExpressionReducer import ch.kleis.lcaac.core.lang.expression.* @@ -14,6 +15,7 @@ import ch.kleis.lcaac.grammar.parser.LcaLangLexer import ch.kleis.lcaac.grammar.parser.LcaLangParser import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.YamlConfiguration +import com.charleskorn.kaml.decodeFromStream import org.antlr.v4.runtime.CharStreams import org.antlr.v4.runtime.CommonTokenStream import java.io.File @@ -28,13 +30,10 @@ val yaml = Yaml(configuration = YamlConfiguration( )) const val defaultLcaacFilename = "lcaac.yaml" -fun parseProjectPath(path: File): Pair { - if (path.isDirectory) { - val configFile = Path(defaultLcaacFilename).toFile() - return path to configFile - } - val workingDirectory = path.parentFile ?: Path(".").toFile() - return workingDirectory to path +fun parseLcaacConfig(path: File): LcaacConfig { + return if (path.exists()) path.inputStream().use { + yaml.decodeFromStream(LcaacConfig.serializer(), it) + } else LcaacConfig() } fun lcaFiles(root: File): Sequence { diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt index 225f1c1d..e95261b6 100644 --- a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt @@ -19,54 +19,30 @@ import kotlin.test.assertEquals class UtilsKtTest { - @Nested - inner class ParseProjectPath { - @Test - fun whenSimpleFile() { - // given - val path = mockk() - every { path.isDirectory } returns false - every { path.parentFile } returns null - every { path.path } returns "lcaac.yaml" - - // when - val (workingDir, configFile) = parseProjectPath(path) - - // then - assertEquals(".", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) - } - + inner class ParseLcaacConfig { @Test - fun whenFileWithParentDirectory() { + fun `when file exists decode it`() { // given - val path = mockk() - every { path.isDirectory } returns false - every { path.parentFile } returns Paths.get("some", "directory").toFile() - every { path.path } returns "lcaac.yaml" + val path = File("src/test/resources/validLcaacConfig.yaml") // when - val (workingDir, configFile) = parseProjectPath(path) + val config = parseLcaacConfig(path) - // then - assertEquals("some/directory", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) + // + assertEquals("Valid LCAAC Config", config.name) } @Test - fun whenDirectory() { + fun `when file does not exist return default config`() { // given - val path = mockk() - every { path.isDirectory } returns true - every { path.path } returns "some/directory" + val path = File("") // when - val (workingDir, configFile) = parseProjectPath(path) + val config = parseLcaacConfig(path) - // then - assertEquals("some/directory", workingDir.path) - assertEquals("lcaac.yaml", configFile.path) + // + assertEquals("", config.name) } } diff --git a/cli/src/test/resources/validLcaacConfig.yaml b/cli/src/test/resources/validLcaacConfig.yaml new file mode 100644 index 00000000..e641d1f0 --- /dev/null +++ b/cli/src/test/resources/validLcaacConfig.yaml @@ -0,0 +1,8 @@ +name: Valid LCAAC Config +description: Valid LCAAC Config for test purposes +connectors: + - name: csv + cache: + enabled: true + options: + directory: data diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt index 2e1fc47d..25048756 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable data class LcaacConfig( val name: String = "", val description: String = "", + // TODO clean datasources val datasources: List = emptyList(), val connectors: List = listOf(CsvConnectorKeys.defaultConfig()), ) { From 852e4094d4c8e2125f89886f976832d82ea243ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Thu, 4 Sep 2025 10:26:39 +0200 Subject: [PATCH 3/7] feat: unzip source clean code clean code and add test for archive extraction add tests --- cli/build.gradle.kts | 2 + .../ch/kleis/lcaac/cli/cmd/AssessCommand.kt | 54 +--- .../ch/kleis/lcaac/cli/cmd/SharedOptions.kt | 53 ++++ .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 22 +- .../ch/kleis/lcaac/cli/cmd/TraceCommand.kt | 42 +-- .../kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt | 45 ++- .../cli/csv/assess/AssessCsvProcessor.kt | 4 +- .../kleis/lcaac/cli/cmd/SharedOptionTest.kt | 281 ++++++++++++++++++ .../cli/cmd/{UtilsKtTest.kt => UtilsTest.kt} | 54 +++- cli/src/test/resources/main.tar.gz | Bin 0 -> 356 bytes cli/src/test/resources/main.tgz | Bin 0 -> 356 bytes cli/src/test/resources/main.zip | Bin 0 -> 1211 bytes .../lcaac/core/config/ConnectorConfig.kt | 10 +- .../ch/kleis/lcaac/core/config/LcaacConfig.kt | 13 - .../lcaac/core/datasource/ConnectorFactory.kt | 4 +- .../datasource/csv/CsvConnectorBuilder.kt | 2 +- 16 files changed, 464 insertions(+), 122 deletions(-) create mode 100644 cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt create mode 100644 cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptionTest.kt rename cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/{UtilsKtTest.kt => UtilsTest.kt} (69%) create mode 100644 cli/src/test/resources/main.tar.gz create mode 100644 cli/src/test/resources/main.tgz create mode 100644 cli/src/test/resources/main.zip diff --git a/cli/build.gradle.kts b/cli/build.gradle.kts index 1048554c..626a5b65 100644 --- a/cli/build.gradle.kts +++ b/cli/build.gradle.kts @@ -47,6 +47,8 @@ dependencies { implementation("org.apache.commons:commons-csv:1.10.0") implementation("com.charleskorn.kaml:kaml:0.59.0") + + implementation("org.apache.commons:commons-compress:1.28.0") } tasks.build { diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt index 39071cb8..1bea377c 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommand.kt @@ -10,60 +10,32 @@ import ch.kleis.lcaac.grammar.LoaderOption import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help -import com.github.ajalt.clikt.parameters.options.associate -import com.github.ajalt.clikt.parameters.options.default -import com.github.ajalt.clikt.parameters.options.help -import com.github.ajalt.clikt.parameters.options.option -import com.github.ajalt.clikt.parameters.types.file import java.io.File -import kotlin.io.path.Path + +const val assessCommandName = "assess" @Suppress("MemberVisibilityCanBePrivate", "DuplicatedCode") -class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary impacts of a process in CSV format") { +class AssessCommand : CliktCommand(name = assessCommandName, help = "Returns the unitary impacts of a process in CSV format") { val name: String by argument().help("Process name") - val labels: Map by option("-l", "--label") - .help( - """ - Specify a process label as a key value pair. - Example: lcaac assess -l model="ABC" -l geo="FR". - """.trimIndent()) - .associate() - - val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) - .default(File(defaultLcaacFilename)) - .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") - - val file: File? by option("-f", "--file").file(canBeDir = false) - .help(""" - CSV file with parameter values. - Example: `lcaac assess -f params.csv`. - """.trimIndent()) - val arguments: Map by option("-D", "--parameter") - .help( - """ - Override parameter value as a key value pair. - Example: `lcaac assess -D x="12 kg" -D geo="UK" -f params.csv`. - """.trimIndent()) - .associate() - val globals: Map by option("-G", "--global") - .help( - """ - Override global variable as a key value pair. - Example: `lcaac assess -G x="12 kg"`. - """.trimIndent() - ).associate() + val configFile: File by configFileOption() + val source: File by sourceOption() + val file: File? by fileOption(assessCommandName) + val labels: Map by labelsOption(assessCommandName) + val arguments: Map by argumentsOption(assessCommandName) + val globals: Map by globalsOption(assessCommandName) override fun run() { - val workingDirectory = Path(".").toFile() + val sourceDirectory = parseSource(source) + val projectDirectory = configFile.parentFile val yamlConfig = parseLcaacConfig(configFile) - val files = lcaFiles(workingDirectory) + val files = lcaFiles(sourceDirectory) val symbolTable = Loader( ops = BasicOperations, overriddenGlobals = dataExpressionMap(BasicOperations, globals), ).load(files, listOf(LoaderOption.WITH_PRELUDE)) - val processor = AssessCsvProcessor(yamlConfig, symbolTable, workingDirectory.path) + val processor = AssessCsvProcessor(yamlConfig, symbolTable, projectDirectory.path) val iterator = loadRequests() val writer = AssessCsvResultWriter() var first = true diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt new file mode 100644 index 00000000..62a6ea4d --- /dev/null +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt @@ -0,0 +1,53 @@ +package ch.kleis.lcaac.cli.cmd + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.options.associate +import com.github.ajalt.clikt.parameters.options.default +import com.github.ajalt.clikt.parameters.options.help +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.types.file +import java.io.File +import kotlin.io.path.Path + +fun CliktCommand.configFileOption() = option("-c", "--config", help = "Path to LCAAC config file") + .file(canBeDir = false) + .default(File("./$defaultLcaacFilename")) + .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") + +fun CliktCommand.sourceOption() = option("-s", "--source", help = "Path to LCA source folder or zip/tar.gz file") + .file() + .default(Path(".").toFile()) + .help("Path to LCAAC source folder or zip/tar.gz file. Defaults to current working directory.") + +fun CliktCommand.fileOption(commandName: String) = option("-f", "--file") + .file(canBeDir = false) + .help(""" + CSV file with parameter values. + Example: `lcaac $commandName -f params.csv` + """.trimIndent() + ) + +fun CliktCommand.labelsOption(commandName: String) = option("-l", "--label") + .help(""" + Specify a process label as a key value pair. + Example: lcaac $commandName -l model="ABC" -l geo="FR". + """.trimIndent()) + .associate() + +fun CliktCommand.argumentsOption(commandName: String) = option("-D", "--parameter") + .help( + """ + Override parameter value as a key value pair. + Example: `lcaac $commandName -D x="12 kg" -D geo="UK" -f params.csv`. + """.trimIndent()) + .associate() + +fun CliktCommand.globalsOption(commandName: String) = option("-G", "--global") + .help( + """ + Override global variable as a key value pair. + Example: `lcaac $commandName -G x="12 kg"`. + """.trimIndent() + ).associate() + + diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index ba8db316..47ca73bf 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -17,34 +17,26 @@ import com.github.ajalt.clikt.core.ProgramResult import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.default import com.github.ajalt.clikt.parameters.arguments.help -import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option -import com.github.ajalt.clikt.parameters.types.file import java.io.File -import kotlin.io.path.Path private const val greenTick = "\u2705" private const val redCross = "\u274C" +const val testCommandName = "test" + @Suppress("MemberVisibilityCanBePrivate", "DuplicatedCode") -class TestCommand : CliktCommand(name = "test", help = "Run specified tests") { +class TestCommand : CliktCommand(name = testCommandName, help = "Run specified tests") { val name: String by argument().help("Process name").default("") - - val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) - .default(File(defaultLcaacFilename)) - .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") - - val file: File? by option("-f", "--file").file(canBeDir = false) - .help(""" - CSV file with parameter values. - Example: `lcaac assess -f params.csv`. - """.trimIndent()) + val configFile: File by configFileOption() + val source: File by sourceOption() + val file: File? by fileOption(testCommandName) val showSuccess: Boolean by option("--show-success").flag(default = false).help("Show successful assertions") override fun run() { - val workingDirectory = Path(".").toFile() + val workingDirectory = parseSource(source) val yamlConfig = parseLcaacConfig(configFile) val ops = BasicOperations diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt index 51eabb6c..7363626f 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt @@ -18,42 +18,20 @@ import com.github.ajalt.clikt.parameters.types.file import java.io.File import kotlin.io.path.Path +const val traceCommandName = "trace" + @Suppress("MemberVisibilityCanBePrivate", "DuplicatedCode") -class TraceCommand : CliktCommand(name = "trace", help = "Trace the contributions") { +class TraceCommand : CliktCommand(name = traceCommandName, help = "Trace the contributions") { val name: String by argument().help("Process name") - val labels: Map by option("-l", "--label") - .help( - """ - Specify a process label as a key value pair. - Example: lcaac assess -l model="ABC" -l geo="FR". - """.trimIndent()) - .associate() - val configFile: File by option("-c", "--config", help = "Path to LCAAC config file").file(canBeDir = false) - .default(File(defaultLcaacFilename)) - .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") - - val file: File? by option("-f", "--file").file(canBeDir = false) - .help(""" - CSV file with parameter values. - Example: `lcaac trace -f params.csv`. - """.trimIndent()) - val arguments: Map by option("-D", "--parameter") - .help( - """ - Override parameter value as a key value pair. - Example: `lcaac assess -D x="12 kg" -D geo="UK" -f params.csv`. - """.trimIndent()) - .associate() - val globals: Map by option("-G", "--global") - .help( - """ - Override global variable as a key value pair. - Example: `lcaac assess -G x="12 kg"`. - """.trimIndent() - ).associate() + val configFile: File by configFileOption() + val source: File by sourceOption() + val file: File? by fileOption(traceCommandName) + val labels: Map by labelsOption(traceCommandName) + val arguments: Map by argumentsOption(traceCommandName) + val globals: Map by globalsOption(traceCommandName) override fun run() { - val workingDirectory = Path(".").toFile() + val workingDirectory = parseSource(source) val yamlConfig = parseLcaacConfig(configFile) val files = lcaFiles(workingDirectory) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt index 6a187df6..550020ab 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt @@ -18,18 +18,61 @@ import com.charleskorn.kaml.YamlConfiguration import com.charleskorn.kaml.decodeFromStream import org.antlr.v4.runtime.CharStreams import org.antlr.v4.runtime.CommonTokenStream +import org.apache.commons.compress.archivers.examples.Expander +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream +import java.io.BufferedInputStream import java.io.File +import java.io.FileInputStream import java.io.InputStream import java.lang.Double.parseDouble import java.nio.file.Files -import kotlin.io.path.Path import kotlin.io.path.isRegularFile + val yaml = Yaml(configuration = YamlConfiguration( strictMode = false )) const val defaultLcaacFilename = "lcaac.yaml" +fun parseSource(path: File): File { + if (path.isDirectory) return path + + val name = path.name.lowercase() + return when { + name.endsWith(".zip") -> extractZip(path) + name.endsWith(".tar.gz") || name.endsWith(".tgz") -> extractTarGz(path) + else -> + error("Unsupported file format: ${path.name}. Supported file formats are zip, tar.gz and tgz.") + } +} + +private fun extractZip(zipFile: File): File { + val outputDir = Files.createTempDirectory("lca_zip_source_").toFile() + Expander().expand(zipFile, outputDir) + return outputDir +} + +private fun extractTarGz(tarGzFile: File): File { + val outputDir = Files.createTempDirectory("lca_targz_source_").toFile() + TarArchiveInputStream(GzipCompressorInputStream(BufferedInputStream(FileInputStream(tarGzFile)))).use { tarInput -> + var entry = tarInput.nextEntry + while (entry != null) { + val outputFile = File(outputDir, entry.name) + if (entry.isDirectory) { + outputFile.mkdirs() + } else { + outputFile.parentFile.mkdirs() + outputFile.outputStream().use { output -> + tarInput.copyTo(output) + } + } + entry = tarInput.nextEntry + } + } + return outputDir +} + fun parseLcaacConfig(path: File): LcaacConfig { return if (path.exists()) path.inputStream().use { yaml.decodeFromStream(LcaacConfig.serializer(), it) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt index e2104df3..48f23f13 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt @@ -17,11 +17,11 @@ import ch.kleis.lcaac.core.math.basic.BasicOperations class AssessCsvProcessor( config: LcaacConfig, private val symbolTable: SymbolTable, - workingDirectory: String, + projectDirectory: String, ) { private val ops = BasicOperations private val factory = ConnectorFactory( - workingDirectory, + projectDirectory, config, ops, symbolTable, diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptionTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptionTest.kt new file mode 100644 index 00000000..fb82ff2c --- /dev/null +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptionTest.kt @@ -0,0 +1,281 @@ +package ch.kleis.lcaac.cli.cmd + +import com.github.ajalt.clikt.core.BadParameterValue +import com.github.ajalt.clikt.core.CliktCommand +import org.junit.jupiter.api.Nested +import java.io.File +import kotlin.io.path.createTempDirectory +import kotlin.io.path.createTempFile +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +class SharedOptionTest { + private class DummyCommand : CliktCommand() { + val configFile by configFileOption() + val source by sourceOption() + val file by fileOption("dummy") + val labels by labelsOption("dummy") + val arguments by argumentsOption("dummy") + val globals by globalsOption("dummy") + override fun run() { + // no-op + } + } + + @Nested + inner class ConfigFileOption { + @Test + fun `when no option is provided uses default config file`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(emptyArray()) + + // then + val expected = File("./$defaultLcaacFilename") + assertEquals(expected, cmd.configFile) + } + + @Test + fun `when directory provided should throw`() { + // given + val tmpDir = createTempDirectory().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + then + val exception = assertFailsWith { + cmd.parse(arrayOf("--config", tmpDir)) + } + assertEquals(exception.message, "file \"$tmpDir\" is a directory.") + } + + @Test + fun `when valid file provided should parse successfully`() { + // given + val tmpFile = createTempFile().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("--config", tmpFile)) + + assertEquals(tmpFile, cmd.configFile.absoluteFile.toString()) + } + } + + @Nested + inner class SourceOption { + @Test + fun `when no option is provided uses current work directory`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(emptyArray()) + + // then + val expected = File(".") + assertEquals(expected, cmd.source) + } + + @Test + fun `when valid file provided should parse successfully`() { + // given + val tmpFile = createTempFile().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("--source", tmpFile)) + + assertEquals(tmpFile, cmd.source.absoluteFile.toString()) + } + + @Test + fun `when valid directory provided should parse successfully`() { + // given + val tmpFile = createTempDirectory().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("--source", tmpFile)) + + assertEquals(tmpFile, cmd.source.absoluteFile.toString()) + } + } + + @Nested + inner class FileOption { + @Test + fun `when directory provided should throw`() { + // given + val tmpDir = createTempDirectory().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + then + val exception = assertFailsWith { + cmd.parse(arrayOf("--file", tmpDir)) + } + assertEquals(exception.message, "file \"$tmpDir\" is a directory.") + } + + @Test + fun `when valid file provided should parse successfully`() { + // given + val tmpFile = createTempFile().toAbsolutePath().toString() + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("--file", tmpFile)) + + assertEquals(tmpFile, cmd.file?.absoluteFile.toString()) + } + + @Test + fun `when display help should write example with the corresponding command`() { + // given + val cmd = DummyCommand() + + // when + val helpText = cmd.getFormattedHelp() + + assertTrue( + helpText!!.contains("-f, --file= CSV file with parameter values. Example: lcaac dummy"), + "Help for -f options should contain an example with the corresponding command." + ) + } + } + + @Nested + inner class LabelsOption { + @Test + fun `when single label provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-l", """model="ABC"""")) + + // then + val expected = mapOf("model" to "\"ABC\"") + assertEquals(expected, cmd.labels) + } + + @Test + fun `when multiple arguments provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-l", """model="ABC"""", "-l", """geo=UK""")) + + // then + val expected = mapOf("model" to "\"ABC\"", "geo" to "UK") + assertEquals(expected, cmd.labels) + } + + @Test + fun `when display help should write example with the corresponding command`() { + // given + val cmd = DummyCommand() + + // when + val helpText = cmd.getFormattedHelp() + + assertTrue( + helpText!!.contains("-l, --label= Specify a process label as a key value pair.\n" + + " Example: lcaac dummy"), + "Help for -l options should contain an example with the corresponding command." + ) + } + } + + @Nested + inner class ArgumentsOption { + @Test + fun `when single argument provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-D", """x="12 kg"""")) + + // then + val expected = mapOf("x" to "\"12 kg\"") + assertEquals(expected, cmd.arguments) + } + + @Test + fun `when multiple arguments provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-D", """x="12 kg"""", "-D", """y=42""")) + + // then + val expected = mapOf("x" to "\"12 kg\"", "y" to "42") + assertEquals(expected, cmd.arguments) + } + + @Test + fun `when display help should write example with the corresponding command`() { + // given + val cmd = DummyCommand() + + // when + val helpText = cmd.getFormattedHelp() + + assertTrue( + helpText!!.contains("-D, --parameter= Override parameter value as a key value pair.\n" + + " Example: lcaac dummy -D"), + "Help for -l options should contain an example with the corresponding command." + ) + } + } + + @Nested + inner class GlobalsOption { + @Test + fun `when single global provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-G", """x="12 kg"""")) + + // then + val expected = mapOf("x" to "\"12 kg\"") + assertEquals(expected, cmd.globals) + } + + @Test + fun `when multiple globals provided should parse correctly`() { + // given + val cmd = DummyCommand() + + // when + cmd.parse(arrayOf("-G", """x="12 kg"""", "-G", """y=42""")) + + // then + val expected = mapOf("x" to "\"12 kg\"", "y" to "42") + assertEquals(expected, cmd.globals) + } + + @Test + fun `when display help should write example with the corresponding command`() { + // given + val cmd = DummyCommand() + + // when + val helpText = cmd.getFormattedHelp() + + assertTrue( + helpText!!.contains("-G, --global= Override global variable as a key value pair.\n" + + " Example: lcaac dummy"), + "Help for -l options should contain an example with the corresponding command." + ) + } + } +} \ No newline at end of file diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsTest.kt similarity index 69% rename from cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt rename to cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsTest.kt index e95261b6..f42d218c 100644 --- a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsTest.kt @@ -6,19 +6,61 @@ import ch.kleis.lcaac.core.lang.expression.EQuantityMul import ch.kleis.lcaac.core.lang.expression.EQuantityScale import ch.kleis.lcaac.core.math.basic.BasicNumber import ch.kleis.lcaac.core.prelude.Prelude -import io.mockk.every -import io.mockk.mockk import org.junit.jupiter.api.Nested import org.junit.jupiter.api.assertThrows import java.io.File -import java.nio.file.Path -import java.nio.file.Paths -import kotlin.io.path.Path +import java.nio.file.Files +import kotlin.io.path.createTempDirectory import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue -class UtilsKtTest { +class UtilsTest { + @Nested + inner class ParseSourceTest { + @Test + fun `directory should be returned as-is`() { + // given + val tmpDir = createTempDirectory().toFile() + + // when + val result = parseSource(tmpDir) + + // then + assertEquals(tmpDir.absoluteFile, result.absoluteFile) + } + + @Test + fun `archived sources should be extracted`() { + val extensions = listOf("zip", "tar.gz", "tgz") + extensions.forEach { extension -> + // given + val zipFile = File("src/test/resources/main.$extension") + + // when + val result = parseSource(zipFile) + + // then + val extractedMainFile = File(result, "src/main.lca") + assertTrue( + extractedMainFile.exists() && extractedMainFile.isFile, + "Expected main.lca to exist inside extracted directory" + ) + } + } + + @Test + fun `unsupported file format should throw`() { + val tmpFile = Files.createTempFile("test", ".txt").toFile() + val exception = assertFailsWith { + parseSource(tmpFile) + } + assertEquals(exception.message, "Unsupported file format: ${tmpFile.name}. Supported file formats are zip, tar.gz and tgz.") + } + } + @Nested inner class ParseLcaacConfig { @Test diff --git a/cli/src/test/resources/main.tar.gz b/cli/src/test/resources/main.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..742173646e6341fa2396fc4668c31e7357876f8b GIT binary patch literal 356 zcmV-q0h|6GiwFP!000001MS!CZh|lr24H@B6}^FNEwtr&3RFjiAL)UZW#Qh}f?Jf$ z5fi{HzRwR)(!`Rt=d_T^U!s|DFIB3)>i)`O*1QC=+lH+x zzec)SZTDI34$Z}=IE*^JT2r4!wfBBH7&EBPcQS2g-8VY{}R6Xf7iB0Hh}Zi{_6(NjoLUvgbm=I2=%`;RBVC;$Mt C;=Gyw literal 0 HcmV?d00001 diff --git a/cli/src/test/resources/main.tgz b/cli/src/test/resources/main.tgz new file mode 100644 index 0000000000000000000000000000000000000000..742173646e6341fa2396fc4668c31e7357876f8b GIT binary patch literal 356 zcmV-q0h|6GiwFP!000001MS!CZh|lr24H@B6}^FNEwtr&3RFjiAL)UZW#Qh}f?Jf$ z5fi{HzRwR)(!`Rt=d_T^U!s|DFIB3)>i)`O*1QC=+lH+x zzec)SZTDI34$Z}=IE*^JT2r4!wfBBH7&EBPcQS2g-8VY{}R6Xf7iB0Hh}Zi{_6(NjoLUvgbm=I2=%`;RBVC;$Mt C;=Gyw literal 0 HcmV?d00001 diff --git a/cli/src/test/resources/main.zip b/cli/src/test/resources/main.zip new file mode 100644 index 0000000000000000000000000000000000000000..4469149f78ce5c3841440ad57545d0daa880a3b2 GIT binary patch literal 1211 zcmWIWW@h1H0D-$Hs?lHulwe_yVJI$2)(;KgWMDqDcUQ&{ATF)oW?*Fb%E-XLA_7zw z0N1@1O*cPOcX4TwZgGBTQF1E8pfsQ%Yw#I#4$UArOoPB?qM5rGx49sPaxj3*{VyKo zYXRiN1FUIE!T!f#ytc+Ee?MKlFpcvbzB+*`o&_;9H7)ux<AmLyn2SoYRWeNfvATEyN1W?q?XffJr2edv8h{Z8OCO0!D z2ksgiQ3!X<*)u1x28HOQqEFu4aM!p_74!(LbjwQOgoFqqlN>Xylqdmo76=G1ymbW8 zkaWokNtYOD5@8Z%szf#kLSRr13sMJK$-TuvM5T5ZS6SppBp~LZnB0p$>68W`aUC@h8+oq), val cache: CacheConfig = CacheConfig(), -) { - fun modifyOption(name: String, fn: (String) -> String) : ConnectorConfig = - this.copy( - options = this.options.mapValues { - if (it.key == name) fn(it.value) - else it.value - } - ) -} +) @Serializable data class CacheConfig( diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt index 25048756..6d302b84 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt @@ -12,16 +12,11 @@ data class LcaacConfig( val connectors: List = listOf(CsvConnectorKeys.defaultConfig()), ) { private val datasourcesMap = datasources.associateBy { it.name } - private val connectorsMap = connectors.associateBy { it.name } fun getDataSource(name: String): DataSourceConfig? { return datasourcesMap[name] } - fun getConnector(name: String): ConnectorConfig? { - return connectorsMap[name] - } - fun setOrModifyDatasource(datasource: DataSourceConfig): LcaacConfig { val mergedConfig = this.datasources .firstOrNull { it.name == datasource.name } @@ -37,13 +32,5 @@ data class LcaacConfig( datasources = newDatasources ) } - - fun modifyConnector(name: String, fn: (ConnectorConfig) -> ConnectorConfig): LcaacConfig = - this.copy( - connectors = this.connectors.map { - if (it.name == name) fn(it) - else it - } - ) } diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt index 2c445674..e7178327 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt @@ -7,14 +7,14 @@ import ch.kleis.lcaac.core.lang.SymbolTable import ch.kleis.lcaac.core.math.QuantityOperations class ConnectorFactory( - private val workingDirectory: String, + private val projectDirectory: String, private val lcaacConfig: LcaacConfig, private val ops: QuantityOperations, private val symbolTable: SymbolTable, private val builders: List> = listOf(CsvConnectorBuilder()) ) { - fun getWorkingDirectory(): String = workingDirectory + fun getProjectDirectory(): String = projectDirectory fun getLcaacConfig(): LcaacConfig = lcaacConfig fun getQuantityOperations(): QuantityOperations = ops fun getSymbolTable(): SymbolTable = symbolTable diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt index b46b8c86..fcef0128 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt @@ -25,7 +25,7 @@ class CsvConnectorBuilder : ConnectorBuilder { if (config.name != CsvConnectorKeys.CSV_CONNECTOR_NAME) { return null } - val directory = directory(factory.getWorkingDirectory(), config) + val directory = directory(factory.getProjectDirectory(), config) return CsvConnector( config, factory.getQuantityOperations() From 90c2089111a6162e9f9344d3081720c45900f65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Thu, 4 Sep 2025 19:57:25 +0200 Subject: [PATCH 4/7] remove datasource from config --- .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 6 +- .../cli/csv/assess/AssessCsvProcessor.kt | 2 +- .../lcaac/cli/csv/trace/TraceCsvProcessor.kt | 2 +- .../ch/kleis/lcaac/core/config/LcaacConfig.kt | 26 +------ .../core/datasource/DataSourceConnector.kt | 4 +- .../core/datasource/DataSourceOperations.kt | 5 -- .../datasource/DefaultDataSourceOperations.kt | 58 +++----------- .../lcaac/core/datasource/csv/CsvConnector.kt | 6 +- .../datasource/in_memory/InMemoryConnector.kt | 6 +- .../DefaultDataSourceOperationsTest.kt | 75 ++++++------------- 10 files changed, 44 insertions(+), 146 deletions(-) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index 47ca73bf..ad37d596 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -50,11 +50,7 @@ class TestCommand : CliktCommand(name = testCommandName, help = "Run specified t symbolTable, listOf(CsvConnectorBuilder()) ) - val sourceOps = DefaultDataSourceOperations( - ops, - yamlConfig, - factory.buildConnectors(), - ) + val sourceOps = DefaultDataSourceOperations(ops,factory.buildConnectors()) val mapper = CoreTestMapper() val cases = files diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt index 48f23f13..77383d22 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt @@ -27,7 +27,7 @@ class AssessCsvProcessor( symbolTable, listOf(CsvConnectorBuilder()) ) - private val sourceOps = DefaultDataSourceOperations(ops, config, factory.buildConnectors()) + private val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors()) private val dataReducer = DataExpressionReducer(symbolTable.data, symbolTable.dataSources, ops, sourceOps) private val evaluator = Evaluator(symbolTable, ops, sourceOps) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt index a12a7d73..1a6e5eb7 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt @@ -27,7 +27,7 @@ class TraceCsvProcessor( symbolTable, listOf(CsvConnectorBuilder()) ) - private val sourceOps = DefaultDataSourceOperations(ops, config, factory.buildConnectors()) + private val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors()) private val dataReducer = DataExpressionReducer(symbolTable.data, symbolTable.dataSources, ops, sourceOps) private val evaluator = Evaluator(symbolTable, ops, sourceOps) diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt index 6d302b84..a6ace6fc 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt @@ -7,30 +7,6 @@ import kotlinx.serialization.Serializable data class LcaacConfig( val name: String = "", val description: String = "", - // TODO clean datasources - val datasources: List = emptyList(), val connectors: List = listOf(CsvConnectorKeys.defaultConfig()), -) { - private val datasourcesMap = datasources.associateBy { it.name } - - fun getDataSource(name: String): DataSourceConfig? { - return datasourcesMap[name] - } - - fun setOrModifyDatasource(datasource: DataSourceConfig): LcaacConfig { - val mergedConfig = this.datasources - .firstOrNull { it.name == datasource.name } - ?.let { with(DataSourceConfig.merger(it.name)) { - it.combine(datasource) - } } - ?: datasource - val newDatasources = this.datasources - .associateBy { it.name } - .plus(mergedConfig.name to mergedConfig) - .values.toList() - return this.copy( - datasources = newDatasources - ) - } -} +) diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt index d66f3ce6..101002dd 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt @@ -9,11 +9,11 @@ interface DataSourceConnector { fun getName(): String fun getConfig(): ConnectorConfig fun getFirst( - caller: DataSourceOperationsWithConfig, + caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): ERecord fun getAll( - caller: DataSourceOperationsWithConfig, + caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): Sequence> } diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt index 00e4ddf2..708d521a 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt @@ -1,6 +1,5 @@ package ch.kleis.lcaac.core.datasource -import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.lang.expression.DataExpression import ch.kleis.lcaac.core.lang.expression.ERecord import ch.kleis.lcaac.core.lang.value.DataSourceValue @@ -10,7 +9,3 @@ interface DataSourceOperations { fun getAll(source: DataSourceValue): Sequence> fun sumProduct(source: DataSourceValue, columns: List): DataExpression } - -interface DataSourceOperationsWithConfig : DataSourceOperations { - fun getConfig(): LcaacConfig -} diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt index 85babb75..7bf03475 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt @@ -19,7 +19,6 @@ typealias ConnectorName = String class DefaultDataSourceOperations( private val ops: QuantityOperations, - private val config: LcaacConfig, private val connectors: Map>, private val cache: Map> = connectors .filter { it.value.getConfig().cache.enabled } @@ -29,72 +28,41 @@ class DefaultDataSourceOperations( it.value.getConfig().cache.maxRecordsPerCacheLine, ) } -) : DataSourceOperationsWithConfig { - - fun overrideWith(inMemoryConnector: InMemoryConnector): DefaultDataSourceOperations = - DefaultDataSourceOperations( - ops, - inMemoryConnector.getSourceNames() - .fold(config) { cfg, source -> - cfg.setOrModifyDatasource(DataSourceConfig( - name = source, - connector = InMemoryConnectorKeys.IN_MEMORY_CONNECTOR_NAME, - )) - }, - connectors.plus(inMemoryConnector.getName() to inMemoryConnector), - if (inMemoryConnector.getConfig().cache.enabled) - cache.plus(inMemoryConnector.getName() to SourceOpsCache( - inMemoryConnector.getConfig().cache.maxSize, - inMemoryConnector.getConfig().cache.maxRecordsPerCacheLine, - )) - else cache - ) - - private fun configOf(source: DataSourceValue): DataSourceConfig { - return with(DataSourceConfig.merger(source.config.name)) { - config.getDataSource(source.config.name) - ?.let { source.config.combine(it) } // lcaac config takes precedence - ?: source.config - } - } - +) : DataSourceOperations { private fun connectorOf(config: DataSourceConfig): DataSourceConnector { return connectors[config.connector] ?: throw IllegalArgumentException("Unknown connector '${config.connector}'") } override fun getFirst(source: DataSourceValue): ERecord { - val sourceConfig = configOf(source) - val connector = connectorOf(sourceConfig) + val connector = connectorOf(source.config) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") - return connectorCache.recordGetFirst(sourceConfig, source) { - connector.getFirst(this, sourceConfig, source) + return connectorCache.recordGetFirst(source.config, source) { + connector.getFirst(this, source.config, source) } - } else return connector.getFirst(this, sourceConfig, source) + } else return connector.getFirst(this, source.config, source) } override fun getAll(source: DataSourceValue): Sequence> { - val sourceConfig = configOf(source) - val connector = connectorOf(sourceConfig) + val connector = connectorOf(source.config) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") - return connectorCache.recordGetAll(sourceConfig, source) { - connector.getAll(this, sourceConfig, source).toList() + return connectorCache.recordGetAll(source.config, source) { + connector.getAll(this, source.config, source).toList() }.asSequence() - } else return connector.getAll(this, sourceConfig, source) + } else return connector.getAll(this, source.config, source) } override fun sumProduct(source: DataSourceValue, columns: List): DataExpression { - val sourceConfig = configOf(source) - val connector = connectorOf(sourceConfig) + val connector = connectorOf(source.config) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") return connectorCache.recordSumProduct( - sourceConfig, + source.config, source, columns, ) { @@ -145,8 +113,4 @@ class DefaultDataSourceOperations( reducer.reduce(EQuantityAdd(acc, expression)) })) } - - override fun getConfig(): LcaacConfig { - return config - } } diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt index e6549a0c..6764ceb9 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt @@ -3,7 +3,7 @@ package ch.kleis.lcaac.core.datasource.csv import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.datasource.DataSourceConnector -import ch.kleis.lcaac.core.datasource.DataSourceOperationsWithConfig +import ch.kleis.lcaac.core.datasource.DataSourceOperations import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.expression.DataExpression import ch.kleis.lcaac.core.lang.expression.EQuantityScale @@ -40,7 +40,7 @@ class CsvConnector( return header to records.iterator().asSequence() } - override fun getAll(caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): + override fun getAll(caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): Sequence> { val location = config.location ?: throw EvaluatorException("Missing location in configuration for datasource '${config.name}'") @@ -51,7 +51,7 @@ class CsvConnector( return records } - override fun getFirst(caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): ERecord { + override fun getFirst(caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): ERecord { return getAll(caller, config, source).firstOrNull() ?: throw EvaluatorException("no record found in datasource '${config.name}' [${config.location}] matching" + " ${source.filter}") diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt index 77d59ba4..36e78b5e 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt @@ -3,7 +3,7 @@ package ch.kleis.lcaac.core.datasource.in_memory import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.datasource.DataSourceConnector -import ch.kleis.lcaac.core.datasource.DataSourceOperationsWithConfig +import ch.kleis.lcaac.core.datasource.DataSourceOperations import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.expression.ERecord import ch.kleis.lcaac.core.lang.value.DataSourceValue @@ -26,7 +26,7 @@ class InMemoryConnector( fun getSourceNames(): List = content.keys.toList() override fun getAll( - caller: DataSourceOperationsWithConfig, + caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue, ): Sequence> { @@ -42,7 +42,7 @@ class InMemoryConnector( } override fun getFirst( - caller: DataSourceOperationsWithConfig, + caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue, ): ERecord { diff --git a/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt b/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt index 1c18e722..cd410574 100644 --- a/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt +++ b/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt @@ -3,6 +3,7 @@ package ch.kleis.lcaac.core.datasource import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.config.LcaacConfig +import ch.kleis.lcaac.core.datasource.csv.CsvConnectorKeys import ch.kleis.lcaac.core.datasource.in_memory.InMemoryConnector import ch.kleis.lcaac.core.datasource.in_memory.InMemoryConnectorKeys import ch.kleis.lcaac.core.datasource.in_memory.InMemoryDatasource @@ -28,14 +29,12 @@ class DefaultDataSourceOperationsTest { private val connectorConfig = ConnectorConfig(name = connectorName, options = emptyMap()) private val sourceName = "source" - private val sourceConfig = DataSourceConfig(name = sourceName, connector = connectorName) private val symbolTable = SymbolTable.empty() private val config = LcaacConfig( name = "project", description = "description", - datasources = listOf(sourceConfig), connectors = listOf(connectorConfig), ) private val ops = BasicOperations @@ -79,12 +78,7 @@ class DefaultDataSourceOperationsTest { val builder = mockk>() every { builder.buildOrNull(any(), any()) } returns connector val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) - val sourceOps = DefaultDataSourceOperations( - ops, - factory.getLcaacConfig(), - factory.buildConnectors(), - emptyMap(), - ) + val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors(), emptyMap()) val source = DataSourceValue( config = DataSourceConfig( name = sourceName, @@ -144,7 +138,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - factory.getLcaacConfig(), + factory.buildConnectors(), emptyMap() ) @@ -191,7 +185,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - factory.getLcaacConfig(), + factory.buildConnectors(), emptyMap() ) @@ -248,7 +242,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - factory.getLcaacConfig(), + factory.buildConnectors(), emptyMap() ) @@ -313,15 +307,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - connectors = emptyMap(), - ).overrideWith(inMemoryConnector) + connectors = mapOf(inMemoryConnector.getName() to inMemoryConnector), + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", + connector = "in_memory", ), schema = schema, filter = mapOf( @@ -381,12 +372,8 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - connectors = mapOf(connectorName to innerConnector), - ).overrideWith(inMemoryConnector) + connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -453,16 +440,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - emptyMap(), - emptyMap(), - ).overrideWith(inMemoryConnector) + mapOf(inMemoryConnector.getName() to inMemoryConnector) + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", + connector = "in_memory", ), schema = schema, filter = mapOf( @@ -509,12 +492,8 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - connectors = mapOf(connectorName to innerConnector), - ).overrideWith(inMemoryConnector) + connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -573,15 +552,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( ops = BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - connectors = emptyMap(), - ).overrideWith(inMemoryConnector) + connectors = mapOf(inMemoryConnector.getName() to inMemoryConnector), + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", + connector = "in_memory", ), schema = schema, filter = mapOf( @@ -637,12 +613,8 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( ops = BasicOperations, - config = LcaacConfig( - name = "test", - description = "description", - ), - connectors = mapOf(connectorName to innerConnector), - ).overrideWith(inMemoryConnector) + connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), + ) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -690,12 +662,7 @@ class DefaultDataSourceOperationsTest { val builder = mockk>() every { builder.buildOrNull(any(), any()) } returns connector val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) - val sourceOps = DefaultDataSourceOperations( - ops, - factory.getLcaacConfig(), - factory.buildConnectors(), - emptyMap() - ) + val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors(), emptyMap()) val source = DataSourceValue( config = DataSourceConfig( name = sourceName, From d7bfa2e3d58f7d3d1bf16d645d0109cfcb97ccb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Fri, 5 Sep 2025 10:58:23 +0200 Subject: [PATCH 5/7] clean documentation and tutorials fix --- .../ch/kleis/lcaac/cli/cmd/SharedOptions.kt | 11 +++-- .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 7 +-- .../03-advanced/03-project-file/README.md | 7 +++ tutorials/README.md | 3 +- tutorials/run.sh | 46 +++++++++++-------- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt index 62a6ea4d..cfe0fa1d 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/SharedOptions.kt @@ -2,6 +2,7 @@ package ch.kleis.lcaac.cli.cmd import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.associate +import com.github.ajalt.clikt.parameters.options.convert import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.option @@ -11,13 +12,17 @@ import kotlin.io.path.Path fun CliktCommand.configFileOption() = option("-c", "--config", help = "Path to LCAAC config file") .file(canBeDir = false) + .convert { it.absoluteFile } // allow to retrieve its parent file when a relative path is given (useful for finding the project directory) .default(File("./$defaultLcaacFilename")) - .help("Path to LCAAC config file. Defaults to 'lcaac.yaml'") + .help(""" + Path to LCAAC config file. Defaults to 'lcaac.yaml' + The location of the config file is the project directory. Defaults to current working directory. + """.trimIndent()) -fun CliktCommand.sourceOption() = option("-s", "--source", help = "Path to LCA source folder or zip/tar.gz file") +fun CliktCommand.sourceOption() = option("-s", "--source", help = "Path to LCA source folder or zip/tar.gz/tgz file") .file() .default(Path(".").toFile()) - .help("Path to LCAAC source folder or zip/tar.gz file. Defaults to current working directory.") + .help("Path to LCAAC source folder or zip/tar.gz/tgz file. Defaults to current working directory.") fun CliktCommand.fileOption(commandName: String) = option("-f", "--file") .file(canBeDir = false) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index ad37d596..aac3232b 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -36,15 +36,16 @@ class TestCommand : CliktCommand(name = testCommandName, help = "Run specified t val showSuccess: Boolean by option("--show-success").flag(default = false).help("Show successful assertions") override fun run() { - val workingDirectory = parseSource(source) + val sourceDirectory = parseSource(source) + val projectDirectory = configFile.parentFile val yamlConfig = parseLcaacConfig(configFile) val ops = BasicOperations - val files = lcaFiles(workingDirectory) + val files = lcaFiles(sourceDirectory) val symbolTable = Loader(ops).load(files, listOf(LoaderOption.WITH_PRELUDE)) val factory = ConnectorFactory( - workingDirectory.path, + projectDirectory.path, yamlConfig, ops, symbolTable, diff --git a/tutorials/03-advanced/03-project-file/README.md b/tutorials/03-advanced/03-project-file/README.md index f670e1d6..598fc887 100644 --- a/tutorials/03-advanced/03-project-file/README.md +++ b/tutorials/03-advanced/03-project-file/README.md @@ -25,3 +25,10 @@ connectors: options: directory: mock ``` + +Here each file specifies a different location for the folder containing the CSV files supporting the datasources. +You can choose which settings to use with the cli option `-c` or `--config`. +```bash +lcaac assess --config lcaac.yaml main +lcaac assess --config lcaac-mock.yaml main +``` \ No newline at end of file diff --git a/tutorials/README.md b/tutorials/README.md index 5a1c5bfa..1048bd28 100644 --- a/tutorials/README.md +++ b/tutorials/README.md @@ -6,8 +6,7 @@ Use the [cli](../cli/README.md) to interact with the code. Moreover, each code sample contains tests. You can run the tests manually, e.g., ```bash -#TODO adapt command with new --source parameter -lcaac test -p 01-basics/01-getting-started +lcaac test -s 01-basics/01-getting-started ``` The script `run.sh` runs all the tests. diff --git a/tutorials/run.sh b/tutorials/run.sh index d49951f1..5a10729f 100755 --- a/tutorials/run.sh +++ b/tutorials/run.sh @@ -2,46 +2,54 @@ set -euxo -export GIT_ROOT=$(git rev-parse --show-toplevel) +GIT_ROOT=$(git rev-parse --show-toplevel) +export GIT_ROOT LCAAC_PATH=$GIT_ROOT/cli/build/install/lcaac/bin TUTORIALS_PATH=$GIT_ROOT/tutorials function setup() { - $GIT_ROOT/gradlew :cli:installDist + "$GIT_ROOT"/gradlew :cli:installDist } function lcaac() { - $LCAAC_PATH/lcaac $@ + "$LCAAC_PATH"/lcaac "$@" } -if ! [ -f $LCAAC_PATH/lcaac ]; then +if ! [ -f "$LCAAC_PATH"/lcaac ]; then setup fi # Check all lca tests -#TODO adapt command with new --source parameter -lcaac test -p $TUTORIALS_PATH/01-basics/01-getting-started -lcaac test -p $TUTORIALS_PATH/01-basics/02-biosphere -lcaac test -p $TUTORIALS_PATH/01-basics/03-impacts +lcaac test -s "$TUTORIALS_PATH"/01-basics/01-getting-started +lcaac test -s "$TUTORIALS_PATH"/01-basics/02-biosphere +lcaac test -s "$TUTORIALS_PATH"/01-basics/03-impacts -lcaac test -p $TUTORIALS_PATH/02-language-features/01-parametrized-process -lcaac test -p $TUTORIALS_PATH/02-language-features/02-variables -lcaac test -p $TUTORIALS_PATH/02-language-features/03-units -lcaac test -p $TUTORIALS_PATH/02-language-features/04-labels -lcaac test -p $TUTORIALS_PATH/02-language-features/05-datasources +lcaac test -s "$TUTORIALS_PATH"/02-language-features/01-parametrized-process +lcaac test -s "$TUTORIALS_PATH"/02-language-features/02-variables +lcaac test -s "$TUTORIALS_PATH"/02-language-features/03-units +lcaac test -s "$TUTORIALS_PATH"/02-language-features/04-labels -lcaac test -p $TUTORIALS_PATH/03-advanced/01-relational-modeling -lcaac test -p $TUTORIALS_PATH/03-advanced/02-circular-footprint-formula +cd "$TUTORIALS_PATH"/02-language-features/05-datasources +lcaac test +cd - -lcaac test -p $TUTORIALS_PATH/03-advanced/03-project-file/lcaac.yaml main_with_data -lcaac test -p $TUTORIALS_PATH/03-advanced/03-project-file/lcaac-mock.yaml main_with_mock_data +cd "$TUTORIALS_PATH"/03-advanced/01-relational-modeling +lcaac test +cd - -lcaac test -p $TUTORIALS_PATH/03-advanced/04-cached-processes +cd "$TUTORIALS_PATH"/03-advanced/02-circular-footprint-formula +lcaac test +cd - + +lcaac test -s "$TUTORIALS_PATH"/03-advanced/03-project-file -c "$TUTORIALS_PATH"/03-advanced/03-project-file/lcaac.yaml main_with_data +lcaac test -s "$TUTORIALS_PATH"/03-advanced/03-project-file -c "$TUTORIALS_PATH"/03-advanced/03-project-file/lcaac-mock.yaml main_with_mock_data + +lcaac test -s "$TUTORIALS_PATH"/03-advanced/04-cached-processes # Check custom dimensions tutorial set -euo # The following assessment is expected to fail. -if lcaac assess -p $TUTORIALS_PATH/02-language-features/03-units customer; then +if lcaac assess -s "$TUTORIALS_PATH"/02-language-features/03-units customer; then exit 0 fi 2> /dev/null From 564039280fe0f62dbb166b62550803c9b47ec8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Fri, 5 Sep 2025 16:24:19 +0200 Subject: [PATCH 6/7] add integration test for CLI --- .../ch/kleis/lcaac/cli/cmd/TraceCommand.kt | 7 +-- .../kleis/lcaac/cli/cmd/AssessCommandTest.kt | 42 ++++++++++++++++ .../ch/kleis/lcaac/cli/cmd/TestCommandTest.kt | 49 +++++++++++++++++++ .../kleis/lcaac/cli/cmd/TraceCommandTest.kt | 45 +++++++++++++++++ .../data-src-split/data/foo_inventory.csv | 4 ++ .../test/resources/data-src-split/lcaac.yaml | 13 +++++ .../resources/data-src-split/src/main.lca | 25 ++++++++++ .../test/resources/simple-project/main.lca | 27 ++++++++++ 8 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommandTest.kt create mode 100644 cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TestCommandTest.kt create mode 100644 cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommandTest.kt create mode 100644 cli/src/test/resources/data-src-split/data/foo_inventory.csv create mode 100644 cli/src/test/resources/data-src-split/lcaac.yaml create mode 100644 cli/src/test/resources/data-src-split/src/main.lca create mode 100644 cli/src/test/resources/simple-project/main.lca diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt index 7363626f..e1084427 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommand.kt @@ -31,16 +31,17 @@ class TraceCommand : CliktCommand(name = traceCommandName, help = "Trace the con val globals: Map by globalsOption(traceCommandName) override fun run() { - val workingDirectory = parseSource(source) + val sourceDirectory = parseSource(source) + val projectDirectory = configFile.parentFile val yamlConfig = parseLcaacConfig(configFile) - val files = lcaFiles(workingDirectory) + val files = lcaFiles(sourceDirectory) val symbolTable = Loader( ops = BasicOperations, overriddenGlobals = dataExpressionMap(BasicOperations, globals), ).load(files, listOf(LoaderOption.WITH_PRELUDE)) - val processor = TraceCsvProcessor(yamlConfig, symbolTable, workingDirectory.path) + val processor = TraceCsvProcessor(yamlConfig, symbolTable, projectDirectory.path) val iterator = loadRequests() val writer = TraceCsvResultWriter() var first = true diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommandTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommandTest.kt new file mode 100644 index 00000000..e1370563 --- /dev/null +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/AssessCommandTest.kt @@ -0,0 +1,42 @@ +package ch.kleis.lcaac.cli.cmd + +import com.github.ajalt.clikt.testing.test +import kotlin.test.Test +import kotlin.test.assertEquals + +class AssessCommandTest { + @Test + fun `simple assessment`() { + // given + val cmd = AssessCommand() + val argv = arrayOf("-s", "src/test/resources/main.zip", "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals("product,amount,reference unit,grass,grass_unit\n" + + "bread,1.0,kg,2.0,kg\n", + result.output + ) + } + + @Test + fun `assessment with data and src split`() { + // given + val cmd = AssessCommand() + val argv = arrayOf( + "-s", "src/test/resources/data-src-split/src", + "-c", "src/test/resources/data-src-split/lcaac.yaml", + "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals("product,amount,reference unit,foo_fn,foo_fn_unit\n" + + "main,1.0,u,6.0,u\n", + result.output + ) + } +} \ No newline at end of file diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TestCommandTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TestCommandTest.kt new file mode 100644 index 00000000..7d00c77c --- /dev/null +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TestCommandTest.kt @@ -0,0 +1,49 @@ +package ch.kleis.lcaac.cli.cmd + +import com.github.ajalt.clikt.testing.test +import kotlin.test.Test +import kotlin.test.assertEquals + +class TestCommandTest { + @Test + fun `no test`() { + // given + val cmd = TestCommand() + val argv = arrayOf("-s", "src/test/resources/main.zip", "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals("Run 0 tests, 0 passed, 0 failed\n", result.output) + } + + @Test + fun `test simple project`() { + // given + val cmd = TestCommand() + val argv = arrayOf("-s", "src/test/resources/simple-project", "bake") + + // when + val result = cmd.test(argv) + + // then + assertEquals("Run 1 tests, 1 passed, 0 failed\n", result.output) + } + + @Test + fun `test with data and src split`() { + // given + val cmd = TestCommand() + val argv = arrayOf( + "-s", "src/test/resources/data-src-split/src", + "-c", "src/test/resources/data-src-split/lcaac.yaml", + "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals("Run 1 tests, 1 passed, 0 failed\n", result.output) + } +} \ No newline at end of file diff --git a/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommandTest.kt b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommandTest.kt new file mode 100644 index 00000000..25d35fa2 --- /dev/null +++ b/cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/TraceCommandTest.kt @@ -0,0 +1,45 @@ +package ch.kleis.lcaac.cli.cmd + +import com.github.ajalt.clikt.testing.test +import kotlin.test.Test +import kotlin.test.assertEquals + +class TraceCommandTest { + @Test + fun `simple trace`() { + // given + val cmd = TraceCommand() + val argv = arrayOf("-s", "src/test/resources/main.zip", "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals( + "depth,d_amount,d_unit,d_product,alloc,name,a,b,c,amount,unit,grass,grass_unit\n" + + "0,1.0,kg,bread,1.0,bread,main,{},{},1.0,kg,2.0,kg\n" + + "1,1.0,kg,bread,1.0,flour,mill,{},{},1.0,kg,2.0,kg\n" + + "2,1.0,kg,bread,1.0,wheat,wheat,{},{},2.0,kg,2.0,kg\n", + result.output + ) + } + + @Test + fun `trace with data and src split`() { + // given + val cmd = TraceCommand() + val argv = arrayOf( + "-s", "src/test/resources/data-src-split/src", + "-c", "src/test/resources/data-src-split/lcaac.yaml", + "main") + + // when + val result = cmd.test(argv) + + // then + assertEquals("depth,d_amount,d_unit,d_product,alloc,name,a,b,c,amount,unit,foo_fn,foo_fn_unit\n" + + "0,1.0,u,main,1.0,main,main,{},{},1.0,u,6.0,u\n", + result.output + ) + } +} \ No newline at end of file diff --git a/cli/src/test/resources/data-src-split/data/foo_inventory.csv b/cli/src/test/resources/data-src-split/data/foo_inventory.csv new file mode 100644 index 00000000..0d6552a4 --- /dev/null +++ b/cli/src/test/resources/data-src-split/data/foo_inventory.csv @@ -0,0 +1,4 @@ +id,quantity +foo-01,1 +foo-02,2 +foo-03,3 \ No newline at end of file diff --git a/cli/src/test/resources/data-src-split/lcaac.yaml b/cli/src/test/resources/data-src-split/lcaac.yaml new file mode 100644 index 00000000..49c1ec4f --- /dev/null +++ b/cli/src/test/resources/data-src-split/lcaac.yaml @@ -0,0 +1,13 @@ +name: Cloud Assess Trusted Library +description: Reference models for Cloud Assess + +# -------------------------------------- # +# Generic +# -------------------------------------- # + +connectors: + - name: csv + cache: + enabled: true + options: + directory: data diff --git a/cli/src/test/resources/data-src-split/src/main.lca b/cli/src/test/resources/data-src-split/src/main.lca new file mode 100644 index 00000000..af7ee6d3 --- /dev/null +++ b/cli/src/test/resources/data-src-split/src/main.lca @@ -0,0 +1,25 @@ +datasource foo_inventory { + schema { + id = "foo-01" + quantity = 1 u + } +} +process main { + products { + 1 u main + } + inputs { + for_each foo from foo_inventory { + foo.quantity foo_fn + } + } +} + +test main { + given { + 1 u main + } + assert { + foo_fn between 6 u and 6 u + } +} \ No newline at end of file diff --git a/cli/src/test/resources/simple-project/main.lca b/cli/src/test/resources/simple-project/main.lca new file mode 100644 index 00000000..64d4661a --- /dev/null +++ b/cli/src/test/resources/simple-project/main.lca @@ -0,0 +1,27 @@ +process bake { + products { + 1 kg bread + } + inputs { + 1 kg flour + } +} + +process mill { + products { + 1 kg flour + } + inputs { + 2 kg wheat + } +} + +test bake { + given { + 1 kg bread + } + assert { + wheat between 2 kg and 2 kg + } +} + From f0d6b21112afeeb4d002a06e301a964432a2959e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Bros=20de=20Puechredon?= Date: Mon, 15 Sep 2025 09:05:42 +0200 Subject: [PATCH 7/7] revert core changes --- README.md | 2 +- .../ch/kleis/lcaac/cli/cmd/TestCommand.kt | 2 +- .../cli/csv/assess/AssessCsvProcessor.kt | 2 +- .../lcaac/cli/csv/trace/TraceCsvProcessor.kt | 2 +- .../main/resources/META-INF/lcaac.properties | 2 +- .../lcaac/core/config/ConnectorConfig.kt | 10 ++- .../ch/kleis/lcaac/core/config/LcaacConfig.kt | 38 +++++++++- .../lcaac/core/datasource/ConnectorFactory.kt | 4 +- .../core/datasource/DataSourceConnector.kt | 4 +- .../core/datasource/DataSourceOperations.kt | 5 ++ .../datasource/DefaultDataSourceOperations.kt | 58 +++++++++++--- .../lcaac/core/datasource/csv/CsvConnector.kt | 6 +- .../datasource/csv/CsvConnectorBuilder.kt | 2 +- .../datasource/in_memory/InMemoryConnector.kt | 6 +- .../DefaultDataSourceOperationsTest.kt | 75 +++++++++++++------ gradle.properties | 2 +- 16 files changed, 169 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index c5326f3c..435f4ddf 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ See our [book](https://lca-as-code.com/book) to learn more about the language. From the source ```bash -git checkout v1.8.1 +git checkout v2.0.0 ./gradlew :cli:installDist alias lcaac=$GIT_ROOT/cli/build/install/lcaac/bin/lcaac lcaac version diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt index aac3232b..d1fb8bde 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt @@ -51,7 +51,7 @@ class TestCommand : CliktCommand(name = testCommandName, help = "Run specified t symbolTable, listOf(CsvConnectorBuilder()) ) - val sourceOps = DefaultDataSourceOperations(ops,factory.buildConnectors()) + val sourceOps = DefaultDataSourceOperations(ops,yamlConfig, factory.buildConnectors()) val mapper = CoreTestMapper() val cases = files diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt index 77383d22..c400f6f1 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/assess/AssessCsvProcessor.kt @@ -27,7 +27,7 @@ class AssessCsvProcessor( symbolTable, listOf(CsvConnectorBuilder()) ) - private val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors()) + private val sourceOps = DefaultDataSourceOperations(ops, config,factory.buildConnectors()) private val dataReducer = DataExpressionReducer(symbolTable.data, symbolTable.dataSources, ops, sourceOps) private val evaluator = Evaluator(symbolTable, ops, sourceOps) diff --git a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt index 1a6e5eb7..a12a7d73 100644 --- a/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt +++ b/cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/trace/TraceCsvProcessor.kt @@ -27,7 +27,7 @@ class TraceCsvProcessor( symbolTable, listOf(CsvConnectorBuilder()) ) - private val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors()) + private val sourceOps = DefaultDataSourceOperations(ops, config, factory.buildConnectors()) private val dataReducer = DataExpressionReducer(symbolTable.data, symbolTable.dataSources, ops, sourceOps) private val evaluator = Evaluator(symbolTable, ops, sourceOps) diff --git a/cli/src/main/resources/META-INF/lcaac.properties b/cli/src/main/resources/META-INF/lcaac.properties index f095f5b2..9c39f8ba 100644 --- a/cli/src/main/resources/META-INF/lcaac.properties +++ b/cli/src/main/resources/META-INF/lcaac.properties @@ -1,3 +1,3 @@ author=Kleis Technology description=LCA as Code CLI -version=1.8.1 +version=2.0.0 diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/config/ConnectorConfig.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/config/ConnectorConfig.kt index 3326f533..9b765c54 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/config/ConnectorConfig.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/config/ConnectorConfig.kt @@ -7,7 +7,15 @@ data class ConnectorConfig( val name: String, val options: Map, val cache: CacheConfig = CacheConfig(), -) +) { + fun modifyOption(name: String, fn: (String) -> String) : ConnectorConfig = + this.copy( + options = this.options.mapValues { + if (it.key == name) fn(it.value) + else it.value + } + ) +} @Serializable data class CacheConfig( diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt index a6ace6fc..2e1fc47d 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/config/LcaacConfig.kt @@ -7,6 +7,42 @@ import kotlinx.serialization.Serializable data class LcaacConfig( val name: String = "", val description: String = "", + val datasources: List = emptyList(), val connectors: List = listOf(CsvConnectorKeys.defaultConfig()), -) +) { + private val datasourcesMap = datasources.associateBy { it.name } + private val connectorsMap = connectors.associateBy { it.name } + + fun getDataSource(name: String): DataSourceConfig? { + return datasourcesMap[name] + } + + fun getConnector(name: String): ConnectorConfig? { + return connectorsMap[name] + } + + fun setOrModifyDatasource(datasource: DataSourceConfig): LcaacConfig { + val mergedConfig = this.datasources + .firstOrNull { it.name == datasource.name } + ?.let { with(DataSourceConfig.merger(it.name)) { + it.combine(datasource) + } } + ?: datasource + val newDatasources = this.datasources + .associateBy { it.name } + .plus(mergedConfig.name to mergedConfig) + .values.toList() + return this.copy( + datasources = newDatasources + ) + } + + fun modifyConnector(name: String, fn: (ConnectorConfig) -> ConnectorConfig): LcaacConfig = + this.copy( + connectors = this.connectors.map { + if (it.name == name) fn(it) + else it + } + ) +} diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt index e7178327..2c445674 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/ConnectorFactory.kt @@ -7,14 +7,14 @@ import ch.kleis.lcaac.core.lang.SymbolTable import ch.kleis.lcaac.core.math.QuantityOperations class ConnectorFactory( - private val projectDirectory: String, + private val workingDirectory: String, private val lcaacConfig: LcaacConfig, private val ops: QuantityOperations, private val symbolTable: SymbolTable, private val builders: List> = listOf(CsvConnectorBuilder()) ) { - fun getProjectDirectory(): String = projectDirectory + fun getWorkingDirectory(): String = workingDirectory fun getLcaacConfig(): LcaacConfig = lcaacConfig fun getQuantityOperations(): QuantityOperations = ops fun getSymbolTable(): SymbolTable = symbolTable diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt index 101002dd..d66f3ce6 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceConnector.kt @@ -9,11 +9,11 @@ interface DataSourceConnector { fun getName(): String fun getConfig(): ConnectorConfig fun getFirst( - caller: DataSourceOperations, + caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): ERecord fun getAll( - caller: DataSourceOperations, + caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): Sequence> } diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt index 708d521a..00e4ddf2 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DataSourceOperations.kt @@ -1,5 +1,6 @@ package ch.kleis.lcaac.core.datasource +import ch.kleis.lcaac.core.config.LcaacConfig import ch.kleis.lcaac.core.lang.expression.DataExpression import ch.kleis.lcaac.core.lang.expression.ERecord import ch.kleis.lcaac.core.lang.value.DataSourceValue @@ -9,3 +10,7 @@ interface DataSourceOperations { fun getAll(source: DataSourceValue): Sequence> fun sumProduct(source: DataSourceValue, columns: List): DataExpression } + +interface DataSourceOperationsWithConfig : DataSourceOperations { + fun getConfig(): LcaacConfig +} diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt index 7bf03475..85babb75 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperations.kt @@ -19,6 +19,7 @@ typealias ConnectorName = String class DefaultDataSourceOperations( private val ops: QuantityOperations, + private val config: LcaacConfig, private val connectors: Map>, private val cache: Map> = connectors .filter { it.value.getConfig().cache.enabled } @@ -28,41 +29,72 @@ class DefaultDataSourceOperations( it.value.getConfig().cache.maxRecordsPerCacheLine, ) } -) : DataSourceOperations { +) : DataSourceOperationsWithConfig { + + fun overrideWith(inMemoryConnector: InMemoryConnector): DefaultDataSourceOperations = + DefaultDataSourceOperations( + ops, + inMemoryConnector.getSourceNames() + .fold(config) { cfg, source -> + cfg.setOrModifyDatasource(DataSourceConfig( + name = source, + connector = InMemoryConnectorKeys.IN_MEMORY_CONNECTOR_NAME, + )) + }, + connectors.plus(inMemoryConnector.getName() to inMemoryConnector), + if (inMemoryConnector.getConfig().cache.enabled) + cache.plus(inMemoryConnector.getName() to SourceOpsCache( + inMemoryConnector.getConfig().cache.maxSize, + inMemoryConnector.getConfig().cache.maxRecordsPerCacheLine, + )) + else cache + ) + + private fun configOf(source: DataSourceValue): DataSourceConfig { + return with(DataSourceConfig.merger(source.config.name)) { + config.getDataSource(source.config.name) + ?.let { source.config.combine(it) } // lcaac config takes precedence + ?: source.config + } + } + private fun connectorOf(config: DataSourceConfig): DataSourceConnector { return connectors[config.connector] ?: throw IllegalArgumentException("Unknown connector '${config.connector}'") } override fun getFirst(source: DataSourceValue): ERecord { - val connector = connectorOf(source.config) + val sourceConfig = configOf(source) + val connector = connectorOf(sourceConfig) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") - return connectorCache.recordGetFirst(source.config, source) { - connector.getFirst(this, source.config, source) + return connectorCache.recordGetFirst(sourceConfig, source) { + connector.getFirst(this, sourceConfig, source) } - } else return connector.getFirst(this, source.config, source) + } else return connector.getFirst(this, sourceConfig, source) } override fun getAll(source: DataSourceValue): Sequence> { - val connector = connectorOf(source.config) + val sourceConfig = configOf(source) + val connector = connectorOf(sourceConfig) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") - return connectorCache.recordGetAll(source.config, source) { - connector.getAll(this, source.config, source).toList() + return connectorCache.recordGetAll(sourceConfig, source) { + connector.getAll(this, sourceConfig, source).toList() }.asSequence() - } else return connector.getAll(this, source.config, source) + } else return connector.getAll(this, sourceConfig, source) } override fun sumProduct(source: DataSourceValue, columns: List): DataExpression { - val connector = connectorOf(source.config) + val sourceConfig = configOf(source) + val connector = connectorOf(sourceConfig) if (connector.getConfig().cache.enabled) { val connectorCache = cache[connector.getName()] ?: throw IllegalStateException("internal error: cache not found for cache-enabled connector '${connector.getName()}'") return connectorCache.recordSumProduct( - source.config, + sourceConfig, source, columns, ) { @@ -113,4 +145,8 @@ class DefaultDataSourceOperations( reducer.reduce(EQuantityAdd(acc, expression)) })) } + + override fun getConfig(): LcaacConfig { + return config + } } diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt index 6764ceb9..e6549a0c 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnector.kt @@ -3,7 +3,7 @@ package ch.kleis.lcaac.core.datasource.csv import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.datasource.DataSourceConnector -import ch.kleis.lcaac.core.datasource.DataSourceOperations +import ch.kleis.lcaac.core.datasource.DataSourceOperationsWithConfig import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.expression.DataExpression import ch.kleis.lcaac.core.lang.expression.EQuantityScale @@ -40,7 +40,7 @@ class CsvConnector( return header to records.iterator().asSequence() } - override fun getAll(caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): + override fun getAll(caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): Sequence> { val location = config.location ?: throw EvaluatorException("Missing location in configuration for datasource '${config.name}'") @@ -51,7 +51,7 @@ class CsvConnector( return records } - override fun getFirst(caller: DataSourceOperations, config: DataSourceConfig, source: DataSourceValue): ERecord { + override fun getFirst(caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue): ERecord { return getAll(caller, config, source).firstOrNull() ?: throw EvaluatorException("no record found in datasource '${config.name}' [${config.location}] matching" + " ${source.filter}") diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt index fcef0128..b46b8c86 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/csv/CsvConnectorBuilder.kt @@ -25,7 +25,7 @@ class CsvConnectorBuilder : ConnectorBuilder { if (config.name != CsvConnectorKeys.CSV_CONNECTOR_NAME) { return null } - val directory = directory(factory.getProjectDirectory(), config) + val directory = directory(factory.getWorkingDirectory(), config) return CsvConnector( config, factory.getQuantityOperations() diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt index 36e78b5e..77d59ba4 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/in_memory/InMemoryConnector.kt @@ -3,7 +3,7 @@ package ch.kleis.lcaac.core.datasource.in_memory import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.datasource.DataSourceConnector -import ch.kleis.lcaac.core.datasource.DataSourceOperations +import ch.kleis.lcaac.core.datasource.DataSourceOperationsWithConfig import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.expression.ERecord import ch.kleis.lcaac.core.lang.value.DataSourceValue @@ -26,7 +26,7 @@ class InMemoryConnector( fun getSourceNames(): List = content.keys.toList() override fun getAll( - caller: DataSourceOperations, + caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue, ): Sequence> { @@ -42,7 +42,7 @@ class InMemoryConnector( } override fun getFirst( - caller: DataSourceOperations, + caller: DataSourceOperationsWithConfig, config: DataSourceConfig, source: DataSourceValue, ): ERecord { diff --git a/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt b/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt index cd410574..1c18e722 100644 --- a/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt +++ b/core/src/test/kotlin/ch/kleis/lcaac/core/datasource/DefaultDataSourceOperationsTest.kt @@ -3,7 +3,6 @@ package ch.kleis.lcaac.core.datasource import ch.kleis.lcaac.core.config.ConnectorConfig import ch.kleis.lcaac.core.config.DataSourceConfig import ch.kleis.lcaac.core.config.LcaacConfig -import ch.kleis.lcaac.core.datasource.csv.CsvConnectorKeys import ch.kleis.lcaac.core.datasource.in_memory.InMemoryConnector import ch.kleis.lcaac.core.datasource.in_memory.InMemoryConnectorKeys import ch.kleis.lcaac.core.datasource.in_memory.InMemoryDatasource @@ -29,12 +28,14 @@ class DefaultDataSourceOperationsTest { private val connectorConfig = ConnectorConfig(name = connectorName, options = emptyMap()) private val sourceName = "source" + private val sourceConfig = DataSourceConfig(name = sourceName, connector = connectorName) private val symbolTable = SymbolTable.empty() private val config = LcaacConfig( name = "project", description = "description", + datasources = listOf(sourceConfig), connectors = listOf(connectorConfig), ) private val ops = BasicOperations @@ -78,7 +79,12 @@ class DefaultDataSourceOperationsTest { val builder = mockk>() every { builder.buildOrNull(any(), any()) } returns connector val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) - val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors(), emptyMap()) + val sourceOps = DefaultDataSourceOperations( + ops, + factory.getLcaacConfig(), + factory.buildConnectors(), + emptyMap(), + ) val source = DataSourceValue( config = DataSourceConfig( name = sourceName, @@ -138,7 +144,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - + factory.getLcaacConfig(), factory.buildConnectors(), emptyMap() ) @@ -185,7 +191,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - + factory.getLcaacConfig(), factory.buildConnectors(), emptyMap() ) @@ -242,7 +248,7 @@ class DefaultDataSourceOperationsTest { val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) val sourceOps = DefaultDataSourceOperations( ops, - + factory.getLcaacConfig(), factory.buildConnectors(), emptyMap() ) @@ -307,12 +313,15 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - connectors = mapOf(inMemoryConnector.getName() to inMemoryConnector), - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + connectors = emptyMap(), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", - connector = "in_memory", ), schema = schema, filter = mapOf( @@ -372,8 +381,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + connectors = mapOf(connectorName to innerConnector), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -440,12 +453,16 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - mapOf(inMemoryConnector.getName() to inMemoryConnector) - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + emptyMap(), + emptyMap(), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", - connector = "in_memory", ), schema = schema, filter = mapOf( @@ -492,8 +509,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( BasicOperations, - connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + connectors = mapOf(connectorName to innerConnector), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -552,12 +573,15 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( ops = BasicOperations, - connectors = mapOf(inMemoryConnector.getName() to inMemoryConnector), - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + connectors = emptyMap(), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", - connector = "in_memory", ), schema = schema, filter = mapOf( @@ -613,8 +637,12 @@ class DefaultDataSourceOperationsTest { ) val sourceOps = DefaultDataSourceOperations( ops = BasicOperations, - connectors = mapOf(connectorName to innerConnector, inMemoryConnector.getName() to inMemoryConnector), - ) + config = LcaacConfig( + name = "test", + description = "description", + ), + connectors = mapOf(connectorName to innerConnector), + ).overrideWith(inMemoryConnector) val source = DataSourceValue( config = DataSourceConfig( name = "inventory", @@ -662,7 +690,12 @@ class DefaultDataSourceOperationsTest { val builder = mockk>() every { builder.buildOrNull(any(), any()) } returns connector val factory = ConnectorFactory(".", config, ops, symbolTable, listOf(builder)) - val sourceOps = DefaultDataSourceOperations(ops, factory.buildConnectors(), emptyMap()) + val sourceOps = DefaultDataSourceOperations( + ops, + factory.getLcaacConfig(), + factory.buildConnectors(), + emptyMap() + ) val source = DataSourceValue( config = DataSourceConfig( name = sourceName, diff --git a/gradle.properties b/gradle.properties index 368f657e..b6053d68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ javaVersion=17 gradleVersion=7.6 org.gradle.jvmargs=-Xmx4096m lcaacGroup=ch.kleis.lcaac -lcaacVersion=1.8.1 +lcaacVersion=2.0.0