java - Gradle Build 的规范设置

标签 java python gradle

我想建立一个大型项目,我被告知 gradle 是这样做的方法。

我对 Gradle 感到很困惑,整个系统似乎有很多魔法,挥手,知识,我不想阅读 Gradle 指南的所有 60 章来 grok。

我将最终得到以下组件:

  • 定义一堆消息的 ProtoBuf 文件
  • Java 库 1 和测试(依赖于 ProtoBufs)
  • Java 库 2 和测试(依赖于 Java 库 1)
  • Java 应用程序(依赖于 Java 库 2)
  • Android 应用程序(依赖于 Java 库 2)
  • iOS 应用程序
  • 所有 Java 内容的副本,但用于 Python、C++ 和 Objective-C)

  • 我希望能够一次构建和测试所有内容。所以通常我会像这样构建一棵树:
    project/ proto/
             lib1/ java/   src/
                           test/
                   python/ src/
                           test/
                   ...
             lib2/ java/   src/
                           test/
                   python/ src/
                           test/
                   ...
             app1/ java/   src/
                           test/
                   python/ src/
                           test/
                   ...
             app2/ java/   src/
                           test/
                   python/ src/
                           test/
                   ...
             android/ src/
                      test/
             iOS/ src/
                  test/
    

    我知道从 gradle 构建 iOS 可能是不可能的,所以我很高兴暂时忽略它。

    这是一个合适的结构吗?如何构建和放置我的 gradle.build 文件,以便其他团队可以正确使用库?我如何确保我的依赖关系紧密,以便库只包含它们需要包含的最小集合?

    Gradle 构建文件似乎留下了一堆可能未使用的任务。我只是试图忽略这些吗?

    最佳答案

    我居住的结构是基于将类似项目分组为子项目结构。

    project/client/core/common-android
    project/client/core/features-android
    project/client/core/ui-android
    project/client/app/client-android
    project/server/admin
    project/server/base
    project/server/util
    project/server/api-deployment
    project/bundles/bundle1
    project/bundles/bundle2
    project/bundles/bundle3
    project/bundles/bundle4
    

    这种结构使得使用子项目比平面目录结构更直观。现在我们可以将配置应用于类似的子项目。我的最终项目结构如下所示
    ------------------------------------------------------------
    Root project
    ------------------------------------------------------------
    
    Root project 'platform'
    +--- Project ':client' - Client: Android core projects
    |    +--- Project ':client:common-android' - Client: Common library for Android aar
    |    +--- Project ':client:features-android' - Client: Features library for Android aar
    |    +--- Project ':client:ui-android' - Client: UI library for Android aar
    |    +--- Project ':client:app-android' - Client: Apk client Android apk
    +--- Project ':bundles' - bundles: OSGi bundles container project
    |    +--- Project ':bundles:bundle1' - bundles: OSGi bundle jar
    |    +--- Project ':bundles:bundle2' - bundles: OSGi bundle jar
    |    +--- Project ':bundles:bundle3' - bundles: OSGi bundle jar
    |    +--- Project ':bundles:bundle4' - bundles: OSGi bundle jar
    \--- Project ':server' - Server: Coriolis root project
         +--- Project ':server:admin' - Server: admin jar
         +--- Project ':server:base' - Server: jar base
         +--- Project ':server:apiDeployment' - Server: platform deployment war
         \--- Project ':server:util' - Server: utils jar
    

    由于我们不希望父项目尽可能少地了解他们的子项目,我们可以让每个项目分组在配置期间通过 settings.gradle 进行配置。

    设置.gradle:
    rootProject.name = 'platform'
    
    Map<String, String> projectProperties = startParameter.getProjectProperties()
    projectProperties.put('platform', true.toString())
    
    // TODO: Make project imports smarter by removing hardcoding of paths
    
    def subprojects = settingsDir.listFiles(new FileFilter() {
        @Override
        boolean accept(File file) {
            return file.isDirectory() && (file.name == 'client' || file.name == 'server')
        }
    })
    
    for (File file : subprojects) {
        println "Found subproject directory: $file.absolutePath"
        switch (file.name) {
            case 'client':
                def androidHome = 'ANDROID_HOME'
                // any non-null value will add android modules to the build.
                // Assumption is only a valid SDK location will be set.
                if (System.getenv(androidHome)) {
                    def clientFile = new File("$file.absolutePath/core/childProjectSettings.gradle")
                    if (clientFile.exists()) {
                        println "Adding android client"
                        include ':client'
                        project(":client").projectDir = clientFile.parentFile
                        apply from: clientFile.absolutePath
                    }
                } else {
                    println "WARNING: Environment variable {$androidHome} not set.  Not adding Android modules as they are " +
                            "impossible to build without the Android SDK being installed.  To install the Android SDK " +
                            "please see: http://developer.android.com/sdk/installing/index.html"
                }
                break
            case 'server':
                def serverFile = new File("$file.absolutePath/server/childProjectSettings.gradle")
                if (serverFile.exists()) {
                    println "Adding server"
                    include ':server'
                    project(':server').projectDir = serverFile.parentFile
                    apply from: serverFile.absolutePath
                }
    
                def bundlesFile = new File("$file.absolutePath/bundles/childProjectSettings.gradle")
                if (bundlesFile.exists() && !projectProperties.containsKey('noBundles')) {
                    println "Adding osgi bundles"
                    include ':bundles'
                    project(':bundles').projectDir = bundlesFile.parentFile
                    apply from: bundlesFile.absolutePath
                }
                break
            default:
                println "Unknown subproject found: $file.absolutePath"
        }
    }
    

    现在只包含磁盘上存在的子项目,我们可以删除剩余的硬编码以获得更动态的示例,但这更简单。然后我们创建一个文件(在本例中)childProjectSettings.gradle对于我们的每个项目分组(客户端、服务器、捆绑包)。您的 childProjectSettings.gradle应该以不需要每次添加新子项目时都更新的方式指定它的子项目。

    childProjectSettings.gradle:
    File moduleSettingsDir = new File("$settingsDir.absolutePath/server", "bundles")
    
    println "Bundles sees settings dir as: $moduleSettingsDir.absolutePath"
    
    def bundleDirectories = moduleSettingsDir.listFiles(new FileFilter() {
        @Override
        boolean accept(File pathname) {
            return pathname.isDirectory()
        }
    })
    
    // get a reference to this project's descriptor so we can add subprojects
    ProjectDescriptor bundles = project(':bundles')
    
    bundleDirectories.each { File bundleDir ->
        if (new File(bundleDir, "build.gradle").exists()) {
            // normalize project names (blah-blah -> blahBlah)
            def bundleName = bundleDir.name
            if (bundleName.contains("-")) {
                def names = bundleDir.name.split("-")
                bundleName = names[0] + names[1].capitalize()
            }
    
            // include a subproject in the build
            include ":bundles:$bundleName"
            // default location will be wrong lets update the project's directory
            project(":bundles:$bundleName").projectDir = bundleDir
            // add the project as a subproject giving us better grouping
            bundles.children.add(project(":bundles:$bundleName"))
        }
    }
    
    project(':bundles').children.each {
        println "Parent {$it.parent} found child {$it} in path {$it.path} using buildScript {$it.buildFile $it.path}"
    }
    

    Gradle build files seem to leave a bunch of potentially unused tasks littered around. Do I just try to ignore these?



    创建任务的不是构建文件,而是在 build.gradle 中应用的插件。文件。为了使任务尽可能紧凑,请仅在 build.gradle 中声明插件。它实际上已被使用。任务不是从依赖项目继承的,但声明的依赖是从依赖项目继承的。

    *这里有一个重要说明,所有依赖项都是transitive默认情况下,如果 ui取决于 core声明 gson然后依赖 ui默认有 gson在它的类路径中。

    对于你关于源文件夹的问题,一个更 gradle 的结构可能看起来更像下面。您的应用程序组在哪里 lib1:java|lib1:python|lib2:java|lib2:python|app1:java|app1:python|app2:java|app2:python每一篇论文都将是其包含小组的一个子项目。

    然后lib1项目包含两个子项目lib1:javalib1:python每个都用自己的插件编译 build.gradle文件。通用代码可以放在 buildSrc 中的自定义插件中如果需要的话。
    project/ proto/
             lib1/ java/   src/main/java/
                           src/main/javaTest/
                   python/ src/main/python/
                           src/main/pythonTest/
                   ...
             lib2/ java/   src/main/java/
                           src/main/javaTest/
                   python/ src/main/python/
                           src/main/pythonTest/
                   ...
             app1/ java/   src/main/java/
                           src/main/javaTest/
                   python/ src/main/python/
                           src/main/pythonTest/
                   ...
             app2/ java/   src/main/java/
                           src/main/javaTest/
                   python/ src/main/python/
                           src/main/pythonTest/
                   ...
             android/ src/
                      test/
             iOS/ src/
                  test/
    

    关于java - Gradle Build 的规范设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37147407/

    相关文章:

    java - ASP特定代码的XSLT处理问题

    Python 子进程未启动但也没有错误

    android - Flutter第一次构建错误:Could not open settings remapped class cache for 7yvt6la2007dno98lt3rzbguf

    hibernate - 从Netbeans JPA添加 hibernate 到现有的Jersey项目

    java - hibernate 异常: transaction roll back failed

    java - 如何从ajax表单中的HttpServletResponse获取数据

    python - Selenium Webdriver - PhantomJS 卡在 send_keys() 上以文件输入元素

    python - 如何通过列中的分组值过滤数据框中的值

    Android Studio - Gradle 始终构建所有模块,而不仅仅是我运行的模块

    java - Xerces UTF8Reader 中导致 MalformedByteSequenceException 的编码问题