Better multi-project include options


(Thibault Kruse) #1

Hi,

I believe the current include command in the settings.gradle should be extended. It has several annoying limitations, as the example of the gradle project’s settings. gradle shows.

First, the fact that gradle by default uses ‘build.gradle’ as name in subprojects quickly makes it a pain to work with gradle with many editors.

Second, including ‘subprojects:foo’ also makes ‘:subprojects’ a project, even if it has no other function than containing further projects, leading to unnecessary and confusing output. Also it is a pain to reference other tasks in this situation with ‘:subprojects:projectx:taskx’, where most of the times ‘projectx:taskx’ would be sufficiently unambiguous. Similarly refactoring the project structure becomes a pain, because all these references need to be fixed.

So I suggest that the include command get’s alternatives where it is possible to point to a named file, such that this files containing directory becomes a subproject having the name of that directory.

If any subproject of that name exists, this should raise an error.

E.g.:

includeProject(String path, String file, String name)

My recipe, in settings.gradle:

def addProject(projectPath) {
    // need to use rootDir for IntelliJ
    File projectFile = new File("$rootDir/$projectPath")
    assert projectFile.exists()
    String buildFileName
    File projectDir
    if (projectFile.isDirectory()) {
        buildFileName = 'build.gradle'
        projectDir = projectFile
    } else {
        buildFileName = projectFile.name
        projectDir = new File(projectFile.parent)
        if (buildFileName != 'build.gradle') {
            assert buildFileName == projectDir.name + '.gradle'
        }
    }
    String projectName = ':' + projectDir.name
    assert null == findProject(projectName), "Cannot add project $projectFile, project of that name exists at ${findProject(projectName).projectDir}"
    include projectName
    ProjectDescriptor subproject = project(projectName)
    if (projectDir.parent != null) {
        subproject.projectDir = projectDir
    }
    subproject.buildFileName = buildFileName
    assert subproject.projectDir.isDirectory()
    assert subproject.buildFile.isFile()
}

This does not yet solve what to do to get some semantic clustering of projects without introducing parent projects that merely act as project containers.


(Radim Kubacki) #2

Those limitations can be solved using current features. In fact exactly the things that you have mentioned are addressed by a short snippets of code at the end of https://github.com/gradle/gradle/blob/master/settings.gradle

Subprojects of Gradle codebase have .gradle files like

core.gradle

or

plugins.gradle

and even if they live in subprojects folder the project hierarchy doesn’t include :subprojects and :core is a direct child of a root project.


(Thibault Kruse) #3

Yes (I changed my original post including a recipe using the same ideas). But IMO gradle should do a better job of establishing such standards thoughout the community.

Setting up a project reasonably with gradle should not consist of a step of piecing to gether hacks found throughout the internet. IMO writing imperative code in gradle files should remain an exception for exceptional situations, not become the rule for everyday situations.

If the existing standards features in the gradle DSL have proven insufficient for even the gradle project itself, then it would only be honest to improve gradle until gradle itself can be build again using only standard gradle features.

I understand that changing standards is painful, but IMO it would pay off in the long run.