3 minute read Published:

Using Gradle Setup Info Outside of Gradle

There is a Dev/Ops at my company that is always trying to be clever. His ultimate goal is reduce build times, so I can’t get upset. Recently, he was trying to figure out what project were building and where they were located. He generated this list by making some assumptions about how our Gradle build was determining subprojects and created a script to generate a list of those locations. The problem with that is, if the scheme for subproject generation changed he would have to manually maintain his script.

In comes a little cheat.

Most project that you work on will have more than one subproject. It is good to separate concerns even if all the parts of the project are required to work together. This eliminates pesky problems like circular dependencies, full recompilation, etc. (See, Chapter 57.5) You can use the settings.gradle file to setup a multiproject build. A typical settings.gradle file looks like so: (Actually, this one comes from the Gradle github page.)

    include 'distributions'
    .
    .
    .
    include 'modelGroovy'
    include 'cunit'
    include 'platformPlay'

    rootProject.name = 'gradle'
    rootProject.children.each {project ->

    String fileBaseName = project.name
    String projectDirName = "subprojects/$fileBaseName"
    project.projectDir = new File(settingsDir, projectDirName)

    project.buildFileName = "${fileBaseName}.gradle"
}

This is typical of a multiproject build-create a bunch of subprojects and set their properties. In fact, instead of listing each subproject individually, you can set a standard location for projects and resolve them dynamically.

new File("$settingsDir/subprojects/").eachDir {
    include it.name
}

Where include is the method to specify new subprojects.

The goal of the Dev/Ops is to get the list of projects and their locations. There are two ways of accomplishing this task: 1) Create a task in Gradle (that is essentially only a task with a doLast block). 2) Or, use a Groovy script to read the settings file. The problem with the first option is that once your company wide Gradle system starts to grow, so does the configuration time. This configuration time is inconsequential with the respect to the rest of the build. But you might become impatient if all you want is a quick list of projects and project locations. The problem with the second one is that it hacky. But sometimes that fun.

I’ll assume you know how to use Gradle to get this task done and just show the groovy script.

The secret is Groovy Bindings. The script goes in the root directory next to settings.gradle file. It uses bindings to mock out the key pieces that are usually found in the settings file (settindsDir, rootProject, include, project). After creating the mock data you call evaluate on the settings.gradle file. In the end the fake Project object will hold each project.

Binding binding = new Binding()
def workingDir = new File().getCanonicalPath()
binding.setVariable("settingsDir", workingDir)
binding.setVariable('rootProject', ['name':"])

def include = { component ->
}

def projects = []
def project = { projectName ->
    def currentProject = new Project(projectName)
    projects << currentProject
    return currentProject
}
binding.setVariable("include", include)
binding.setVariable("project", project)

GroovyShell shell = new GroovyShell(binding)
shell.evaluate(new File(workingDir, 'settings.gradle'))

class Project{
    def name
    def projectDir
    def buildFileName
    def Project(def name){
        this.name = name
    }
}

def getProjects() {
    return projects
}