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

时间:2017-11-20 11:02:08

标签: java gradle jar release-management

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

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

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

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

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

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

我试过的东西

此部分与问题无关。

起点

我有以下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检查提取的类时,不包含任何调试信息。欢呼。不,我们需要一种方法来制作调试版本。

添加调试&发布任务

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),而我只想运行一个。所以我想我想在执行时运行它们?

添加一些doLast任务

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任务以不同方式“配置”?

使用配置?

我注意到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在运行时似乎没有任何依赖,因此没有任何有用的效果。
  4. 迭代任务?

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

    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. 我还必须将所有“操作”从当前的现有任务“移动”到调试和释放任务中,以避免重复每个操作的影响。我不知道该怎么做。
    3. 简而言之,我不知道自己在做什么。作为最后的手段,我可​​以手动创建所有任务,但这似乎打败了使用java插件的点,并且非常垃圾?

4 个答案:

答案 0 :(得分:4)

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

“构建脚本基础知识”Gradle教程的“按DAG配置”部分介绍了执行此操作的方法,即

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

从教程中引用

“Gradle具有配置阶段和执行阶段。在配置阶段之后,Gradle知道应该执行的所有任务.Gradle为您提供了一个钩子来利用这些信息。一个用例就是检查是否发布任务是要执行的任务之一。根据这一点,你可以为一些变量分配不同的值。“

以下是使用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是一个值得学习的熊。我确实错过了很好的制作。

答案 1 :(得分:3)

您是否需要使用一次gradle创建两个罐子?如果没有,它可以像使用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论坛上得到更好的帮助。

答案 2 :(得分:1)

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

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
        }
    }
}

// Here you are telling the buildDebug task to be executed right after the 
// buildRelease task is finalized.
buildDebug.mustRunAfter buildRelease

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

答案 3 :(得分: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任务等,您也可以为每种风格指定自定义资源,资源,测试和依赖关系。

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

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