Gradle: is it possible to publish to Gradle's own local cache? - gradle

I know that I can use the maven plugin coupled with mavenLocal() to install an artifact and use it locally.
However investigating this a bit further, I notice that this means the artifacts are installed to Mavens's standard ~/.m2, but at the same time Gradle's own cache lives under ~/.gradle/caches in a different format.
This seems wasteful to me, a) working with two local caches, and b) having to add mavenLocal() to all projects. I was wondering if there is a way to publish an artifact to Gradle's ~/.gradle/caches ?

Note that the local Maven repository is not (really) a cache, and that the Gradle cache is not a repository. Gradle uses its cache only to cache remote artifacts, it should not copy artifacts retrieved from local Maven repositories there. In turn, you cannot publish artifacts to the Gradle cache.
So the approach to publish to and use mavenLocal() should not be as wasteful as you think. Also, you do not have to add mavenLocal() to all projects of a multi-project separately. You can simply use something like allprojects { repositories { mavenLocal() } } in your root project. Or if you want mavenLocal() in all your independent Gradle projects you could even try adding it to ~/.gradle/init.gradle.

Here is an example with code.
As it's not possible to publish into Gradle. The workaround is to publish into the maven and use it in Gradle.
Step 1 publish the code to local maven repository /users/jay/.m2/repository/
Step2 - Use the local maven repo code in another project.
Step #1 (Publish to local maven repo)
apply plugin: 'maven-publish'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Step #2 (Use the local maven repo in your gradle project)
repositories {
// ..... Other repositories
mavenLocal()
}
dependencies {
compile 'com.jai:myapp:1.0.0'
}

Related

Gradle, mavenLocal() and --refresh-dependencies

When declaring the following into my build.gradle:
repositories {
mavenLocal()
}
I can re-deploy similar Maven Artifacts (similar = with the exact same version) to Maven local, Gradle will pick up the latest which has been installed, without the need of using --refresh-dependencies
If, instead of declaring a mavenLocal() repository, I'm declaring a Maven Remote Repository, then I'll have to include --refresh-dependencies in order to be 100% sure I'm getting the latest of a published version. No problem here, this is expected ...
However, I don't understand why the same is not true for a mavenLocal() repository. I couldn't find any explanation in the documentation: Declaring a changing version.
Does anyone have any hints?
Caching is disabled for local repositories.
The paragraph The case for mavenLocal() from the Declaring repositories enumerates the various downsides of using mavenLocal() and explains the behavior you observe:
To mitigate the fact that metadata and/or artifacts can be changed, Gradle does not perform any caching for local repositories

Gradle does not use the Maven Local Repository for a new dependency

