2016년 4월 12일 화요일

Writing Build Scripts

The Gradle build language

Gradle은 build를 작성하기 위해 domain specific language를 제공한다.
build language는 Groovy 바탕이며, build를 쉽게 하기 위한 몇가지 사항이 추가된다.

build script는 어떠한 Groovy language 요소를 포함할 수 있다.
그리고, Gradle은 각각의 build script는 UTF-8을 통해 인코딩한다.

The Project API

build의 각각의 프로젝트에서, Gradle은 Project라는 타입의 객체를 생성하고, build script에 그 객체를 연계시킨다.
build script가 실행되면, 이 것은 Project object를 설정한다.

- build script에서 정의되지 않은 method는 Project 객체로 위임되어 처리된다.
- build script에서 정의되지 않은 property는 Project 객체로 위임되어 처리된다.

그럼 아래 예를 보자.


Accessing property of the Project object

build.gradle

apply plugin: 'java'

println name
println project.name

gradle -q check 의 실행 결과

> gradle -q check
projectApi
projectApi

위의 두 개의 println 은 모두 같은 property를 출력한다.
첫 번째 것은 build script안에 정의되지 않은 property들을 위해서, Project object 로의 자동 위임을 사용한다.
다른 것은 build script 에서 사용가능한 project property를 사용한다.
만약 당신이 Project object의 property나 method와 같은 이름의 method나 property를 사용한다면, project property를 사용하게 될 것이다.


Standard project properties

Project object는 build script에서 사용할 수 있는 몇몇의 property들을 제공한다.
아래는 종종 사용되는 것들의 list이다.

Project Properties

Name Type Default Value
project Project The Project instance
name String The name of the project directory.
path String The absolute path of the project.
description String A description for the project.
projectDir File The directory containing the build script.
buildDir File projectDir/build
group Object unspecified
version Object unspecified
ant AntBuilder An AntBuilder instance



The Script API

Gradle이 script를 실행할 때, script를 구현한 class 속으로 현재의 script를 compile한다.
이 것은 class에 포함된 script에 선언된 properties와 method는 당신의 script에서 사용할 수 있다는 것을 의미한다.


Declaring variables

build script에 선언될 수 있는 두가지의 변수가 있다.
local 변수와 extra property이다.


Local variables

로컬 변수는 def keyword에 의해 정의된다.
그 것들은 오직 선언된 곳의 범위에서만 사용 가능하다.
또한 로컬 변수는 Groovy 언어에 의존하고 있다.

Using local variables

build.gradle

def dest = "dest"

task copy(type: Copy) {
    from "source"
    into dest
}


Extra properties

Gradle의 domain model 안에 올라와 있는 object들은 모두 사용자 정의 속성을 저장할 수 있다.
이 것은 project, task, source set 등을 포함한다.
Extra properties 는 더해질 수 있고, 읽혀질 수 있고, object의 ext property를 통해 설정될 수 있다.
ext block은 여러개의 속성을 한번에 추가할 때 사용될 수 있다.


Using extra properties

build.gradle

apply plugin: "java"

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
    }
    plugin {
        purpose = "production"
    }
}

task printProperties << {
    println springVersion
    println emailNotification
    sourceSets.matching { it.purpose == "production" }.each { println it.name }
}
gradle -q printProperties 의 결과
> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

이 예에서, ext block은 두 개의 extra properties를 project 객체에 추가한다.
추가적으로, purpose의 이름을 가진 property는 각각의 source set에 ext.purpose 를 null 로 설정하는 것을 통해 추가된다.
properties가 추가되면, 그것들은 이전에 설정된 값으로 읽혀지게 된다.
property를 추가할 때 특별한 syntax를 요청함으로써, Gradle은 property를 설정하려는 시도가 있을 경우, property가 스펠링이 틀렸거나 존재하지않을때 빠르게 실패할 수 있다.
Extra property는 스스로의 객체에서는 어디에서나 접근할 수 있어, 지역 변수보다 더 넓은 범위를 가능하게 한다.
Extra property 는 subproject에서도 접근이 가능하다. 더 자세한 사항을 위해서, API 문서의 ExtraPropertiesExtension 클래스 부분을 살펴보면 된다.


