Skip to content

Commit a7809a8

Browse files
authored
Added save-overrides.toml (#438)
* introduced `save-overrides.toml` * removed `--override-exec-cmd` and `--override-exec-flags` from cli * moved `batchSize` and `batchSeparator` from cli to save.toml
1 parent c1c6eaa commit a7809a8

33 files changed

Lines changed: 911 additions & 521 deletions

File tree

OptionsTable.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,4 @@ Most (except for `-h` and `-prop`) of the options below can be passed to a SAVE
1212
| i | include-suites | Test suites, only which ones will be checked | - |
1313
| l | language | Language that you are developing analyzer for | UNDEFINED |
1414
| out | result-output | Data output stream | STDOUT |
15-
| - | report-dir | Path to directory, where to store output (when `resultOutput` is set to `FILE`) | save-reports |
16-
| - | override-exec-cmd | A temporary workaround for save-cloud to override `execCmd` in `save.toml` | - |
17-
| - | override-exec-flags | A temporary workaround for save-cloud to override `execFlags` in `save.toml` | - |
18-
| - | batch-size | Number of files execCmd will process at a time | 1 |
19-
| - | batch-separator | A separator to join test files to string if the tested tool supports processing of file batches (`batch-size` > 1) | , |
15+
| - | report-dir | Path to directory, where to store output (when `resultOutput` is set to `FILE`) | save-reports |

buildSrc/src/main/resources/config-options.json

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -78,37 +78,5 @@
7878
"shortName" : "",
7979
"description" : "Path to directory, where to store output (when `resultOutput` is set to `FILE`)",
8080
"default" : "save-reports"
81-
},
82-
"overrideExecCmd" : {
83-
"argType": "ArgType.String",
84-
"kotlinType": "kotlin.String",
85-
"fullName": "override-exec-cmd",
86-
"shortName" : "",
87-
"description" : "A temporary workaround for save-cloud to override `execCmd` in `save.toml`",
88-
"default" : null
89-
},
90-
"overrideExecFlags" : {
91-
"argType": "ArgType.String",
92-
"kotlinType": "kotlin.String",
93-
"fullName": "override-exec-flags",
94-
"shortName" : "",
95-
"description" : "A temporary workaround for save-cloud to override `execFlags` in `save.toml`",
96-
"default" : null
97-
},
98-
"batchSize" : {
99-
"argType" : "ArgType.Int",
100-
"kotlinType": "kotlin.Int",
101-
"fullName" : "batch-size",
102-
"shortName" : "",
103-
"description" : "Number of files execCmd will process at a time",
104-
"default" : "1"
105-
},
106-
"batchSeparator" : {
107-
"argType": "ArgType.String",
108-
"kotlinType": "kotlin.String",
109-
"fullName": "batch-separator",
110-
"shortName" : "",
111-
"description" : "A separator to join test files to string if the tested tool supports processing of file batches (`batch-size` > 1)",
112-
"default" : ", "
11381
}
11482
}

save-cli/src/commonNonJsMain/kotlin/com/saveourtool/save/cli/config/SavePropertiesExt.kt

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package com.saveourtool.save.cli.config
77
import com.saveourtool.save.cli.ExitCodes
88
import com.saveourtool.save.cli.fs
99
import com.saveourtool.save.cli.logging.logErrorAndExit
10-
import com.saveourtool.save.cli.logging.logWarn
1110
import com.saveourtool.save.core.config.SaveProperties
1211
import com.saveourtool.save.core.config.resolveSaveTomlConfig
1312
import com.saveourtool.save.core.logging.logDebug
@@ -52,24 +51,6 @@ private fun SaveProperties.validate(): SaveProperties {
5251
" Please provide a valid path to the test config via command-line or using the file with properties."
5352
)
5453
}
55-
if (batchSize < 1) {
56-
return logErrorAndExit(
57-
ExitCodes.INVALID_CONFIGURATION, "Property `batch-size` should be more or equal to 1."
58-
)
59-
}
60-
overrideExecCmd?.also {
61-
logWarn {
62-
"Property `override-exec-cmd` is a temporary workaround for `save-cloud`, " +
63-
"please be aware this property can be removed in future versions"
64-
}
65-
}
66-
overrideExecFlags?.also {
67-
logWarn {
68-
"Property `override-exec-flags` is a temporary workaround for `save-cloud`, " +
69-
"please be aware this property can be removed in future versions"
70-
}
71-
}
72-
7354
return this
7455
}
7556

