How to create custom repository type?

Hello.

I would like to add custom “repository method” to my gradle configuration.

Context: We have our own copy of Maven local repo. But is is not rule. It depends on system environment. It means I can configure gradle repositories this way:

repositories {
    if (System.getenv('ALT_REPO')) {
        maven { url "file://${System.getenv('ALT_REPO')}" }
    }
    mavenLocal()
    mavenCentral()
    jcenter()
}

And I would like to simplify that expression for other in our company and hide that “logic” somehow. So I would like to end up with something like:

repositories {
    altRepo()
    mavenLocal()
    mavenCentral()
    jcenter()
}

So is it possible to prepare altRepo method that is accessible from repositories section? Is it possible to place that logic and method definition somewhere to buildSrc?

Thanks a lot for your help, -libor

Most of the time, an organization will put this sort of thing into a plug-in or init.gradle script (that’s bundled inside a custom Gradle distribution).

buildSrc is for a single repo usually, so if you were to put something in buildSrc, no other repo would be able to (easily) use it.

ALT_REPO is your organization wide artifact repository? You could put your first block of code into a plug-in, publish it to your ALT_REPO and then in projects that wanted to use your plug-in:

buildscript {
       repositories {
        maven {
            url "to/alt/repo"
        }
    }
    dependencies {
        classpath group: 'your.company', name: 'Plugin', version: '1.0'
    }
}
  apply plugin: 'your.company.Plugin'

This is not organization wide repo. It is more our framework oriented. And the solution should work also outside of our company.

  • Each developer can have alternative repository in different director. That is the reason I need to use system environment (‘ALT_REPO’). - Alternative repository is optional and that’s the reason I need to use ‘IF’ statement.

So I’m looking for the how to “extend” somehow RepositoryHandler. There are methods like ‘mavenLocal()’, ‘mavenCentral()’, etc. And I would like to “add” my method ‘altRepo()’ that will return instance of MavenArtifactRepository.

So the question is: is it possible to extend ‘RepositoryHandler’?

One way to do this is ‘repositories.ext.altRepo = { repositories.maven { url “…” } }’.

Thanks a lot. It looks promising. For repositories it works. Is it possible to do it also for ‘buildscript.repositories’?

I tried 3 options but no one from them works:

buildscript.repositories.ext.altRepo1 = {
    buildscript.repositories.maven { url "..." }
}
buildscript.ext.repositories.altRepo2 = {
    buildscript.repositories.maven { url "..." }
}
buildscript.ext.repositories.ext.altRepo3 = {
    buildscript.repositories.maven { url "..." }
}

The ‘buildscript’ block is very special, and cannot be configured from the outside (at least not from a build script). ‘buildscript { repositories.ext.altRepo = { repositories.maven { … } } }’ should work though.

It works, thanks a lot!

But what dow you mean by “cannot be configured from the outside (at least not from a build script)”? I configured it in ‘build.gradle’. Does it mean ‘build.gradle’ is NOT build script? Thanks.

I mean that you have to do ‘buildscript { foo = bar }’, not ‘buildscript.foo = bar’.

I see.

Now I would like to move ‘buildscript/repositories’ and ‘repositories’ with and without ‘ext’ block into ‘buildSrc/build.gradle’. But it seams it does not work. Should it work? It is necessary to say I try it on single (not multi) project.

That won’t work because ‘buildSrc/build.gradle’ is a separate build for ‘buildSrc’. You could move it into a separate build script applied with ‘apply from:’, or into a plugin class in ‘buildSrc/src/main/groovy’ applied with ‘apply plugin:’. Not sure if this can be made to work for buildscript repositories though (you’d probably need at least a separate ‘apply from:/plugin:’ within ‘buildscript {}’).

I tried to move the logic into separate build script applied with ‘apply from:’ but it looks like it is executed in different context than main build script. It really seams that ‘buildscript’ is processed different way and currently I did not find elegant way how to hide the ‘IF’ statement from my ‘buildscript/repositories’ and ‘repositories’ sections.

There shouldn’t be any problems to get this to work for the regular ‘repositories’ block. For the buildscript repositories, did you try in the way I mentioned (another ‘apply from:’ within the ‘buildscript’ block)? Not entirely sure if this will work though. The only alternative I can think of is to add both extra properties in ‘init.gradle’ (which, if necessary, could even be shipped as part of a custom Gradle distribution).

Yes I tried it but it did not work. And you are right there is no problem with ‘repositories’ block. Just ‘buildscript’ has problems:

Following block works:

buildscript {
    repositories.ext.altRepo = {
        if (System.getenv('ALT_REPO')) {
            repositories.maven { url "file://${System.getenv('ALT_REPO')}" }
        }
    }
    repositories {
        altRepo()
    }
    dependencies {
        classpath "my:plugin:v1"
    }
}

But whenever I move ‘altRepo’ to another gradle file it is not visible to “master” build script.

Master ‘build.gradle’:

buildscript {
    apply from: "$rootDir/gradle/alt-repo.gradle"
    repositories {
        altRepo()
    }
    dependencies {
        classpath "my:plugin:v1"
    }
}

And ‘alt-repo.gradle’:

repositories.ext.altRepo = {
    if (System.getenv('ALT_REPO')) {
        repositories.maven { url "file://${System.getenv('ALT_REPO')}" }
    }
}

Maybe that it is just about content/syntax of ‘alt-repo.gradle’ file. I just moved the block from “master” file to new one.

And than build fails: ‘’‘Could not find method altRepo() for arguments [] on repository container.’’’

Try with this alt-repo.gradle:

project.buildscript.repositories.ext.altRepo = { ... }
1 Like

+1

Thanks a lot Peter we found out final solution.

Summary for others:

‘gradle/alt-repo.gradle’:

repositories.ext.altRepo = {
    if (System.getenv('ALT_REPO')) {
        repositories.maven { url "file://${System.getenv('ALT_REPO')}" }
    }
}
  project.buildscript.repositories.ext.altRepo = {
    if (System.getenv('ALT_REPO')) {
        project.buildscript.repositories.maven { url "file://${System.getenv('ALT_REPO')}" }
    }
}

‘build.gradle’:

apply from: "$rootDir/gradle/alt-repo.gradle"
buildscript {
    apply from: "$rootDir/gradle/alt-repo.gradle"
    repositories {
        altRepo()
        ...
    }
    dependencies {
        classpath "my:plugin:v1"
    }
}
  repositories {
    altRepo()
    ...
}
  apply plugin: 'my-plugin'

It is fantastic. I believed it is possible to do it. :wink:

Thanks a lot again. -libor

2 Likes