Configuring arbitrary objects


당신은 매우 읽기 좋은 방법으로 임의 객체를 추가할 수 있다.

Configuring arbitrary objects

build.gradle

task configure << {
    def pos = configure(new java.text.FieldPosition(10)) {
        beginIndex = 1
        endIndex = 5
    }
    println pos.beginIndex
    println pos.endIndex
}

gradle -q configure 의 실행 결과

> gradle -q configure
1
5

Configuring arbitrary objects using an external script

당신은 또한 외부 스크립트를 통해서도 임의 객체를 설정할 수 있다.

Configuring arbitrary objects using a script

billd.gradle

task configure << {
    def pos = new java.text.FieldPosition(10)
    // Apply the script
    apply from: 'other.gradle', to: pos
    println pos.beginIndex
    println pos.endIndex
}

other.gradle

// Set properties.
beginIndex = 1
endIndex = 5

gradle -q configure 의 실행 결과

> gradle -q configure
1
5

Some Groovy basics

Groovy 언어는 DSL을 만들기에 많은 feature를 제공하고 있고, Gradle build language는 이로부터 이점을 얻고 있다.
build language가 어떻게 동작하는 지를 아는 것은 당신이 build script를 쓰는 데에 도움이 되고, 특히 자신만의 plugin과 task를 쓰는 데에 도움이 될 것이다.


Groovy JDK

Groovy는 표준 자바 클래스에 유용한 method들을 많이 추가하였다.
예를 들어, Iterable은 각각의 method를 가져 올 수 있다.


Groovy JDK methods

build.gradle

// Iterable gets an each() method
configurations.runtime.each { File f -> println f }

자세한 사항을 위해서는 http://groovy-lang.org/gdk.html 를 살펴보면 된다.


Property accessors

Groovy 는 property 참조를 자동으로 적합한 getter 나 setter method로 변환한다.

build.gradle

/ Using a getter method
println project.buildDir
println getProject().getBuildDir()

// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')


Optional parentheses on method calls 괄호는 method 호출 시 선택적이다.

build.gradle

test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')


List and map literals

Groovy는 List와 Map 객체를 정의할 수 있는 몇몇의 손쉬운 방법을 제공한다.
두 종류의 literal은 모두 복잡하지 않지만, map literal은 몇몇의 복잡한 부분이 있다.
예를 들어 "apply" method ( 보통 apply plugins에서 사용되는 )는 사실 map 파라미터를 가진다.
하지만, 당신이 “apply plugin:'java'”를 사용할 때에는 실질적으로 당신은 map literal을 사용하는 것이 아니라 "named parameter"를 사용하는 것이다.
이러한 named parameter list는 method가 호출될 때 map을 커버하지만, map으로서 시작하는 것은 아니다.

List and map literals

build.gradle

// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']

List list = new ArrayList()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list

// Map literal.
Map map = [key1:'value1', key2: 'value2']

// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'


Closures as the last parameter in a method


Gradle DSL 은 많은 곳에서 closure를 사용한다.
당신은 여기서 closure에 대한 것을 더 많이 발견할 수 있을 것이다.
method의 마지막 파라미터가 closure일때, method 호출 이후에 당신은 closure를 둘 수 있다.


Closure as method parameter

build.gradle

repositories {
    println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })


Closure delegate

build.gradle

dependencies {
    assert delegate == project.dependencies
    testCompile('junit:junit:4.12')
    delegate.testCompile('junit:junit:4.12')
}


Default imports


build script를 더 간결하게 만들기 위해서 Gradle은 자동으로 중요한 import문을 Gradle script에 추가한다.
이 것은 throw new org.gradle.api.tasks.StopExecutionException() 대신에, throw new StopExecutionException() 를 간단히 사용할 수 있다는 것을 의미한다.
아래에 있는 것은 각각의 script에 추가될 import들이다.

gradle-imports

