我们有一个大型的多项目,其中包含许多使用sbt构建的模块。原来,关于包装不需要的罐子,我们有很多问题。作为解决该问题的第一步,我们创建了一个使用过的工件的“全局图”,其定义如下: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
的传递性依赖项添加到classpath中,而是将其添加到类似jcl-over-slf4j
的桥中。像上面的地图可以解决这个问题。同样,将不会加载不同的版本。并且任何可能更改其名称的工件(例如
google-collections
现在更改为guava
或org.jboss.netty
groupID更改为io.netty
)都不会成为问题。当然,只要不是所要求的依赖项,就应该在屏幕上显示警告,并且每当添加一个新的依赖项时,用户都应该将其手动添加到映射中,而所有传递性的依赖项都不存在(或会引发匹配错误)
所以我的问题是,有可能实现这样的目标吗?
如果是这样,怎么办?
关于如何解决该问题的当前想法:
修改
ivyReport
任务或update
任务:据我了解,sbt创建了一个IvyReport xml文件,根据该文件,ivy获取了请求的工件。我想以某种方式修改update任务或生成的报告,因此可传递依赖关系将是我想要的,而不是最初获取的依赖。使用与我们已经拥有的解决方案类似的解决方案:仅将地图中的所有
ModuleID
标记为intransitive()
,但(以某种方式)获取其依赖项,并也获取它们(在映射到所需的工件之后) 最佳答案
我从未使用过它,但是您可以尝试sbt-one-log并将其用作您要解决的其他事情的起点。