Pull to refresh

Динамическое подключение внешних собственных модулей и плагинов в Gradle

Reading time 3 min
Views 6.6K

Преамбула


Есть своя «внешняя» библиотека и есть своё приложение, использующее эту библиотеку (подгружается через внешний репозитарий). Требуется внести изменение и в библиотеку и в приложение.

Казалось бы, собери библиотеку и выложи её в локальный maven-репозитарий, а потом уже собирай приложение. Но хочется, чтобы можно было поправив код в библиотеке сразу попробовать изменения в приложении и при этом сохранить раздельное хранение кода библиотеки и приложения, включая настройки IDE и прочее.

С помощью gradle и символических связей в файловой системе такое можно легко устроить.

Библиотека


Для начала приведу пример содержимого build.gradle в библиотеке:

import java.text.SimpleDateFormat

apply plugin: 'java'
apply plugin: 'maven-publish'

sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8

jar.baseName = 'library'

publishing {
    publications {
        mavenJava(MavenPublication) {
            groupId='name.alenkov.habr.gradle-dynamic-dependency'
            
            version = new SimpleDateFormat('yyyyMMddHHmm').format(new Date())

            from components.java
        }
    }
}

Здесь ключевым является строка «version = new SimpleDateFormat('yyyyMMddHHmm').format(new Date())», которая задаёт версию сборки на основе текущего времени в момент её публикации в репозитарий — в остальное время версия для библиотеки нам не требуется.

Disclaimer: В нашем демонстрационном приложении мы не поддерживаем более одной ветки библиотек в продуктовой среде и потому нет потребности в поддержке версионности вида X.Y.Z

Note: в примерах я использую локальный Maven и не привожу примеры с использованием Artifactory, т.к. это не влияет на подход.

Приложение


Теперь перейдём к настройке нашего build.gradle в приложении.

Исходное состояние build.gradle:

apply plugin: 'java'

sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
    compile 'name.alenkov.habr.gradle-dynamic-dependency:library:+'
}



Теперь давайте модифицируем конфигурацию gradle так, чтобы получить желаемое — динамическое подключение модулей.

Первый шагом, слинкуем нашу библиотеку в проект приложения в подкаталог ext:

cd ./app/ext
ln -s ../../library/ ./

Вторым шагом добавим небольшой код в settings.gradle, который сканирует каталог "/ext" на наличие gradle-проектов и будет подключать их к нам в проект:

final extDir = new File(rootDir, 'ext')
if (extDir.exists()) {
    extDir.eachDir { dir ->
        if (new File(dir, 'build.gradle').exists()) {
            logger.trace('found ext module: ' + dir.name)

            final String prjName = ':' + dir.name
            logger.lifecycle('include ext project: ' + prjName)
            include prjName
            project(prjName).projectDir = dir
            project(prjName).name = 'ext-' + dir.name
        }
    }
}

И третий, заключительный штрих — модифицируем секцию dependencies в build.gradle:

dependencies {
  compile findProject(':ext-library') ?: module(group: 'name.alenkov.habr.gradle-dynamic-dependency', name: 'library', version: '+')
}



и пример, когда в library есть дополнительные gradle-задачи:



Gradle-плагин


Аналогичным способом можно добавить и внешние gradle-плагины.

Шаги:

1. Создаём каталог buildSrc
2. Создаём файл buildSrc/settings.gradle

final extDir = rootDir
if (extDir.exists()) {
    extDir.eachDir { dir ->
        if (new File(dir, 'build.gradle').exists()) {
            logger.trace('found ext plugin: ' + dir.name)

            final String prjName = ':' + dir.name
            logger.lifecycle('include ext plugin: ' + prjName)
            include prjName
            project(prjName).projectDir = dir
            project(prjName).name = 'ext-plugin-' + dir.name
        }
    }
}

3. Создаём файл buildSrc/build.gradle

dependencies {
    runtime subprojects.collect { owner.project(it.path) }
}

Теперь достаточно прилинковать в buildSrc внешний плагин, как он подхватится проектом в работу:

cd ./app/buildSrc
ln -s ../../gradle-plugin/ ./



Из текущего неудобства — в IDEA динамические модули и плагины подключаются не совсем корректно — баг и баг.

Исходный код обоих модулей и плагина можно посмотреть на github

UPD: аналогичным способом можно подключать и плагины gradle, только монтируя их в buildSrc. Если будут желающие, могу написать пример…

UPD: добавил пример с плагином
Tags:
Hubs:
+9
Comments 6
Comments Comments 6

Articles