与 Gradle 个子项目相关的依赖项,这些子项目也可以独立构建

Dependencies relative to Gradle subprojects which are also buildable independently

背景

我继承了一个非常复杂的基于 Gradle 的 Java 项目,其中包含许多子项目。其中许多都有闭源 *.jar 库,这些库不应泄露给其他(子)项目,以避免在多个项目使用不同版本的 "same" 库时发生命名空间冲突。

我正在尝试更新项目以使用其中一些库的一些新版本,并且通常清理依赖项,因为开发变得极其复杂。 更糟糕的是,一个项目被嵌套为 Git submodule,它应该能够独立构建 作为主项目 Gradle 的子项目我正在处理的项目。

Git 子模块

这是一个类似于 Git submodule/Gradle project/Gradle 子项目的简化结构:

robotcontroller
+--.git
+--gradle
+--libs
+--planning
|  +--src
|  +--build.gradle
+--plugins
|  +--nao
|  |  +--libs
|  |  |  +--robocommons.jar
|  |  +--src
|  |  +--build.gradle
|  +--pepper
|  |  +--libs
|  |  |  +--graphadapter.jar
|  |  +--src
|  |  +--build.gradle
+--build.gradle
+--gradlew
+--gradlew.bat
+--settings.gradle

plugins/nao/build.gradle:

dependencies {
    compile project(':planning')
    // This is inside the subproject's "libs/" dir
    compile name: 'robocommons'
    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
}

[rootProject, this].each {
    it.repositories {
        flatDir {
            dirs "${rootDir}/plugins/nao/libs/"
        }
    }
}

plugins/pepper/build.gradle:

dependencies {
    compile project(':planning')
    // This is inside the subproject's "libs/" dir
    compile name: 'graphadapter'
    compile group: 'com.google.guava', name: 'guava', version: '19.0'
}

[rootProject, this].each {
    it.repositories {
        maven {
            // Some proprietary, closed-source repo
        }
        flatDir {
            dirs "${rootDir}/plugins/pepper/libs/"
        }
    }
}   

plugins/build.gradle:

dependencies {
    compile project(':plugins:nao')
    compile project(':plugins:pepper')
}

build.gradle:

// Stuff like plugins here
...

allprojects {
  repositories {
    flatDir {
      dirs "${rootDir}/libs"
    }
    jcenter()

    maven {
        // Some other proprietary repo here
    }
  }

  dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
  }
}

dependencies {
    compile subprojects
}

// Stuff like javadoc and sourceJar tasks
...

settings.gradle:

include 'planning'
include 'plugins'
include 'plugins:nao'
include 'plugins:pepper'

"root" Git 存储库

Gradle项目及其上面的所有子项目不仅需要能够自行构建,而且该项目本身是另一个Gradle项目的子项目,它位于不同的 Git 存储库中:

complicatedrobotproject
+--.git
+--gradle
+--robotcontroller@SOMEREVISION // This is managed by the ".gitmodules" file
+--robocommons // A different, partially-compatible version of the source code used to make "robocommons.jar" is here
|  +--src
|  +--build.gradle
+--.gitmodules
+--build.gradle
+--gradlew
+--gradlew.bat
+--settings.gradle

build.gradle:

allprojects {
    repositories {
        flatDir {
            dirs "${rootDir}/robotcontroller/libs"
        }
    }
}

dependencies {
    // some external dependencies
    ...
    compile project(":robotcontroller")
    compile project(":robocommons")

    // TEST
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

settings.gradle:

include 'robocommons'
include 'robotcontroller:planning'
include 'robotcontroller:plugins'
include 'robotcontroller:plugins:nao'
include 'robotcontroller:plugins:pepper'

问题

在上面的示例中,我的直接目标是将在 complicatedrobotproject/robocommons 处找到的源代码替换为 robocommons.jar。然而,构建项目的唯一方法是使用 Git 子模块 robotcontroller 的修改版本,它实际上依赖于:

robotcontroller/plugins/nao/build.gradle 来自修订 SOMEREVISION:

dependencies {
    compile name ':robocommons' // When building "complicatedrobotproject", this in fact links "robocommons" the directory, not "robocommons.jar"!
    compile project(':robotcontroller:planning')
    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
}

通过添加:robotcontroller到依赖项,可以构建项目complicatedrobotproject,但是robotcontroller不能构建为独立的Gradle项目。采用该限定符则可以以牺牲前者为代价来构建后者。 robocommons.jar 中的 类 和目录 robocommons 中的 类 大部分但不完全相同。最终,我想用适当的外部依赖替换 both 例如compile group: 'com.complicatedrobots', name: 'robocommons', version: '2.0.3',但这需要大量的重新实现,我首先需要解决这个依赖问题。

我的任务不是让项目有意义;尽管这让我头疼,但我只需要两个 Git 存储库都是可构建的,并且还需要在所有 Gradle 项目中使用单个版本的 robocommons,无论哪个 Git 正在构建存储库。我什至无法直接考虑这个问题,因为我想到的每一种可能性都阻碍了其他需要解决的问题。

我不能说我理解那个版本中发生的事情,我也能感受到你的痛苦。我要说的第一件事是 composite builds 可能会提供通往 "normal"、可维护构建的途径,允许您将 robotcontroller 作为一个单独的项目。如果你走这条路,你将不得不从父文件的 settings.gradle 文件中删除 `include ":robotcontroller" 并将其替换为等效的复合构建配置。

也就是说,我认为您可以相当轻松地完成这项工作,因为大部分内容似乎都已到位。我会这样做:

  1. 将当前在 plugins/*/libs 中的所有 JAR 移动到 robotcontroller/libs,添加他们文件名的版本

  2. 更新这些 JAR 的所有依赖项,以便它们包含适当的版本

  3. 删除/robocommons目录

你看,robotcontroller/libs 似乎已经在 robotcontroller 和父级中设置为平面目录存储库项目。在我看来,有问题的库位于项目特定目录中的唯一原因是它们的名称中没有版本号来区分它们。通过添加版本号,您可以将它们并排放在同一目录中。

这有意义吗?希望它能有所帮助!