Skip to content

Commit

Permalink
Fix #790 replace distage-config backend with pureconfig instead o…
Browse files Browse the repository at this point in the history
…f `circe-config`
  • Loading branch information
neko-kai committed Feb 18, 2020
1 parent 19fe058 commit 4487851
Show file tree
Hide file tree
Showing 21 changed files with 340 additions and 751 deletions.
791 changes: 225 additions & 566 deletions build.sbt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package distage.config

import izumi.distage.config.{codec, model}
import izumi.distage.config.{codec, extractor, model}

trait DistageConfig {

Expand All @@ -15,6 +15,6 @@ trait DistageConfig {
type ConfigReader[T] = codec.ConfigReader[T]
val ConfigReader: codec.ConfigReader.type = codec.ConfigReader

type ConfigPathExtractorModule = izumi.distage.config.ConfigPathExtractorModule
type ConfigPathExtractorModule = extractor.ConfigPathExtractorModule

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package distage

import izumi.distage.config.{codec, model}
import izumi.distage.config.{codec, extractor, model}

package object config extends DistageConfig {

Expand All @@ -15,6 +15,6 @@ package object config extends DistageConfig {
override type ConfigReader[T] = codec.ConfigReader[T]
override val ConfigReader: codec.ConfigReader.type = codec.ConfigReader

override type ConfigPathExtractorModule = izumi.distage.config.ConfigPathExtractorModule
override type ConfigPathExtractorModule = extractor.ConfigPathExtractorModule

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package izumi.distage.config

import com.typesafe.config.Config
import izumi.distage.config.model.AppConfig
import izumi.distage.model.definition.ModuleDef

class AppConfigModule(appConfig: AppConfig) extends ModuleDef {
def this(config: Config) = this(AppConfig(config))

make[AppConfig].fromValue(appConfig)
}
object AppConfigModule {
def apply(appConfig: AppConfig): AppConfigModule = new AppConfigModule(appConfig)
def apply(config: Config): AppConfigModule = new AppConfigModule(config)
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
package izumi.distage.config

import com.typesafe.config.Config
import izumi.distage.config.codec.ConfigReader
import izumi.distage.config.model.AppConfig
import distage.config.{AppConfig, ConfigReader}
import distage.{ModuleDef, Tag}
import izumi.distage.config.model.exceptions.DIConfigReadException
import izumi.distage.model.definition.BindingTag.ConfTag
import izumi.distage.model.definition.dsl.ModuleDefDSL.{MakeDSL, MakeDSLNamedAfterFrom, MakeDSLUnnamedAfterFrom}
import izumi.distage.model.definition.{BootstrapModuleDef, ModuleDef}
import izumi.distage.model.planning.PlanningHook
import izumi.fundamentals.platform.language.CodePositionMaterializer
import izumi.fundamentals.platform.language.Quirks._
import izumi.fundamentals.reflection.Tags.Tag

import scala.util.{Failure, Success, Try}

class AppConfigModule(appConfig: AppConfig) extends ModuleDef {
def this(config: Config) = this(AppConfig(config))

make[AppConfig].fromValue(appConfig)
}
object AppConfigModule {
def apply(appConfig: AppConfig): AppConfigModule = new AppConfigModule(appConfig)
def apply(config: Config): AppConfigModule = new AppConfigModule(config)
}

class ConfigPathExtractorModule extends BootstrapModuleDef {
many[PlanningHook]
.add[ConfigPathExtractor]
}

trait ConfigModuleDef extends ModuleDef {
final def makeConfig[T: Tag: ConfigReader](path: String)(implicit pos: CodePositionMaterializer): MakeDSLUnnamedAfterFrom[T] = {
pos.discard()
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
package izumi.distage.config.codec

import com.typesafe.config.{ConfigObject, ConfigValue, ConfigValueFactory}
import io.circe.Decoder
import io.circe.config.parser
import com.typesafe.config.ConfigValue
import pureconfig.error.ConfigReaderException

import scala.jdk.CollectionConverters._
import scala.util.Try
import scala.reflect.ClassTag
import scala.util.{Failure, Success, Try}

/**
* Config reader that uses Circe Json Decoder instance for a type
* Config reader that uses pureconfig.ConfigReader instance for a type
* to decode Typesafe Config.
*
* Always automatically derives a codec if it's not available.
*
* Automatic derivation will also make additional Decoder instances
* in [[CirceConfigInstances]] available. If you want to use this
* deriving strategy for your own Decoder instance, you may use
* `ConfigReader.deriveDecoder`:
* Automatic derivation will use **`camelCase`** fields, not `snake-case` fields,
* as in default pureconfig. It will also work without importing `pureconfig.generic.auto._`.
* If you want to use it to recursively derive a pureconfig codec,
* you may use `PureconfigAutoDerive[T]`:
*
* {{{
* case class Abc(a: Duration, b: Regex, c: URL) // types for which there is no default instance in Circe
* final case class Abc(a: Duration, b: Regex, c: URL)
* object Abc {
* implicit val decoder: Decoder[Abc] = ConfigReader.deriveDecoder
* }
* }}}
*
* Or just import [[CirceConfigInstances]]:
*
* {{{
* object Abc {
* import CirceConfigInstances._
*
* implicit val decoder: Decoder[Abc] = io.circe.derivation.deriveDecoder
* implicit val configReader: pureconfig.ConfigReader[Abc] = PureconfigAutoDerive[Abc]
* }
* }}}
*/
Expand All @@ -43,28 +32,23 @@ trait ConfigReader[A] {
}

object ConfigReader extends LowPriorityConfigReaderInstances {
def apply[T: ConfigReader]: ConfigReader[T] = implicitly
@inline def apply[T: ConfigReader]: ConfigReader[T] = implicitly

def derive[T](implicit dec: CirceDerivationConfigStyle[T]): ConfigReader[T] = ConfigReader.deriveFromCirce(dec.value)
def derive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): ConfigReader[T] = {
ConfigReader.deriveFromPureconfig[T](implicitly, dec.value)
}

implicit def deriveFromCirce[T](implicit dec: Decoder[T]): ConfigReader[T] = {
implicit def deriveFromPureconfig[T: ClassTag](implicit dec: pureconfig.ConfigReader[T]): ConfigReader[T] = {
cv =>
val (wrappedValue, path) = cv match {
case configObject: ConfigObject =>
configObject.toConfig -> None
case _ =>
ConfigValueFactory.fromMap(Map("_root_" -> cv).asJava).toConfig -> Some("_root_")
dec.from(cv) match {
case Left(errs) => Failure(ConfigReaderException[T](errs))
case Right(value) => Success(value)
}
Try {
path.fold(parser.decode[T](wrappedValue)(dec)) {
parser.decodePath[T](wrappedValue, _)(dec)
}.toTry
}.flatten
}
}

trait LowPriorityConfigReaderInstances {
implicit def materializeFromCirceDerivationWithCirceConfigInstances[T](implicit dec: CirceDerivationConfigStyle[T]): ConfigReader[T] = {
ConfigReader.deriveFromCirce(dec.value)
implicit def materializeFromPureconfigAutoDerive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): ConfigReader[T] = {
ConfigReader.deriveFromPureconfig(implicitly, dec.value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package izumi.distage.config.codec

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

/** Derive `pureconfig.ConfigReader` for A and for its fields recursively with `pureconfig-magnolia` */
final class PureconfigAutoDerive[A](val value: pureconfig.ConfigReader[A]) extends AnyVal

object PureconfigAutoDerive {
@inline def apply[A](implicit ev: PureconfigAutoDerive[A]): pureconfig.ConfigReader[A] = ev.value

implicit def materialize[A]: PureconfigAutoDerive[A] = macro CirceDerivationConfigStyleMacro.materializeImpl[A]

object CirceDerivationConfigStyleMacro {
def materializeImpl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[PureconfigAutoDerive[A]] = {
import c.universe._
c.Expr[PureconfigAutoDerive[A]] {
// Yes, this is legal /_\ !! We add an import so that implicit scope is enhanced
// by new config codecs that aren't in Decoder companion object
q"""{
import _root_.izumi.distage.config.codec.PureconfigInstances._
new ${weakTypeOf[PureconfigAutoDerive[A]]}(_root_.pureconfig.module.magnolia.auto.reader.exportReader[${weakTypeOf[A]}])
}"""
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package izumi.distage.config.codec

import com.typesafe.config.ConfigMemorySize
import pureconfig.ConfigReader.Result
import pureconfig.error.CannotConvert
import pureconfig.generic.ProductHint
import pureconfig.{CamelCase, ConfigCursor, ConfigFieldMapping, Exported, error}

import scala.reflect.classTag
import scala.util.control.NonFatal

object PureconfigInstances extends PureconfigInstances
trait PureconfigInstances {
/** Override pureconfig's default `snake-case` fields – force CamelCase product-hint */
implicit def forceCamelCaseProductHint[T]: ProductHint[T] = productHintAny.asInstanceOf[ProductHint[T]]
private[this] val productHintAny: ProductHint[Any] = ProductHint(fieldMapping = ConfigFieldMapping(CamelCase, CamelCase))

// use `Exported` so that if user imports their own instances, user instances will have higher priority
implicit final val memorySizeDecoder: Exported[pureconfig.ConfigReader[ConfigMemorySize]] = Exported((cur: ConfigCursor) => {
try Right(cur.value.atKey("m").getMemorySize("m")) catch {
case NonFatal(ex) =>
Result.fail(error.ConvertFailure(CannotConvert(cur.value.toString, classTag[ConfigMemorySize].toString, ex.toString), cur))
}
})
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package izumi.distage.config
package izumi.distage.config.extractor

import com.typesafe.config.{Config, ConfigFactory}
import izumi.distage.config.ConfigPathExtractor._
import izumi.distage.config.extractor.ConfigPathExtractor.{ConfigPath, ExtractConfigPath, ResolvedConfig}
import izumi.distage.model.definition.BindingTag.ConfTag
import izumi.distage.model.plan.operations.OperationOrigin
import izumi.distage.model.plan.{ExecutableOp, SemiPlan}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package izumi.distage.config.extractor

import distage.BootstrapModuleDef
import izumi.distage.model.planning.PlanningHook

class ConfigPathExtractorModule extends BootstrapModuleDef {
many[PlanningHook]
.add[ConfigPathExtractor]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.github.pshirshov.configapp

import izumi.distage.config.ConfigPathExtractor.ResolvedConfig
import izumi.distage.config.extractor.ConfigPathExtractor.ResolvedConfig
import izumi.distage.model.PlannerInput
import izumi.distage.model.definition.ModuleDef
import izumi.fundamentals.platform.language.Quirks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Paths}

import com.typesafe.config.{Config, ConfigFactory, ConfigRenderOptions}
import izumi.distage.config.ConfigPathExtractor.ResolvedConfig
import izumi.distage.config.ConfigPathExtractorModule
import izumi.distage.config.extractor.ConfigPathExtractor.ResolvedConfig
import izumi.distage.config.extractor.ConfigPathExtractorModule
import izumi.distage.framework.services.RoleAppPlanner
import izumi.distage.model.definition.Id
import izumi.distage.model.effect.DIEffect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@ object SimpleLoggerConfigurator {
))
layout <- Decoder.forProduct1("layout")(identity[Option[String]])
} yield SinksConfig(levels, options, json, layout)
implicit val configReader: ConfigReader[SinksConfig] = ConfigReader.deriveFromCirce
implicit val configReader: ConfigReader[SinksConfig] = ConfigReader.derive
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import java.nio.charset.StandardCharsets

import izumi.fundamentals.platform.language.Quirks._
import izumi.fundamentals.reflection.macrortti.LightTypeTag.ParsedLightTypeTag.SubtypeDBs
import izumi.fundamentals.reflection.macrortti.LightTypeTagRef.SymName.{SymTermName, SymTypeName}
import izumi.fundamentals.reflection.macrortti.LightTypeTagRef.{AbstractReference, AppliedNamedReference, AppliedReference, NameReference, SymName}
import izumi.fundamentals.reflection.macrortti.LightTypeTagRef._
import izumi.thirdparty.internal.boopickle.Default.Pickler

/**
Expand Down Expand Up @@ -228,8 +227,6 @@ object LightTypeTag {
private[macrortti] val (lttRefSerializer: Pickler[LightTypeTagRef], subtypeDBsSerializer: Pickler[SubtypeDBs]) = {
import izumi.thirdparty.internal.boopickle.Default._

implicit lazy val symTypeName: Pickler[SymTypeName] = generatePickler[SymTypeName]
implicit lazy val symTermName: Pickler[SymTermName] = generatePickler[SymTermName]
implicit lazy val symName: Pickler[SymName] = generatePickler[SymName]
implicit lazy val appliedRefSerializer: Pickler[AppliedReference] = generatePickler[AppliedReference]
implicit lazy val nameRefSerializer: Pickler[NameReference] = generatePickler[NameReference]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ object LightTypeTagRef {
LightTypeTagInheritance.tpeAny
case head :: Nil =>
head
case o =>
case _ =>
IntersectionReference(normalized)
}
}
Expand Down
Loading

0 comments on commit 4487851

Please sign in to comment.