Подтвердить что ты не робот

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. так как сейчас мы не можем изменить структуру каталогов исходного кода проекта.

4b9b3361

Ответ 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 '.