引言:通过上一篇的论述,我们知道gradle脚本是如假包换的groovy代码,但是这个groovy代码是运行在他的上下文环境里面的,学名叫语义模型。这一篇我们就来看看他的语义模型到底是什么,如何使用。

gradle下载安装

gradle的下载安装并没有什么出乎意料的东西,进入他的官网(http://gradle.org/),下载gradle压缩包,解压,配置bin路径到Path即可。

我安装在c盘下,进入目录C:\gradle-2.4\docs\userguide,打开userguide.pdf文件,这个就是gradle的向导帮助文档。

gradle 语义模型

gradle使用project和task来实现构建的操作,project对应工程,task对应具体的任务,例如编译,压缩,生成帮助文档。我们从userguide.pdf的chap 6中截取一个hello world的Demo来说明,以便有个初步的印象。

创建一个空文件夹Demo,进入,再创建一个build.gradle文件,并写入如下的代码:

  1. task hello {
  2. println "hello world"
  3. }

在命令行中输入 gradle -q hello (-q 参数用于删除冗余的输出),会得到hello world的输出。这一段脚本通过调用project类的task方法,添加了一个新的task在project的task map中,其中键是“hello”,后面跟着一个闭包,里面的代码用于配置这个task的一些属性,相当于初始化这个task,这在下面action的例子中表现最明显。需要注意的是这里的task是关键字,并不是调用某一个方法,在解析的过程中,gradle还需要根据这个关键字进行转化才能生成标准的groovy代码。

在gradle中,project和build.gradle文件是一一对应的,通过这个文件可以配置project的各种属性。project的初始化流程如下:

(1)首先创建一个Settings的实例。(对应 org.gradle.api.initialization 下的 Interface Settings )

(2)如果当前目录有settings.gradle,那么用这个文件来配置Settings实例。

(3)用Settings实例来创建Project的层次关系。

(4)最后,如果项目中存在build.gradle就通过它来执行每个Project。项目中,项目分别依次横向执行,以此子项目一定在父项目之后执行。这个规则可以通过调用evaluationdependsonchildren()或加入一个明确的依赖usingevaluationdependson(String)。

从初始化流程来看,项目之间的层次和依赖关系是通过settings.gradle来配置的,而project的具体任务执行是通过build.gradle来配置的。在build.gradle中可以添加系统提供的task和自定义的task,例如上例就是自定义的task。Project还可以通过添加插件来添加能支持的task。task是由action组成,action可以理解成真正的执行功能的代码块,可以调用doFirst,doLast,leftShift和<<添加action。我们举一个既有配置代码,又有action的例子,看下面的代码:

action的例子

  1. task hello {
  2. println "hello world"//初始化
  3. }<<{
  4. println "hello world action"
  5. }
  6.  
  7. task hello1 {
  8. println "hello world1"//初始化
  9. }<<{
  10. println "hello world1 action"
  11. }

  

我们用上一个例子中运行task的方法调用hello1,即输入:gradle hello1,输出为:

  1. # gradle hello1
  2. hello world
  3. hello world1
  4. :hello1
  5. hello world1 action
  6.  
  7. BUILD SUCCESSFUL
  8.  
  9. Total time: 2.086 secs

  

 

  可以看出初始化的代码是一定执行的,而Task hello的Action代码,要用gradle指定task才能执行。

  从上面的两个例子,我们有了一个最初的印象,gradle构建从上到下的机构顺序应该是project---》task---》action。

  每一个Project都通过一个TaskContainer来添加和管理他的task,这是一个task的容器,可以通过调用project的getTasks()方法来获得,不过一般来说大家都通过task关键字来生成task,范例如下:

  1. task myTask1
  2.  
  3. task myTask2 {
  4. println "myTask2"
  5. }
  6.  
  7. task myType3 << {
  8. println "myTask2 -- action"
  9. }
  10. task myTask4("dependsOn": myType3)
  11.  
  12. task myTask5("dependsOn": myType3) {
  13. println "myTask5 -- action"
  14. }

当然可以直接用project里面的task()方法,使代码更加groovy一点:

  1. task nTask1
  2.  
  3. task nTask2,{
  4. println "nTask1"
  5. }
  6.  
  7. task nTask3,{
  8. println "nTask3"
  9. }<<{
  10. println "nTask3 -- action"
  11. }
  12.  
  13. task nTask4,{
  14. dependsOn(nTask3)
  15. }

  一旦task被创建,就可以用它的名字来引用它。

  1. task nTask3,{
  2. println "nTask3"
  3. }<<{
  4. println "nTask3 -- action"
  5. }
  6.  
  7. task nTask4,{
  8. dependsOn(nTask3)
  9. }
  10.  
  11. nTask4 << {
  12. println "nTask4 -- action"
  13. }
  1. # gradle nTask4
  2. nTask3 -- action
  3. nTask3
  4. :nTask3 UP-TO-DATE
  5. :nTask4
  6. nTask4 -- action
  7.  
  8. BUILD SUCCESSFUL
  9.  
  10. Total time: 2.927 secs

应该是通过DSL转换来做的。

上面说Task中具体的执行步骤是通过Action来完成的,Action的结构十分简单,只有一个方法

  1. void execute(T t)
  2.  
  3. ActionTask中排列成一个队列,依次执行。增加Action4个方法,上面已经提过,看下面的例子:
  1. task nTask4 {
  2. println "this is config"//配置这个task
  3. }
  4. nTask4 << {
  5. println "nTask4 -- add action by <<" //通过 <<来增加action
  6. }
  7. nTask4.leftShift {
  8. println "nTask4 -- add action by leftShift "//通过leftShift方法来增加action,等同 <<
  9. }
  10. nTask4.doFirst {
  11. println "nTask4 -- doFirst" //在action队列的最前面插入一个Action
  12. }
  13.  
  14. nTask4.doLast {
  15. println "nTask4 -- doLast" //在action队列的最最后插入一个Action
  16. }

输出为:

  1. # gradle nTask4
  2. this is config
  3. :nTask4
  4. nTask4 -- doFirst
  5. nTask4 -- add action by <<
  6. nTask4 -- add action by leftShift
  7. nTask4 -- doLast
  8.  
  9. BUILD SUCCESSFUL
  10.  
  11. Total time: 2.935 secs

  

结果一目了然,doFirst最先执行,<<和leftShift的调用时序决定先后顺序,而doLast在最后。能这样做的数据结构,当然是队列,事实也确实如此,在Task接口中,用的是List,而在抽象类AbstractTask中用ArrayList实现的。

Project和Task的属性设置和依赖关系可以参考这篇博客:http://www.blogjava.net/wldandan/archive/2012/07/05/382246.html。

增加一个例子作说明

  1. //project 自带属性
  2. println Project.DEFAULT_BUILD_DIR_NAME
  3. println DEFAULT_BUILD_DIR_NAME
  4.  
  5. //本地属性
  6. String msg = "hello world"
  7.  
  8. //extension 属性
  9. ext{//用 ext 关键字
  10. projectProperties = "ext projectProperties-value"
  11. }
  12. //直接调用方法
  13. project.getExtensions().create("mMsg", Msg)
  14.  
  15. task hello (){
  16. println msg //初始化
  17. }<<{
  18. println "ext properties :"+projectProperties
  19. projectProperties = "chang the extension propertise"
  20. println "ext properties :"+projectProperties
  21. // println project.property(projectProperties) //无法执行
  22. println project.property("projectProperties")
  23. println mMsg.des
  24. }
  25.  
  26. class Msg {
  27. String des = "this is a msg"
  28. int id = 10
  29. }

 输出为:

  1. # gradle hello
  2. build
  3. build
  4. hello world
  5. :hello
  6. ext properties :ext projectProperties-value
  7. ext properties :chang the extension propertise
  8. chang the extension propertise
  9. this is a msg
  10.  
  11. BUILD SUCCESSFUL
  12.  
  13. Total time: 3.028 secs

  

通过上面的例子说明了动态增加属性的方式。由此可以见,一个Project增加属性和Task都是可行的。当某一类Task需要集体带入的话(比如整个android的编译过程),一个个通过task方法加入就过于麻烦了,解决方案也很简单,我把Project的实例给这一类Tasks的管理类(比如XXManager,在gradle中叫XXPlugin,或者直接叫 java,android),由这个管理类自己添加需要的task,举个例子:

  1. apply plugin: DateAndTimePlugin
  2.  
  3. dateAndTime {
  4. timeFormat = 'HH:mm:ss.SSS'
  5. dateFormat = 'MM/dd/yyyy'
  6. }
  7.  
  8. class DateAndTimePlugin implements Plugin<Project> {
  9. void apply(Project project) {
  10. project.extensions.create("dateAndTime", DateAndTimePluginExtension)
  11. project.task('showTime') << {
  12. println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
  13. }
  14. project.tasks.create('showDate') << {
  15. println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
  16. }
  17. }
  18. }
  19.  
  20. class DateAndTimePluginExtension {
  21. String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
  22. String dateFormat = "yyyy-MM-dd"
  23. }

  Task已经加入,我们直接使用就可以了,

  1. # gradle showTime showDate
  2. :showTime
  3. Current time is 15:52:15.841
  4. :showDate
  5. Current date is 09/01/2015
  6.  
  7. BUILD SUCCESSFUL
  8.  
  9. Total time: 2.132 secs

  

  

参考:

负责task转换的类:org.gradle.groovy.scripts.internal.TaskDefinitionScriptTransformer.java

http://www.gradle.org/docs/current/javadoc/org/gradle/api/Project.html

http://www.gradle.org/docs/current/javadoc/org/gradle/api/Task.html

第二篇:gradle脚本运行环境分析(gradle的语义模型)的更多相关文章

  1. gradle教程 [原创](eclipse/ADT下 非插件 非Android Studio/AS)纯手打 第二篇:gradle简单实战

    一个bug 一个脚印的叫你们用gradle. 1介于网络上的很多资料都是老的 不适用与现在的新版本gradle 尤其是有些gradle方法改名了老的用不了 2介于网上都是粘贴复制并且零碎我很蛋疼啊,走 ...

  2. 【转载】Gradle for Android 第二篇( Build.gradle入门 )

    理解Gradle脚本 当然我们现在讨论的所有内容都是基于Android studio的,所以请先行下载相关工具.当我们创建一个新的工程,Android studio会默认为我们创建三个gradle文件 ...

  3. 写完批处理脚本,再写个Gradle脚本,解放双手

    前言 上一篇写个批处理来帮忙干活---遍历&字符串处理中,我们已经学习如何写批处理脚本来帮我们做一些简单的重复性工作,本篇继续来学习如何用 Gradle 写脚本,让它也来帮我们干活 Gradl ...

  4. Gradle 脚本剪片---copy

    Gradle是以Groovy语言为基础,基于DSL语法的自动化构建工具,一个构建脚本能够包含任何Groovy语言元素,每个脚本都是UTF-8编码的文件. 6-1 Project对象API 前面我们说过 ...

  5. Android Gradle脚本从Groovy迁移到Kotlin DSL

    Android Gradle从Groovy迁移到Kotlin Android项目用Gradle构建, 其脚本语言之前是Groovy, 目前也提供了Kotlin的支持, 所以可以迁移到Kotlin. 官 ...

  6. Gradle 1.12用户指南翻译——第二十二章. 标准的 Gradle 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  7. 皮肤包项目的 Gradle 脚本演化

    我在做的一个项目需要有换肤功能,换肤的方案是采用第三方库 ThemeSkinning 的实现(在其基础上修复若干 bug).皮肤的制作是把相关的资源放在一个 app module 中打包成 apk,当 ...

  8. 从编程的角度理解gradle脚本﹘﹘Android Studio脚本构建和编程[魅族Degao]

    本篇文章由嵌入式企鹅圈原创团队.魅族资深project师degao撰写. 随着Android 开发环境从Eclipse转向Android Studio,我们每一个人都開始或多或少要接触gradle脚本 ...

  9. 转载 LibGDX: 使用 Gradle 命令运行和打包项目

    版权声明:本文为csdn xietansheng 博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: http://blog.csdn.net/xieta ...

随机推荐

  1. linux文件属性详解

    Linux 文件或目录的属性主要包括:文件或目录的节点.种类.权限模式.链接数量.所归属的用户和用户组.最近访问或修改的时间等内容.具体情况如下: 命令: ls -lih 输出: [root@loca ...

  2. Failed to load unit 'PATM' (VERR_SSM_FIELD_NOT_CONSECUTIVE)

    今天打开虚拟机启动的时候报错:Failed to load unit 'PATM' (VERR_SSM_FIELD_NOT_CONSECUTIVE) 后来发现虚机处于休眠状态,所以在虚机上右键,然后清 ...

  3. IT小说

    最近迷上了IT小说,连着读了好几个连载.伴随着一个项目的一些事,一些矛盾,也能体现出一个社会的缩影.最吸引的应该是一种熟悉感,常常想要是拍成电视剧也应该很好看,像<半泽植树>似的.看完了, ...

  4. NOIP 2013 花匠

    有多种方案,找拐点数目最简单O(n) 注意此题有相邻点价值一样,代码改变一点 #include <cstdio> #include<iostream> #include< ...

  5. HW1.5

    public class Solution { public static void main(String[] args) { System.out.println("(9.5 * 4.5 ...

  6. SignalR Supported Platforms -摘自网络

    SignalR is supported under a variety of server and client configurations. In addition, each transpor ...

  7. MySQL索引和优化查询

    索引和优化查询 恰当的索引可以加快查询速度,可以分为四种类型:主键.唯一索引.全文索引.普通索引. 主键:唯一且没有null值. create table pk_test(f1 int not nul ...

  8. [二]poi实践一

    1.创建时间格式的cell 2.创建不同格式的cell(字符串.布尔.数值) 3.读取遍历xls文件 4.抽取excel的内容

  9. [四]JFreeChart实践三之饼图

    饼图pie 原理总结 1.准备好要显示的数据放入dataset 2.调用ChartFactory将dataset作为参数传递进去,生成chart 3.掉Servlet工具类将chart作为参数传入生成 ...

  10. shiro权限控制方式

    1.基于配置文件(*.ini)[常用jdbcRealm.ini] 2.基于注解的配置 3.基于jsp标签的配置(需要导入对应的标签jar包) 权限包含: 是否为特定用户 是否为特定角色 是否拥有特定操 ...