GitBucket
4.21.2
Toggle navigation
Snippets
Sign in
Files
Branches
1
Releases
Issues
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
mark.george
/
Wiki
Compare Revisions
View Page
Back to Page History
Gradle.md
### Contents - [Pass System.in to Application](#pass-systemin-to-application) - [Dump JVM Details](#dump-jvm-details) - [Working With Multiple Source Sets](#working-with-multiple-source-sets) - [Dependency Version Number Wildcards](#dependency-version-number-wildcards) - [Copy Dependencies](#copy-dependencies) - [Building Generated Code](#building-generated-code) - [Source/Target Versions](#sourcetarget-versions) - [Fat JAR](#fat-jar) - [Adding Dependencies to Manifest Classpath](#adding-dependencies-to-manifest-classpath) - [Managing Source Set Directories](#managing-source-set-directories) - [Preventing Tests from Running](#preventing-tests-from-running) - [Parallel Execution of JUnit Tests](#parallel-execution-of-junit-tests) - [Opening project directories](#opening-project-directories) - [Generating .gitignore](#generating-.gitignore) ### Pass System.in to Application ```groovy run { standardInput = System.in } ``` ### Dump JVM Details In case you are not convinced that Gradle is using the JVM you intend it to use: ```groovy tasks.register("jvm") { doLast { println "Java Version: " + org.gradle.internal.jvm.Jvm.current() println "Java Home: " + org.gradle.internal.jvm.Jvm.current().getJavaHome() } } ``` Run using: ```sh gradle jvm ``` ### Working With Multiple Source Sets All source sets are broken into two sub-trees — one called `java` which can only contain Java code, and one called `resources` for everything else. There are a couple of default source sets — `main` for the main code and `test` for the unit test code. To add a new source set: ```groovy sourceSets { // create a new source set shinyStuff { java { srcDir 'path to source dir' } } } ``` New source sets will automatically get the default `java` and `resources` sub-trees unless they are explicitly excluded: ``` sourceSets { web { resources { srcDirs = ['public'] } java{ srcDirs = [] } } } ``` This will prevent the `java` tree from being used for this source set, and also prevent the default `resource` tree from being used in addition to the new `public` one. Source sets do not see each other by default (one can't use code from another). To make this happen: ```groovy sourceSets { shinyStuff // this is all we need if source dir is in the root of the project and named shinyStuff main { // make compiled shinyStuff visible to main compileClasspath += shinyStuff.output runtimeClasspath += shinyStuff.output // make shinyStuff dependencies also visible to main source set compileClasspath += shinyStuff.compileClasspath } } ``` Dependencies are tied to source sets and prefixed with the source set name: ```groovy dependencies { // dependencies for shinyStuff shinyStuffImplementation '...' shinyStuffImplementation '...' // dependencies for main source set implementation '...' implementation '...' } ``` Alternately you can nest the dependencies with the source sets, and you don't need to prefix anymore: ```groovy sourceSets { shinyStuff { dependencies { implementation '...' } } } ``` **Note** : Only resources in the `main` source set are processed by Gradle — resources in other source sets will not be included in the build output or the generated JAR file by default. Add the following to make this happen: ```groovy processResources { // resources outside of the default 'main' sourceSet are not processed by default from(project.sourceSets.web.resources) { include "**/*.*" } } ``` If you just need an additional resources directory, then you can add a directory to the existing main source set as follows: ```groovy sourceSets { main { resources { srcDirs += ['static'] } } } ``` ### Dependency Version Number Wildcards Sometimes it is handy to just get the latest versions of everything (saves us from having to look up the version numbers manually). You can use the '+' operator as a version wild-card: ```groovy dependencies { def dorisVer='+' // use latest version of doris def borisVer='1+' // use latest 1.x version of boris implementation group: 'com.some.where', name: 'doris', version: dorisVer implementation group: 'com.who.cares', name: 'boris', version: borisVer } ``` ### Copy Dependencies Sometimes it is handy to have actual copies of the JAR files somewhere. The following task will copy the JARs for declared dependencies into the `libs` folder: ``` task copyLibs(type: Copy) { project.configurations.implementation.setCanBeResolved(true) from configurations.implementation into 'libs' } ``` ### Building Generated Code If you are using a task that generates code, then you will probably want the standard build to run the generate task before the `compileJava` task. The can be useful for resolving chicken and egg build problems in addition to removing additional steps that need to be performed to build the project: ``` compileJava.dependsOn tasks.<taskNameGoesHere> ``` This goes at the root level. The `tasks` prefix is there to resolve problems where you are using plugins that have extensions and tasks that have the same name (such as the OpenAPI Generator Gradle plugin). ### Source/Target Versions If you are building with a later version of Java, but want to build binaries that run on older versions: ``` compileJava { sourceCompatibility = '1.8' targetCompatibility = '1.8' } ``` ### Fat JAR Create a JAR that includes the dependencies. This does't always work since some dependencies may be sealed, or otherwise protected. The contents of the individual JAR files will be extracted and added to the final JAR along side the classes for your project. This results in a single self-contained JAR file. ``` task fatJAR(type: Jar) { project.configurations.implementation.setCanBeResolved(true) manifest.from jar.manifest baseName = 'fat' from { configurations.implementation.collect { duplicatesStrategy = 'exclude' it.isDirectory() ? it : zipTree(it) } } destinationDir = file('dist') with jar } ``` ### Adding Dependencies to Manifest Classpath As an alternative to creating a fat JAR, the dependencies can be added to the manifest's classpath. This produces a JAR that is runnable without the need for a script that sets the classpath. ``` jar { project.configurations.implementation.setCanBeResolved(true) manifest { attributes ( 'Main-Class': mainClassName, 'Class-Path': configurations.implementation.collect { 'lib/' + it.name }.join(' ') ) } } ``` This code with assumes the dependencies are in a subdirectory named `libs` relative to the primary JAR. ### Managing Source Set Directories Being able to create and remove a project's source set directories on the fly is very handy, and it is annoying that Gradle doesn't have built-in tasks for this already. Creating missing source folders: ``` task createMissingSourceDirs { group = "Directories" description = "Create all of the missing source set directories for this project." doFirst { sourceSets.each { def sourceRoot -> sourceRoot.allSource.srcDirTrees.each { def sourceDir -> if(!sourceDir.dir.exists()) { println "Creating ${sourceDir}" mkdir sourceDir.dir } } } } } ``` Removing empty source folders: ``` task deleteEmptySourceDirs { group = "Directories" description = "Delete all empty source set directories." doFirst { sourceSets.each { def sourceRoot -> sourceRoot.allSource.srcDirTrees.each { def sourceDir -> if(sourceDir.dir.exists() && sourceDir.dir.isDirectory() && sourceDir.dir.list().length == 0) { println "Removing empty ${sourceDir}" sourceDir.dir.delete() } } } } } ``` ### Preventing Tests from Running You can sometimes end up with chicken and egg situations if the tests are run as part of the standard build (which is the default). In this case you can stop this by adding the following to the root of the `build.gradle`: ``` test.onlyIf { project.gradle.startParameter.taskNames.contains("test") } ``` This will stop the tests from being executed unless you explicitly run the `test` task. ### Parallel Execution of JUnit Tests Note that this will likely cause non-deterministic test results unless you have actually created your module under test to handle concurrency. This is good for demonstrating non-determinism due to poorly implemented concurrency though. ``` test { useJUnitPlatform() systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") } ``` ### Opening project directories If you are using an IDE or editor that lacks an "open project in file manager" feature then you can add this via a Gradle task: ```groovy task openProjectFolder { group = "Directories" description = "Open the project root in the system file manager." doFirst { println('Opening: ' + file(projectDir)) java.awt.Desktop.getDesktop().open(file(projectDir)); } } ``` ### Generating .gitignore ```groovy def gitIgnored=""" .gradle .classpath .project build bin dist *.zip *.tgz *.class .DS_Store """ task createGitIgnore { group = "Git" description = "Create the project's .gitignore file." doLast { def file = new File(projectDir, ".gitignore") if ( !file.exists() ) { println('Creating .gitignore') file.text = gitIgnored } else { println('.gitignore already exists') } } } ```
### Contents - [Pass System.in to Application](#pass-systemin-to-application) - [Dump JVM Details](#dump-jvm-details) - [Working With Multiple Source Sets](#working-with-multiple-source-sets) - [Dependency Version Number Wildcards](#dependency-version-number-wildcards) - [Copy Dependencies](#copy-dependencies) - [Building Generated Code](#building-generated-code) - [Source/Target Versions](#sourcetarget-versions) - [Fat JAR](#fat-jar) - [Adding Dependencies to Manifest Classpath](#adding-dependencies-to-manifest-classpath) - [Managing Source Set Directories](#managing-source-set-directories) - [Preventing Tests from Running](#preventing-tests-from-running) - [Parallel Execution of JUnit Tests](#parallel-execution-of-junit-tests) - [Opening project directories](#opening-project-directories) - [Generating .gitignore](#generating-gitignore) ### Pass System.in to Application ```groovy run { standardInput = System.in } ``` ### Dump JVM Details In case you are not convinced that Gradle is using the JVM you intend it to use: ```groovy tasks.register("jvm") { doLast { println "Java Version: " + org.gradle.internal.jvm.Jvm.current() println "Java Home: " + org.gradle.internal.jvm.Jvm.current().getJavaHome() } } ``` Run using: ```sh gradle jvm ``` ### Working With Multiple Source Sets All source sets are broken into two sub-trees — one called `java` which can only contain Java code, and one called `resources` for everything else. There are a couple of default source sets — `main` for the main code and `test` for the unit test code. To add a new source set: ```groovy sourceSets { // create a new source set shinyStuff { java { srcDir 'path to source dir' } } } ``` New source sets will automatically get the default `java` and `resources` sub-trees unless they are explicitly excluded: ``` sourceSets { web { resources { srcDirs = ['public'] } java{ srcDirs = [] } } } ``` This will prevent the `java` tree from being used for this source set, and also prevent the default `resource` tree from being used in addition to the new `public` one. Source sets do not see each other by default (one can't use code from another). To make this happen: ```groovy sourceSets { shinyStuff // this is all we need if source dir is in the root of the project and named shinyStuff main { // make compiled shinyStuff visible to main compileClasspath += shinyStuff.output runtimeClasspath += shinyStuff.output // make shinyStuff dependencies also visible to main source set compileClasspath += shinyStuff.compileClasspath } } ``` Dependencies are tied to source sets and prefixed with the source set name: ```groovy dependencies { // dependencies for shinyStuff shinyStuffImplementation '...' shinyStuffImplementation '...' // dependencies for main source set implementation '...' implementation '...' } ``` Alternately you can nest the dependencies with the source sets, and you don't need to prefix anymore: ```groovy sourceSets { shinyStuff { dependencies { implementation '...' } } } ``` **Note** : Only resources in the `main` source set are processed by Gradle — resources in other source sets will not be included in the build output or the generated JAR file by default. Add the following to make this happen: ```groovy processResources { // resources outside of the default 'main' sourceSet are not processed by default from(project.sourceSets.web.resources) { include "**/*.*" } } ``` If you just need an additional resources directory, then you can add a directory to the existing main source set as follows: ```groovy sourceSets { main { resources { srcDirs += ['static'] } } } ``` ### Dependency Version Number Wildcards Sometimes it is handy to just get the latest versions of everything (saves us from having to look up the version numbers manually). You can use the '+' operator as a version wild-card: ```groovy dependencies { def dorisVer='+' // use latest version of doris def borisVer='1+' // use latest 1.x version of boris implementation group: 'com.some.where', name: 'doris', version: dorisVer implementation group: 'com.who.cares', name: 'boris', version: borisVer } ``` ### Copy Dependencies Sometimes it is handy to have actual copies of the JAR files somewhere. The following task will copy the JARs for declared dependencies into the `libs` folder: ``` task copyLibs(type: Copy) { project.configurations.implementation.setCanBeResolved(true) from configurations.implementation into 'libs' } ``` ### Building Generated Code If you are using a task that generates code, then you will probably want the standard build to run the generate task before the `compileJava` task. The can be useful for resolving chicken and egg build problems in addition to removing additional steps that need to be performed to build the project: ``` compileJava.dependsOn tasks.<taskNameGoesHere> ``` This goes at the root level. The `tasks` prefix is there to resolve problems where you are using plugins that have extensions and tasks that have the same name (such as the OpenAPI Generator Gradle plugin). ### Source/Target Versions If you are building with a later version of Java, but want to build binaries that run on older versions: ``` compileJava { sourceCompatibility = '1.8' targetCompatibility = '1.8' } ``` ### Fat JAR Create a JAR that includes the dependencies. This does't always work since some dependencies may be sealed, or otherwise protected. The contents of the individual JAR files will be extracted and added to the final JAR along side the classes for your project. This results in a single self-contained JAR file. ``` task fatJAR(type: Jar) { project.configurations.implementation.setCanBeResolved(true) manifest.from jar.manifest baseName = 'fat' from { configurations.implementation.collect { duplicatesStrategy = 'exclude' it.isDirectory() ? it : zipTree(it) } } destinationDir = file('dist') with jar } ``` ### Adding Dependencies to Manifest Classpath As an alternative to creating a fat JAR, the dependencies can be added to the manifest's classpath. This produces a JAR that is runnable without the need for a script that sets the classpath. ``` jar { project.configurations.implementation.setCanBeResolved(true) manifest { attributes ( 'Main-Class': mainClassName, 'Class-Path': configurations.implementation.collect { 'lib/' + it.name }.join(' ') ) } } ``` This code with assumes the dependencies are in a subdirectory named `libs` relative to the primary JAR. ### Managing Source Set Directories Being able to create and remove a project's source set directories on the fly is very handy, and it is annoying that Gradle doesn't have built-in tasks for this already. Creating missing source folders: ``` task createMissingSourceDirs { group = "Directories" description = "Create all of the missing source set directories for this project." doFirst { sourceSets.each { def sourceRoot -> sourceRoot.allSource.srcDirTrees.each { def sourceDir -> if(!sourceDir.dir.exists()) { println "Creating ${sourceDir}" mkdir sourceDir.dir } } } } } ``` Removing empty source folders: ``` task deleteEmptySourceDirs { group = "Directories" description = "Delete all empty source set directories." doFirst { sourceSets.each { def sourceRoot -> sourceRoot.allSource.srcDirTrees.each { def sourceDir -> if(sourceDir.dir.exists() && sourceDir.dir.isDirectory() && sourceDir.dir.list().length == 0) { println "Removing empty ${sourceDir}" sourceDir.dir.delete() } } } } } ``` ### Preventing Tests from Running You can sometimes end up with chicken and egg situations if the tests are run as part of the standard build (which is the default). In this case you can stop this by adding the following to the root of the `build.gradle`: ``` test.onlyIf { project.gradle.startParameter.taskNames.contains("test") } ``` This will stop the tests from being executed unless you explicitly run the `test` task. ### Parallel Execution of JUnit Tests Note that this will likely cause non-deterministic test results unless you have actually created your module under test to handle concurrency. This is good for demonstrating non-determinism due to poorly implemented concurrency though. ``` test { useJUnitPlatform() systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") } ``` ### Opening project directories If you are using an IDE or editor that lacks an "open project in file manager" feature then you can add this via a Gradle task: ```groovy task openProjectFolder { group = "Directories" description = "Open the project root in the system file manager." doFirst { println('Opening: ' + file(projectDir)) java.awt.Desktop.getDesktop().open(file(projectDir)); } } ``` ### Generating .gitignore ```groovy def gitIgnored=""" .gradle .classpath .project build bin dist *.zip *.tgz *.class .DS_Store """ task createGitIgnore { group = "Git" description = "Create the project's .gitignore file." doLast { def file = new File(projectDir, ".gitignore") if ( !file.exists() ) { println('Creating .gitignore') file.text = gitIgnored } else { println('.gitignore already exists') } } } ```