I have Maven with M2_HOME defined to /Users/manuelj/apache/maven/3.2.5
I have the settings.xml file, located on /Users/manuelj/apache/maven/3.2.5/conf/settings.xml
where I have the following declared:
<localRepository>/Users/manuelj/apache/maven/repository</localRepository>
Until here with Maven all works fine. Any new dependency goes there.
I have a project based with Gradle, among many things in my build.gradle, exists the following:
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'eclipse'
apply plugin: 'application'
version = '1.0.0'
sourceCompatibility = '1.8'
repositories {
mavenLocal()
mavenCentral()
}
… more
Until here, all works fine too. Code compile, executes well.
My confusion is the following.
According with my understanding is that Gradle's mavenLocal() should use the same path than <localRepository> defined on Maven's settings.xml file.
Now confirming that in the Maven local repository exists some dependencies already downloaded.
When I execute for example gradle build, I did realize that
If a dependency already exists from the Maven Local Repository, it is used from there.
If a dependency does not exist from the Maven Local Repository Gradle download the new dependency to: /Users/manuelj/.gradle/caches/modules-2/files-2.1
I want that the new dependency go directly to the same Maven Local Repository.
Therefore, what extra configuration is need it?
Resolving Dependencies From Local Maven Repository
Gradle is able to resolve artifacts stored in the local Maven repository (usually ~/.m2/repository) via mavenLocal().
According to the documentation, mavenLocal() is resolved like this:
Gradle uses the same logic as Maven to identify the location of your local Maven cache. If a local repository location is defined in a settings.xml, this location will be used. The settings.xml in USER_HOME/.m2 takes precedence over the settings.xml in M2_HOME/conf. If no settings.xmlis available, Gradle uses the default location USER_HOME/.m2/repository.
To resolve artifacts from a non-standard local Maven repository, you can use the following configuration in your build.gradle:
repositories {
maven {
url '/Users/manuelj/apache/maven/repository'
}
}
(From: How does Gradle resolve the directory of the local maven repository?)
Custom Maven repositories are documented here.
Storing Artifacts in the Local Maven Repository
Gradle stores resolved dependencies in its own Dependency Cache. The dependency cache is so much more than just a simple Maven artifact repository:
Stores binaries (jars), artifact meta-data (POM, Ivy files), dependency resolution results and module descriptors.
Tuned for performance, for example shorter file paths.
De-duplicates artifacts: Same binaries are stored only once.
Tracks where a dependency came from. A dependency resolved from jcenter() might be different to the one resolved from mavenCentral().
Automatic, time and usage bases, cache cleanup.
Artifacts produced by the build can be easily pushed to the local Maven repository via publishToMavenLocal task contributed by the Maven Publish Plugin.
But what about resolved dependencies? For the aforementioned reasons, Gradle cannot store dependencies in the local Maven repository. There's currently no built-in functionality to even publish dependencies to the Maven's local repository from the build script. So what are your options:
Create a shell script that does the necessary legwork. Daniel Dietrich once wrote one and published it on Twitter (Gist).
Use an artifact proxy like Nexus or Artifactory. Maven and Gradle can be configured to consume dependencies from the same proxy. This setup is quite common in professional environments and my personal preference.
Use
mavenLocal()
for example:
buildscript {
ext {
springBootVersion = '2.0.0.M1'
}
repositories {
mavenCentral()
mavenLocal()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
mavenLocal()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.oracle:ojdbc6:11.2.0.4')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
I am using Gradle 3.5
This drove me to drink.
If I do mvn install for a project having a version of 1.1.1.SNAPSHOT it goes into my local maven repository (~/m2/repository/...) with no errors. However, Gradle using mavenLocal() will not attempt to locate it in the local maven repository (having used ./gradlew bootRun --debug and inspecting the logs).
If I change the version to 1.1.1-SNAPSHOT (note the dash), then Gradle will attempt, and will find the repository.
It doesn't make sense to me that Maven finds this to be a valid version number for local use, but Gradle completely ignores it.
I came across this issue because I'm working on a legacy project where I need to run my build with the sudo gradle build command. The build involves copying XSD files, which require root permissions. I opted not to employ the solutions of the previous answers because I didn't want to change the build file; I didn't want to accidentally checkin my build.gradle changes. What I found was that Gradle was checking for mavenLocal in the /var/root/.m2 folder. My solution was to copy /Users/me/.m2/settings.xml to /var/root/.m2 and add a line for the localRepository to point back to my /Users/me/.m2 folder. A sample line and where to add it is:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>/Users/me/.m2/repository</localRepository>
<profiles>

How to add an additional repository at the top of the list for a particular subproject in Gradle

I have a multi project setup in Gradle, the root of which specifies a bunch of repositories that are shared by all subprojects:
subprojects {
repositories {
maven { url '...' }
mavenLocal()
mavenCentral()
}
}
How can I specify an additional repository for a particular subproject, and have it as the first in the list of repositories?
Why do I need to do this? I need to include an Android library in .aar format. It is present in .aar format in this additional repository, and in .apklib format in Maven Central. If Gradle hits Maven Central first and finds the .apklib it will bail out.
By postponing the addition of the repositories in the root build script, the repositories are added after the ones added in the subproject:
subprojects {
afterEvaluate {
repositories {
maven { url '...' }
mavenLocal()
mavenCentral()
}
}
}
i would recommend to use something for external&internal repository management.
i think that artifactory or nexus can handle remote/virtual repositories, and makes it possible to use only one repository in your project.
note: if repository order is relevant to you, that might mean that the artifact identifier (group:ident:version) can mean different artifacts - i think that violates some maven/etc guideline which can cause invalid caches behind gradle and cause mysterious problems

Gradle prefer repository on duplicate entries

I have a build tool thats tied the version to the SCM. I can't set the version of a jar when I build it locally. If someone were to change what I'm working on locally it would push the version number (which I can get), but when I publish to my local repo (Ivy) Gradle seems to prefer the external repo.
build.gradle
repositories {
mavenCentral()
ivy {
url "${System.properties['user.home']}/.ivy2/local/"
layout "pattern", {
artifact "[organization]/[module]/[revision]/[artifact](-[classifier]).[ext]"
ivy "[organization]/[module]/[revision]/ivy.xml"
}
}
ivy {
url "https://repo/"
layout "pattern", {
artifact myPattern
ivy myIvyPattern
}
}
}
Without changing the build for the jar that I'm editing. How can I have gradle always prefer the local repo? I have a feeling that resolutionStrategy might be the best way, but I don't know how accomplish this.
Edit 1
To help clarify, Artifactory has a jar (published by jenkins) with version 1.2.3. I have a jar that I build locally that saves into my local repository as 1.2.3. When I build a project having both repositories in my repository closure (with my local one on top) Gradle seems to pull in the one from Artifactory.
Edit 2
Dependency definition
dependencies {
compile ('company:project:1.2.+')
}
I don't really understand what you are saying, but Gradle searches repositories in their declared order, and picks the first matching module that it finds (as least as long as fixed versions are used).

How to publish in order to resolve latest.integration with gradle?

What I have is a maven repository (nexus) to which maven has been publishing. In each artifact version folder in my artifact repository folder there are the standard maven artifacts: a maven-metadata.xml, a jar, and a pom.xml, etc.
Now I want to resolve these using gradle. In my gradle.build file if I list them as:
dependencies {
compile group: 'com.company', name: 'artifact', version: '1.0-SNAPSHOT'
}
Then they will resolve correctly. However, I want to use the version "latest.integration" so that I can automatically integrate the latest versions of my dependencies. When I do this though, gradle fails to resolve it.
I imagine that gradle is looking for some ivy specific files that maven is not publishing up to the repository in order to resolve latest.integration, but I am not sure. Should I go back and re-publish all of my upstream dependencies with gradle before trying to resolve down stream? It would seem that since gradle supports maven repositories under the repositories element that it should already know how to interpret "latest.integration" for that repository type.
This is my repositories section:
repositories {
mavenCentral()
maven { url "http://<server>/nexus/content/repositories/snapshots" }
}
Thank you for any help you can provide
latest.integration is an Ivy concept, and only works for Ivy repositories. In other words, both publication and consumption would have to happen in an Ivy-compatible manner. (Gradle is capable of this; not sure about Nexus.)
The obvious alternative is to use Maven snapshot dependencies. What do you hope to gain from using latest.integration?

Resources