Skip to content

Commit

Permalink
Merge pull request #25 from Sqooba/0.5.3
Browse files Browse the repository at this point in the history
0.5.3
  • Loading branch information
pietrotull committed Dec 16, 2019
2 parents 2ed6249 + bd0a19f commit b560e3c
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 58 deletions.
6 changes: 3 additions & 3 deletions build.sbt
@@ -1,15 +1,15 @@
organization := "io.sqooba"
scalaVersion := "2.13.0"
scalaVersion := "2.13.1"
name := "sq-conf"
description := "Unified configuration interface."
homepage := Some(url("https://github.com/Sqooba/sq-conf"))
licenses := Seq("Apache 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0"))

crossScalaVersions := Seq("2.13.0", "2.12.8", "2.11.12")
crossScalaVersions := Seq("2.13.1", "2.12.10", "2.11.12")

// scalatest available in 2.13, scala-logging not yet (only 2.13-RC3)
libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.3.4",
"com.typesafe" % "config" % "1.4.0",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
"ch.qos.logback" % "logback-classic" % "1.2.3" % Test,
"org.scalatest" %% "scalatest" % "3.0.8" % Test,
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
@@ -1 +1 @@
sbt.version=1.3.0-RC2
sbt.version=1.3.5
4 changes: 2 additions & 2 deletions project/plugins.sbt
Expand Up @@ -2,5 +2,5 @@ addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")
addSbtPlugin("com.dwijnand" % "sbt-travisci" % "1.1.1")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.10")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.5")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.0")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
48 changes: 26 additions & 22 deletions readme.md
@@ -1,28 +1,28 @@
# Sq-Conf - unified interface for all your configuration needs

