forked from detekt/detekt
/
YamlConfig.kt
79 lines (68 loc) · 2.77 KB
/
YamlConfig.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@file:Suppress("UNCHECKED_CAST")
package io.gitlab.arturbosch.detekt.core.config
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Config.Companion.CONFIG_SEPARATOR
import io.gitlab.arturbosch.detekt.api.Notification
import io.gitlab.arturbosch.detekt.core.config.validation.ValidatableConfiguration
import io.gitlab.arturbosch.detekt.core.config.validation.validateConfig
import org.yaml.snakeyaml.Yaml
import java.io.Reader
import java.nio.file.Path
/**
* Config implementation using the yaml format. SubConfigurations can return sub maps according to the
* yaml specification.
*/
class YamlConfig internal constructor(
val properties: Map<String, Any>,
override val parentPath: String? = null
) : Config, ValidatableConfiguration {
override fun subConfig(key: String): Config {
val subProperties = properties.getOrElse(key) { emptyMap<String, Any>() }
return YamlConfig(
subProperties as Map<String, Any>,
if (parentPath == null) key else "$parentPath $CONFIG_SEPARATOR $key"
)
}
override fun <T : Any> valueOrDefault(key: String, default: T): T {
val result = properties[key]
return valueOrDefaultInternal(key, result, default) as T
}
override fun <T : Any> valueOrNull(key: String): T? {
return properties[key] as? T?
}
override fun toString(): String {
return "YamlConfig(properties=$properties)"
}
override fun validate(baseline: Config, excludePatterns: Set<Regex>): List<Notification> =
validateConfig(this, baseline, excludePatterns)
companion object {
/**
* Factory method to load a yaml configuration. Given path must exist
* and point to a readable file.
*/
fun load(path: Path): Config =
load(
path.toFile().apply {
require(exists()) { "Configuration does not exist: $path" }
require(isFile) { "Configuration must be a file: $path" }
require(canRead()) { "Configuration must be readable: $path" }
}.reader()
)
/**
* Constructs a [YamlConfig] from any [Reader].
*
* Note the reader will be consumed and closed.
*/
fun load(reader: Reader): Config = reader.buffered().use { bufferedReader ->
val map: Map<*, *>? = runCatching {
@Suppress("USELESS_CAST") // runtime inference bug
Yaml().loadAs(bufferedReader, Map::class.java) as Map<*, *>?
}.getOrElse { throw Config.InvalidConfigurationError(it) }
if (map == null) {
YamlConfig(emptyMap())
} else {
YamlConfig(map as Map<String, Any>)
}
}
}
}