save-common-test/src/commonNonJsMain/kotlin/com/saveourtool/save/plugin/MockPlugin.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.saveourtool.save.plugin
22

3-
import com.saveourtool.save.core.config.EvaluatedToolConfig
43
import com.saveourtool.save.core.config.TestConfig
54
import com.saveourtool.save.core.files.createFile
65
import com.saveourtool.save.core.plugin.Plugin
@@ -15,13 +14,17 @@ internal expect val fs: FileSystem
1514
* No-op implementation of [Plugin] that can be used to test reporters, which expect only a class name of the plugin.
1615
*/
1716
class MockPlugin(baseDir: Path, testFiles: List<String> = emptyList()) : Plugin(
18-
TestConfig((baseDir / "save.toml").also { fs.createFile(it) }, null, fs = fs),
17+
TestConfig(
18+
(baseDir / "save.toml").also { fs.createFile(it) },
19+
null,
20+
overridesPluginConfigs = emptyList(),
21+
fs = fs),
1922
testFiles,
2023
fs,
2124
useInternalRedirections = true,
2225
redirectTo = null
2326
) {
24-
override fun handleFiles(evaluatedToolConfig: EvaluatedToolConfig, files: Sequence<TestFiles>): Sequence<TestResult> = emptySequence()
27+
override fun handleFiles(files: Sequence<TestFiles>): Sequence<TestResult> = emptySequence()
2528

2629
override fun rawDiscoverTestFiles(resourceDirectories: Sequence<Path>): Sequence<TestFiles> = emptySequence()
2730

save-common/src/commonMain/kotlin/com/saveourtool/save/core/config/EvaluatedToolConfig.kt

Lines changed: 0 additions & 16 deletions
This file was deleted.

save-common/src/commonMain/kotlin/com/saveourtool/save/core/config/TestConfig.kt

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,30 @@ import com.saveourtool.save.core.logging.logTrace
1010
import com.saveourtool.save.core.plugin.GeneralConfig
1111
import com.saveourtool.save.core.plugin.Plugin
1212
import com.saveourtool.save.core.plugin.PluginConfig
13+
import com.saveourtool.save.core.utils.mergeWith
14+
import com.saveourtool.save.core.utils.overrideBy
15+
import com.saveourtool.save.core.utils.singleIsInstanceOrNull
1316

1417
import okio.FileSystem
1518
import okio.Path
1619
import okio.Path.Companion.toPath
20+
1721
import kotlin.js.JsName
1822

1923
/**
2024
* Configuration for a test suite, that is read from test suite configuration file (toml config)
2125
* @property location [Path] denoting the location of this file
2226
* @property parentConfig parent config in the hierarchy of configs, `null` if this config is root.
2327
* @property pluginConfigs list of configurations for plugins that are active in this config
28+
* @property overridesPluginConfigs list of configurations for plugins that overrides [pluginConfigs]
2429
* @property fs filesystem which can access test configs
2530
*/
2631
@Suppress("TYPE_ALIAS", "TooManyFunctions")
2732
data class TestConfig(
2833
val location: Path,
2934
val parentConfig: TestConfig?,
3035
val pluginConfigs: MutableList<PluginConfig> = mutableListOf(),
36+
val overridesPluginConfigs: List<PluginConfig>,
3137
val fs: FileSystem,
3238
) {
3339
/**
@@ -78,7 +84,7 @@ data class TestConfig(
7884
*
7985
* @return [GeneralConfig] or `null` if not found
8086
*/
81-
fun getGeneralConfig() = pluginConfigs.filterIsInstance<GeneralConfig>().singleOrNull()
87+
fun getGeneralConfig(): GeneralConfig? = pluginConfigs.singleIsInstanceOrNull()
8288

8389
/**
8490
* @param withSelf if true, include this config as the first element of the sequence or start with parent config otherwise
@@ -122,15 +128,17 @@ data class TestConfig(
122128
* @return an update this [TestConfig]
123129
*/
124130
fun processInPlace(createPluginConfigList: (TestConfig) -> List<PluginConfig>): TestConfig {
125-
// need to process parent first
126-
this.parentConfig?.processInPlace(createPluginConfigList)
127131
// discover plugins from the test configuration
128-
createPluginConfigList(this).forEach {
129-
logTrace("Discovered new pluginConfig: $it")
130-
this.pluginConfigs.merge(it)
132+
createPluginConfigList(this).forEach { pluginConfig ->
133+
logTrace("Discovered new pluginConfig: $pluginConfig")
134+
require(this.pluginConfigs.none { it.type == pluginConfig.type }) {
135+
"Found duplicate for $pluginConfig"
136+
}
137+
this.pluginConfigs.add(pluginConfig)
131138
}
132139
// merge configurations with parents
133-
this.mergeConfigWithParent()
140+
mergeConfigWithParent()
141+
overrideConfig()
134142
return this
135143
}
136144

@@ -161,27 +169,28 @@ data class TestConfig(
161169
*
162170
* @return all plugin configs without general config
163171
*/
164-
fun pluginConfigsWithoutGeneralConfig() = pluginConfigs.filterNot { it is GeneralConfig }
172+
private fun pluginConfigsWithoutGeneralConfig() = pluginConfigs.filterNot { it is GeneralConfig }
165173

166174
/**
167175
* Merge parent list of plugins with the current list
168176
*
169177
* @return merged test config
170178
*/
171-
fun mergeConfigWithParent(): TestConfig {
172-
logDebug("Merging configs (with parental configs from higher directory level) for ${this.location}")
179+
private fun mergeConfigWithParent(): TestConfig {
180+
logDebug("Merging configs (with parental configs from higher directory level) for ${this.location}")
173181

174-
if (parentConfig != null) {
182+
parentConfig?.let {
175183
logTrace("Using parental config ${parentConfig.location} to merge it with child config: ${this.location}")
176-
// return from the function if we stay at the root element of the plugin tree
177-
val parentalPlugins = parentConfig.pluginConfigs
178-
parentalPlugins.forEach { parentalPluginConfig ->
179-
this.pluginConfigs.merge(parentalPluginConfig)
180-
}
184+
this.pluginConfigs.mergeWith(parentConfig.pluginConfigs)
181185
}
182186
return this
183187
}
184188

189+
private fun overrideConfig() {
190+
logDebug("Overriding configs for $location")
191+
pluginConfigs.overrideBy(overridesPluginConfigs)
192+
}
193+
185194
/**
186195
* Method, which validates all plugin configs and set default values, if possible
187196
*/
@@ -192,23 +201,6 @@ data class TestConfig(
192201
logDebug("Validated plugin configuration for [$location] " +
193202
"(${pluginConfigs.map { it.type }.filterNot { it == TestConfigSections.GENERAL }})")
194203
}
195-
196-
private fun MutableList<PluginConfig>.merge(parentalPluginConfig: PluginConfig) {
197-
val childConfigs = this.filter { it.type == parentalPluginConfig.type }
198-
if (childConfigs.isEmpty()) {
199-
// if we haven't found a plugin from parent in a current list of plugins - we will simply copy it
200-
this.add(parentalPluginConfig)
201-
} else {
202-
require(childConfigs.size == 1) {
203-
"Duplicate config with type ${parentalPluginConfig.type} in $this"
204-
}
205-
val childConfig = childConfigs.single()
206-
// else, we will merge plugin with a corresponding plugin from a parent config
207-
// we expect that there is only one plugin of such type, otherwise we will throw an exception
208-
logTrace("Merging process of ${parentalPluginConfig.type} from $parentalPluginConfig into $childConfig")
209-
this[this.indexOf(childConfig)] = childConfig.mergeWith(parentalPluginConfig)
210-
}
211-
}
212204
}
213205

214206
/**
@@ -235,3 +227,8 @@ fun Path.isSaveTomlConfig() = name == "save.toml"
235227
* @return a file (save.toml) in current directory
236228
*/
237229
fun Path.resolveSaveTomlConfig() = this / "save.toml"
230+
231+
/**
232+
* @return a file (save-overrides.toml) in current directory
233+
*/
234+
fun Path.resolveSaveOverridesTomlConfig() = this / "save-overrides.toml"

save-common/src/commonMain/kotlin/com/saveourtool/save/core/plugin/Plugin.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.saveourtool.save.core.plugin
22

3-
import com.saveourtool.save.core.config.EvaluatedToolConfig
43
import com.saveourtool.save.core.config.TestConfig
54
import com.saveourtool.save.core.config.isSaveTomlConfig
65
import com.saveourtool.save.core.files.createRelativePathToTheRoot
@@ -12,6 +11,7 @@ import com.saveourtool.save.core.result.Ignored
1211
import com.saveourtool.save.core.result.TestResult
1312
import com.saveourtool.save.core.utils.PathSerializer
1413
import com.saveourtool.save.core.utils.ProcessBuilder
14+
import com.saveourtool.save.core.utils.singleIsInstanceOrNull
1515

1616
import okio.FileSystem
1717
import okio.Path
@@ -44,17 +44,15 @@ abstract class Plugin(
4444
/**
4545
* Perform plugin's work.
4646
*
47-
* @param evaluatedToolConfig a configuration for evaluated tool
4847
* @return a sequence of [TestResult]s for each group of test resources
4948
*/
50-
fun execute(evaluatedToolConfig: EvaluatedToolConfig): Sequence<TestResult> {
49+
fun execute(): Sequence<TestResult> {
5150
clean()
5251
val testFilesList = discoverTestFiles(testConfig.directory).toList()
5352

5453
val excludedTests = testConfig
5554
.pluginConfigs
56-
.filterIsInstance<GeneralConfig>()
57-
.singleOrNull()
55+
.singleIsInstanceOrNull<GeneralConfig>()
5856
?.excludedTests
5957

6058
if (!excludedTests.isNullOrEmpty()) {
@@ -71,7 +69,7 @@ abstract class Plugin(
7169
val excludedTestResults = excludedTestFiles.map {
7270
TestResult(it, Ignored("Excluded by configuration"))
7371
}
74-
handleFiles(evaluatedToolConfig, actualTestFiles.asSequence()) + excludedTestResults
72+
handleFiles(actualTestFiles.asSequence()) + excludedTestResults
7573
} else {
7674
emptySequence()
7775
}
@@ -80,11 +78,10 @@ abstract class Plugin(
8078
/**
8179
* Perform plugin's work on a set of files.
8280
*
83-
* @param evaluatedToolConfig a configuration for evaluated tool
8481
* @param files a sequence of file groups, corresponding to tests.
8582
* @return a sequence of [TestResult]s for each group of test resources
8683
*/
87-
abstract fun handleFiles(evaluatedToolConfig: EvaluatedToolConfig, files: Sequence<TestFiles>): Sequence<TestResult>
84+
abstract fun handleFiles(files: Sequence<TestFiles>): Sequence<TestResult>
8885

8986
/**
9087
* Discover groups of resource files which will be used to run tests, applying additional filtering

0 commit comments

Comments
 (0)