11package org.utbot.taint
22
3+ import kotlinx.serialization.ExperimentalSerializationApi
4+ import kotlinx.serialization.cbor.Cbor
5+ import kotlinx.serialization.decodeFromByteArray
6+ import kotlinx.serialization.encodeToByteArray
37import org.utbot.common.PathUtil.toPath
8+ import org.utbot.common.utBotTempDirectory
49import org.utbot.taint.model.TaintConfiguration
510import org.utbot.taint.parser.TaintYamlParser
11+ import java.io.File
612
713/* *
814 * Provide the [TaintConfiguration].
915 */
1016interface TaintConfigurationProvider {
17+
18+ /* *
19+ * Returns the time that the configuration was last modified.
20+ *
21+ * Uses the same format as the [java.io.File.lastModified].
22+ */
23+ fun lastModified (): Long
24+
25+ /* *
26+ * Provides [TaintConfiguration].
27+ */
1128 fun getConfiguration (): TaintConfiguration
1229}
1330
@@ -17,6 +34,12 @@ interface TaintConfigurationProvider {
1734 * @param configPath relative path to the .yaml file in resources
1835 */
1936class TaintConfigurationProviderResources (private val configPath : String ) : TaintConfigurationProvider {
37+
38+ override fun lastModified (): Long {
39+ val selfJarFile = File (javaClass.protectionDomain.codeSource.location.toURI().path)
40+ return selfJarFile.lastModified()
41+ }
42+
2043 override fun getConfiguration (): TaintConfiguration {
2144 val configUrl = javaClass.classLoader.getResource(configPath)
2245 ? : return TaintConfiguration ()
@@ -32,6 +55,15 @@ class TaintConfigurationProviderResources(private val configPath: String) : Tain
3255 * @param configPath relative path to the .yaml file in the user's project.
3356 */
3457class TaintConfigurationProviderUserRules (private val configPath : String ) : TaintConfigurationProvider {
58+
59+ override fun lastModified (): Long {
60+ val configFile = configPath.toPath().toFile()
61+ if (! configFile.exists()) {
62+ return 0
63+ }
64+ return configFile.lastModified()
65+ }
66+
3567 override fun getConfiguration (): TaintConfiguration {
3668 val configFile = configPath.toPath().toFile()
3769 if (! configFile.exists()) {
@@ -43,11 +75,64 @@ class TaintConfigurationProviderUserRules(private val configPath: String) : Tain
4375 }
4476}
4577
78+ /* *
79+ * Combines taint configurations from several providers.
80+ */
4681class TaintConfigurationProviderCombiner (private val inners : List <TaintConfigurationProvider >) : TaintConfigurationProvider {
82+
83+ override fun lastModified (): Long {
84+ return inners.maxOf { it.lastModified() }
85+ }
86+
4787 override fun getConfiguration (): TaintConfiguration =
4888 inners.fold(TaintConfiguration ()) { resultConfig, configProvider ->
4989 resultConfig + configProvider.getConfiguration()
5090 }
5191}
5292
53- // TODO: TaintConfigurationProviderCached -- stores binary config to the temp directory
93+ /* *
94+ * Stores binary configuration file to the utbot temp directory to reduce parsing time in the future.
95+ *
96+ * @param nameSuffix the cached file will have "-$nameSuffix" suffix
97+ * @param inner provider to cache
98+ */
99+ class TaintConfigurationProviderCached (
100+ nameSuffix : String ,
101+ private val inner : TaintConfigurationProvider ,
102+ ) : TaintConfigurationProvider {
103+
104+ private val cachedConfigName = " taint-config-cached-$nameSuffix "
105+
106+ private val cachedConfigFile = utBotTempDirectory.resolve(cachedConfigName).toFile()
107+
108+ override fun lastModified (): Long {
109+ return cachedConfigFile.lastModified()
110+ }
111+
112+ @OptIn(ExperimentalSerializationApi ::class )
113+ override fun getConfiguration (): TaintConfiguration =
114+ if (! cachedConfigFile.exists() || cachedConfigFile.lastModified() < inner.lastModified()) {
115+ val config = inner.getConfiguration()
116+ val bytes = Cbor .encodeToByteArray(config)
117+ cachedConfigFile.writeBytes(bytes)
118+ config
119+ } else {
120+ val bytes = cachedConfigFile.readBytes()
121+ Cbor .decodeFromByteArray(bytes)
122+ }
123+ }
124+
125+ fun constructDefaultProvider (
126+ taintUserConfigPath : String? ,
127+ taintResourcesConfigPath : String = "taint/config.yaml"
128+ ): TaintConfigurationProvider {
129+ val resourcesConfig = TaintConfigurationProviderResources (taintResourcesConfigPath)
130+ val cachedResourcesConfig = TaintConfigurationProviderCached (" resources" , resourcesConfig)
131+
132+ val cachedUserConfigOrNull = taintUserConfigPath?.let {
133+ val userConfig = TaintConfigurationProviderUserRules (taintUserConfigPath)
134+ TaintConfigurationProviderCached (" user" , userConfig)
135+ }
136+
137+ return TaintConfigurationProviderCombiner (listOfNotNull(cachedUserConfigOrNull, cachedResourcesConfig))
138+ }
0 commit comments