Understanding buildscript - java

How to understand following build.gradle script:
buildscript
{
repositories {
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.4.1'
}
}
According to my understanding repositories{} defines dependencies{} locations.
I see that dependencies wrapped inside of buildscript defines tomcat plugin. But what is idea to do so in such strange way?
Whole script:
apply plugin: 'com.bmuschko.tomcat'
apply plugin: 'eclipse-wtp'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.4.1'
}
}
dependencies {
def tomcatVersion = '8.0.46'
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
api 'org.apache.commons:commons-math3:3.6.1'
}
tomcat {
httpPort = 8080
enableSSL = true
contextPath = '/library-spring'
}

Nowadays almost all plugins for Gradle are published to the Gradle Plugin Portal, so Gradle knows how to resolve them and you can simply use the plugins block to define them in your build script:
plugins {
id 'com.bmuschko.tomcat' version '2.5'
}
In earlier days of Gradle, plugins could only be distributed in the same way as any other library, e.g. using a public Maven repository like Maven Central or Bintray. This way they could be resolved in the same way as other libraries, using the dependencies block to define what to resolve and using the repositories block to define where to resolve.
The problem of using the regular repositories and dependencies blocks is, that those dependencies are loaded when the build script gets evaluated. But to evaluate the build script, the plugin libraries are required to be on the classpath.
For this reason, the buildscript block was introduced to load all the dependencies before evaluating the actual build script. This is also the reason why the buildscript block should always go first in a build script:
buildscript {
repositories {
// where to resolve dependencies of your build script
}
dependencies {
// what dependencies to resolve for your build script
}
}
repositories {
// where to resolve dependencies of your project code
}
dependencies {
// what dependencies to resolve for your project code
}

Related

Gradle : How to bump transitive dependency version which is coming from plugin?

I have a huge java multimodule application which uses gradle to manage build and dependencies.
In one of the modules let's say module1 the project is using gretty plugin
module1/build.gradle
plugins{
id 'org.gretty'
}
gretty is having a transitive dependency on ch.qos.logback:logback-classic:1.1.3
I want to bump the logback version to the latest. For that I have tried below solutions
dependencies {
// 1 try
implementation 'ch.qos.logback:logback-classic:1.2.6'
// 2nd try
implementation ('ch.qos.logback:logback-classic:1.2.6') {
force = true
}
// 3rd try
constraints {
implementation('ch.qos.logback:logback-classic:1.2.6') {
because 'some xyz reason'
}
}
}
But none of this is having any impact on logback version. Need some suggestion now
What you have done so far is for application dependencies, not build dependencies. To change or add additional dependencies to the build itself, use the buildscript block. So for you case, to bring in a more recent version of Logback:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
mavenCentral()
}
dependencies {
classpath 'ch.qos.logback:logback-classic:1.2.6'
}
}
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
You can then invoke the buildEnvironment task to view the dependencies of the build.

Gradle custom plugin jar with dependencies