import org.gradle.*
import org.gradle.api.*
import org.gradle.api.artifacts.*
import org.gradle.api.artifacts.cache.*
import org.gradle.api.artifacts.component.*
import org.gradle.api.artifacts.dsl.*
import org.gradle.api.artifacts.ivy.*
import org.gradle.api.artifacts.maven.*
import org.gradle.api.artifacts.query.*
import org.gradle.api.artifacts.repositories.*
import org.gradle.api.artifacts.result.*
import org.gradle.api.component.*
import org.gradle.api.credentials.*
import org.gradle.api.distribution.*
import org.gradle.api.distribution.plugins.*
import org.gradle.api.dsl.*
import org.gradle.api.execution.*
import org.gradle.api.file.*
import org.gradle.api.initialization.*
import org.gradle.api.initialization.dsl.*
import org.gradle.api.invocation.*
import org.gradle.api.java.archives.*
import org.gradle.api.logging.*
import org.gradle.api.plugins.*
import org.gradle.api.plugins.announce.*
import org.gradle.api.plugins.antlr.*
import org.gradle.api.plugins.buildcomparison.gradle.*
import org.gradle.api.plugins.jetty.*
import org.gradle.api.plugins.osgi.*
import org.gradle.api.plugins.quality.*
import org.gradle.api.plugins.scala.*
import org.gradle.api.plugins.sonar.*
import org.gradle.api.plugins.sonar.model.*
import org.gradle.api.publish.*
import org.gradle.api.publish.ivy.*
import org.gradle.api.publish.ivy.plugins.*
import org.gradle.api.publish.ivy.tasks.*
import org.gradle.api.publish.maven.*
import org.gradle.api.publish.maven.plugins.*
import org.gradle.api.publish.maven.tasks.*
import org.gradle.api.publish.plugins.*
import org.gradle.api.reporting.*
import org.gradle.api.reporting.components.*
import org.gradle.api.reporting.dependencies.*
import org.gradle.api.reporting.model.*
import org.gradle.api.reporting.plugins.*
import org.gradle.api.resources.*
import org.gradle.api.specs.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.ant.*
import org.gradle.api.tasks.application.*
import org.gradle.api.tasks.bundling.*
import org.gradle.api.tasks.compile.*
import org.gradle.api.tasks.diagnostics.*
import org.gradle.api.tasks.incremental.*
import org.gradle.api.tasks.javadoc.*
import org.gradle.api.tasks.scala.*
import org.gradle.api.tasks.testing.*
import org.gradle.api.tasks.testing.junit.*
import org.gradle.api.tasks.testing.testng.*
import org.gradle.api.tasks.util.*
import org.gradle.api.tasks.wrapper.*
import org.gradle.authentication.*
import org.gradle.authentication.http.*
import org.gradle.buildinit.plugins.*
import org.gradle.buildinit.tasks.*
import org.gradle.external.javadoc.*
import org.gradle.ide.cdt.*
import org.gradle.ide.cdt.tasks.*
import org.gradle.ide.visualstudio.*
import org.gradle.ide.visualstudio.plugins.*
import org.gradle.ide.visualstudio.tasks.*
import org.gradle.ivy.*
import org.gradle.jvm.*
import org.gradle.jvm.application.scripts.*
import org.gradle.jvm.application.tasks.*
import org.gradle.jvm.platform.*
import org.gradle.jvm.plugins.*
import org.gradle.jvm.tasks.*
import org.gradle.jvm.tasks.api.*
import org.gradle.jvm.test.*
import org.gradle.jvm.toolchain.*
import org.gradle.language.assembler.*
import org.gradle.language.assembler.plugins.*
import org.gradle.language.assembler.tasks.*
import org.gradle.language.base.*
import org.gradle.language.base.artifact.*
import org.gradle.language.base.plugins.*
import org.gradle.language.base.sources.*
import org.gradle.language.c.*
import org.gradle.language.c.plugins.*
import org.gradle.language.c.tasks.*
import org.gradle.language.coffeescript.*
import org.gradle.language.cpp.*
import org.gradle.language.cpp.plugins.*
import org.gradle.language.cpp.tasks.*
import org.gradle.language.java.*
import org.gradle.language.java.artifact.*
import org.gradle.language.java.plugins.*
import org.gradle.language.java.tasks.*
import org.gradle.language.javascript.*
import org.gradle.language.jvm.*
import org.gradle.language.jvm.plugins.*
import org.gradle.language.jvm.tasks.*
import org.gradle.language.nativeplatform.*
import org.gradle.language.nativeplatform.tasks.*
import org.gradle.language.objectivec.*
import org.gradle.language.objectivec.plugins.*
import org.gradle.language.objectivec.tasks.*
import org.gradle.language.objectivecpp.*
import org.gradle.language.objectivecpp.plugins.*
import org.gradle.language.objectivecpp.tasks.*
import org.gradle.language.rc.*
import org.gradle.language.rc.plugins.*
import org.gradle.language.rc.tasks.*
import org.gradle.language.routes.*
import org.gradle.language.scala.*
import org.gradle.language.scala.plugins.*
import org.gradle.language.scala.tasks.*
import org.gradle.language.scala.toolchain.*
import org.gradle.language.twirl.*
import org.gradle.maven.*
import org.gradle.model.*
import org.gradle.nativeplatform.*
import org.gradle.nativeplatform.platform.*
import org.gradle.nativeplatform.plugins.*
import org.gradle.nativeplatform.tasks.*
import org.gradle.nativeplatform.test.*
import org.gradle.nativeplatform.test.cunit.*
import org.gradle.nativeplatform.test.cunit.plugins.*
import org.gradle.nativeplatform.test.cunit.tasks.*
import org.gradle.nativeplatform.test.googletest.*
import org.gradle.nativeplatform.test.googletest.plugins.*
import org.gradle.nativeplatform.test.plugins.*
import org.gradle.nativeplatform.test.tasks.*
import org.gradle.nativeplatform.toolchain.*
import org.gradle.nativeplatform.toolchain.plugins.*
import org.gradle.platform.base.*
import org.gradle.platform.base.binary.*
import org.gradle.platform.base.component.*
import org.gradle.platform.base.plugins.*
import org.gradle.play.*
import org.gradle.play.distribution.*
import org.gradle.play.platform.*
import org.gradle.play.plugins.*
import org.gradle.play.tasks.*
import org.gradle.play.toolchain.*
import org.gradle.plugin.use.*
import org.gradle.plugins.ear.*
import org.gradle.plugins.ear.descriptor.*
import org.gradle.plugins.ide.api.*
import org.gradle.plugins.ide.eclipse.*
import org.gradle.plugins.ide.idea.*
import org.gradle.plugins.javascript.base.*
import org.gradle.plugins.javascript.coffeescript.*
import org.gradle.plugins.javascript.envjs.*
import org.gradle.plugins.javascript.envjs.browser.*
import org.gradle.plugins.javascript.envjs.http.*
import org.gradle.plugins.javascript.envjs.http.simple.*
import org.gradle.plugins.javascript.jshint.*
import org.gradle.plugins.javascript.rhino.*
import org.gradle.plugins.javascript.rhino.worker.*
import org.gradle.plugins.signing.*
import org.gradle.plugins.signing.signatory.*
import org.gradle.plugins.signing.signatory.pgp.*
import org.gradle.plugins.signing.type.*
import org.gradle.plugins.signing.type.pgp.*
import org.gradle.process.*
import org.gradle.sonar.runner.*
import org.gradle.sonar.runner.plugins.*
import org.gradle.sonar.runner.tasks.*
import org.gradle.testing.base.*
import org.gradle.testing.base.plugins.*
import org.gradle.testing.jacoco.plugins.*
import org.gradle.testing.jacoco.tasks.*
import org.gradle.testkit.runner.*
import org.gradle.util.*


원본 출처 : https://docs.gradle.org/current/userguide/writing_build_scripts.html

댓글 없음 :

댓글 쓰기