Как создать толстую банку с помощью скрипта gradle kotlin
Как и хотелось бы узнать, как изменить gradle.build.kts
для того, чтобы иметь задачу создать уникальный jar
со всеми зависимостями (включая kotlin lib) внутри.
Я нашел этот образец в Groovy:
//create a single Jar with all dependencies
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'com.mkyong.DateUtils'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
Но я понятия не имею, как я мог написать это в kotlin, кроме:
task("fatJar") {
}
5 ответов
Вот версия, которая не использует плагин, больше похожая на версию Groovy.
import org.gradle.jvm.tasks.Jar
val fatJar = task("fatJar", type = Jar::class) {
baseName = "${project.name}-fat"
manifest {
attributes["Implementation-Title"] = "Gradle Jar File Example"
attributes["Implementation-Version"] = version
attributes["Main-Class"] = "com.mkyong.DateUtils"
}
from(configurations.runtime.map({ if (it.isDirectory) it else zipTree(it) }))
with(tasks["jar"] as CopySpec)
}
tasks {
"build" {
dependsOn(fatJar)
}
}
Обратите внимание, что первые 3 метода изменяют существующую задачу Gradle.
Способ 1: размещение файлов библиотеки рядом с JAR-файлом результата
Этот метод не нуждается
application
или любые другие плагины.
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
manifest.attributes["Class-Path"] = configurations
.runtimeClasspath
.get()
.joinToString(separator = " ") { file ->
"libs/${file.name}"
}
}
Обратите внимание, что Java требует, чтобы мы использовали относительные URL-адреса для
Class-Path
атрибут. Таким образом, мы не можем использовать абсолютный путь зависимостей Gradle (который также подвержен изменениям и недоступен в других системах). Если вы хотите использовать абсолютные пути, возможно, этот обходной путь сработает.
Создайте JAR с помощью следующей команды:
./gradlew jar
Результирующий JAR будет создан в каталоге build/libs/ по умолчанию.
После создания JAR-файла скопируйте JAR-файлы своей библиотеки в подкаталог libs/ того места, куда вы поместили полученный JAR-файл. Убедитесь, что JAR-файлы вашей библиотеки не содержат пробелов в имени файла (их имя файла должно совпадать с именем, указанным
${file.name}
переменная выше в задаче).
Способ 2. Встраивание библиотек в итоговый JAR-файл (толстый или убер-JAR)
Этот метод также не нуждается в каком-либо плагине Gradle.
tasks.jar {
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree) // OR .map { zipTree(it) }
from(dependencies)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Создание JAR точно такое же, как и в предыдущем методе.
Способ 3: использование плагина Shadow (для создания толстого или убер JAR)
plugins {
id("com.github.johnrengelman.shadow") version "6.0.0"
}
// Shadow task depends on Jar task, so these configs are reflected for Shadow as well
tasks.jar {
manifest.attributes["Main-Class"] = "org.example.MainKt"
}
Создайте JAR с помощью этой команды:
./gradlew shadowJar
См. документацию Shadow для получения дополнительной информации о настройке плагина.
Способ 4: Создание новой задачи (вместо изменения
Jar
задача)
tasks.create("MyFatJar", Jar::class) {
group = "my tasks" // OR, for example, "build"
description = "Creates a self-contained fat JAR of the application that can be run."
manifest.attributes["Main-Class"] = "com.example.MyMainClass"
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
val dependencies = configurations
.runtimeClasspath
.get()
.map(::zipTree)
from(dependencies)
with(tasks.jar.get())
}
Запуск созданного JAR
java -jar my-artifact.jar
Вышеупомянутые решения были протестированы с:
- Ява 17
- Gradle 7.1 (который использует Kotlin 1.4.31 для сценариев сборки .kts )
См. официальную документацию Gradle для создания uber (толстых) JAR -файлов .
Дополнительные сведения о манифестах см. в документации Oracle Java: работа с файлами манифестов .
Для разницы между
tasks.create()
а также
tasks.register()
см. этот пост .
Обратите внимание, что ваши файлы ресурсов будут автоматически включены в файл JAR (при условии, что они были помещены в каталог /src/main/resources/ или любой пользовательский каталог, заданный как корень ресурсов в файле сборки). Чтобы получить доступ к файлу ресурсов в вашем приложении, используйте этот код (обратите внимание на
/
в начале имен):
- Котлин
val vegetables = MyClass::class.java.getResource("/vegetables.txt").readText() // Alternative ways: // val vegetables = object{}.javaClass.getResource("/vegetables.txt").readText() // val vegetables = MyClass::class.java.getResourceAsStream("/vegetables.txt").reader().readText() // val vegetables = object{}.javaClass.getResourceAsStream("/vegetables.txt").reader().readText()
- Ява
var stream = MyClass.class.getResource("/vegetables.txt").openStream(); // OR var stream = MyClass.class.getResourceAsStream("/vegetables.txt"); var reader = new BufferedReader(new InputStreamReader(stream)); var vegetables = reader.lines().collect(Collectors.joining("\n"));
Вот как это сделать в Gradle 6.5.1, Kotlin/Kotlin-Multiplatform 1.3.72, используя файл build.gradle.kts и без использования дополнительного плагина, который кажется ненужным и проблематичным для мультиплатформенности;
Примечание: на самом деле, насколько я могу судить, с многоплатформенным плагином хорошо работают несколько плагинов, поэтому я подозреваю, что его философия дизайна сама по себе очень многословна. На самом деле это довольно элегантно, IMHO, но недостаточно гибкое или документированное, поэтому для настройки даже БЕЗ дополнительных плагинов требуется масса проб и ошибок.
Надеюсь, это поможет другим.
kotlin {
jvm {
compilations {
val main = getByName("main")
tasks {
register<Jar>("fatJar") {
group = "application"
manifest {
attributes["Implementation-Title"] = "Gradle Jar File Example"
attributes["Implementation-Version"] = archiveVersion
attributes["Main-Class"] = "[[mainClassPath]]"
}
archiveBaseName.set("${project.name}-fat")
from(main.output.classesDirs, main.compileDependencyFiles)
with(jar.get() as CopySpec)
}
}
}
}
}
Вы можете использовать плагин ShadowJar для создания толстой банки:
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
buildscript {
repositories {
mavenCentral()
gradleScriptKotlin()
}
dependencies {
classpath(kotlinModule("gradle-plugin"))
classpath("com.github.jengelman.gradle.plugins:shadow:1.2.3")
}
}
apply {
plugin("kotlin")
plugin("com.github.johnrengelman.shadow")
}
repositories {
mavenCentral()
}
val shadowJar: ShadowJar by tasks
shadowJar.apply {
manifest.attributes.apply {
put("Implementation-Title", "Gradle Jar File Example")
put("Implementation-Version" version)
put("Main-Class", "com.mkyong.DateUtils")
}
baseName = project.name + "-all"
}
Просто запустите задачу с помощью shadowJar.
ПРИМЕЧАНИЕ. Предполагается, что вы используете GSK 0.7.0 (последний по состоянию на 13.02.2017).
Теперь есть документация о том, как это сделать в последних версиях gradle, см. Https://docs.gradle.org/current/userguide/building_java_projects.html#sec:java_packaging