Gradle fails to download dependencies if not present in mavenLocal()

Hi, Let me start by admitting that I’m an absolute newbie to Gradle; in fact, I started using it only as part of learning “Cascading” which uses Gradle for build. When I’m trying to build, I’m getting the following exception. It appears that the dependency is not present in the local Maven repo and Gradle, for some reason, fails instead of downloading it. Option --refresh-dependencies does not help. I found two workarounds 1) Put mavenCentral() before mavenLocal() in the build file, or 2) Delete the failing group from Maven local. However, none of these are desirable because using Maven Central all the time just makes the build slower and user shouldn’t have to delete dependencies from Maven local to satisfy Gradle.

My development environment is: Mac OS X 10.8.4, Apple Java 1.6.0_51, Gradle 1.3/1.6 (both have the same issue).

FAILURE: Build failed with an exception.
  * What went wrong:
Could not resolve all dependencies for configuration ':providedCompile'.
> Artifact 'commons-httpclient:commons-httpclient:3.1@jar' not found.

Here’s a Gist to the build file. https://gist.github.com/abhijitsarkar/6145223

Any help is appreciated. If I missed to provide any information above, just let me know.

Using Maven local is usually pointless in Gradle, so you should just remove mavenLocal(). That is, Gradle has its own cache in ‘~/.gradle/caches’ and will not redownload artifacts if they were already retrieved. Maven local can be useful if you happen to install some artifacts locally (some of your builds are Maven builds).

I believe your problem is caused by the fact that hadoop-core is found within .m2, so Gradle assumes that all of its dependencies can be found in .m2, which is not the case for some reason.

So I think you should just remove “mavenLocal()”.

I don’t think hadoop-core is the issue here. As I mentioned, when I deleted the failing group (httpclient), Gradle built fine. There’s some talk on the Internet about a Maven repo having the pom but not jar for a dependency which causes Gradle to fail. I didn’t check if that’s the case before until I deleted the group. Also, I know very little about Gradle but I still don’t agree that mavenLocal() is useless. My understanding is that it saves precious build time by not going out to Maven central all the time. This issue seems like a bug to me. The fix should be simple-if you don’t find a jar, don’t fail until you’ve tried all the repos.

Using mavenLocal() is saving you precisely nothing. Gradle had its own transparent cache that is always used. Furthermore, if something isn’t in the cache but it could be downloaded from a listed repository, Gradle will transparently check if the same bit-for-bit file is in mavenLocal and copy from their instead of downloading over the network. So, putting mavenLocal() in your build script IS NOT making your build any faster.

I don’t know exactly on what condition does Gradle assume that it should not attempt to look in other repositories but the case is something like that Gradle believed that this artifact should be in .m2. I don’t say that your expectation is unreasonable though (i.e. “don’t fail until tried every options”).

Regardless, your assumption that adding ‘mavenLocal()’ will make anything faster is wrong. If you don’t install artifacts directly to Maven local then it is pointless. Gradle won’t put artifacts downloaded from Maven cental to .m2.

EDIT: Actually, adding ‘mavenLocal()’ may even cause a minor performance overhead.

Understood, mavenLocal() doesn’t make it any faster. However, that doesn’t make this behavior acceptable. Can I raise a JIRA about it?

Our process is that users report issues in this forum (like you just have), and Gradle developers promote them to JIRA.

Before promoting this issue, it would be good to know if you are running into the known issue that resolution fails if the local Maven repository contains the requested module’s POM but not its artifact. The reason this causes resolution to fail in Gradle but not in Maven is that Gradle treats the local Maven repository in the same way as any other Maven repository, whereas Maven treats it differently. (When Maven finds a requested module’s POM but not its artifact in a repository other than Maven local, it will fail immediately as well, without continuing search in other Maven repositories.)

It took me a while to reproduce the issue but finally I got a build (different one than in OP) to fail on log4j. I then verified that the local Maven repo has the pom but not the jar.

Execution failed for task ':jar'.
> Could not resolve all dependencies for configuration ':compile'.
   > Artifact 'log4j:log4j:1.2.16@jar' not found.
Abhijits-MacBook-Pro:1.2.16 Abhijit$ ls -l
total 56
-rw-r--r--
1 Abhijit
staff
  169 Jul 21 22:56 _maven.repositories
-rw-r--r--
1 Abhijit
staff
20340 Jul 21 22:56 log4j-1.2.16.pom
-rw-r--r--
1 Abhijit
staff
   40 Jul 21 22:56 log4j-1.2.16.pom.sha1

OK, thanks. It’s a known issue then.

Does “known issue” mean it is already logged as a defect or did the community decide not to do anything about it by blaming the local Repo? My suggestion, for what it’s worth, is not to fail until all the repos have been tried. Gradle does not need to treat the local repo differently like Maven does; in fact, now that I know it, it doesn’t sound like a good design decision on Maven’s part.

