Использование Configafe Config Config Config для настройки ключа в build.sbt?
sbt.version = 0.13.1
В build.sbt
Я назначаю ключ настройки, вызывая часть кода моего проекта, который, в свою очередь, настраивается через Configafe Config ConfigFactory
. Моя зависимость имеет reference.conf
в корневом банке, а сам мой проект содержит переопределение application.conf
в src/main/resources
.
lib/dependency также является моим кодом, btw.
import com.mylib.Finders
import com.myproj.sbt.Keys._
projKeyColorSetting in Compile := Finders.findColor // this calls ConfigFactory.load
seq(projSettings:_*)
Сборка даже не загружается, потому что она не может найти первый ключ conf, который я пытаюсь ссылаться в моем коде lib.
В моем файле сборки я попытался использовать несколько комбинаций областей видимости и манипуляции с Classpath, но безрезультатно. Я предположил, что jar reference.conf
был бы в пути класса Compile
scope, но он не работает, как я ожидаю.
Я провел большую часть вчерашней работы над документацией SBT по Classpath, Scopes, Keys, Tasks и ResourceGenerators. Я намерен выполнить собственный плагин, который полагается на параметр projKeyColorSetting
в build.sbt
следующим образом:
lazy val projSettings = inConfig(Compile) {
Seq(
resourceGenerators in Compile <+= Def.task {
val fileCreated = createColorFile(projKeyColorSetting.value)
Seq(fileCreated)
}
)
}
Ответы
Ответ 1
Если вы получаете класс из foo.jar, то ConfigFactory.load()
должен получить reference.conf, найденный в той же банке. Если это не так, то что-то не так, но трудно догадаться. Возможно, что reference.conf имеет в нем некоторый недопустимый синтаксис; может быть, что reference.conf не находится в банке; может быть, что reference.conf находится в подкаталоге вместо корня jar; трудно догадаться. Я бы попробовал -Dconfig.trace=loads
искать проблемы там (он должен сказать вам, пытается ли config загружать reference.conf, например). Вы также можете сделать свой собственный classLoader.getResources
и посмотреть, можете ли вы найти файл без использования конфигурации.
Вы также можете попробовать ConfigFactory.parseResourcesAnySyntax("reference")
и посмотреть, находятся ли ваши эталонные настройки, и попробовать напрямую вызвать ConfigFactory.load
и посмотреть, находятся ли ваши настройки там. Как правило, дважды проверьте все допущения и посмотрите, где это происходит.
Что касается того, как добавить src/main/resources, две основные стратегии: 1) как-то получить его на пути к классу (что, вероятно, в этом случае затруднено, вам понадобится его до запуска sbt или потребуется сделать какой-то пользовательский класс ClassLoader весело) или, вероятно, более практично 2) загрузить его вручную с помощью ConfigFactory.parseFile()
.
Я бы, вероятно, взял ключ resourceDirectory
в качестве зависимости от вашей задачи, а затем сделал что-то вроде (untested):
myTask := {
val resourceDir = (resourceDirectory in Compile).value
val appConfig = ConfigFactory.parseFile(resourceDir / "application.conf")
val config = ConfigFactory.load(appConfig) // puts reference.conf underneath
Finders.findColor(config)
}
Обратите внимание, что это включает в себя изменение findColor для принятия параметра Config
, или, возможно, вы предпочтете сделать Finders неэлементным, который можно построить с помощью Config
; см. пример в https://github.com/typesafehub/config/blob/master/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala#L22, где я пытался проиллюстрировать, что при использовании Config
обычно библиотека должна по умолчанию ConfigFactory.load
, но также имеет конструктор, который позволяет настраивать Config
для таких ситуаций.
Ответ 2
Я думаю, что это ошибка в sbt.
Здесь мое понимание вашего прецедента и того, как sbt в конечном итоге вел себя.
Проект /build.properties
sbt.version=0.13.5-M2
Папка config-only-project предназначена для проекта со следующими двумя файлами: build.sbt и src/main/resources/application.conf. Это должно имитировать внешнюю зависимость от проекта с application.conf
внутри.
build.sbt в config-only-project
libraryDependencies += "com.typesafe" % "config" % "1.2.0"
src/main/resources/application.conf в config-only-project
app-name {
hello = "Hello from Typesafe Config"
}
Следующие файлы настраивают проект по умолчанию plugins
, а также саму конфигурацию сборки (и, следовательно, сборку для исследуемого проекта).
Проект /build.sbt
lazy val configOnlyProject = uri("../config-only-project")
lazy val plugins = project in file(".") dependsOn (configOnlyProject)
Проект /build.scala
import sbt._
import Keys._
import com.typesafe.config._
object build extends Build {
lazy val mySetting = taskKey[String]("Setting using Typesafe Config")
lazy val myS = mySetting := {
// Compiler issue Config conf???
println((fullClasspath in Compile).value)
val conf = ConfigFactory.load()
conf getString "app-name.hello"
}
lazy val configOnlyProject = uri("config-only-project")
lazy val root = project in file(".") settings (myS) dependsOn (configOnlyProject)
}
Это дает следующую структуру каталогов:
jacek:~/sandbox/so/setting-typesafe-config
$ tree
.
├── config-only-project
│ ├── build.sbt
│ ├── project
│ └── src
│ └── main
│ └── resources
│ └── application.conf
└── project
├── application.conf
├── build.properties
├── build.sbt
└── build.scala
6 directories, 6 files
Я не мог понять, что сама настройка не сработала - ни для основного проекта, ни для проекта plugins
.
> mySetting
List(Attributed(/Users/jacek/sandbox/so/setting-typesafe-config/target/scala-2.10/classes), Attributed(/Users/jacek/sandbox/so/setting-typesafe-config/config-only-project/target/scala-2.10/classes), Attributed(/Users/jacek/.sbt/boot/scala-2.10.4/lib/scala-library.jar), Attributed(/Users/jacek/.ivy2/cache/com.typesafe/config/bundles/config-1.2.0.jar))
[trace] Stack trace suppressed: run last root/*:mySetting for the full output.
[error] (root/*:mySetting) com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
[error] Total time: 0 s, completed Mar 31, 2014 10:24:12 PM
Ошибка была следующей:
> last root/*:mySetting
com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:124)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:147)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:159)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:164)
at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:206)
at build$$anonfun$myS$1.apply(build.scala:11)
at build$$anonfun$myS$1.apply(build.scala:7)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
[error] (root/*:mySetting) com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
Он работал, когда я выполнил тот же код в консоли Scala:
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import com.typesafe.config._
import com.typesafe.config._
scala> ConfigFactory.load()
res0: com.typesafe.config.Config = ...
scala> res0 getString "app-name.hello"
res1: String = Hello from Typesafe Config
Когда я переключился на проект plugins
, он тоже работал отлично:
> reload plugins
[info] Loading project definition from /Users/jacek/sandbox/so/setting-typesafe-config/project
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import com.typesafe.config._
import com.typesafe.config._
scala> ConfigFactory.load()
res0: com.typesafe.config.Config = ...
scala> res0 getString "app-name.hello"
res1: String = Hello from Typesafe Config
Мне хотелось бы объяснить это, но для меня это кажется слишком большой когнитивной нагрузкой: (
Ответ 3
Такая же проблема с проектом Play, решена путем добавления параметра ClassLoader
в ConfigFactory.parseResourcesAnySyntax()
в определении задачи:
import com.typesafe.config.ConfigFactory
lazy val root = (project in file(".")).
settings(
myTask := {
val cl = new java.net.URLClassLoader(Array((resourceDirectory
in Compile).value.toURI.toURL))
// load ./conf/foo.conf
val config = ConfigFactory.parseResourcesAnySyntax(cl, "foo.conf")
}
)