【发布时间】:2014-07-07 12:52:51
【问题描述】:
我们有一个大型的多项目,其中包含我们使用 sbt 构建的许多模块。事实证明,我们在打包不需要的 jar 方面有很多问题。作为解决该问题的第一步,我们创建了一个已使用工件的“全局地图”,其定义如下:
project/Build.scala:
type PartialFunction2[-T1,-T2,+R] = PartialFunction[Tuple2[T1,T2],R]
lazy val dependenciesManager = settingKey[PartialFunction2[String, String, ModuleID]]("a setting containing versions for dependencies. if we only use it to declare dependencies, we can avoid a lot of version collisions.")
build.sbt 在根目录中:
dependenciesManager in Global := {
case ("ch.qos.logback","logback-classic") => "ch.qos.logback" % "logback-classic" % "1.1.1"
case ("com.typesafe","config") => "com.typesafe" % "config" % "1.2.0"
case ("com.typesafe","scalalogging-slf4j") => "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"
case ("com.typesafe.akka",art) => "com.typesafe.akka" %% art % "2.2.4"
case ("com.typesafe.play", art) => "com.typesafe.play" %% art % "2.2.3"
...
}
这允许我们在任何模块自己的build.sbt 文件中使用以下语法:
libraryDependencies <++= (dependenciesManager)(dm => Seq(
dm("com.typesafe.akka","akka-cluster"),
dm("com.typesafe.akka","akka-contrib"),
dm("com.typesafe.play","play"),
dm("ch.qos.logback","logback-classic")
))
其中没有提到依赖版本。 但是,由于传递依赖仍然会导致问题,它只解决了部分问题。
所以我在想,如果我能以某种方式定义一个像上面那样的依赖关系映射,sbt 的解析机制将“通过它”并且它可能会改变所要求的依赖关系。
例如,假设我将logback 与slf4j-api 一起使用,我不希望将log4j 或commons-logging 的传递依赖添加到类路径,而是像jcl-over-slf4j 这样的桥反而。像上面这样的地图可以解决这个问题。
此外,不会加载不同的版本。并且任何可能已更改其名称的工件(例如 google-collections 现在称为 guava 或 org.jboss.netty groupID 已更改为 io.netty)都不会成为问题。
当然,只要给定的依赖项不是所要求的,就应该在屏幕上打印一个警告,并且每当添加新的依赖项时,用户应该手动将其添加到地图中,其中包含所有不存在的传递依赖项然而(或将引发匹配错误)
所以我的问题是,是否有可能实现这样的目标? 如果有,怎么做?
目前关于如何解决问题的想法:
-
修改
ivyReport任务或update任务:据我了解,sbt 创建一个 IvyReport xml 文件,根据该文件,ivy 获取请求的工件。我想以某种方式修改update 任务或生成的报告,因此传递依赖项将是我想要的,而不是最初获取的。 -
使用类似于我们已有的解决方案:仅将映射中的所有
ModuleIDs 标记为intransitive(),但(以某种方式)获取它们的依赖项,并获取它们(在映射到想要的文物)
【问题讨论】:
-
开启了相关问题:github.com/sbt/sbt/issues/1753
标签: scala dependencies sbt dependency-management