Gradle несколько банок из папки с одним исходным кодом
Теперь у нас есть структура проекта с папкой с одним исходным кодом с именем src
, которая содержит исходный код для трех модулей. Я хочу сделать это:
1) Скомпилируйте исходный код. Это легко сделать с помощью определения sourceSets:
sourceSets {
main {
java {
srcDir 'src'
}
}
}
2) Поместите результаты компиляции в три баночки. Я делаю это с помощью трех задач типа "jar":
Я делаю это сейчас с помощью трех отдельных задач:
-
util.jar
task utilJar(type: Jar) {
from(sourceSets.main.output) {
include "my/util/package/**"
}
}
-
client.jar
task clientJar(type: Jar) {
from(sourceSets.main.output) {
include "my/client/package/**"
}
}
-
server.jar
task serverJar(type: Jar) {
from(sourceSets.main.output) {
include "**"
}
excludes.addAll(utilJar.includes)
excludes.addAll(clientJar.includes)
}
Дело в том, что server.jar
должно содержать все классы, которые не содержатся в client.jar
и util.jar
. В ant build script мы решим эту проблему, используя задачу difference
ant. Как это можно сделать в gradle (мой текущий подход не работает)?
Возможно, мой подход совершенно неправильный. Пожалуйста, совет.
P.S. так как сейчас мы не можем изменить структуру каталогов исходного кода проекта.
Ответы
Ответ 1
Я опубликую здесь свое рабочее решение в качестве ответа (у меня есть подсказка на форуме gradle).
Области в gradle очень странные вещи:) Я думал, что каждое определение задачи создает объект некоторого класса Task, что в данном конкретном случае является чем-то вроде JarTask. Затем я могу получить доступ к любому свойству класса из любой точки моего build.gradle script. Однако я нашел единственное место, где я могу увидеть шаблоны, которые включены в файл jar - внутри блока from
задачи. Итак, теперь мое рабочее решение:
1) Определите коллекцию уровня проекта, чтобы содержать шаблоны, исключаемые из server.jar
2) Исключите все шаблоны в from
блоке задачи serverJar
.
См. окончательную версию ниже
sourceSets {
main {
java {
srcDir 'src'
}
}
}
// holds classes included into server.jar and util.jar, so they are to be excluded from server.jar
ext.serverExcludes = []
// util.jar
task utilJar(type: Jar) {
from(sourceSets.main.output) {
include "my/util/package/**"
project.ext.serverExcludes.addAll(includes)
}
}
// client.jar
task clientJar(type: Jar) {
from(sourceSets.main.output) {
include "my/client/package/**"
project.ext.serverExcludes.addAll(includes)
}
}
// server.jar
task serverJar(type: Jar) {
from(sourceSets.main.output) {
exclude project.ext.serverExcludes
}
}
Ответ 2
Я думаю, что подход неправильный. Я рекомендую сделать проект с тремя подпроектами.
project
- util
- server (depends on util)
- client (depends on util)
Если по какой-то причине вы не можете изменить структуру класса, используйте такие файлы сборки:
settings.gradle
include 'util', 'client', 'server'
build.gradle
subprojects {
apply plugin: 'java'
}
project(':util') {
sourceSets {
main {
java {
srcDir '../src'
include 'util/**'
}
}
}
}
project(':server') {
sourceSets {
main {
java {
srcDir '../src'
include 'server/**'
}
}
}
dependencies {
compile project(':util')
}
}
project(':client') {
sourceSets {
main {
java {
srcDir '../src'
include 'client/**'
}
}
}
dependencies {
compile project(':util')
}
}
Вам все еще нужны каталоги для подпроектов, но источники находятся в одном месте по вашему желанию.
При запуске gradle assemble
у вас будет 3 баночки с отдельным набором классов. Преимущество этого решения состоит в том, что мы создаем подходящий проект с несколькими модулями Gradle с правильными зависимостями, а не только с задачами для сборки банок.
Прочитайте Multi-Project Builds.
Ответ 3
У нас такая же проблема в моей компании, т.е. устаревший код, который трудно перенести в "хорошую" структуру проекта, и необходимость создания нескольких банок из одной и той же базы кода. Мы решили определить разные sourceSets и построить каждый из исходных наборов, используя стандартный Gradle.
Затем мы используем итераторы для добавления jar- и javadoc-задач для каждого sourceSet:
sourceSets.all { SourceSet sourceSet ->
Task jarTask = tasks.create("jar" + sourceSet.name, Jar.class)
jarTask.from(sourceSet.output)
// Configure other jar task properties: group, description, manifest etc
Task javadocTask = tasks.create("javadoc" + sourceSet.name, Javadoc.class)
javadocTask.setClasspath(sourceSet.output + sourceSet.compileClasspath)
javadocTask.setSource(sourceSet.allJava)
// Extra config for the javadoc task: group, description etc
Task javadocJarTask = tasks.create("javadocJar" + sourceSet.name, Jar.class)
javadocJarTask.setClassifier("javadoc") // adds "-javadoc" to the name of the jar
javadocJarTask.from(javadocTask.outputs)
// Add extra config: group, description, manifest etc
}
Ответ 4
Я согласен с принятым ответом.
Я нашел проект, в котором клиенту требуется два JAR по существу одного и того же файла, за исключением того, что манифест отличается только ключом Class-Path.
jar {
manifest {
attributes(
"Main-Class": platformMainClass,
"Implementation-Title": platformDisplayName,
"Implementation-Description": platformDescription,
"Platform-Version": platformVersion,
"Implementation-Version": version,
"Build-Assembly-User": System.getProperty("user.name"),
"Build-Assembly-Date": new java.util.Date().toString(),
"Class-Path": configurations.compile.collect { "lib/"+it.getName() }.join(' ')
)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' ])
}
Тот же манифест и исходный код:
task applicationClientJar(type: Jar, description: "Creates the Application Client JAR file.") {
dependsOn compileJava
manifest {
attributes(
"Main-Class": platformMainClass,
"Implementation-Title": platformDisplayName,
"Implementation-Description": platformDescription,
"Platform-Version": platformVersion,
"Implementation-Version": version,
"Assembly-Date": new java.util.Date().toString()
)
}
archiveName = "acme-client-${platformVersion}.jar"
destinationDir = file("${buildDir}/libs")
from sourceSets.main.output
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude( [ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' }
Итак, нотация Гжегожа правильная, потому что Gradle должен знать, что есть два разных JAR с GAV. Предпочтительным вариантом является мультимодуль.
compile "uk.gov.acme.secret:acme:1.0" // CORE
compile "uk.gov.acme.secret:acme-client:1.0"
Единственный способ настроить для этого - использовать проект Multi-Module Gradle, а затем добавить компиляцию и/или развертывание зависимости к основному/основному проекту.
project(':common:acme-micro-service-webapp') {
dependencies {
compile project(':common:acme-core')
}
}
Внутри проекта "acme-micro-service-webapp" это гарантирует, что сначала будет скомпилирован зависимый "общий: acme-core".
PS: Я все еще пытаюсь найти лучшее решение.
PS PS: Если вы используете Maven так же, как это возможно, возможно, можно зацепить задачу `install '.