本文转载至:http://my.oschina.net/zjzhai/blog/220028
目录[-]
- Gradle介绍
- gradle命令行创建项目
- 构建Java应用程序
- Gradle 任务
- 定义task
- 为task分配行为(`action`)
- 设置默认任务
- task的配置
- task的方法与属性
- DefaultTask包含的方法
- dependsOn(task) 设置依赖task
- doFirst(closure)
- doLast(closure)
- onlyIf(closure) 只有在onlyIf返回true时才运行task
- DefaultTask包含的属性
- 可以在任务中写Groovy代码
- 为任务分组
- 忽略任务
- 增量构建的任务
- task类型
- 自定义task类型
- 四个位置可以写你的自定义构建代码
- Gradle 守护进程
- Gradle的生命周期
- 项目的属性
- Gradle包装器
- 依赖管理
- Repository管理
- Gradle常用命令
Gradle介绍
Gradle是一种自动化构建工具。
其实,Gradle被设计为一种构建语言,而非一个严格的框架。Gradle的核心使用Java和Groovy语言实现,所以,你可使用Java或者Groovy语言来扩展Gradle。当然,你也可以使用Scala。
gradle命令行创建项目
gradle本身没有创建项目的命令。最好的解决方案就是使用第三方插件来实现。步骤:
- 新你的项目的文件夹
project
- 进入文件项目文件夹添加文件
build.gradle
,并加入:
apply from: 'http://www.tellurianring.com/projects/gradle-plugins/gradle-templates/1.3/apply.groovy'
- 运行
gradle initJavaProject
用到的第三方插件:gradle-templates :
以下就是它的API:
createGradlePlugin - Creates a new Gradle Plugin project in a new directory named after your project.
createGroovyClass - Creates a new Groovy class in the current project.
createGroovyProject - Creates a new Gradle Groovy project in a new directory named after your project.
createJavaClass - Creates a new Java class in the current project.
createJavaProject - Creates a new Gradle Java project in a new directory named after your project.
createScalaClass - Creates a new Scala class in the current project.
createScalaObject - Creates a new Scala object in the current project.
createScalaProject - Creates a new Gradle Scala project in a new directory named after your project.
createWebappProject - Creates a new Gradle Webapp project in a new directory named after your project.
initGradlePlugin - Initializes a new Gradle Plugin project in the current directory.
initGroovyProject - Initializes a new Gradle Groovy project in the current directory.
initJavaProject - Initializes a new Gradle Java project in the current directory.
initScalaProject - Initializes a new Gradle Scala project in the current directory.
initWebappProject - Initializes a new Gradle Webapp project in the current directory.
构建Java应用程序
- 使用application插件:
apply plugin: 'application'
- 设置主函数:
mainClassName = "WebTest"
- 运行
gradle run
Gradle 任务
定义task
task hello
为task分配行为(`action`)
task hello << {
println "hello"
}
<<
操作符代表task的doLast
方法
task hello { doLast { println "hello" } }
还可以
def printTaskName = { task ->
println "Running ${task.name}"
}
task 'five' {
doFirst printTaskName
}
task 'two' << printTaskName
重复定义task的行为
task hello <<{
println "hello"
}
task world <<{
println "world"
}
输出:
hello world
使用Action接口定义action
task first {
doFirst (
new Action(){
void execute(task){
println 'Running ${task.name}'
}
}
)
}
设置默认任务
defaultTasks 'first', 'second'
task first {
doLast {
println "I am first"
}
}
task second {
doFirst {
println "I am second"
}
}
在gradle
命令后不加入任何任务名时,就会执行默认任务。
task的配置
task initializeDatabase
initializeDatabase << { println 'connect to database' }
initializeDatabase << { println 'update database schema' }
initializeDatabase { print 'configuring' }
initializeDatabase { println 'database connection' }
输出:
print 'configuring'
println 'database connection'
println 'connect to database'
println 'update database schema'
配置闭包将会在Gradle的配置期(configuration lifecycle phase)执行。
task的方法与属性
task其实是一个对象,它也会有方法和属性,同时,也会有类型。默认情况下,定义的task继承自DefaultTask。
DefaultTask包含的方法
dependsOn(task) 设置依赖task
// Declare that world depends on hello
// Preserves any previously defined dependencies as well
task loadTestData {
dependsOn createSchema
}
// An alternate way to express the same dependency
task loadTestData {
dependsOn << createSchema
}
// Do the same using single quotes (which are usually optional)
task loadTestData {
dependsOn 'createSchema'
}
// Explicitly call the method on the task object
task loadTestData
loadTestData.dependsOn createSchema
// A shortcut for declaring dependencies
task loadTestData(dependsOn: createSchema)
还可以多重依赖
// Declare dependencies one at a time
task loadTestData {
dependsOn << compileTestClasses
dependsOn << createSchema
}
// Pass dependencies as a variable-length list
task world {
dependsOn compileTestClasses, createSchema
}
// Explicitly call the method on the task object
task world
world.dependsOn compileTestClasses, createSchema
// A shortcut for dependencies only
// Note the Groovy list syntax
task world(dependsOn: [ compileTestClasses, createSchema ])
doFirst(closure)
注意同时定义两个doFirst
方法时的输出
task setupDatabaseTests << {
println 'load test data'
}
setupDatabaseTests.doFirst {
println 'create database schema'
}
setupDatabaseTests.doFirst {
println 'drop database schema'
}
$ gradle world
:setupDatabaseTests
drop database schema
create database schema
load test data
也可以这样写:
// Initial task definition (maybe not easily editable)
task setupDatabaseTests << {
println 'load test data'
}
// Our changes to the task (in a place we can edit them)
setupDatabaseTests {
doFirst {
println 'create database schema'
}
doFirst {
println 'drop database schema'
}
}
doLast(closure)
task setupDatabaseTests << {
println 'create database schema'
}
setupDatabaseTests.doLast {
println 'load test data'
}
setupDatabaseTests.doLast {
println 'update version table'
}
onlyIf(closure) 只有在onlyIf返回true时才运行task
task createSchema << {
println 'create database schema'
}
task loadTestData(dependsOn: createSchema) << {
println 'load test data'
}
loadTestData.onlyIf {
System.properties['load.data'] == 'true'
}
$ build loadTestData
create database schema
:loadTestData SKIPPED
$ gradle -Dload.data=true loadTestData
:createSchema
create database schema
:loadTestData
load test data
DefaultTask包含的属性
-
didWork
apply plugin: 'java'
task emailMe(dependsOn: compileJava) « {if(tasks.compileJava.didWork) { println 'SEND EMAIL ANNOUNCING SUCCESS' }
}
-
enabled
task templates « {
println 'process email templates'
}
task sendEmails(dependsOn: templates) « {println 'send emails'
}
sendEmails.enabled = false -
path,指此task的在构建文件中的路径
task echoMyPath « {
println "THIS TASK'S PATH IS ${path}"
}
$ gradle echoMyPath
THIS TASK'S PATH IS :echoMyPath如果
echoMyPath
是子项目(subProject
)下的一个task,那么它的路径将会是::subProject:echoMyPath
-
logger,实现的日志接口是:org.slf4j.Logger,同时有少量的日志级别添加。
task logLevel « {
def levels = ['DEBUG', 'INFO', 'LIFECYCLE', 'QUIET', 'WARN', 'ERROR'] levels.each { level -> logging.level = level def logMessage = "SETTING LogLevel=${level}" logger.error logMessage logger.error '-' * logMessage.size() logger.debug 'DEBUG ENABLED' logger.info 'INFO ENABLED' logger.lifecycle 'LIFECYCLE ENABLED' logger.warn 'WARN ENABLED' logger.quiet 'QUIET ENABLED' logger.error 'ERROR ENABLED' println 'THIS IS println OUTPUT' logger.error ' ' }
}
-
description
task helloWorld(description: 'Says hello to the world') « {
println 'hello, world'
}
task helloWorld « {
println 'hello, world'
}
helloWorld {description = 'Says hello to the world'
}
// Another way to do it
helloWorld.description = 'Says hello to the world' -
temporaryDir 临时目录
-
Dynamic Properties 动态属性
task copyFiles {
// Find files from wherever, copy them // (then hardcode a list of files for illustration) fileManifest = [ 'data.csv', 'config.json' ]
}
task createArtifact(dependsOn: copyFiles) « {println "FILES IN MANIFEST: ${copyFiles.fileManifest}"
}
$ gradle -b dynamic.gradle createArtifact
FILES IN MANIFEST: [data.csv, config.json]
可以在任务中写Groovy代码
为任务分组
def taskGroup = 'base'
task first2(description: 'Base task', group: taskGroup) << {
println "I am first"
}
task second2(dependsOn: first2, description: 'Secondary task', group: taskGroup) << {
println "I am second"
}
分组似乎只是用于gradle tasks
时,显示更好看。因为同一组的任务分显示在一组里。
忽略任务
-
使用onlyIf断言
每一个任务都会有一个onlyIf
方法,如果方法返回true
则执行任务,否则跳过。task longrunning { onlyIf { task -> def now = Calendar.instance def weekDay = now[DAY_OF_WEEK] def weekDayInWeekend = weekDay in [SATURDAY, SUNDAY] return weekDayInWeekend } doLast { println "Do long running stuff" } }
-
实现
Spec()
方法def file = new File('data.sample') task 'handleFile' << { println "Work with file ${file.name}" } handleFile.onlyIf(new Spec() { boolean isSatisfiedBy(task) { file.exists() } })
-
抛出异常
StopExecutionException
def printTaskName = { task -> println "Running ${task.name}" } task first << printTaskName first.doFirst { def today = Calendar.instance def workingHours = today[Calendar.HOUR_OF_DAY] in 8..17 if (workingHours) { throw new StopExecutionException() } } task second(dependsOn: 'first') << printTaskName
-
设置任务有效或者失效
task 'listDirectory' { def dir = new File('assemble') enabled = dir.exists() doLast { println "List directory contents: ${dir.listFiles().join(',')}" } }
-
使用命令行参数
-x
gradle third -x second
增量构建的任务
在source发生变化时才执行任务
task convert {
def source = new File('source.xml')
def output = new File('output.txt')
// Define input file
inputs.file source
// Define output file
outputs.file output
doLast {
def xml = new XmlSlurper().parse(source)
output.withPrintWriter { writer ->
xml.person.each { person ->
writer.println "${person.name},${person.email}"
}
}
println "Converted ${source.name} to ${output.name}"
}
}
或者
task createVersionDir {
def outputDir = new File('output')
// If project.version changes then the
// task is no longer up-to-date
inputs.property 'version', project.version
outputs.dir outputDir
doLast {
println "Making directory ${outputDir.name}"
mkdir outputDir
}
}
task convertFiles {
// Define multiple files to be checked as inputs.
inputs.files 'input/input1.xml', 'input/input2.xml'
// Or use inputs.dir 'input' to check a complete directory.
// Use upToDateWhen method to define predicate.
outputs.upToDateWhen {
// If output directory contains any file which name
// starts with output and has the txt extension,
// then the task is up-to-date.
new File('output').listFiles().any {
it.name ==~ /output.*\.txt$/
}
}
doLast {
println "Running convertFiles"
}
}
task类型
-
copy
task copyFiles(type: Copy) { from 'resources' into 'target' include '**/*.xml', '**/*.txt', '**/*.properties' }
-
jar
apply plugin: 'java' task customJar(type: Jar) { manifest { attributes firstKey: 'firstValue', secondKey: 'secondValue' } archiveName = 'hello.jar' destinationDir = file("${buildDir}/jars") from sourceSets.main.classes }
-
JavaExec 运行一个java类的main方法
apply plugin: 'java' repositories { mavenCentral() } dependencies { runtime 'commons-codec:commons-codec:1.5' } task encode(type: JavaExec, dependsOn: classes) { main = 'org.gradle.example.commandline.MetaphoneEncoder' args = "The rain in Spain falls mainly in the plain".split().toList() classpath sourceSets.main.classesDir classpath configurations.runtime }
自定义task类型
-
在构建文件中定义
task createDatabase(type: MySqlTask) {
sql = 'CREATE DATABASE IF NOT EXISTS example'
}
task createUser(type: MySqlTask, dependsOn: createDatabase) {sql = "GRANT ALL PRIVILEGES ON example.* TO exampleuser@localhost IDENTIFIED BY 'passw0rd'"
}
task createTable(type: MySqlTask, dependsOn: createUser) {username = 'exampleuser' password = 'passw0rd' database = 'example' sql = 'CREATE TABLE IF NOT EXISTS users (id BIGINT PRIMARY KEY, username VARCHAR(100))'
}
class MySqlTask extends DefaultTask {def hostname = 'localhost' def port = 3306 def sql def database def username = 'root' def password = 'password' @TaskAction def runQuery() { def cmd if(database) { cmd = "mysql -u ${username} -p${password} -h ${hostname} -P ${port} ${database} -e " } else { cmd = "mysql -u ${username} -p${password} -h ${hostname} -P ${port} -e " } project.exec { commandLine = cmd.split().toList() + sql }
}
-
在源码树中定义
在构建文件中:
task createDatabase(type: MySqlTask) { sql = 'CREATE DATABASE IF NOT EXISTS example' } task createUser(type: MySqlTask, dependsOn: createDatabase) { sql = "GRANT ALL PRIVILEGES ON example.* TO exampleuser@localhost IDENTIFIED BY 'passw0rd'" } task createTable(type: MySqlTask, dependsOn: createUser) { username = 'exampleuser' password = 'passw0rd' database = 'example' sql = 'CREATE TABLE IF NOT EXISTS users (id BIGINT PRIMARY KEY, username VARCHAR(100))' }
在
buildSrc
文件夹中新建一个MySqlTask.groovy
:import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction class MySqlTask extends DefaultTask { def hostname = 'localhost' def port = 3306 def sql def database def username = 'root' def password = password @TastAction def runQuery(){ def cmd if(database){ cmd = "mysql -u ${username} -p${password} -h ${hostname} -P ${port} ${database} -e" }else{ cmd = "mysql -u ${username} -p${password} -h ${hostname} -P ${port} -e" } project.exec{ commandLine = cmd.split().toList() + sql } } }
四个位置可以写你的自定义构建代码
- 在构建文件中的task代码块中
- 在
buildSr
文件夹中,此文件夹在.gradle文件同级 - 将分散的构建文件写入到主构建文件中
- 使用java或groovy写插件
Gradle 守护进程
Gradle需要运行在一个Java虚拟机中,每一次执行gradle
命令就意味着一个新的Java虚拟机被启动,然后加载Gradle类和库,最后执行构建。这样,构建起来会花费大量的时间在Java虚拟机的启动与关闭。
通过Gradle 守护进程
,只需要启动一次Java虚拟机,之后就可以再利用,无需再次重启Java虚拟机。这样就达到缩短构建时间的目的。
方法是在执行gradle
命令时加上--daemon
参数,或者-m
参数。中止Gradle守护进程的方法是执行gradle -stop
命令。
如果希望能每一次的构建都使用Gradle的守护进程进行,那么可以通过设置Gradle的环境变量来达到目的。方法是添加GRADLE_OPTS="-Dorg.gradle.daemon=true"
`到系统环境变量中。
Gradle的生命周期
- initialization(初始化)
在多项目的构建中,决定哪个项目是主项目 - configuration(配置)
将所有的task对象装配到一个叫做DAG(for directed acyclic graph)的对象模型中 - execution(运行)
根据task之间的依赖执行task
项目的属性
-
项目中默认的属性
version = '1.0'
group = 'Sample'
description = 'Sample build file to show project properties'
task defaultProperties « {println "Project: $project" println "Name: $name" println "Path: $path" println "Project directory: $projectDir" println "Build directory: $buildDir" println "Version: $version" println "Group: $project.group" println "Description: $project.description" println "AntBuilder: $ant" println "customProperty: $customProperty" println "customProperty1: $customProperty1" println "customProperty2: $customProperty2"
}
-
在项目构建脚本中自定义项目属性
ext.customProperty = 'customProperty'
ext {
customProperty1 = "customProperty1" customProperty2 = "customProperty2"
}
-
通过命令行设置项目属性
gradle -Pversion=1.1 -PcustomProperty=custom showProperties
-
通过系统属性设置项目属性
gradle -Dorg.gradle.project.version=2.0 -Dorg.gradle.project.customProperty=custom showProperties
-
通过引用外部配置文件设置项目属性
在项目目录下新建一个纯文本文件:gradle.properties
。在此文件中写入键值对,就可以了。 -
从其它构建文件读取配置信息
- build.gradle
apply from: 'other.gradle' - other.gradle
println “configuring $project”
task hello « {
}println 'hello from other script'
- build.gradle
-
判断项目中是否有设置某个属性
hasProperty('propertyName')
Gradle包装器
可以在机器中没有gradle的情况下,进行构建
依赖管理
在Gradle的构建文件中,可以将一组依赖定义在一个配置里。每一个配置都有一个名字,同时,它可以继承自其它配置。
每一个Gradle构建文件都有一个ConfigurationContainer
对象。可以通过project
属性访问这个对象。ConfigurationContainer
下可以定义一批配置,但它们至少有一个名称。
configurations {
commonsLib {
description = 'Common libraries'
}
mainLib {
description = 'Main libraries'
extendsFrom commonsLib
}
}
println configurations['mainLib'].name
println configurations.commonsLib.name
//取消间接依赖下载
dependencies {
// Configure transitive property with closure.
compile('org.slf4j:slf4j-simple:1.6.4') {
transitive = false
}
// Or we can use the transitive property
// as method argument.
compile group: 'org.slf4j', name: 'slf4j-simple', version:
'1.6.4', transitive: false
}
//排除某个间接依赖
dependencies {
// Configure transitive property with closure.
compile('org.slf4j:slf4j-simple:1.6.4') {
exclude 'org.slf4j:slf4j-api'
}
}
//当依赖需要不同版本的jdk时
dependencies {
// Use artifact-only notation with @ symbol
// together with classifier jdk16.
compile('sample:simple:1.0:jdk16@jar')
// Or we can use the classifier property
// as method argument.
compile group: 'sample', name: 'simple', version: '1.0',classifier: 'jdk16'
}
//依赖其它子项目
dependencies {
compile project(':projectA')
compile project(':projectB') {
c onfiguration = 'compile'
}
}
//依赖文件或文件夹
dependencies {
compile files('spring-core.jar', 'spring-aap.jar')
compile fileTree(dir: 'deps', include: '*.jar')
}
Repository管理
repository支持各种仓库,包括远程和本地的。
repositories {
mavenLocal()
mavenCentral()
maven {
// Name is optional. If not set url property is used
name = 'Main Maven repository'
url = 'http://intranet/repo'
}
mavenRepo(name: 'Snapshot repository', url: 'http://intranet/snapshots')
//XML描述文件和jar包不在同一个地方的时候的定义方式:
maven {
url: 'http://intranet/mvn'
artifactUrls 'http://intranet/jars'
artifactUrls 'http://intranet/snapshot-jars'
}
//有权限控制的仓库
maven(name: 'Secured repository') {
credentials {
username = 'username'
password = 'password'
}
url = 'http://intranet/repo'
}
//本地仓库
repositories {
flatDir(dir: '../lib', name: 'libs directory')
flatDir {
dirs '../project-files', '/volumes/shared-libs'
name = 'All dependency directories'
}
}
}
Gradle常用命令
gradle tasks --all
查看所有的可执行的任务
gradle -m
查看可执行的任务
compile ('com.ali.reactandroid:react_android:0.8.0-SNAPSHOT'){ transitive = true exclude group: 'com.android.support', module: 'support-v4' exclude group: 'com.android.support', module: 'support-v7' }
compile project (':ReactSDK')
//排除maven库指定工程中的间接依赖(测试成功) /* compile (group:'com.android.common',name:'DeviceProject',version:'1.3.143-SNAPSHOT'){ exclude group:'com.het.common',module:'udpcore' }*/ //排除本地工程间接依赖库(测试成功) compile(project(':DeviceProject')) { // transitive = true;//false,取消所以间接依赖下载,true:下载所有间接依赖 exclude group: 'com.het.common', module: 'udpcore'//排除间接依赖 } /* //排除所有的指定库的依赖(写在dependencies里面与外面都测试成功) configurations { all*.exclude group: 'com.het.common', module: 'udpcore' }