Hello everyone, today I would like to tell you about my experience with Gradle, not just rewrite the manual (although it is well written), but tell me what real problems I faced and how I defeated them, and also show what opportunities Gradle gives us. The topic is very extensive, so unfortunately I will not be able to consider many aspects in detail and consistently, I hope that readers are already a little familiar with Gradle and will be able to understand the essence of the solutions described.
Lyrics
Important note about maven - many tasks that I did with the help of Gradle I never tried to do before maven, therefore I can’t unfortunately compare many things that are better and worse.
The first thing that I liked about it was finally “goodbye xml”, oh yes, for me it really is like being reborn, how incredibly pleasant it was to write an assembly in a real programming language, what kind of freedom and inspiration it is.
The article will use some concepts from OSGI and eclipse rcp, I will not focus on them so as not to be distracted from the main topic.
')
The application has a simple project with examples of scripts and some sources used in the article:
tyntsThe scale of the problem
So, what we had at the beginning: we have a large (by my standards) system running on the OSGI platform, projects in the system are eclipse plug-in projects, there is no integration with the build system, ant is used as the build system, dependency control system did not have. There was a task to make everything cool.
So I offered a gradle I was given a go-ahead and started.
Description of the project structure
The essence of the problem is that there is a directory with a certain structure in which projects are stored.
The first thing to do was to describe the directory structure and all existing projects in the build scripts. I could do this with ease. In Gradle, the concept of a
multi project is used for this. In the root directory, create a file settings.gradle and write the paths to each folder where the projects are the path separator ":". Example settings.gradle:
include "subproject-first" include "subproject-first:child-first" include "subproject-first:child-first:another-child:last-child" include "subproject-first:child-first:another-child:another-last-child" include "subproject-second"
Now we can see the structure of our system by running the command:
gradle projects -q
Result:

IDE Setup
The next step was the ability to import projects into the IDE. In Gradle, there are plugins for idea and eclipse:
tyntsbarabyantsWe have projects that are very tightly tied to eclipse because of osgi, and a piece of eclipse-rcp that did not allow just taking the target platform (this is such a terrible thing from the world of osgi, in fact, this is the osgi framework and a folder with a bunch of jar-nicknames) and use its in idea, but in general it is a lyrical digression.
Taking the eclipse plugin, I was able to set up projects exactly as I had to, and I had to make projects as eclipse plug-in, set in the plugin dependencies settings, specify the version of the compiler used. Setup Example:
project.apply plugin: 'java' project.apply plugin: 'eclipse' project.apply plugin: 'idea' project.eclipse { jdt { sourceCompatibility = '1.6' } project {
That is, as you can see there are a lot of settings for eclipse, but what cannot be done through the api eclipse plugin can be done manually by correcting the xml settings file.
Dependencies
The next step is dependency management:
documentation .
I used to think that there is nothing better than the dependency managment in maven, now I think I was wrong. Gradle can use dependencies from maven, ivy, and simple folders and files, and indeed, if you wish, you can do something very nonstandard, for example, use an ftp server as a repository. For example, how dependencies are written:
project(":myproject") { dependencies {
But this is only the beginning. In Gradle, there is the concept of configurations - this is something similar to groups in which dependencies are added. That is, in our example compile this is the configuration that the java plugin creates.
This feature helped me beautifully solve one problem with dependencies, the essence of this problem is this: we have a kernel developed abroad, and the result comes to us in the form of a zip archive, within which there are many different files, including the necessary set of libraries. This archive is poured into the artifactory by external forces, and I, in turn, get it from the artifactory, save it to the temp directory, unpack it, take all the libraries I need from the unpacked folder.
Downloading and unpacking the archive:
Note that the entire set of actions is programmed using the Gradle dsl language in terms of assembly. No need to write your own low-level code in a programming language.
Connecting dependencies to the project from the unpacked archive:
project.dependencies { libsFromSdk project.fileTree(dir: "$pathToSdk/libs", include: "*.jar") …
As a result, we get all our dependencies for compilation.
I love you code, which in itself is not new
Our scripts in the meantime grow and increase, it is time to think about the question of
copy-paste code duplication. Suppose we have a software system and we all understand that duplicating code in the system is bad, but for some reason duplicating lines of text in the build system settings is not considered to be something wrong. I think the reason for this is, the description of the assembly in xml, because xml is essentially configuration files and it is not entirely correct to use the programming rules for configuration files. But at the same time, writing the same configuration text in hundreds of files is not very nice, it is difficult for the programmer to be oriented and can cause implicit and difficult to detect errors in the assembly. In Gradle, if we write code for the assembly, it means that we will be able to get rid of duplication of the configuration code in the assembly system, in the standard way, as we do in normal code. And here Gradle again showed its power and beauty.
Tryam .
After some stage of research, I wrote my first plugin. It turns out that you can create the buildSrc folder in the system root folder, which will be java, groovy, scala etc the project of your choice, and when you start the build system, the buildSrc project will be compiled first and the classes from this project can be used in the build scripts. For me it is so brilliant.
As a result, for example, now I have names and paths to projects written in only one place in the class in buildSrc, and all other scripts use these variables in which project names are stored (of course, talking about the advantages and disadvantages of this approach is a separate conversation), while I have auto code completion, I just write anywhere in the assembly like this: MyProjects.subproject.child.absolutePath. In addition, most of the build logic is in the same plugins in buildSrc.
Below is an example of a plugin and its invocation in an assembly script:
Example plugin:
package org.gradle.example import org.gradle.api.Project import org.gradle.api.Plugin class MyPlugin implements Plugin<Project>{ private static final String PLUGIN_EXTENSION = 'my' Project project; @Override public void apply(Project project) { MyPlugin plugin = project.extensions.create(PLUGIN_EXTENSION, MyPlugin.class) plugin.project = project; } public void applyCommonSettings() { project.apply plugin: 'java' project.apply plugin: 'eclipse' project.apply plugin: 'idea' } }
Example of calling a plugin:
project.apply plugin: MyPlugin my{ applyCommonSettings() }
Do you have exactly the same thing with pearl buttons?
And going to the Gradle plugins: we have different projects in the system with different structures and settings, These are java, flex, android projects. And all this economy needs to be configured differently for export to the IDE. For example, we have a large part of the projects - these are the Osgi projects, the other part are simple projects, some projects have a legacy structure (that is, only the src folder), etc. And here Gradle made it easy to cope with this task. I wrote several classes in which I specified what settings we can have, wrote a factory class in which I described all the settings for each project, and when the project is imported into ide, we get these settings and apply them. I will not give an example of a code here, because this is just a groovy code with ordinary logic.
I was also able to write my own validators checking the correctness of the project structure.
Also planned all sorts of cool pieces. Unfortunately, there is no time to tell about writing unit tests for gradle plug-ins, logging capabilities and much more.
Conclusion
I am very pleased with Gredl, he justified himself 101% and I wish you to know the joy of working with this system.