Gradle学习

来源:互联网 发布:js点击小图查看大图 编辑:程序博客网 时间:2024/05/22 06:26


目录[-]

  • 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本身没有创建项目的命令。最好的解决方案就是使用第三方插件来实现。步骤:

    1. 新你的项目的文件夹project
    2. 进入文件项目文件夹添加文件build.gradle,并加入:
      apply from: 'http://www.tellurianring.com/projects/gradle-plugins/gradle-templates/1.3/apply.groovy'
    3. 运行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应用程序

    1. 使用application插件:apply plugin: 'application'
    2. 设置主函数:mainClassName = "WebTest"
    3. 运行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 initializeDatabaseinitializeDatabase << { 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 welltask loadTestData {    dependsOn createSchema}// An alternate way to express the same dependencytask loadTestData {    dependsOn << createSchema}// Do the same using single quotes (which are usually optional)task loadTestData {    dependsOn 'createSchema'}// Explicitly call the method on the task objecttask loadTestDataloadTestData.dependsOn createSchema// A shortcut for declaring dependenciestask loadTestData(dependsOn: createSchema)

    还可以多重依赖

    // Declare dependencies one at a timetask loadTestData {    dependsOn << compileTestClasses    dependsOn << createSchema}// Pass dependencies as a variable-length listtask world {    dependsOn compileTestClasses, createSchema}// Explicitly call the method on the task objecttask worldworld.dependsOn compileTestClasses, createSchema// A shortcut for dependencies only// Note the Groovy list syntaxtask 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:setupDatabaseTestsdrop database schemacreate database schemaload 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 loadTestDatacreate database schema:loadTestData SKIPPED$ gradle -Dload.data=true loadTestData:createSchemacreate database schema:loadTestDataload 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 << printTaskNamefirst.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 = 3306def sqldef databasedef username = 'root'def password = 'password'@TaskActiondef 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.DefaultTaskimport org.gradle.api.tasks.TaskActionclass 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        }    }}

    四个位置可以写你的自定义构建代码

    1. 在构建文件中的task代码块中
    2. buildSr文件夹中,此文件夹在.gradle文件同级
    3. 将分散的构建文件写入到主构建文件中
    4. 使用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的生命周期

    1. initialization(初始化)
      在多项目的构建中,决定哪个项目是主项目
    2. configuration(配置)
      将所有的task对象装配到一个叫做DAG(for directed acyclic graph)的对象模型中
    3. 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'
        }
    • 判断项目中是否有设置某个属性

      hasProperty('propertyName')

    Gradle包装器

    可以在机器中没有gradle的情况下,进行构建

    依赖管理

    在Gradle的构建文件中,可以将一组依赖定义在一个配置里。每一个配置都有一个名字,同时,它可以继承自其它配置。

    每一个Gradle构建文件都有一个ConfigurationContainer对象。可以通过project属性访问这个对象。ConfigurationContainer下可以定义一批配置,但它们至少有一个名称。

    configurations {    commonsLib {        description = 'Common libraries'    }    mainLib {        description = 'Main libraries'        extendsFrom commonsLib    }}println configurations['mainLib'].nameprintln 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 查看可执行的任务


    原文 http://my.oschina.net/zjzhai/blog/220028

    0 0
    原创粉丝点击