用于构建“调试”和“发布”JAR文件的Idiomatic Gradle脚本

问题描述 投票:7回答:4

我正在尝试创建一个Gradle构建脚本,该脚本将在“发布”或“调试”模式下构建Java .jar文件,并且在参数化脚本时遇到问题。

问题是:使用Java插件在Gradle脚本中执行此操作的惯用方法是什么? (或者,如果没有惯用的方法,什么是真正有用的hacky解决方案?)

我不介意参数化的方法,只要命令行和IDE调用可以轻松地在两个输出选项之间进行选择。 jar文件将用作其他项目中的库,例如一个Android应用程序和一个JavaFX应用程序,所以我希望参数化方法可以从他们自己的Gradle脚本中调用/依赖。

理想情况下,我想'模仿'Android gradle插件能够拥有每个任务的调试/发布版本,即

$ ./gradlew build    
$ ./gradlew assembleRelease
$ ./gradlew checkDebug

但即使是顶级buildDebug和buildRelease也不合适。


我试过的东西

本节与该问题无关。

Starting point

我有以下gradle文件/项目:

group 'TestGradleProjectGroup'
apply plugin: 'java'
sourceCompatibility = 1.8

version '1.0-release'
compileJava {
    options.debug = false
}

repositories {
    mavenCentral()
}

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

这工作正常,并生成jar文件:

$ ls TestGradleModule/build/libs/
TestGradleModule-1.0-release.jar

当使用javap检查提取的类时,它不包含任何调试信息。欢呼。不,我们需要一种方法来制作调试版本。

Add debug & release tasks

version '1.0-release'
compileJava {
    options.debug = false
}

task buildRelease(type: GradleBuild, dependsOn: build) {
    project.version = '1.0-release'
    compileJava {
        options.debug = false
    }
}

task buildDebug(type: GradleBuild, dependsOn: build) {
    project.version = '1.0-debug'
    compileJava {
        options.debug = true
    }
}

这不起作用,因为总是构建调试项目,即使buildRelease是命令行上给出的任务。我想这是因为这两个任务的代码都是在配置时运行(Gradle build lifecycle),而我只想运行一个。所以我想我想在执行时运行它们?

Add some doLast tasks

version '1.0-release'
compileJava {
    options.debug = false
}

task buildRelease(type: GradleBuild, dependsOn: build) {
    doLast {
        project.version = '1.0-release'
        compileJava {
            options.debug = false

        }
    }
}

task buildDebug(type: GradleBuild, dependsOn: build) {
    doLast {
        project.version = '1.0-debug'
        compileJava {
            options.debug = true
        }
    }
}

这更糟糕。输出文件始终是1.0版本,这是因为顶层的“默认”。如果我发表评论然后没有制作版本化的jar,而是制作默认的TestGradleModule.jar。似乎doLast块的内容对compileJava任务的影响完全没用(但是没有关于这个的警告?)。我想这些修改为时已晚,无法在执行时完成,或者还有其他需要完成的事情,以便compileJava任务以不同方式“配置”?

Using Configurations?

我注意到the Java plugin的手册包含对buildConfigNameuploadConfigName的引用,并声称它们依赖于“在配置ConfigName中产生工件的任务。”。鉴于我在配置时未能对参数进行参数化,插件执行此操作的能力看起来很有希望:

group 'TestGradleProjectGroup'
apply plugin: 'java'
sourceCompatibility = 1.8

configurations {
    debug
    release
}

version '1.0-release'
compileJava {
    options.debug = false
}

repositories {
    mavenCentral()
}

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

但:

  1. 这并没有像我预期的那样将buildReleasebuildDebug添加到./gradlew tasks --all的输出中。但我可以完成这些任务。
  2. 它似乎只是制作buildReleasebuildDebug,而不是例如assembleRelease
  3. buildRelease在运行时似乎没有任何依赖,因此没有任何有用的效果。

Iterating tasks?

作为最后的尝试,我试图创建所有适当的任务并链接所有的依赖项。我尝试迭代任务并添加依赖项:

gradle.taskGraph.whenReady { taskGraph ->

    taskGraph.allTasks.each { taskIter ->

        println("iterating" + taskIter)

        def releaseTask = project.task(taskIter.name + "Release")
        def debugTask = project.task(taskIter.name + "Debug")

        taskIter.dependsOn += [releaseTask, debugTask].toSet()
        println("new taskIter.dependsOn:" + taskIter.dependsOn)

        /*
            set debug mode here,
            copy over effects of task to debug/release
            disable effects of task
        */
    }
}

  1. 这似乎没有正确地创建任务,它们无法从命令行访问,并且运行“build”没有运行“buildRelease”等。
  2. 我还必须将所有“操作”从当前的现有任务“移动”到调试和释放任务中,以避免重复每个操作的影响。我不知道该怎么做。

简而言之,我不知道我在做什么。作为最后的手段,我可​​以手动创建所有任务,但这似乎打败了使用java插件的点,并且非常垃圾?

java gradle jar release-management
4个回答
4
投票

经过几个小时的搜索......

“构建脚本基础”Gradle教程的“按DAG配置”部分描述了一种方法,即

https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#configure-by-dag

从教程中引用

"Gradle has a configuration phase and an execution phase. After the configuration phase, Gradle knows all tasks that should be executed. Gradle offers you a hook to make use of this information. A use-case for this would be to check if the release task is among the tasks to be executed. Depending on this, you can assign different values to some variables."

以下是使用gradle.taskGraph.whenReady{}buildRelease()任务应用buildDebug()的示例...

gradle.taskGraph.whenReady { taskGraph ->
    if (taskGraph.hasTask(buildRelease)) {
        compileJava.options.debug = false
        project.version = '1.0-release'
    } else if (taskGraph.hasTask(buildDebug)) {
        compileJava.options.debug = true
        project.version = '1.0-debug'
    }
}

task buildRelease(type: GradleBuild, dependsOn: build) {
}

task buildDebug(type: GradleBuild, dependsOn: build) {
}

IMO,Gradle是一个值得学习的熊。我确实错过了很好的制作。


3
投票

您是否需要使用一次gradle创建两个罐子?如果没有,它可以像使用一些额外的参数一样容易,例如

compileJava {
    options.debug = project.hasProperty('debugBuild')
}

gradle assemble -PdebugBuild

请参阅此处获取文档:https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_properties_and_system_properties

也不是说你可以在gradle论坛上获得更好的帮助。


1
投票

不确定,但也许我的gradle-java-flavours插件可以帮助到这里。例如:

plugins {
    id "com.lazan.javaflavours" version "1.2"
}
javaFlavours {
    flavour 'debug'
    flavour 'release'
}
debugJar {
    version = "${project.version}-debug"
}
releaseJar {
    version = "${project.version}-release"
}

每种味道都有它自己的JarJavaCompile任务等,你也可以为每种味道指定自定义源,资源,测试,依赖性。

有关可用任务,目录和配置的更多概述,请参阅qazxsw poi;有关涵盖功能的测试,请参阅qazxsw poi。

这种方法与您的here风格不同,因为“风味”可以愉快地生活在一个项目中,该项目构建多个工件,而不是使用两个不同的参数运行两次项目。


1
投票

由于您对问题进行了深入分析,因此您的问题很详细。虽然我认为如果你能以更简单的方式思考,这个问题就可以解决了。 因此,如果我们认为简单,您的案例的可能解决方案是在完成发布后运行调试任务。请参阅以下示例:

here

通过上述方式,您可以控制任务执行的顺序,而不会在它们之间引入显式依赖关系。

© www.soinside.com 2019 - 2024. All rights reserved.