I have the following project config (pure java):
/
/Base_module
/A_module
A_module depends on Base_module.
I want a .jar containing the A_module classes + the Base_module classes, but can't make it.
With the following config, I can only achieve different jars for each module:
settings.gradle
include 'Base_module', 'A_module'
build.gradle
....
project(':Base_module') {
}
project(':A_module') {
dependencies {
compile project(':Base_module')
}
}
....
What do I need to add to achieve the full .jar?
Thanks in advance.
You can try to make a custom task of Jar type in your root build script, which will include all the classes of all subprojects or just a number of subprojects. It could be something similar to:
//declare an array, containing subproject names, which classes you want to collect
def projectsToCollect = [':Base_Module',':A_Module']
//create a custom task, which assembles an jar-archive and depends on subproject compilation tasks,
//that causes sibprojects sources been compiled before thist task runs
task singleJar( type: Jar , dependsOn: projectsToCollect.collect{ it+":compileJava"}) {
//set new jar name
baseName = 'singleJar'
//set files, which will be included in this new jar
from files(projectsToCollect.collect{ project(it).sourceSets.main.output })
}
You can play it around, modifying sourcesets, if you have some custom in your subprojects, or if you want to add tests.
That would be fatJar aka uberJar aka shadowJar
take a look at https://github.com/johnrengelman/shadow
You would need to configure for you ':A_module' project
Related
I'm asking you about a very basic question but I hope you can find the time to help me:
I'm trying to realise a java-project, that can spit out several different programs which partially have dependencies on other projects of mine.
In order to keep it simple, I want to have all the code in one project, run by Gradle, so if I make changes to a central library (the database connector for example) all the child-programs automatically recieve the changes.
An example could look like this:
project:
program_A
central_library
program_B
output:
program_A.jar (including central library)
program_B.jar (including central library)
Now I'm having serious troubles finding a correct buildscript for this and was wondering if someone here could help me out.
P.S. : Since I'm new to this, if I should realize this through different modules within the Gradleproject instead of different packages in the Gradleprojects sourcefile, feel free to tell me :)
One way to approach this is to have a root project, that holds the three other projects inside of it.
Specify the sub-projects inside its settings.gradle file:
rootProject.name = 'RootProject'
include 'program_A'
include 'central_library'
include 'program_B'
With this in place, program_a can depend on central_library by adding a dependency in its build.gradle:
dependencies {
compile project(':central_library')
}
I have a similar setup in one of my projects, although the "central library" is the root project and the submodules are test environments.
Create a root directory and put each library or program into its own sub-directory.
Create a gradle project in each subproject.
You can for example create a skeleton gradle project by running
gradle init --type=java-library
or
gradle init --type=java-application
Then in the root directory create a gradle multi-module project. Basically
run only
gradle init
and then create a settings.gradle and list all sub-projects there.
This is actually described very well in the gradle documentation:
https://guides.gradle.org/creating-multi-project-builds/
If I understand correctly, what you want to do is, when you change your local projects, you want other projects to see those details. For this you need to publish your projects to some kind of repo, like maven repo. You can do this from command line gradle publishToMavenLocal, or gradle build pTMl. You can also do this in build.gradle file with something like the following:
task sourceJar (type : Jar) {
classifier = constants.extSources
from sourceSets.main.allSource
}
publications {
mavenJava(MavenPublication) {
from components.java
artifact(sourceJar) {
classifier "sources" //classifier = constants.extSources
}
}
}
I would like to have the default configuration from task "jar" from the java plugin for gradle, but I would also like to add several different configurations for different "jar" tasks. The way I am doing it now is just commenting out the jar tasks that I am not using.
Example:
//jar {
// archiveName = 'a.jar'
// include 'path/to/package/1/*'
//}
jar {
archiveName = 'b.jar'
include include 'path/to/package/2/*'
}
Is there a better way?
I am aware that I can create new tasks of type "Jar", but then I don't get that default configuration for free; I would have to provide it myself. Which is troublesome, since I don't know what that configuration is.
I am looking for something like:
task myJar(type: Jar, dependsOn: classes) {
extends "jar"
...include additional configuration here
}
I have the same issue for other types of default tasks, not just "jar".
I found the way, simple, yet I found it very hard to find information about it.
Using the keyword "with" I can include another task's configs with the current task:
task(testJar, type: Jar) {
archiveName = 'test.jar'
with jar
}
Yields the same result as
jar {
archiveName = 'test.jar'
}
This is a basic gradle question but I could not find an answer:
If I have multiple independent projects that share the same root directory, how should I use different build.gradle file for them?
for example the directory structure is like this:
src/main/java/package1/base1/project1package/
src/main/java/package1/base1/project2package/
It looks like the build.gradle file should be placed at root, but how to differ two projects which are totally independent and not related to each other? When I use gradle build command, how can I specify one project to be built? Thanks.
To be honest I don't like the structure you are proposing. The standard one looks like this:
<root>/build.gradle
<root>/<subproject1>/build.gradle
<root>/<subproject1>/src/main/java/<basepackage>/<subproject1>/
<root>/<subproject2>/build.gradle
<root>/<subproject2>/src/main/java/<basepackage>/<subproject2>/
The subproject1 and subproject2 are independent of each other. Moreover:
<root>/build.gradle can contain a build configuration, tasks and so on common to all sub-projects. subproject1-specific stuff is then in <root>/<subproject1>/build.gradle
If you execute gradle build in <root>/, all sub-projects will be built. If you do this in <root>/<subproject1>/, only the subproject1 will be built.
For more, see http://www.gradle.org/docs/current/userguide/multi_project_builds.html
Let me know if I am off base, but essentially what I think you want to do is simply produce two separate JARs from two sets of source that happen to live in the same root directory. This is a pretty funny way to structure your project, as #Tomas mentioned, but assuming you cannot change your project structure, you could simply create custom source sets to solve this problem.
Your build could look something like this.
apply plugin: 'java-base'
sourceSets {
projA {
java {
srcDir 'src/main/java'
include 'pkg1/**'
}
}
projB {
java {
srcDir 'src/main/java'
include 'pkg2/**'
}
}
}
task projAJar(type: Jar) {
baseName 'projA'
from sourceSets.projA.output
}
task projBJar(type: Jar) {
baseName 'projB'
from sourceSets.projB.output
}
Although this is technically one Gradle project, these two source sets each have their own compile tasks, jar tasks, and configurations. You would configure your dependencies like so.
dependencies {
projACompile 'foo.org:lib:1.0'
projBCompile 'bar.org:lib:2.0'
}
I am trying to create two 'fatJars' using ShadowJar plugin as part of the same build file. I am trying to run the shadowJar task twice inside the build by declaring two tasks of ShadowJar type
So far, I have defined two tasks like so:
task shadowjar_one (type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar)
task shadowjar_two (type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar)
and now trying to create my jars like so:
shadowjar_one {
mergeServiceFiles()
exclude 'somefile.txt'
archiveName = 'jar1.jar'
appendManifest {
attributes 'Main-Class': 'some.package.someClass'
}
}
shadowjar_two {
mergeServiceFiles()
exclude 'someOtherfile.txt'
archiveName = 'jar2.jar'
appendManifest {
attributes 'Main-Class': 'some.package.someOtherClass'
}
}
The problem I am facing is that the jars are created, but they do not contain any of the other dependencies (packages, files etc) from 'other' jars. The jars only contain the META-INF and current project's package directories.
Any idea what could be the issue?
Note:
I am expecting two slightly different jar files to be produced. Both must have the same project codebase with differences in the Main-Class attribute of manifest (and a couple of other small differences)
Many Thanks!
The author gave a very good solution (in that it is both short and working) here:
https://github.com/johnrengelman/shadow/issues/108
I'm actually using a tweak to that solution, appearing at the bottom of that page (I've added remarks to explain it a little):
task bootstrapNodeJar(type: ShadowJar) {
group = "shadow" // Not a must have, but it's always good to have a group, you can chose whichever - this is the one shadowJar belongs to
description = "Builds a Bitsquare bootstrap node executable jar" // Same as the above
manifest.attributes 'Main-Class': 'io.bitsquare.app.cli.BootstrapNodeMain' // The main attraction! Be sure to update this line
classifier = 'bootstrapNode' // General jar task property - see more about it in the Gradle manual
from(project.convention.getPlugin(JavaPluginConvention).sourceSets.main.output) // Leave as is
configurations = [project.configurations.runtime] // Same as the above
exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA') // This one is actually really important!
// Here you can add other Jar properties like destinationDir, for example
}
Shadow plugin author here - I was just made aware of this question here. What you are encountering is the fact that the Shadow plugin creates and configures a shadowJar task using a set of defined conventions for that task.
When you are creating your own tasks using that type, you'll need to manually define a number of those configuration options since there is no way for the plugin to know what your intent is with those tasks.
You can reference the configuration that is being applied to the built in task here: https://github.com/johnrengelman/shadow/blob/master/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy#L38-L63
A workaround that I've used is to have a single shadowJar task, but pass parameters.
In your case, something like:
shadowJar {
mergeServiceFiles()
exclude System.properties.getProperty('exclude')
archiveName = System.properties.getProperty('archiveName')
appendManifest {
attributes 'Main-Class': System.properties.getProperty('mainClass')
}
}
Then, when starting your application:
gradlew shadowJar -Dexclude=... -DarchiveName=... -DmainClass=...
I have a complex Gradle script that wraps up a load of functionality around building and deploying a number of NetBeans projects to a number of environments.
The script works very well, but in essence it is all configured through half a dozen maps holding project and environment information.
I want to abstract the tasks away into another file, so that I can simply define my maps in a simple build file, and import the tasks from the other file. In this way, I can use the same core tasks for a number of projects and configure those projects with a simple set of maps.
Can anyone tell me how I can import one Gradle file into another, in a similar manner to Ant's task? I've trawled Gradle's docs to no avail so far.
Additional Info
After Tom's response below, I thought I'd try and clarify exactly what I mean.
Basically I have a Gradle script which runs a number of subprojects. However, the subprojects are all NetBeans projects, and come with their own ant build scripts, so I have tasks in Gradle to call each of these.
My problem is that I have some configuration at the top of the file, such as:
projects = [
[name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
[name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]
I then generate tasks such as:
projects.each({
task "checkout_$it.shortname" << {
// Code to for example check module out from cvs using config from 'it'.
}
})
I have many of these sort of task generation snippets, and all of them are generic - they entirely depend on the config in the projects list.
So what I want is a way to put this in a separate script and import it in the following sort of way:
projects = [
[name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
[name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]
import("tasks.gradle") // This will import and run the script so that all tasks are generated for the projects given above.
So, in this example, tasks.gradle will have all the generic task generation code in, and will get run for the projects defined in the main build.gradle file. In this way, tasks.gradle is a file that can be used by all large projects that consist of a number of sub-projects with NetBeans ant build files.
There is a new feature in 0.9. You can use apply from: 'other.gradle' command.
Read my question about same thing at: Is there a way to split/factor out common parts of Gradle build
The answer to the question turned out to be in the Plugins system, where you can add the desired functionality in a set of plugins which can be groovy files located in the directory buildSrc/src/main/groovy. Plugins can also be bundled as a Jar though I haven't tried this.
Details here: Custom Plugins
Well, it is hard to tell what serves you best without actually seeing your build file.
I could assume that stetting up your environment as multi-project build should provide you the abstraction you are looking for.
In your project root build.gradle you define all your domain specific stuff as well as the things that apply to all your subprojects:
repositories {
add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
name = 'destRepo'
addIvyPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/ivys/ivy(-[revision]).xml')
addArtifactPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/[type]s/[artifact](-[revision]).[ext]')
descriptor = 'optional'
checkmodified = true
}
...
}
...
subprojects {
sourceCompatibility = 1.5
targetCompatibility = 1.5
group = 'my.group'
version = '1.0'
uploadArchives {
uploadDescriptor = true
repositories {
add rootProject.repositories.destRepo
}
}
apply{ type my.group.gradle.api.plugins.MyPlugin }
...
}
dependsOnChildren()
The project root directory might also contain a gradle.properties file where you define properties used by your projects:
buildDirName=staging
repo.dest.dir=/var/repo
...
Then in an additional file from your project root named settings.gradle you actually point to your subprojects:
include 'my-first-component',
'my-second-component'
...
project(':my-first-component').projectDir = new File(rootDir, 'path/to/first/component')
project(':my-second-component').projectDir = new File(rootDir, 'path/to/second/component')
...
Each sub-project directory contains a build.gradle file containing the sub-project specific stuff only.
No matter if you invoke gradle from your project root or sub-project directory, gradle will automatically consider all your definitions done in the various files.
Also note that no compile task will be executed for your project root as long as you don't load any plugin beyond the default plugin at the root level.
This is an example for Kotlin DSL (build.gradle.kts).
apply(from = "scripts/my-script.gradle.kts")
scripts/my-script.gradle.kts:
println(
"""
I am defined at the top level of the script and
executed at the configuration phase of build process
"""
)
tasks.create("MyTask") {
println(
"""
I am defined in a task and
run at the configration phase of build process"""
)
doLast {
// ...
}
}
See this answer and this answer for how to import a function from another script in Kotlin DSL.
Based off this similar question/answer, the easiest solution I've found after searching for days is using buildscript.sourceFile. It correctly gives the file being run rather than the pwd/cwd/parent-file of said process. I feel like this would solve your issue.