Gradle fails to detect flat dependency - gradle

I have a multi-project Gradle build (Gradle 4.4).
And I encountered the following issue.
Let's say I have proj1 project with the following build.gradle:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile name: 'lombok-edge'
}
proj1 has libs folder with lombok-edge.jar. Project is built successfully.
And I have proj2 that imports proj1:
dependencies {
compile project(':proj1')
}
When I try to build the whole project proj1 is build but Gradle fails to build proj2 with an error:
What went wrong:
Could not resolve all files for configuration ':proj2:compileClasspath'.
Could not find :lombok-edge:.
Required by:
project :proj2 > project :proj1
Please advise.

Well, Gradle supports transitive dependencies, but the way how to get a dependency (and therefor any repository information) is not transitive. Gradle (like Maven) does not care where a dependency comes from, as long as it matches a given signature (group, id, version).
In your example, project 1 defines a Maven dependency and can resolve it via the given flatDir repository. Project 2 has dependencies on both project 1 (which is resolved by Gradle) and the transitive Maven dependency. It's the responsibility of project 2 to resolve this dependency and it will check any defined repository, but cannot find it, because the local repository is unkown. This is the reason why the build fails.
If the two projects are related, as they should be if they are both parts of a multi-project build, you should define the local repository in a top-level build.gradle file and a subprojects closure.

Related

Multi-project gradle build with Nexus artifact repository

Consider the following multi-project gradle build, where ProjectA depends on ProjectB, and ProjectB depends on ProjectC. Dependencies are specified in the form compile project(':ProjectX'). This requires that each project be checked out in order to build, say, ProjectA.
I want to use an artifact repo such as Sonatype Nexus, to make the build simpler for developers so that if they are only working on ProjectA, then they do not need to have the dependent projects checked out, and they can be retrieved from Nexus. Similarly, if you are working on the dependent projects and they are checked out locally, I want them to be build instead of being retrieved from Nexus.
In summary, the dependency resolution strategy is: If project dependency and checked out, build locally, else retrieve from Nexus
How can I achieve this in gradle?
I got this working by flipping my dependency definitions from compile project(':ProjectX') to compile "my-group:ProjectX:version", and use the following dependency substitution resolution strategy:
configurations.all {
resolutionStrategy.dependencySubstitution.all { DependencySubstitution dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == "my-group") {
def proj = "${dependency.requested.module}"
if (new File(rootDir, '../' + proj).exists()) {
dependency.useTarget findProject(":${proj}")
}
}
}
}

How to Make Gradle Download Dependency Libraries to Project Directory

Is there a way that makes gradle download dependency libraries to the project directory, just like maven does? I know that gradle keeps its own cache in local machine directory, but how can I know what libraries will be used for my project, especially the library I defined in the build.gradle file has its own dependency?
To know what libraries will be used for your project you can use dependencies task. It will help you to find out the dependencies of your module and its recursive dependencies.
If your module name is app, then you can try gradle :app:dependencies in the project directory. You'll get something like below as output.
compile - Classpath for compiling the main sources.
\--- com.android.support:appcompat-v7:22.2.0
\--- com.android.support:support-v4:22.2.0
\--- com.android.support:support-annotations:22.2.0
Here com.android.support:appcompact-v7:22.2.0 is dependency of the module and the one below is its recursive dependency.
If you really what to get the dependencies in your project directory, then you can create a task for it like this.
task copyDependencies(type: Copy) {
from configurations.compile
into 'dependencies'
}
now you can run gradle :app:copyDependencies to get all the dependencies in location <projectDir>/app/dependencies. Note that this just give you the dependencies in your project directory and gradle is still resolving the dependencies from the local cache.

Add dependencies via transitive dependencies of another configuration in Gradle