[![Build Status](https://travis-ci.org/Sqooba/sq-conf.svg?branch=master)](https://travis-ci.org/Sqooba/sq-conf/)
[![Build Status](https://travis-ci.org/Sqooba/sq-conf.svg?branch=master)](https://travis-ci.org/Sqooba/sq-conf/)
[![Coverage Status](https://coveralls.io/repos/github/Sqooba/sq-conf/badge.svg?branch=coverall-test)](https://coveralls.io/github/Sqooba/sq-conf?branch=coverall-test)
[![Maven](https://img.shields.io/maven-central/v/io.sqooba/sq-conf_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/io.sqooba/sq-conf_2.11)

## Description

SqConf is unified interface for all your configuration needs. Essentially it's a thin wrapper for
[typesafe-config](https://github.com/lightbend/config) library ("com.typesafe.config" % "1.3.3")
that was mainly created to make configuring applications running on containers easier.
Mainly overriding values from environment variables is made easier, no need to specifically
define this in config. Also key does not need to exist in the config in the first place.
SqConf is unified interface for all your configuration needs. Essentially it's a thin wrapper for
[typesafe-config](https://github.com/lightbend/config) library ("com.typesafe.config" % "1.3.3")
that was mainly created to make configuring applications running on containers easier.
Mainly overriding values from environment variables is made easier, no need to specifically
define this in config. Also key does not need to exist in the config in the first place.

```
// reads application.conf
val sqConf = new SqConf()
val sqConf = SqConf.default()
val sqConf = SqConf.forFilename("other.conf") // reads other.conf from classpath instead.
val sqConf = SqConf.forConfig(typeSafeConfig) // wrap existing instance of typesafe config.
val sqConf = SqConf.forFile(configAsFile) // java.util.File
val sqConf = SqConf.forFile(configAsFile) // java.util.File
```

## Value overrides example
Expand All @@ -31,7 +31,7 @@ Values in the config can be programatically overriden. This is convenient especi
val overrideMap = Map("some.testIntValue" -> "15", "some.testStringValue" -> "overridenstring")
val sqConf: SqConf = SqConf.default.withOverrides(overrides = overrideMap)
sqConf.getInt("some.testIntValue") // returns 15
```

Expand All @@ -42,7 +42,7 @@ in the original config file.
export SOME_TESTINTVALUE="150"
val sqConf: SqConf = SqConf.default()
sqConf.getInt("some.testIntValue") // returns 150
```

Expand All @@ -53,8 +53,9 @@ SqConf supports all the formats that the underlying typesafe config also support
SqConf also provides a java wrapper that returns java data types.
```
val javaWrapper = new SqConf().asJava()
javaWrapper.getInt("some.testIntValue") // returns java.lang.Integer
javaWrapper.getString("some.testStringValue") // returns java.lang.String
```

Expand All @@ -63,8 +64,9 @@ Both native scala sqConf and the javaWrapper now have a convenience method to co
object.
```
val asProperties: Properties = new SqConf().toProperties()
val someIntVal = asProperties.getProperty("some.testIntValue").toInt // properties always returns string
val someStringVal = asProperties.getProperty("some.testStringValue")
```

Expand All @@ -79,17 +81,18 @@ Order of preference defines in which order configuration keys are read. By defau
OrderOfPreference.CONF_FIlE,
OrderOfPreference.ENV_VARIABLE,
OrderOfPreference.VALUE_OVERRIDES)
val conf = new SqConf().configureOrder(oop)
```
Now order would be reversed in comparison to the default.

## Getting started
Sq-conf is cross compiled for scala 2.11, 2.12 and 2.13. For the latest of the latest, sq-conf snapshots
are available in sonatype repo:
[sonatype-snapshots](https://oss.sonatype.org/content/repositories/snapshots/io/sqooba/).
Sq-conf is cross compiled for scala 2.11, 2.12 and 2.13. For the latest of the latest, sq-conf snapshots
are available in sonatype repo:
[sonatype-snapshots](https://oss.sonatype.org/content/repositories/snapshots/io/sqooba/).
Add sqConf to your project, with sbt add this simple line:
```
libraryDependencies += "io.sqooba" %% "sq-conf" % "0.5.2"
libraryDependencies += "io.sqooba" %% "sq-conf" % "0.5.2"
```

Sq-conf works also with maven. Just add this to your pom.xml:
Expand All @@ -102,13 +105,14 @@ Sq-conf works also with maven. Just add this to your pom.xml:
```

## Future Plans
- improve api documentation/ from nonexistent to something
- improve api documentation from nonexistent to something
- yml support
- test more complex type conversions from app.conf, also with java transformers
- getAvailableKeys, already exists, but requires work


## Change History
- 0.5.2 Scala 2.13 support, preliminary
- 0.5.3 getAvailableKeys redefined and also available for a key, getAsOption
- 0.5.2 Scala 2.13 support
- 0.5.1 Allow configuring order of preference, bug fix value overrides not being passed on to sub confix, scala 2.13 support
- 0.5.0 Add get config method to java wrapper, deployed first snapshot to sonatype repo.
- 0.4.2 New toProperties convenience method, transformer interface for java to transform from string to any type.
Expand Down
51 changes: 44 additions & 7 deletions src/main/scala/io/sqooba/conf/SqConf.scala
Expand Up @@ -6,6 +6,7 @@ import java.util.Properties

import scala.collection.JavaConverters._
import scala.reflect.ClassTag
import scala.util.Try

import com.typesafe.config._
import com.typesafe.config.impl.DurationParser
Expand All @@ -19,7 +20,7 @@ class SqConf(fileName: String = null,
prefix: String = null,
valueOverrides: Map[String, String] = Map(), orderOfPreference: List[OrderOfPreference] = SqConf.DEFAULT_ORDER_OF_PREFERENCE) extends LazyLogging {

def this() = this(null, null, null, null)
def this() = this(null, null, null, null)

def asJava() = new JavaSqConf(this)

Expand Down Expand Up @@ -51,16 +52,36 @@ class SqConf(fileName: String = null,

def getOrderOfPreference: List[OrderOfPreference] = orderOfPreference

def getInt(key: String): Int = getValueAccordingOrderOfOfPreference[Int](key, x => x.toInt)
def getInt(key: String): Int = getValueAccordingOrderOfOfPreference[Int](key, _.toInt)

def getInt(key: String, default: Int): Int = getValueAsOptionAccordingOrderOfOfPreference[Int](key, _.toInt).getOrElse(default)

def getIntOption(key: String): Option[Int] = getValueAsOptionAccordingOrderOfOfPreference[Int](key, _.toInt)

def getString(key: String): String = getValueAccordingOrderOfOfPreference[String](key, x => x)

def getBoolean(key: String): Boolean = getValueAccordingOrderOfOfPreference[Boolean](key, x => x.toBoolean)
def getString(key: String, default: String): String = getValueAsOptionAccordingOrderOfOfPreference[String](key, x => x).getOrElse(default)

def getStringOption(key: String): Option[String] = getValueAsOptionAccordingOrderOfOfPreference[String](key, x => x)

def getBoolean(key: String): Boolean = getValueAccordingOrderOfOfPreference[Boolean](key, _.toBoolean)

def getBoolean(key: String, default: Boolean): Boolean = getValueAsOptionAccordingOrderOfOfPreference[Boolean](key, _.toBoolean).getOrElse(default)

def getLong(key: String): Long = getValueAccordingOrderOfOfPreference[Long](key, x => x.toLong)
def getBooleanOption(key: String): Option[Boolean] = getValueAsOptionAccordingOrderOfOfPreference[Boolean](key, _.toBoolean)

def getLong(key: String): Long = getValueAccordingOrderOfOfPreference[Long](key, _.toLong)

def getLong(key: String, default: Long): Long = getValueAsOptionAccordingOrderOfOfPreference[Long](key, _.toLong).getOrElse(default)

def getLongOption(key: String): Option[Long] = getValueAsOptionAccordingOrderOfOfPreference[Long](key, _.toLong)

def getBigInt(key: String): BigInt = getValueAccordingOrderOfOfPreference[BigInt](key, x => BigInt(x))

def getBigInt(key: String, default: BigInt): BigInt = getValueAsOptionAccordingOrderOfOfPreference[BigInt](key, BigInt(_)).getOrElse(default)

def getBigIntOption(key: String): Option[BigInt] = getValueAsOptionAccordingOrderOfOfPreference[BigInt](key, BigInt(_))

def getDuration(key: String): Duration = {
val fullKey = buildKey(key)
if (valueOverrides.contains(fullKey)) {
Expand All @@ -73,6 +94,10 @@ class SqConf(fileName: String = null,
}
}

def getDuration(key: String, default: Duration): Duration = Try(getDuration(key)).getOrElse(default)

def getDurationOption(key: String): Option[Duration] = Try(getDuration(key)).toOption

def getValueAccordingOrderOfOfPreference[T: ClassTag](key: String, converter: String => T): T = {
var value: T = null.asInstanceOf[T]

Expand All @@ -83,6 +108,9 @@ class SqConf(fileName: String = null,
value
}

def getValueAsOptionAccordingOrderOfOfPreference[T: ClassTag](key: String, converter: String => T): Option[T] =
Try({getValueAccordingOrderOfOfPreference[T](key, converter)}).toOption

def getListOfValuesAccordingOrderOfPreference[T: ClassTag](key: String, converter: String => T): List[T] = {
var values: List[T] = List()

Expand Down Expand Up @@ -139,6 +167,10 @@ class SqConf(fileName: String = null,

def get[T](key: String): T = conf.getAnyRef(key).asInstanceOf[T]

def get[T](key: String, default: T): T = getOption[T](key).getOrElse(default)

def getOption[T](key: String): Option[T] = Try(conf.getAnyRef(key).asInstanceOf[T]).toOption

def keyAsEnv(key: String): String = {
val asEnvKey = key.toUpperCase.replaceAll("""\.""", "_")
logger.debug(s"PropertyKey: '$key' is as envKey: '$asEnvKey'")
Expand Down Expand Up @@ -199,20 +231,25 @@ class SqConf(fileName: String = null,
}
}

def getListOfKeys: Set[String] = {
def getListOfKeys(): Set[String] = {
val confRoot = if (prefix == null) {
conf
} else {
conf.getConfig(prefix)
}

val keys = confRoot.root().entrySet().asScala.filter(k => {
k.getValue.origin().filename() != null
k.getValue.origin().filename() != null ||
(k.getValue.origin().resource() != null && k.getValue.origin().resource().endsWith(".conf"))
}).map(_.getKey)

keys.toSet
}

def getListOfKeys(key: String): Set[String] = {
this.getSubConfig(key).getListOfKeys()
}

def configureOrder(order: List[OrderOfPreference]): SqConf =
new SqConf(null, null, config, prefix, valueOverrides, order)
}
Expand Down Expand Up @@ -244,4 +281,4 @@ object SqConf {
def default(): SqConf = {
new SqConf(null, null, null, null)
}
}
}
13 changes: 12 additions & 1 deletion src/test/resources/application.conf
Expand Up @@ -29,4 +29,15 @@ subConf {

simplevalue = "this is a simple string"

filename = "this is test application.conf"
filename = "this is test application.conf"

keyConf {
sub {
complex1 {
id = 1
}
complex2 {
id = 2
}
}
}
6 changes: 3 additions & 3 deletions src/test/resources/ymlconf.yml
@@ -1,3 +1,3 @@
invoice: 34843
date : 2001-01-23
filename: "this is ymlconf.yml"
invoice : 34843
date : 2001-01-23
filename: "this is ymlconf.yml"

0 comments on commit b560e3c

Please sign in to comment.