2013-11-15 62 views
25

至于现在我们有一个项目结构,其中包含单个源文件夹src,其中包含三个模块的源代码。我想要做的是:单个来源文件夹中的Gradle多个罐子

1)编译源代码。这很容易用sourceSets定义:

sourceSets { 
    main { 
     java { 
      srcDir 'src' 
     } 
    } 
} 

2)将编译结果放入三个罐子中。现在通过三个独立的任务

我这样做::我通过三个 '罐子' 类型的任务,这样做

  • 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.jarutil.jar所有类。在ant构建脚本中,我们通过使用difference ant任务来解决此问题。如何在gradle中完成这项工作(我目前的方法无效)?

也许我的方法是完全错误的。请指教。

P.S.至于现在我们不能更改项目源代码文件夹结构。

回答

26

我会在这里发布我的工作解决方案作为答案(我在Gradle的论坛上有提示)。

gradle中的范围是非常奇怪的事情:)我认为每个任务定义都会创建一些'Task'类的对象,在这种情况下就像'JarTask'。然后,我可以从我的build.gradle脚本中的任何地方访问该类的任何属性。但是,我发现唯一可以看到包含在jar文件中的模式的地方 - 在任务的from块内。所以现在我的工作的解决方案是:

1)定义项目级集合包含模式从server.jar

2除外)排除所有图案serverJar任务from块。

请参考下面

sourceSets { 
    main { 
     java { 
      srcDir 'src' 
     } 
    } 
} 

// holds classes included into client.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 
    } 
} 
+0

这很好,但是您如何引用其他项目的单独'.jar'文件 - 例如你怎么能把'client.jar'放到另一个子项目中呢? – z0r

+0

@z0r我们只是将工件发布到存储库,然后将它们用作子项目中的依赖关系。 P.S.对于延迟回复抱歉。 – vitalidze

16

我认为这种做法是错误的。我建议制作一个包含3个子项目的项目。

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

+0

感谢您的评论。我曾考虑过这种方法,但根本不需要改变目录结构。主要原因是我们有很多SVN分支(超过五十个),在目录结构变化(你知道,树冲突)之后合并它们应该是一个真正的痛苦。另一个原因是'util'和'client'互相依赖,所以我猜他们应该放在一个单独的模块中,这会带来同样的问题。我知道在源代码结构设计中这是一团糟,但我相信gradle可以完成蚂蚁可以做的所有事情:) – vitalidze

+1

@vitalidze我提出的解决方案并没有改变目录结构。额外的空目录是否有问题?你有依赖周期吗? –

+0

事情是这些类不是由文件夹(即客户端,服务器,util)分隔的。例如,我包含在客户端jar'a/b'和'z/x/y'中,util包含'q/w/e',并且服务器应该包含所有的休息类,它们可以在'a','z ','z/x','q','q/w'。 – vitalidze

4

最终版本中,我们有同样的问题在我的公司,即。难以迁移到“良好”项目结构的遗留代码,以及需要从同一代码库构建多个罐子的需求。我们决定定义不同的sourceSets,并使用标准Gradle构建每个sourceSets。

然后,使用迭代器添加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 
} 
1

我同意与接受的答案太本金。 我发现一个项目,其中客户端需要两个JAR基本上是相同的文件,但Manifest仅通过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/**'  } 

所以格热戈日表示法是正确的,因为摇篮应该知道有两种不同的JAR与GAVs。多模块是首选。

compile "uk.gov.acme.secret:acme:1.0" // CORE 
compile "uk.gov.acme.secret:acme-client:1.0" 

来配置这个问题的唯一方法是使用多模块式摇篮项目,然后添加一个编译和/或部署依赖于核心/主项目。

project(':common:acme-micro-service-webapp') { 
    dependencies { 
     compile project(':common:acme-core') 
    } 
} 

在'acme-micro-service-webapp'项目中,这确保首先编译从属'common:acme-core'。 PS:我仍在试图找出更好的解决方案。

PS PS:如果您使用的是Maven,也可以勾选`install'任务。

相关问题