It’s already logged (e.g. http://issues.gradle.org/browse/GRADLE-2709).

Thank you for explaining this Peter, I always see this issue with ‘com.oracle:ojdbc14:10.2.0.2.0’ and never understood it until now. As long as I put mavenLocal in front of mavenCentral it finds the local version before the pom-only version in central.

For dealing with known POM-only versions (e.g. due to Maven Central licensing restrictions), there is ‘artifactUrls’, e.g. ‘repositories { mavenCentral(artifactUrls: [“http://other.repo”]) }’.

I hit this issue all the time. I agree that “-if you don’t find a jar, don’t fail until you’ve tried all the repos.”

In my case some of my builds ARE Maven builds but I don’t not want to deploy every local build to our Artifactory server. Later on during the build of some Gradle projects the assets are therefore expected to be found in mavenLocal(), so I need it in repos that are searched.

However, some of the Maven builds will populate the Maven cache partially - i.e. they won’t get the asset with the javadoc classifier. Then when the Gradle build does need the asset with the javadoc classifier it fails to see it in the Maven cache and gives up.

A similar problem happens when some versions of the asset are found in the mavenLocal() but others are not. It seems Gradle stops looking if it sees the groupId+assetId and assumes that all versions can be found in the same repo.

Lets put this another way: You aren’t really saving anything by not continuing to search all repos when you don’t find an asset. There is only a slight (premature) optimization in the failure case where you might have failed faster if you ultimately never find what you are looking for. However this is not worth the cost of failing builds that would otherwise work! Why optimize the obviously uncommon failure case at the cost of causing failures?

I’m currently fighting this now…

Could not resolve all dependencies for configuration ‘:javadocZip’.

Could not download artifact ‘com.google.guava:guava:13.0.1:javadoc@jar’

Artifact ‘com.google.guava:guava:13.0.1:javadoc@jar’ not found.

I go off and delete ~.m2\repository\com\google\guava\guava Try again: > Could not resolve all dependencies for configuration ‘:javadocZip’.

Could not download artifact ‘commons-lang:commons-lang:2.6:javadoc@jar’

Artifact ‘commons-lang:commons-lang:2.6:javadoc@jar’ not found.

Note that I just finished going through all this once already… but then I came to the point where the missing asset was because I needed to do a Maven build of one my projects. That project also used these assets (directly or via a Maven plug-in) and it re-populated the .m2 cache… so I need to start all over cleaning it out manually.

In the previous pass Gradle already claimed: >gradle Download http://dcm-maven-repo/repo/commons-lang/commons-lang/2.6/commons-lang-2.6.pom Download http://dcm-maven-repo/repo/commons-lang/commons-lang/2.6/commons-lang-2.6-javadoc.jar

(dcm-maven-repo is our artifactory server) But apparently it didn’t put these assets in the gradle cache yet?

Had to compile another Maven project so I’m now on the third try… argh!

…again!.. fourth pass…

Finally made it through… though there were no “Download” messages for any of the artifacts that it had trouble with the first time. According to the timestamps Gradle had already put them it its cache several builds ago (the first time I worked through this but hit a snag with a local maven build that I hadn’t done)… it just complained about missing assets even though they were already in the gradle artifact cache!

There is no doubt that the Maven local problems need fixing; we simply haven’t gotten around to do it yet. It’s among the next few stories on my list.

I know this is a bit old.

After running into this and considering the impact using mavenLocal() has on my build, I have to say that I think the caching behavior described by Luke is the kind of behavior I prefer. I like the idea of using .m2 as a cache, but don’t like the idea of having dependencies resolved from mavenLocal().

Today I ran into a problem where my project would build on one machine, but not on another. The cause was using mavenLocal() which differed between machines. I had recently added mavenLocal() to my build to do some really quick local testing using artifacts that were created by patching & building a third party library I use. I wanted to give things a quick try before going through the hassle of deploying a patched version of the library to my local Nexus repository.

IMO care should be taken when using mavenLocal(). Personally, I think I will use something like this:

if(project.hasProperty("useMavenLocal")) {
    mavenLocal()
}

…and make sure that mavenLocal() is the last repository used for dependency resolution (I assume the declared order is used for this). That way, in the rare cases where I intentionally want to allow Gradle to use artifacts that are only installed locally, it’s something that has to be done explicitly.

After almost a year, this issue still exists and is very much a problem for many users.

As far as I know, the partial artifact issues with ‘mavenLocal()’ were fixed in a recent Gradle version. Note that specifying ‘mavenLocal()’ gives no performance gain whatsoever. On the contrary, it can slow down dependency resolution considerably, and it will make your build less repeatable. The only good reason to use ‘mavenLocal()’ is for consuming artifacts produced by a local Maven build.

I’m not so sure. I can try it out and report back. Besides, the issue is not limited to maven local. Any maven repo that has only the pom fails the build.