I would like Gradle to compute the dependencies for a configuration by adding dependencies from dependencies loaded via a second configuration.
Example with two Gradle projects:
dependency/build.gradle:
configurations {
other
}
dependencies {
other "bar:artifact1:0.4"
}
top/build.gradle:
configurations {
other
modules
}
dependencies {
modules "foo:dependency:1.0"
other "bar:artifact2:0.1"
}
So the top project depends on dependency via the modules configuration, but I want the other configuration in top to contain both "bar:artifact1:0.4" and "bar:artifact2:0.1".
In my concrete case, the other dependencies are listed in an Ivy file for each artifact. I want to collect the other dependencies of all the artifacts a project depends on.
This is not a multi-project build, but other projects' artifacts are loaded from a remote repository.
Is there a way to configure Gradle to include the configurations of all transitive dependencies?

Transitive project dependencies when dependency has a zip artifact

Typically, I define project dependencies simply:
dependencies {
compile project(':someProject')
}
This works well for java projects. However, I have a project that produces a zip artifact:
artifacts {
archives file: zipDistribution.archivePath, type: 'zip', builtBy: zipDistribution
}
And when I do the dependency definition above, I don't get the zip artifact when I iterate over the dependencies in the compile configuration. A jar file is there, but no zip. This, however, gets the zip file:
dependencies {
compile project(path: ':someProject', configuration: 'archives')
}
Great! It works! Except "someProject" has its own dependencies... and we're not getting those transitively any more. Adding transitive: true to the project dependency didn't help, either.
How can I get the project's zip artifact AND the transitive dependencies associated with it? I can add both flavors of dependencies, but I feel there's got to be a way to do it in one dependency definition.
The archives configuration contains the artifacts to be uploaded, but it doesn't contain any dependencies. Try this instead:
dependencies {
runtime ...
}
artifacts {
runtime zipDistribution // assuming this is a `Zip` task
}
dependencies {
compile project(':someProject')
}
Instead of the Java plugin's runtime configuration, the former script can also add dependencies and artifacts to a custom configuration, which would then have to be reflected in the project dependency (project(path: ..., configuration: ...)).

Using gradle for a flat, multi-module project where settings.gradle is not the highest-level dependency

I have a multi-module project with a directory structure like:
proj
|-modA
|-modB
|-modMain
\-modSysTest
The dependencies are:
modB -> modA
modMain -> modB
modMain -> modA
modSysTest -> modMain
We currently use Ant as our build system. Every module has a build.xml. There is a master.xml that runs the multi-module build, which is in modMain.
I am investigating switching our project to use gradle. I can get a multi-module build working if I put a build.gradle and settings.gradle in a new sibling directory and set up the dependent modules using includeFlat.
I tried moving the gradle files into modMain, which is the home of both the main component of our system as well as the top-level build script (master.xml) that builds the whole system, but I cannot get the build working this way. My main stumbling block at the moment is trying to configure modSysTest to depend on modMain from within modMain.
Here is the settings.gradle from modMain:
includeFlat 'modA', 'modB', 'modSysTest'
Here is the build.gradle file from modMain:
allprojects {
apply plugin: 'java'
repositories {
mavenCentral()
};
dependencies {
testCompile 'junit:junit:4.11'
}
}
project(':modB') {
dependencies {
compile project(':modA')
}
}
project(':modSysTest') {
dependencies {
compile project(':modMain')
}
}
dependencies {
compile project(':modA'), project(':modB')
}
When using this configuration, I get the error:
A problem occurred evaluating root project 'modMain'.
> Project with path ':modMain' could not be found in project ':modSysTest'.
I am not sure how to specify modMain as a dependency for modSysTest.
The project path of the root project is :, not :modMain. It's not very customary (but possible) to have code in the root project. I don't see how putting build.gradle and settings.gradle into a sibling directory of modMain would give a different result (unless you also changed the contents of settings.gradle). Note that with such a setup, Gradle won't find settings.gradle unless you start the build from the modMain directory or pass the location of the settings file with -c.

Resources