I have some trouble with gradle and I don't know why this doesn't work:
Project A with 2 sub-project B and C
B and C have a configuration named masterConfiguration and superConfiguration (who extend masterConfiguration)
I add some dependencies in both.
When I do this:
configurations.superConfigurations.resolvedConfiguration.files
All is fine, and I have all files from superConfiguration and masterConfiguration.
Now, the problem.
I create a configuration (projectAConfiguration) in the project A (the rootProject).
This configuration extends superConfiguration from B and C.
I add no new dependencies in this one.
If I do this:
configurations.projectAConfiguration.resolvedConfiguration.files
I have nothing. I don't understand why?
settings.gradle =>
include 'B'
include 'C'
build.gradle =>
configurations {
projectAConfiguration
}
def rootConfiguration = configurations.projectAConfiguration
subprojects {
configurations {
masterConfiguration
superConfiguration {
extendsFrom masterConfiguration
}
}
rootConfiguration.extendsFrom configurations.superConfiguration
dependencies {
masterConfiguration 'group:artifactid:version'
superConfiguration 'anotherGroup:anotherArtifactid:version'
}
//ALL IS OK
println configurations.superConfiguration.resolvedConfiguration.files
}
//NOT OK
println configurations.projectAConfiguration.resolvedConfiguration.files
I have solve my problem with this solution :
Add task on all subproject.
task resolveMyConf {
doLast {
it.ext.confResolve = it.configurations.superConfiguration..resolvedConfiguration.files
}
}
and in the project A
task resolveAllConf {
suprojects.each {
dependsOn it.resolveMyConf
}
doLast {
//and now, we can collect all task result
}
}
I don't know if it's good, maybe there is a better solution. But it works.
You can get the configuration of a sub-project just by referencing the project in the same way as you would declare a dependency to it. You don't need to create another configuration that extends it.
For example (Groovy DSL):
// Root project A
task printConfigurationB {
doLast {
println project("B").configurations.superConfiguration.resolve()
}
}
Related
How can I get list of a subproject dependecies as list of Project object?
subproject.dependencies gives list of DependencyHandler objects. And I can't find how extract Project from DependencyHandler.
After a short have found solution myself :)
subprojects {
configurations.all {
allDependencies.each {
if (it instanceof ProjectDependency) {
println it.dependencyProject
}
}
}
}
I'm trying to do something which I feel should be relatively straightforward but nothing on the internet seems to be giving me what I'm after.
Basically, I want to take the compile/testCompile dependencies from my build.gradle (I don't want any of the sub-dependencies - just literally as they are in the file), and for each one I want to do something with the group name, name and version. Let's just say I want to print them.
So here is my build.gradle:
dependencies {
compile 'org.spring.framework.cloud:spring-cloud-example:1.0.6'
compile 'org.spring.framework.cloud:spring-cloud-other-example:1.1.6'
testCompile 'org.spring.framework.cloud:spring-cloud-example-test:3.1.2'
}
task printDependencies {
//some code in here to get results such as...
// org.spring.framework.cloud spring-cloud-other-example 1.1.6
}
Thanks all.
To iterate over all you dependencies, you can itareate over all the configurations and the over all configuration dependencies. Like so:
task printDependencies {
project.configurations.each { conf ->
conf.dependencies.each { dep ->
println "${dep.group}:${dep.name}:${dep.version}"
}
}
}
If you need exactly configuration dependencies, you can get them separately:
task printDependencies {
project.configurations.getByName('compile') { conf ->
conf.dependencies.each { dep ->
println "${dep.group}:${dep.name}:${dep.version}"
}
}
project.configurations.getByName('testCompile') { conf ->
conf.dependencies.each { dep ->
println "${dep.group}:${dep.name}:${dep.version}"
}
}
}
Or modify the first example, by adding condition to check conf.name
This Question is similar to Make one source set dependent on another
Besides the main SourceSet I also have a testenv SourceSet.
The code in the testenv SourceSet references the main code, therefor I need to add the main SourceSet to the testenvCompile configuration.
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main
}
This does not work, because you cannot directly add sourceSets as dependencies. The recommended way to do this is:
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main.output
}
But this does not work correctly with eclipse, because when I clean the gradle build folder, eclipse can't compile anymore, since it depends on the gradle build.
Also if I change main code I'd have to rebuild the project in gradle for the changes to take effect in eclipse.
How do I declare the dependencies correctly?
EDIT:
This
sourceSets {
testenv
}
dependencies {
testenvCompile files(sourceSets.testenv.java.srcDirs, sourceSets.testenv.resources.srcDirs)
}
works for the main source, but because I now reference the .java files I am missing generated classes from the Annotation-Processor :(
So after all this is the way to go:
sourceSets {
testenv
}
dependencies {
testenvCompile sourceSets.main.output
}
To make it work correctly with eclipse you have to manually exclude all sourceSet outputs from the eclipse classpath.
This is ugly, but it works for me:
Project proj = project
eclipse {
classpath {
file {
whenMerged { cp ->
project.logger.lifecycle "[eclipse] Excluding sourceSet outputs from eclipse dependencies for project '${project.path}'"
cp.entries.grep { it.kind == 'lib' }.each { entry ->
rootProject.allprojects { Project project ->
String buildDirPath = project.buildDir.path.replace('\\', '/') + '/'
String entryPath = entry.path
if (entryPath.startsWith(buildDirPath)) {
cp.entries.remove entry
if (project != proj) {
boolean projectContainsProjectDep = false
for (Configuration cfg : proj.configurations) {
boolean cfgContainsProjectDependency = cfg.allDependencies.withType(ProjectDependency).collect { it.dependencyProject }.contains(project)
if(cfgContainsProjectDependency) {
projectContainsProjectDep = true
break;
}
}
if (!projectContainsProjectDep) {
throw new GradleException("The project '${proj.path}' has a dependency to the outputs of project '${project.path}', but not to the project itself. This is not allowed because it will cause compilation in eclipse to behave differently than in gradle.")
}
}
}
}
}
}
}
}
}
I would like to add a certain project dependency to various subproject starting with a specific name.
I tried this
subprojects.findAll { project -> project.name.startsWith("myproject-sample") }.each { project ->
dependencies {
//compile project(":myproject-core")
}
}
but it gives
A problem occurred evaluating root project 'myproject'.
> Could not find method call() for arguments [:myproject-core] on project ':myproject-sample-hello-world'.
When I do this
subprojects {
dependencies {
compile project(":myproject-core")
}
}
it seems to work. But it adds the dep to all subprojects.
How should I add a project dep to a limited set of subprojects?
A clean solution is:
def sampleProjects = subprojects.findAll { it.name.startsWith("sample") }
configure(sampleProjects) {
dependencies {
compile project(":myproject-core")
}
}
Or:
subprojects {
if (project.name.startsWith("sample")) {
dependencies {
compile project(":myproject-core")
}
}
}
Both snippets assume that the sample projects have already had the java plugin applied (otherwise add apply plugin: "java" before the dependencies block).
The subprojects method delegates to an instance of the Project interface for each subproject, which is why your second example works (Project has a method called dependencies()). The each method however is simply passed a Project object as an argument. You then need to call the dependencies() method on that object. This requires a simple syntactical change.
subprojects.findAll { project ->
project.name.startsWith("myproject-sample")
}.each { project ->
project.dependencies {
compile project(":myproject-core")
}
}
I've hacked together combination of build.gradle and settings.gradle below for creating an ad-hoc multi-module project out of several single-module projects (e.g., an application and all of its dependencies, or a shared library and everything that uses that library).
settings.gradle:
// find all subprojects and include them
rootDir.eachFileRecurse {
if (it.name == "build.gradle") {
def projDir = it.parentFile
if (projDir != rootDir) {
include projDir.name
project(":${projDir.name}").projectDir = projDir
}
}
}
build.gradle::
// Make sure we've parsed subproject dependencies
evaluationDependsOnChildren()
// Map of all projects by artifact group and name
def declarationToProject = subprojects.collectEntries { p -> [toDeclaration(p), p] }
// Replace artifact dependencies with subproject dependencies, if possible
subprojects.each { p ->
def changes = [] // defer so we don't get ConcurrentModificationExceptions
p.configurations.each { c ->
c.dependencies.each { d ->
def sub = declarationToProject[[group:d.group, name:d.name]]
if (sub != null) {
changes.add({
c.dependencies.remove(d)
p.dependencies.add(c.name, sub)
})
}
}
}
for (change in changes) {
change()
}
}
This works, but it's hard to share -- if somebody else wants to do something similar they have to copy my *.gradle files or cut and paste.
What I'd like to do is take this functionality and encapsulate it in a plugin. The build.gradle part looks easy enough to do in the plugin apply() method, but it seems like the list of subprojects is already set in stone before the plugin gets a chance at it. Is there any way to get in earlier in the build process, e.g. by applying to something other than Project? Or should I resign myself to giving my plugin a task for overwriting settings.gradle?
Solution: Per Peter Niederweiser's answer, I moved the code above into two plugins, one to be called from settings.gradle and the other to be called from build.gradle. In settings.gradle:
buildscript {
repositories { /* etc... */ }
dependencies { classpath 'my-group:my-plugin-project:1.0-SNAPSHOT' }
}
apply plugin: 'find-subprojects'
And in build.gradle:
buildscript {
repositories { /* etc... */ }
dependencies { classpath 'my-group:my-plugin-project:1.0-SNAPSHOT' }
}
evaluationDependsOnChildren()
apply plugin: 'local-dependencies'
Note that calling the plugin from settings.gradle doesn't work in Gradle 1.11 or 1.12 but does work in Gradle 2.0.
You'd need to apply a plugin in settings.gradle, which I believe is supported in recent versions.