体验Gradle(9):制品

所谓制品,无外乎两类:项目依赖的和项目发布的。前者供项目自己使用,后者则供其它项目使用。在Java社区,管理制品有两大主流工具:MavenIvy。Gradle制品管理的基础就是Ivy。

Gradle通过配置(configuration)将制品组织起来,每个配置有一个名字,对应一组文件名。由于制品的双重作用,这些配置既可以用来声明项目依赖,也可以声明项目要发布的制品。跟Maven只能发布一个制品不同,Gradle对于要发布的制品数目并没有限制。配置的声明如下:

configurations {
    compile
}

上述代码定义了一个名为compile的配置,你可以在以后使用它,然后供任务使用。例如,你就像第一篇的做法,你可以使用配置名来声明依赖。

dependencies {
    groovy ':groovy-all:1.7.0'
    compile fileTree(dir: 'lib', includes: ['*.jar'])
    runtime fileTree(dir: 'lib', includes: ['*.jar'])
}

其中的groovy、compile和runtime应该是配置名。可是仔细想想,在第一篇的例子里,我们并没有一个地方声明这些配置呀?

奥秘就在咱们使用的插件身上。在那个例子里,我们使用了groovy插件,它继承自java插件。这些插件都预定义了一些配置名:compile和runtime是java插件定义的,groovy是groovy插件定义的。因此,我们只需使用就行了。这些配置最终会被相应的任务来使用,这些任务利用它们检索所需的制品,然后将它们置于自己的classpath里。你当然也可以定义自己的配置,供自己的任务使用。在任务里引用配置的方法:configurations.配置名,之后通过这个引用直接访问属性和方法即可。关于java插件和groovy插件的预定义配置与任务之间的关联,请访问参考文档的相关章节。

制品需要有个地方保存,这样你的项目才会知道从哪里去寻找所依赖的制品,以及将要发布的制品公开供其它项目使用。这个地方就是仓库(Repository)。

第一篇的例子里,我们已经看到了repositories的使用。

repositories {
    flatDir dirs: "lib"
}

单独使用repositories的话,定义的是项目依赖的制品存放的位置,项目会到此处来寻找所依赖的制品,然后把它下载到本地。对于要发布制品的项目来讲,需要使用uploadArchives,然后在其中定义要上载的repositories。以第一篇的例子为例,如果要让它发布一个制品,那么整个build.gradle将是:

usePlugin 'groovy'

version= "0.1"

repositories {
    flatDir dirs: "lib"
    flatDir name: "dist", dirs: "dist"
}

dependencies {
    groovy ':groovy-all:1.7.0'
    compile fileTree(dir: 'lib', includes: ['*.jar'])
    runtime fileTree(dir: 'lib', includes: ['*.jar'])
}

uploadArchives {
    uploadDescriptor = false
    repositories {
        add project.repositories.dist
    }
}

// usage: gradle -i run
task run(dependsOn: classes) << {
    captureStandardOutput(LogLevel.INFO)
    ant.java( 
        classname: 'fox.gem.GroovyClass',
        fork: true,
        classpath: "${sourceSets.main.runtimeClasspath.asPath}"
    )
}

相比前例,主要的变化:

  • 增加了version= 0.1,定义版本号之后,项目产生的文件名中将包含它,如xxx-0.1.jar;否则便是如xxx-unspecified.jar。
  • 在repositories中多定义了一个文件类型的仓库,用于存放项目发布的制品。
  • 增加了uploadArchives,用于制品上载,其中使用的仓库为上面定义的dist。

运行“gradle uploadArchives”,然后检查dist目录,就会发现制品已经发布过去了。按照常规的步骤,为了定义发布制品,需要:

  1. 首先定义配置
  2. 在artifacts中使用配置
  3. 定义upload[配置名],形式同上面的uploadArchives例子。因为上面的例子用到了groovy插件,而groovy插件又继承自java插件。因此,它可以直接使用java插件预定义archives配置。这也就是上面为什么使用uploadArchives的原因。
  4. 在命令行上输入:gradle upload[配置名]即可。

下面还原一下整个过程,其实就是这些代码:

configurations {
    newArchives
}

artifacts {
    //此处的jar是java插件预定义的任务。
    newArchives jar
}

uploadNewArchives {
    uploadDescriptor = false
    repositories {
        add project.repositories.dist
    }
}

将上述代码贴到前面的build.gradle里面,运行“gradle uploadNewArchives”,其效果跟咱们之前的“gradle uploadArchives”一样。如果要发布多个制品,那就定义多个配置,然后在artifacts里使用即可。当然,每个制品可能用到的打包文件不一样,这个只需要扩展jar任务,然后指定不同的文件集合便可以了。

前面的例子都是以文件系统为例的,把制品发布到这里当然没有什么意思。通过定义不同的仓库,你可以把制品发布到互联网上攻他人下载使用。而且更好的是,Gradle还提供了将制品发布到Maven仓库里的功能,只需要使用maven插件就行了。这部分内容参考手册给出了详尽的例子,请查阅。

最后再谈谈制品依赖的问题,因为制品本身也会有依赖,当发布到Maven仓库上时,产生的POM文件里需要给出它的依赖信息,否则将会让Maven的传递依赖特性无用武之地。好消息是,Gradle可以自动为我们创建POM,只要给了足够的信息,那么依赖也会出现在其中。对于上面的例子只需要进行小的修改即可:在compile中按照“组:制品:版本”的格式列出所依赖的包名即可。因此整个例子变成:

usePlugin 'groovy'
usePlugin 'maven'

version= "0.1"

repositories {
    flatDir dirs: "lib"
    flatDir name: "dist", dirs: "dist"
}

dependencies {
    groovy ':groovy-all:1.7.0'
    compile 'org.codehaus.groovy:groovy-all:1.7.0', ...
    runtime fileTree(dir: 'lib', includes: ['*.jar'])
}

configurations {
    newArchives
}

artifacts {
    newArchives jar
}

uploadNewArchives {
    repositories.mavenDeployer {
        repository(url: "file://localhost/D:/...")
        pom.groupId= '...'
    }
}

uploadArchives {
    uploadDescriptor = false
    repositories {
        add project.repositories.dist
    }
}

// usage: gradle -i run
task run(dependsOn: classes) << {
    captureStandardOutput(LogLevel.INFO)
    ant.java( 
        classname: '...',
        fork: true,
        classpath: "${sourceSets.main.runtimeClasspath.asPath}"
    )
}

运行“gradle uploadNewArchives”,进入dist即可看到最终结果,检查其子目录下的pom文件将会看到dependencies元素。这个例子同时还演示了一个使用Maven插件的例子。


本系列的其它部分:

By foxgem - Posted on 25 七月 2010