vlovgr / ciris Goto Github PK
View Code? Open in Web Editor NEWFunctional Configurations for Scala
Home Page: https://cir.is
License: MIT License
Functional Configurations for Scala
Home Page: https://cir.is
License: MIT License
I have open this issue just as a placeholder to keep track of it.
I am working on it using Scala 2.13.0-RC2
Is there a reason orRaiseErrors
/orRaiseThrowable
on ConfigResult
require MonadError
instead of the more general ApplicativeError
?
This PR aims to provide an artifact of Ciris using scala 2.13.0-RC1
Ciris is very good. I am enjoying it!
I have run into some unexpected (to me) behavior regarding the interaction of missing properties and sequential vs. parallel composition. In the following code I have two configs that differ only in composition mode. I would expect that both will succeed or both will fail, the difference being only in the error message on failure. However this is not the case. config2
fails to load even though there is a default alternative provided. This seems like a bug to me.
import cats.effect._
import cats.implicits._
import ciris._
object CirisTest extends IOApp {
val config1 = (prop("a"), prop("b")).tupled or default(("foo", "bar"))
val config2 = (prop("a"), prop("b")).parTupled or default(("foo", "bar"))
def run(args: List[String]): IO[ExitCode] =
for {
_ <- IO(System.getProperties().put("a", "A"))
_ <- config1.load[IO].flatMap(c => IO(println(s"config1 is $c")))
_ <- config2.load[IO].flatMap(c => IO(println(s"config2 is $c")))
} yield ExitCode.Success
}
Output looks like this.
config1 is (foo,bar)
[E] ciris.ConfigException: configuration loading failed with the following errors.
[E]
[E] - Missing system property b.
[E]
[E] at ciris.ConfigException$.apply(ConfigException.scala:57)
[E] at ciris.ConfigError.throwable(ConfigError.scala:114)
[E] at ciris.ConfigValue.$anonfun$load$1(ConfigValue.scala:176)
[E] at cats.effect.Resource.$anonfun$fold$1(Resource.scala:118)
...
I experimented a bit and found that this only happens if the failure in config2
is partial. If both system properties are missing that config2
succeeds (i.e., if you change it to (prop("b"), prop("b")).parTupled ...
.
We could add file[Value](path)
and file[Value](path, encoding)
helpers for this.
Suggestions on what such a module could include:
ConfigValue
from Cats Either
instances, such as Traverse
, Bitraverse
, MonadError
, and custom instances for SemigroupK
and Show
.Show
instances for the user-visible types.When working with a context F[_]
with a MonadError[F, Throwable]
instance (for example, IO
from cats-effect), one often ends up writing code similar to the following, in order to raise ConfigErrors
as a Throwable
error in the context.
val config: F[Either[ConfigErrors, Config]] = ...
config.flatMap {
case Right(config) => F.pure(config)
case Left(errors) => F.raiseError(errors.toException)
}
The idea is to provide syntax for this common code, so that we can instead write the following.
import ciris.syntax._
val config: F[Either[ConfigErrors, Config]] = ...
config.orRaiseError
The Scala Native user guide provides a lot of detail on this:
http://www.scala-native.org/en/latest/user/sbt.html
It might also help to look at how another project added Scala Native support:
propensive/contextual#17
Scala Native only compiles with specific 2.11 versions (most relevant, 2.11.12). Depending on if dependent libraries are supporting Scala Native or not, tests may not be able to run for Scala Native (ScalaTest, ScalaCheck) and some modules may not build on Scala Native. The core module, being dependency free, should build just fine though. We'll also somehow need to reflect which modules are available for Scala Native in the readme.
Any reason not to have instances for functor/monad etc. for ConfigResult[F, ?]
as long as these instances exist for F
? Would be nice to be able to use mapN
instead of loadConfig
- or use for
comprehensions if the context type allows it.
Have been falling for Ciris lately and begun efforts to move our configuration patterns over to it. In-house I've been developing extensions for Hashicorp Consul and Vault. Any guidance on how such contributions should be structured? I have been utilizing the ciris
namespace, which seems to be an established pattern. In regards to dependencies, neither has a Hashicorp-provided JVM lib; should I wrap against their HTTP endpoints via a Typelevel HTTP client, e.g. http4s, or is it okay to include third party Java wrappers?
We should start using the Migration Manager for Scala (MiMa) to make sure we don't break backwards compatibility without knowing about it, and make sure we communicate such changes by bumping version numbers accordingly.
I noticed that reading in config with propF
and argF
require instances of Sync
in order to suspend side-effects properly, but envF
does not. It only seems to require Applicative
, and as a result it seems that the side-effect of reading from the environment is not deferred as expected, merely lifted into F
after the fact.
Was this an intentional design choice? If not, I can work on a quick an MR to fix it. Also, is there a use case for an env/prop/argF
that does not depend on Sync
? Maybe this could be solved by separate APIs for lifting to F
and supending in F
. Let me know what you think, and thanks in advance for reading this issue.
How can I use the application.conf
in Typesafe configuration format (HOCON) as a config source for ciris?
Extending Ciris to include a ConfigSource, for loading secrets using credstash (https://github.com/fugue/credstash)
Hi! Are there any blockers for enabling cross-building to Scala.js? We'd probably need some separate sources, but other than that do you see any potential issues, JVM dependencies etc.?
It would be a great addition to have changes published as soon as they are merged to master, in line with sbt-release-early. This work also involves setting up Travis CI to do the publishing work, which is done manually by me at the moment.
Hi! Would you be interested in adding support for iron, in a similar way to the existing refined module? I haven't looked into it yet, but would be happy to and submit a draft if you don't have any objections?
Hey there -
I recently had to drop my use of Ciris in one of my projects due to the inability to use it properly in GraalVM. I've attached the full stack trace. Switching to Pureconfig solved this for me. I was also able to solve this using ConfigValue.default
. Seemed like the issue was being thrown in the flatMap
command here: https://github.com/vlovgr/ciris/blob/master/modules/core/src/main/scala/ciris/ConfigValue.scala#L155
https://github.com/etspaceman/kinesis-mock/tree/4acc3ee60a6dda9ea85629c2551a25faa9985ac6
You can reproduce this by running sbt dockerComposeUp
.
Hello!
I have been using Ciris for a little while now. I am preparing an upgrade to the 1.x version, and I noticed that the entire library now depends on Cats Effect. I guess I'm trying to find out why. The PR that introduced this had no description or issue.
Effects tend to be used to contain side effects, but aren't your functions for checking environment variables and whatnot pure? If so, wouldn't we want to use something like MonadError[ConfigError, A]? The extra effect layer is a bit of a burden to work with and I'm just curious as to why these decisions were made. I would think that I should be able to run a ConfigValue.load without introducing any side effects.
Updated ciris-refined to version 1.2.1 but are not able to update ciris-cats or ciris-core to this version:
[error] not found: https://repo1.maven.org/maven2/is/cir/ciris-cats_2.12/1.2.1/ciris-cats_2.12-1.2.1.pom
[error] not found: https://repo1.maven.org/maven2/is/cir/ciris-core_2.12/1.2.1/ciris-core_2.12-1.2.1.pom
Ciris currently has ConfigReader
instances for many java.time
types in the core library (see JavaTimeConfigReaders). Some of these types support parsing with different formats, rather than the default one used by the current instances. The idea is to add configurable java.time
instances, where the user supplies the format (DateTimeFormatter
) and we create a ConfigReader
for the requested type.
For inspiration, PureConfig has done something similar, as seen here:
https://github.com/pureconfig/pureconfig/blob/master/core/src/main/scala/pureconfig/configurable/package.scala
The idea is to parametrise ConfigSource
with an additional type parameter F[_]
, so that the type signature becomes ConfigSource[F[_], Key]
, and so that it now reads keys with return type F[ConfigSourceEntry[Key]]
.
Remaining parts of Ciris, including documentation, will need to be updated to account for the type parameterisation. Existing functions can use the Id
type as context. New functions will need to be created where the context can be specified or inferred.
This would allow to write code similar to the following, replacing Future
with some other type for which you can define a Monad
instance.
type F[A] = Future[A]
val source: ConfigSource[F, String] = ???
def fetch[Value: ConfigReader](key: String): F[ConfigValue[Value]] = ???
val sum: F[BigDecimal] =
loadConfig(
fetch[BigDecimal]("FIRST_KEY"),
fetch[Int]("SECOND_KEY"),
fetch[Double]("THIRD_KEY")
)(_ + _ + _)
This work will also involve:
Id
, Applicative
, and Monad
from Cats in the core module.I have some YAML that I need to load into a configuration (via ciris-kubernetes). I had a brief look into what's needed to get this working with circe-yaml.
Amazingly, all it took to get this working was to add the circe-yaml dependency, and replace the parser.
- import io.circe.parser.parse
+ import io.circe.yaml.parser.parse
It just works because the parse
method in circe-yaml
has the same signature as the circe json parser:
def parse(yaml: String): Either[ParsingFailure, Json]
So perhaps we can extend def circeConfigDecoder
to take a parser
(or delegate that to a private method) and then add a yaml module that uses the circe-yaml
parser instead of the json parser.
Happy to draft a PR if you're interested.
Is it a good idea to use sha-1 for hashes? I wonder if it is okay to print these as sha-1 is considered broken.
On the other hand the shorthash only prints the first 7 characters, which relaxes the problem a bit.
Thoughts on that?
Ciris currently only have ConfigReader
instances for scala.math.BigDecimal
and scala.math.BigInt
, but not the underlying Java java.math.BigDecimal
and java.math.BigInteger
. We could use the existing Scala support and simply use underlying
to get the Java versions.
@ BigInt(123).underlying
res0: java.math.BigInteger = 123
@ BigDecimal(123).underlying
res1: java.math.BigDecimal = 123
Depends on the following plugins being updated to SBT 1.0.
The current contributing guide only exists as a markdown document in the repository root. It would be a nice addition if this document moved to the docs
project, and got it's own page on the microsite. We could still generate the document for the repository root, similar to how we generate the readme.
Hi,
is it documented somewhere how to load and parse a local configuration file?
In the "Quick example" and "Configurations" documentation sections I mostly find example snippets for environment variables - but maybe I am missing something.
Thank you!
ConfigException
currently creates a message from ConfigErrors
. Sometimes it's useful to be able to retrieve this message without creating a ConfigException
. The idea is that we move it to a function on ConfigErrors
(message
?) and make use of it in ConfigException
.
We currently have custom source generators for generating boilerplate code (see SourceGenerators). We should investigate whether we should move to use sbt-boilerplate instead, and if so, rewrite the current source generators to use sbt-boilerplate.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.