Gradle resolves "." in dependecies as "/"? - maven

I have following part of the build.gradle:
def external = file('../external').absolutePath
repositories {
maven {
url file(external).toURI()
}
}
dependencies {
api 'ch.qos.cal10n:cal10n-api:0.7.7'
}
Third-party library that my project uses is stored in the ../external/ch.qos.cal10n/cal10n-api/0.0.7/(.jar and .pom).
However when running gradle build I got following:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Could not find ch.1qos.cal10n:cal10n-api:0.7.7.
Searched in the following locations:
- file:/home/a/b/external/ch/1qos/cal10n/cal10n-api/0.7.7/cal10n-api-0.7.7.pom
Why /home/a/b/external/ch/1qos/cal10n/cal10n-api/0.7.7/cal10n-api-0.7.7.pom
and not /home/a/b/external/ch.1qos.cal10n/cal10n-api/0.7.7/cal10n-api-0.7.7.pom ?
UPD: .pom and .jar files are downloaded manually from Maven Repository and placed into /home/a/b/external/ch.1qos.cal10n/cal10n-api/0.7.7/`

Because that is the layout of local-maven repositories, i.e., the group will be turned to directories. This is in part for performance and usability reasons. Consider the alternative, you'd have one huge directory containing all the groupIds. Working with directories with lots of entries slows down processing a lot. Instead, this layout is hierarchical, reducing the number of files/sub-directories per directory.
So to solve your problem, just change your directory layout accordingly.
/home/a/b/external/ch.1qos.cal10n/cal10n-api/0.7.7/cal10n-api-0.7.7.pom
->
/home/a/b/external/ch/1qos/cal10n/cal10n-api/0.7.7/cal10n-api-0.7.7.pom

Related

How to manually download file from Maven repository in Gradle

We have a huge monolith application which is build by multiple tools (shell scripts, Ant and Maven). The build process is quite complex:
a lot of manually steps
hidden dependencies between Ant targets
different steps must be executed depending on the used Operating System
We decided to simplify it by creating Gradle scripts which wraps all this logic (it is quite impossible to fix it, so we create a wrapper which standardize the way of executing all the logic). We have to download some files from the Maven repository, but we cannot use the dependencies syntax:
we don't need to always download all files
the versions of the downloaded artifacts are dynamic (depends on configuration located in completely different place)
we need a path to the downloaded files (e.g. we have to unpack an artifact distributed as zip)
How we can achieve it?
The easiest way to achieve it is to create a dynamic configuration with dependencies, and next resolve it. The resolve method returns paths to the dependencies on the local disk. It is important to use a unique name for every configuration. If not, executing the logic twice would fail (cannot overwrite the configuration with XYZ name).
Here is an example method which returns a path to an artifact. If the artifact is already available in the Gradle cache it won't be downloaded for the second time, but of course the path will be returned. In this example all artifacts are downloaded from Maven Central.
Method:
ext.resolveArtifact = { CharSequence identifier ->
def configurationName = "resolveArtifact-${UUID.randomUUID()}"
return rootProject.with {
configurations.create(configurationName)
dependencies.add(configurationName, identifier)
return configurations.getByName(configurationName, {
repositories {
mavenCentral()
}
}).resolve()[0]
}
}
Usage:
def jaCoCoZip = resolveArtifact('org.jacoco:jacoco:0.8.6')
def jaCoCoAgent = resolveArtifact('org.jacoco:org.jacoco.agent:0.8.6')

Could not get unknown property 'a.b.c' for root project

I got some source code and was asked to build it. It was a Gradle project. So I changed to the project directory and ran:
$ gradle clean assemble
and the following error came up:
...
* What went wrong:
A problem occurred evaluating root project 'pcase'.
> Could not get unknown property 'postgresql.jdbc' for root project 'pcase' of type org.gradle.api.Project.
...
There is a settings.gradle file in the project folder too. It contains:
rootProject.name = 'pcase'
I took a look at build.gradle and found lots of occurrences like
${project['x']}
For example:
buildscript {
dependencies {
...
// FlywayDB, JOOQ.
classpath "org.postgresql:postgresql:${project['postgresql.jdbc']}"
classpath "org.flywaydb:flyway-gradle-plugin:${project['flywaydb.plugin.version']}"
classpath "nu.studer:gradle-jooq-plugin:${project['jooq.plugin.version']}"
...
What could be ${project['x']}? Looks like associative array in bash and the build script tries to get the value of the key 'x'.
But I didn't find the place in code where this array would be declared and initialized.
The question is: Is the project buildable or is it better to consult the company that worked at it before me?
From the information provided, the project is perfectly buildable, to some certain extend. First of all, project['a.b.c'] is Groovy syntax to access properties from the project object. They're referred to as project properties.
They can be set via
Project properties via command line: gradle -Ppostgresql.jdbc=x.y.z
System properties via command line: gradle -Dorg.gradle.project.postgresql.jdbc=x.y.z
System properties via gradle.properties: org.gradle.project.postgresql.jdbc=x.y.z
All 3 properties (postgresql.jdbc, flywaydb.plugin.version, jooq.plugin.version) denote the version numbers of the particular build script dependencies. However, which versions to use best is beyond my knowledge. I would certainly consult the respective project websites, Maven artifact search or simply ask the company.
org.postgresql:postgresql is the database JDBC driver and certainly depends on the database version.
org.flywaydb:flyway-gradle-plugin is for database migrations. Try with the latest version.
I wasn't able to find gradle-jooq-plugin on Maven central. It's most likely available on the Gradle Plugin Portal.

Manage generated resources for project in Gradle

I have a Gradle project which has a lot of resources in the /src/main/resources folder. For performance reasons, some resources have to be generated from other resources at build time. So I split everything up into sub-projects:
/MainProj/src/main/java - The application
/MainProj/src/main/resources
/InternalProj/src/main/java - Code for generating additional resources for MainProj
/InternalProj/src/main/resources
When I run InternalProj using a special Gradle task, it generates some files to /InternalProj/output which I then copy to /MainProj/src/main/resources. Needless to say, this is really ugly and I'd like to know how to do this in a better way. Should I put it somewhere into build or directly into /MainProj/src/main/resources? Maybe use a symlink?
Edit
I now use a relative symlink from /src/main/generated-resources to /build/something and so far it works fine. But now I have a different problem: I have task A that generates some resources and task B that depends on those resources and thus on A. If I run gradle B or gradle A B, B will still fail since the resources generated by A didn't get updated into its build folder. How can I force Gradle to update the resources?
You can add the output file to the main source set of the InternalProj:
Example Groovy Code:
sourceSets {
main {
resources {
srcDirs "src/main/resources", "output"
}
}
}
Related answer: https://stackoverflow.com/a/38982006/3708426

Defining cross project versions for gradle build

I have a several projects in a flat structure with dependencies between them.
Currently in each one a have a definition similar to this defining the versions used within the build script:
ext {
versions = [
scala: '2.11.1',
scalatra: '2.3.0',
jetty: '9.1.5.v20140505',
scalaTest: '2.3.0',
junit: '4.8.1',
]
}
and later usage:
compile group:'org.scala-lang' , name:'scala-library',version: versions.scala
As I have this defined in each build.gradle what I would rather want is to define the versions in one place and read in all files in the current build.
Writing to a global value will not be sufficient here as the combination of build files involved in a build may change (e.g. when testing a specific component only none of the components depending on it will be defined)
Put this map into its own .gradle file and include into your projects with apply from: '../dependencies.gradle'. Similar to what Gradle has in its own codebase

GradleException Could not create ZIP

Caused by: org.gradle.api.GradleException: Could not create ZIP '/jenkins/repository/workspace/profile/build/libs/../profile.jar'.
Project
common << I build under this directory
profile
build.gradle(in common)
...
dependencies {
compile project(':../profile')
...
settings.gradle(in common)
include '../profile'
It works on windows environment. But it does not work on linux environment even using root account
The project paths accepted by the include and project methods are logical paths, not physical paths. They cannot contain a ... Physical paths must be declared separately in settings.gradle (if they divert from the logical path). The easiest way to declare a flat physical directory layout is to use the includeFlat method:
common/settings.gradle
includeFlat 'profile'
common/build.gradle
dependencies {
compile project(':profile')
}
You can find more information on this topic in the "multi-project builds" chapter of the Gradle User Guide.
Another common issue that can happen here especially if you're using windows is you could have opened the previous jar up in 7zip or some other tool and that's causing the file to be locked. To test this try to delete the jar that's sitting in build/libs if you can't delete the file it's locked by another program more than likely. :D
An even shorter way to fix this: Add the following line to the build.gradle file of the included profile project:
archivesBaseName = 'profile'
This overwrites the default name of the jar.

Resources