我们有一个大型的多项目,其中包含许多使用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的解析机制将“通过它”,并且它可能会改变所要求的依赖关系。
例如,假设我将logbackslf4j-api一起使用,我不希望将log4jcommons-logging的传递性依赖项添加到classpath中,而是将其添加到类似jcl-over-slf4j的桥中。像上面的地图可以解决这个问题。
同样,将不会加载不同的版本。并且任何可能更改其名称的工件(例如google-collections现在更改为guavaorg.jboss.netty groupID更改为io.netty)都不会成为问题。
当然,只要不是所要求的依赖项,就应该在屏幕上显示警告,并且每当添加一个新的依赖项时,用户都应该将其手动添加到映射中,而所有传递性的依赖项都不存在(或会引发匹配错误)
所以我的问题是,有可能实现这样的目标吗?
如果是这样,怎么办?
关于如何解决该问题的当前想法:

修改ivyReport任务或update任务:据我了解,sbt创建了一个IvyReport xml文件,根据该文件,ivy获取了请求的工件。我想以某种方式修改update任务或生成的报告,因此可传递依赖关系将是我想要的,而不是最初获取的依赖。
使用与我们已经拥有的解决方案类似的解决方案:仅将地图中的所有ModuleID标记为intransitive(),但(以某种方式)获取其依赖项,并也获取它们(在映射到所需的工件之后)

最佳答案

我从未使用过它,但是您可以尝试sbt-one-log并将其用作您要解决的其他事情的起点。

10-08 00:18