I'm trying to build a jar for a custom gradle plugin to be used by other gradle projects. I'm using java to write the plugin. I'm having a problem including dependencies in my jar. If I build the jar using the below build.gradle
plugins {
id 'groovy'
}
repositories{
mavenCentral()
}
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.google.guava:guava:27.0-jre'
testCompile 'junit:junit:4.12'
//compile 'org.apache.commons:commons-lang3:3.8.1'
}
group = 'com.mine'
version = '1.0'
I get a NoClassDefFound exception for guava classes when applying the plugin on a project. If I include a task to create a jar with dependencies like below in the build.gradle
jar {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it)}
}
}
It says Plugin with Id 'my-plugin' not found. How do I include dependencies in a gradle plugin jar?
Your plugin project should be configured as a standalone Plugin project and then published to a maven repository, which will make dependencies resolution work; there is good documentation about writing custom plugin here, specially the following part : using Gradle plugin development plugin
There is also a good example of writing/publishing/consuming a custom Plugin in the Gradle examples here : https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/plugins (see the two subprojects publishing and consuming )
And here is a working example with a plugin that has dependency on external library (commons-lang for example):
Plugin project
build.gradle
plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'maven-publish'
}
group 'org.gradle.sample.plugin'
version '0.1'
// pugin metadata configuration
gradlePlugin {
plugins {
myplugin {
id = "org.gradle.sample.plugin.myplugin"
implementationClass = "org.gradle.sample.plugin.MyPlugin"
}
}
}
// publish to local maven repo for testing
publishing {
repositories {
maven {
url "../repos/maven-repo"
}
}
}
// repo for dependences resolution
repositories{
jcenter()
}
// dependencies of this plugin
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
}
Plugin implementation : src/main/groovy/org/gradle/sample/plugin/MyPLugin.groovy
package org.gradle.sample.plugin
import org.apache.commons.lang3.StringUtils
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin implements Plugin<Project> {
#Override
void apply(final Project project) {
println "Applying custom plugin... "
project.tasks.create('testPlugin'){
doLast{
println " custom plugin task executing."
println "Result: " + StringUtils.capitalize("stringtotest")
}
}
}
}
Build and publish this plugin ./gradlew publish : the plugin jar and "plugin marker artefacts" will be published to local maven repo in ../repos/maven-repo
Consumer project
build.gradle
plugins {
id 'java'
// import/apply your custom plugin
id 'org.gradle.sample.plugin.myplugin' version '0.1'
}
group 'org.gradle.sample.plugin'
version '0.1'
repositories{
maven {
url "../repos/maven-repo"
}
jcenter()
}
To test the plugin, try to execute the plugin task testPlugin
> Task :testPlugin
custom plugin task executing.
Result: Stringtotest
Sorry to add this as an answer but I don't have enough points to comment (yes it is a bit late in coming but I found this in a search and it came so close, maybe this will help someone else).
The answer by #M.Ricciuti is correct, just missing one file, namely a settings.gradle in the referencing project (not the plugin) directory:
pluginManagement {
repositories {
maven {
url '../repos/maven-repo'
}
gradlePluginPortal()
ivy {
url '../repos/ivy-repo'
}
}
}
Many thanks, I have tried many things that didn't work before finding this, even the examples by gradle didn't work (or more likely I didn't run them correctly). Anyway I merged what I saw in the answers with M. Ricciuti's answer and saw that file in the sample.
My complete project is at https://github.com/reddierocket/sampleGradlePlugin
The readme has instructions to run it. (Note I did not include the wrapper but I am using gradle version 5.3.1.)

com.google.appengine:appengine:+ vs com.google.cloud.tools:appengine-gradle-plugin:+

I am new to gradle concept. I'm doing gradle for app engine (I don't know maven or ant) and I gone through in [https://cloud.google.com/appengine/docs/standard/java/tools/gradle] but I can't able to understand the difference between the:
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.google.cloud.tools:appengine-gradle-plugin:+'
}
}
and:
repositories {
jcenter()
mavenCentral()
}
dependencies {
providedCompile 'javax.servlet:servlet-api:2.5'
compile 'com.google.appengine:appengine:+'
}
I searched in the internet I can't able to understand? Can anyone explain this?
It may be confusing at the very beginning but is quite easy. With gradle you do manage the project but both gradle and the project that is managed can have their own dependencies. So, if you'd like e.g. use guava to compile your project files it will be:
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.guava:guava:22.0'
}
but if you'd like to use guava in build.gradle file then the following piece of code is necessary:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.guava:guava:22.0'
}
}
So buildscript is used to configure build.gradle itself.
In the example provided buildscript block is used to configure dependency for plugin that is applied later on in build.gradle and the second block configures the dependencies for the project itself.

Including Java library built with Gradle throws NoClassDefFoundError

