Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pshirshov committed Dec 5, 2023
1 parent 8a27edf commit 03db161
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,11 @@ object ConfigLoadResult {
sealed trait ConfigSource

object ConfigSource {
final case class Resource(name: String, kind: ResourceConfigKind) extends ConfigSource {
final case class Resource(name: String) extends ConfigSource {
override def toString: String = s"resource:$name"
}

final case class File(file: java.io.File) extends ConfigSource {
override def toString: String = s"file:$file"
}
}

sealed trait ResourceConfigKind

object ResourceConfigKind {
case object Primary extends ResourceConfigKind

case object Development extends ResourceConfigKind
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package izumi.distage.framework.services

import izumi.distage.config.model.{ConfigSource, ResourceConfigKind}
import izumi.distage.config.model.ConfigSource

trait ConfigLocationProvider {
def forRole(roleName: String): Seq[ConfigSource]
Expand All @@ -23,9 +23,9 @@ object ConfigLocationProvider {

private def defaultConfigReferences(name: String): Seq[ConfigSource] = {
Seq(
ConfigSource.Resource(s"$name.conf", ResourceConfigKind.Primary),
ConfigSource.Resource(s"$name-reference.conf", ResourceConfigKind.Primary),
ConfigSource.Resource(s"$name-reference-dev.conf", ResourceConfigKind.Development),
ConfigSource.Resource(s"$name.conf"),
ConfigSource.Resource(s"$name-reference.conf"),
ConfigSource.Resource(s"$name-reference-dev.conf"),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,47 @@ object ConfigMerger {
}

override def mergeFilter(shared: List[ConfigLoadResult.Success], role: List[LoadedRoleConfigs], filter: LoadedRoleConfigs => Boolean, clue: String): Config = {
val cfgInfo = shared ++ role.flatMap(_.loaded)
val nonEmpty = cfgInfo.filterNot(_.config.isEmpty)
val nonEmptyShared = shared.filterNot(_.config.isEmpty)
val roleConfigs = role.flatMap(_.loaded)
val nonEmptyRole = roleConfigs.filterNot(_.config.isEmpty)

val toMerge = shared ++ role.filter(filter).flatMap(_.loaded)
val toMerge = (shared ++ role.filter(filter).flatMap(_.loaded)).filterNot(_.config.isEmpty)

val folded = foldConfigs(toMerge)
logger.info(
s"${clue -> "context"}: merged ${shared.size -> "shared configs"} and ${role.size -> "role configs"} of which ${nonEmpty.length -> "non empty"} into config with ${folded
.entrySet().size() -> "root nodes"}, ${nonEmpty
.map(c => c.clue).niceList() -> "config files"}"
)
logger.trace(s"Full list of processed configs: ${cfgInfo.map(c => c.clue).niceList() -> "locations"}")

val repr = toMerge.map(c => c.clue)

val sub = logger("config context" -> clue)
sub.info(s"Config input: ${shared.size -> "shared configs"} of which ${nonEmptyShared.size -> "non empty shared configs"}")
sub.info(s"Config input: ${roleConfigs.size -> "role configs"} of which ${nonEmptyRole.size -> "non empty role configs"}")
sub.info(s"Output config has ${folded.entrySet().size() -> "root nodes"}")
sub.info(s"${repr.niceList() -> "used configs"}")

val configRepr = (shared.map(c => (c.clue, true)) ++ role.flatMap(r => r.loaded.map(c => (s"${c.clue}, role=${r.roleConfig.role}", filter(r)))))
.map(c => s"${c._1}, active = ${c._2}")
logger.debug(s"Full list of processed configs: ${configRepr.niceList() -> "locations"}")

folded
}

def foldConfigs(roleConfigs: List[ConfigLoadResult.Success]): Config = {
roleConfigs.reverse // rightmost config will have the highest priority
.foldLeft(ConfigFactory.empty()) {
case (acc, loaded) =>
verifyConfigs(loaded, acc)
acc.withFallback(loaded.config)
}
val fallbackOrdered = roleConfigs.reverse // rightmost config has the highest priority, so we need it to become leftmost

verifyConfigs(fallbackOrdered)

fallbackOrdered.foldLeft(ConfigFactory.empty()) {
case (acc, loaded) =>
acc.withFallback(loaded.config)
}
}

protected def verifyConfigs(loaded: ConfigLoadResult.Success, acc: Config): Unit = {
val duplicateKeys = getKeys(acc) intersect getKeys(loaded.config)
if (duplicateKeys.nonEmpty) {
loaded.src match {
case ConfigSource.Resource(_, ResourceConfigKind.Development) =>
logger.debug(s"Some keys in supplied ${loaded.src -> "development config"} duplicate already defined keys: ${duplicateKeys.niceList() -> "keys" -> null}")
case _ =>
logger.warn(s"Some keys in supplied ${loaded.src -> "config"} duplicate already defined keys: ${duplicateKeys.niceList() -> "keys" -> null}")
}
private def verifyConfigs(fallbackOrdered: List[ConfigLoadResult.Success]): Unit = {
import izumi.fundamentals.collections.IzCollections.*
fallbackOrdered.flatMap(c => getKeys(c.config).map(key => (key, c))).toUniqueMap(identity) match {
case Left(value) =>
val diag = value.map { case (key, configs) => s"$key is defined in ${configs.map(_.src).niceList(prefix = "* ").shift(2)}" }
logger.warn(s"There were config ${diag.niceList() -> "conflicts"}")
case Right(_) =>
}
}

Expand All @@ -79,7 +86,7 @@ object ConfigMerger {
.withFallback(config)
.resolve()
logger.info(
s"Config with ${config.entrySet().size() -> "root nodes"} had been enhanced with system properties, new config has ${result.entrySet().size() -> "new root nodes"}"
s"Config with ${config.entrySet().size() -> "root nodes"} has been enhanced with system properties, new config has ${result.entrySet().size() -> "new root nodes"}"
)

result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ final case class TestConfig(
parallelSuites: Parallelism = Parallelism.Unlimited,
parallelTests: Parallelism = Parallelism.Unlimited,
// other options
configBaseName: String,
configBaseName: String = "test",
configOverrides: Option[AppConfig] = None,
bootstrapFactory: BootstrapFactory = BootstrapFactory.Impl,
planningOptions: PlanningOptions = PlanningOptions(),
Expand All @@ -96,8 +96,10 @@ final case class TestConfig(

}
object TestConfig {
@deprecated("Use TestConfig() constructor instead, always provide pluginConfig explicitly", "1.2.3")
def forSuite(clazz: Class[?]): TestConfig = {
val packageName = clazz.getPackage.getName

TestConfig(
pluginConfig = PluginConfig.cached(Seq(packageName)),
configBaseName = s"${packageName.split('.').last}-test",
Expand Down

0 comments on commit 03db161

Please sign in to comment.