sbt.version=0.13.1
build.sbt
,我通过调用项目依赖项的代码片段来分配设置键,该代码又通过Typesafe Config的ConfigFactory
进行自我配置。我的依赖项在 jar 的根目录中有一个reference.conf
,我的项目本身在 src/main/resources
中包含一个覆盖application.conf
。
库/依赖项也是我的代码,顺便说一句。
import com.mylib.Finders
import com.myproj.sbt.Keys._
projKeyColorSetting in Compile := Finders.findColor // this calls ConfigFactory.load
seq(projSettings:_*)
构建甚至没有加载,因为它找不到我尝试在我的 lib 代码中引用的第一个 conf 密钥。
我已经在我的构建文件中尝试了许多范围界定和类路径操作的组合,但无济于事。我假设 jar 的reference.conf
应该在 Compile
范围的类路径上,但它没有像我预期的那样工作。
我昨天花了大部分时间研究有关类路径、作用域、键、任务和资源生成器的 SBT 文档 - 我的目的是执行一个依赖于build.sbt
中projKeyColorSetting
设置的自定义插件,如下所示:
lazy val projSettings = inConfig(Compile) {
Seq(
resourceGenerators in Compile <+= Def.task {
val fileCreated = createColorFile(projKeyColorSetting.value)
Seq(fileCreated)
}
)
}
如果你从 foo.jar 获得一个类,那么ConfigFactory.load()
应该得到一个在同一个 jar 中找到的 reference.conf。如果没有,那么有些问题,但很难猜测是什么。可能是 reference.conf 中可能存在一些无效的语法;可能是 reference.conf 不在罐子里;可能是 reference.conf 位于子目录中,而不是 jar 的根目录中;很难猜到。我会尝试-Dconfig.trace=loads
在那里寻找问题(例如,它应该告诉您配置是否尝试加载 reference.conf(。您也可以自己做classLoader.getResources
,看看是否可以在不涉及配置的情况下找到该文件。您也可以尝试ConfigFactory.parseResourcesAnySyntax("reference")
,看看您的参考设置是否在那里,并尝试直接拨打ConfigFactory.load
,看看您的设置是否在那里。一般来说,仔细检查所有假设,看看哪里出了问题。
至于如何添加 src/main/resources,两个基本策略是 1( 以某种方式将其放在类路径上(在这种情况下可能很困难;您甚至在启动 sbt 之前就需要它,或者需要做某种自定义的 ClassLoader 乐趣(或者可能更实用 2( 使用 ConfigFactory.parseFile()
手动加载它。
我可能会抓住resourceDirectory
键作为任务的依赖项,然后做类似的事情(未经测试(:
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
以下情况。这。
我认为这是 sbt 中的一个错误。
以下是我对你的用例以及 sbt 最终行为的理解。
项目/生成属性
sbt.version=0.13.5-M2
文件夹仅配置项目适用于具有以下两个文件 - build.sbt 和 src/main/resources/application.conf 的项目。这是为了模拟对内部application.conf
项目的外部依赖关系。
build.sbt in config-only-project
libraryDependencies += "com.typesafe" % "config" % "1.2.0"
src/main/resources/application.conf in config-only-project
app-name {
hello = "Hello from Typesafe Config"
}
以下文件配置项目的默认plugins
以及生成配置本身(以及正在调查的项目的生成(。
project/build.sbt
lazy val configOnlyProject = uri("../config-only-project")
lazy val plugins = project in file(".") dependsOn (configOnlyProject)
project/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
我希望我能解释一下,但这对我来说似乎太大了:(
Play 项目的相同问题,通过在任务定义中向ConfigFactory.parseResourcesAnySyntax()
添加 ClassLoader
参数来解决:
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")
}
)
sbt 1.4.4 时遇到的问题是我试图在我的元构建(project/build.sbt
(中添加一个依赖项,以便我可以在我的主构建中使用它。
该库使用的是ConfigFactory.load()
,它使用当前线程中的类加载器,最终成为 SbtMetaClassLoader,它没有元构建依赖项的加载器。
解决方法是将库更改为使用 ConfigFactory.load(getClass.getClassLoader)
,以便它使用从库中加载类的类装入器,并可能使用包括reference.conf
文件在内的 JAR 的其余部分。