I am writing a Java library and I would like to build the library with Gradle and then test it from a local test project.
I would prefer using Gradle 3.3 for my objective.
The library should be built for Java5 and higher.
So far my build.gradle looks like this:
plugins {
id 'jvm-component'
id 'java-lang'
}
repositories {
mavenCentral()
}
model {
components {
main(JvmLibrarySpec) {
sources {
java {
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
}
}
api {
exports 'io.simplepush'
}
targetPlatform 'java5'
}
}
}
The source code of the library is located in src/main/java/io/simplepush/Notification.java and depends on the dependencies stated in the build.gradle file.
Building the library with ./gradlew build works fine and generates build/jars/main/jar/main.jar.
However when I run a test project from IntelliJ (after including main.jar into the test project), I get the following runtime error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/HttpEntity.
It seems like the test project does not know about the runtime dependencies needed by my library.
I am not sure on what is the correct way to tell the test project about the dependencies of my library.
I do not want a fat jar which includes all dependencies.
Listing all dependencies in the test project itself is also not an option.
Preferably I want the library itself to tell the test project about which dependencies it needs.
The library jar which you have created does not contain any dependency information which the IDE/Gradle can then resolve to be able to compile/run the test project. I see that you are using the maven central repository so what you need to do is to publish your library to your local maven repository and in the test project just add a dependency information (no just plain jar file).
So in both library and test project build.gradle add a maven local repository config.
repositories {
mavenLocal()
mavenCentral()
}
And now you need to publish the library to local repository. As you are using the gradle 3.3 you can use the Maven Publishing.
So in the library build.gradle add a maven publishing information.
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Gradle “maven-publish” plugin makes this easy to publish to local repository automatically creating a PublishToMavenLocal task.
So you can just run
gradle publishToMavenLocal
Which will publish your library with all the dependency information into local maven repository.
And then you just need to add a library information to you test projects build.gradle
dependencies {
// other dependencies .....
module 'io.simplepush:project1-sample:1.1'
}
I solved it by changing several things.
Thanks to #Babl for pointing me in the right direction.
My new library build.gradle looks like this:
plugins {
id 'java'
id 'maven-publish'
}
sourceCompatibility = 1.5
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'commons-codec:commons-codec:1.10'
compile 'org.apache.httpcomponents:httpcore:4.4.6'
compile 'org.apache.httpcomponents:httpclient:4.5.3'
}
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Now I can push the library to the local maven repository with ./gradlew publishToMavenLocal.
The build.gradle of the test project uses the application plugin and defines a main class (which is Hello in my case). Then I can run ./gradlew installDist to generate an executable file (see Application plugin docs) which puts all dependencies in the classpath and runs just fine.
group 'com.test'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'io.simplepush:project1-sample:1.1'
}
mainClassName = "Hello"
This specify what repositories to check to fetch the dependencies from
repositories {
mavenCentral()
}
Therefore, anything that is in the dependecies{} will be fetched from those above.
If the test project is not coupled with the library project, (#RaGe example) new test project needs to know where to take the dependency from - you need to publish it, using preferred method.
After that, your new test project needs to specify the library with the preferred configuration (compile...runtime etc) in the build.gradle dependencies{}
After that depending on IDE you need to refresh the classpath and download the dependency from the specified before repository, the transitive dependencies specified in the library dependency (in this case) will get fetched from test projects repositories{}
Library build.gradle
repositories {
mavenCentral()
}
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
test project build.gradle
repositories {
mavenCentral() repository to fetch transitives
mavenLocal() or any other repo that you published the library to
}
dependencies {
pref-conf librarygroup:name:version
}
You can use idea or eclipse plugin in gradle for gradle idea or gradle eclipseClasspath tasks to refresh it with your freshly added dependencies.
With this solution, you should not need to pack the transitive dependencies within the library,
PS. I am just confused after you said you want executable jar.

Neokree Navigation drawer: Gradle DSL method not found: 'compile()'

I am trying to Set up a Navigation Drawer by Neokree https://github.com/neokree/MaterialNavigationDrawer on Android Studio with no success.
After adding this to my gradle -> build.gradle file
repositories {
mavenCentral()
}
dependencies {
compile 'it.neokree:MaterialNavigationDrawer:1.3.3'
}
And then i get this Error Saying "Gradle project Sync Failed" and this below
Error:(27, 0) Gradle DSL method not found: 'compile()'
Possible causes: The project 'MaterialNavigationDrawer' may be using a version of Gradle that does not contain the method.
Gradle settings The build file may be missing a Gradle plugin.
Apply Gradle plugin.
This is my gradle folder -> Build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'it.neokree:MaterialNavigationDrawer:1.3.3'
}
I know am doing something wrong for sure, and I can't seem to figure it out.
There is a great library called MaterialDrawer. You can integrate this library in less than 5 minutes in your project (read its README.md and Wiki - a lot of informations is available there!).
Good luck!

Categories