====== Gradle Task ======
* [[http://www.gradle.org/docs/current/dsl/index.html|DSL API에서 Task types]]를 확장해서 사용할 수 있다.
* 빌드 파일에는 이미 수많은 gradle 관련 패키지가 기본 import 된 상태이다. 따라서 gradle 관련 클래스 사용시 import 할 필요가 없는 경우가 많다. [[http://www.gradle.org/docs/current/userguide/ide_support.html|Using Gradle without IDE support]] 참조.
* [[http://www.gradle.org/docs/current/userguide/more_about_tasks.html|More about tasks]]
===== 선언 =====
task hello << {
println "hello"
}
// 괄호하고 이름
task(hello) << {
println "hello"
}
task(copy, type: Copy) {
from(file('srcDir'))
into(buildDir)
}
// 이름을 문자열로
task('hello') <<
{
println "hello"
}
// tasks 에 추가
tasks.add(name: 'taskName', type: org.something.GradleTask, dependsOn: 'anotherTask') {
// task 설정
println "hello"
}
// with create
tasks.create(name: 'taskName', type: org.something.GradleTask, dependsOn: 'anotherTask') {
// task 설정
}
===== 태스크 정보 설정 =====
* Task의 description과 group을 지정하면 ''gradle tasks'' 시에 정보를 표시해 준다.
* group은 마음대로 정할 수 있지만, 기본적으로 ''build'' 등이 있다.
dist {
description = '태스크 설명'
group = '태스크의 그룹'
}
// 혹은
dist.description = '태스크 설명'
dist.group = '태스크의 그룹'
* 동적 프라퍼티 설정
task something {
ext.prop1 = 'xxx'
ext.prop2 = 'yyy'
}
// 외부에서 something.prop1 으로 접근 가능
===== task에 접근하기 =====
* ''task hello''가 있을 때,
* ''hello.name''
* ''project.hello.name''
* ''tasks.hello.name''
* ''tasks['hello'].name''
* ''tasks.getByPath()''로 접근
project(':projectA') {
task hello
}
task hello
println tasks.getByPath('hello').path // :hello
println tasks.getByPath(':hello').path // :hello
println tasks.getByPath('projectA:hello').path // :projectA:hello
println tasks.getByPath(':projectA:hello').path // :projectA:hello
===== task 설정 =====
* [[http://www.gradle.org/docs/current/dsl/index.html|DSL API에서 Task types]] 생성하기
* 설정하기
// 단일 선언
task myCopy(type: Copy)
// 태스크의 메소드 호출 등으로 설정하기 1
Copy myCopy = task(myCopy, type: Copy)
myCopy.from 'resources'
myCopy.into 'target'
myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')
// 설정 2
task(myCopy, type: Copy)
.from('resources')
.into('target')
.include('**/*.txt', '**/*.xml', '**/*.properties')
// 설정 3
task myCopy(type: Copy)
myCopy {
from 'resources'
into 'target'
include('**/*.txt', '**/*.xml', '**/*.properties')
}
// 설정 4, configure() 메소드
task myCopy(type: Copy)
myCopy.configure {
from('source')
into('target')
include('**/*.txt', '**/*.xml', '**/*.properties')
}
// 설정 5. 선언시
task copy(type: Copy) {
from 'resources'
into 'target'
include('**/*.txt', '**/*.xml', '**/*.properties')
}
* 의존성 설정
// 다른 프로젝트의 태스크
project('projectA') {
task taskX(dependsOn: ':projectB:taskY') << {
println 'taskX'
}
}
// 나중에 설정
taskX.dependsOn taskY
// 여러 태스크에 의존
taskX.dependsOn ['taskY', 'taskZ']
// 이름을 리턴하는 클로저를 통한 다중 설정
taskX.dependsOn {
tasks.findAll { task -> task.name.startsWith('lib') }
}
* 설명(description) 추가 : 태스크에 ''description'' 프라퍼티를 설정하면 ''gradle tasks''에서 볼 수 있게 된다.
* 태스크 대체 : 플러그인에서 생성한 태스크를 개발자가 원하는 것으로 대체하길 원하거나 할 때 사용 ''overwrite: true''
task copy(type: Copy)
task copy(overwrite: true) << {
println('I am the new one.')
}
===== 태스크 건너 뛰기 =====
* ''onlyIf''
// hello task에 대해
hello.onlyIf { !project.hasProperty('skipHello') }
// 실행시 skipHello 프라퍼티 지정
gradle hello -PskipHello
* [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/StopExecutionException.html|StopExecutionException]] 예외를 던지면, 해당 지점부터 그 태스크는 실행이 안되고 건너뛴다. 그 이후 실행할 태스크는 계속 실행된다.
task compile << {
println 'We are doing the compile.'
}
compile.doFirst {
// if문에 원하는 조건을 지정한다.
if (true) { throw new StopExecutionException() }
}
task myTask(dependsOn: 'compile') << {
println 'I am not affected'
}
* ''task.enabled=true|false'' 이 값이 true여야만 해당 태스크가 실행된다.
===== 이미 최신으로 갱신된 태스크 건너뛰기 =====
* 자바 컴파일 태스크 같은 경우 이미 모든 최신 java 파일이 컴파일 돼 있다면 건너뛰는 기능이 있다. 이 같은 것을 구현하는 방법.
* 모든 태스크에는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskInputs.html|TaskInputs]] ''inputs''와 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskOutputs.html|TaskOutputs]] ''outputs'' 프라퍼티가 있다. 이 값을 설정해주면 자동으로 UP-TO-DATE인지 검사하여 실행 여부를 결정한다.
task transform {
ext.srcFile = file('mountains.xml')
ext.destDir = new File(buildDir, 'generated')
inputs.file srcFile
outputs.dir destDir
doLast {
println "Transforming source file."
destDir.mkdirs()
// outputs.dir 영역에 파일을 생성하는 코드..
}
}
* 작동방식
* 태스크 실행시작시 inputs에 있는 파일의 스냅샷을 찍는다.
* 태스크 실행후 outputs에 있는 파일의 스냅샷을 찍는다.
* 태스크를 재실행할 때 이전 inputs, outputs의 스냅샷과 현재 inputs와 outputs의 스냅샷을 비교하여 변경 사항이 없으면 해당 태스크를 건너뛴다. 아니면 태스크를 실행하고 모든 스냅샷을 다시 찍는다.
==== 멀티 프로젝트에서 각 프로젝트 별 최신 갱신 여부 검사 ====
inputs/outputs를 사용하여 VCS에서 받은 멀티 프로젝트의 프로젝트별 갱신 여부를 검사할 수 있다.
task checkUpToDate {
description = '프로젝트 최신 갱신 여부 검사'
def checkFile = file(new File(tmpDir, "gradle_${project.name}_check_up_to_date").absoluteFile)
FileTree projectFileTree = fileTree(dir: project.projectDir)
projectFileTree.exclude "${builDir}/**/*"
inputs.files projectFileTree
outputs.file checkFile
doLast {
println "[${project.name}] needs refresh."
if (checkFile.exists()) {
checkFile.delete()
}
checkFile.createNewFile()
}
}
===== Task Rules =====
* ''tasks.addRule'' 태스크 생성 규칙을 통해 동적으로 태스크를 만들어낼 수 있다.
tasks.addRule("Pattern: ping") { String taskName ->
if (taskName.startsWith("ping")) {
task(taskName) << {
println "Pinging: " + (taskName - 'ping')
}
}
}
// Rule에 대해 의존성을 지정하는 것도 가능하다.
task groupPing {
dependsOn pingServer1, pingServer2
}
===== 태스크의 실행 순서 =====
* 태스크에 ''dependsOn [a, b]'' 형태로는 실행 순서를 지정할 수 없다. dependsOn 은 의존 대상을 명시할 뿐 의존 대상의 실행순서는 명시하지 않는다.
* 기존방법 : 다음과 같은 방식으로 순서를 명확히 하는 것도 가능하다.
task somethingLastTask << {
tasks.somethingFirstTask.execute()
tasks.somethingSecondTask.execute()
....
// do somthing last
}
* 새로운 방법(2015년 1월 현재 incubating) :
// 보통은 task1 -> task2 순서로 실행하지만 특정 상황에서는 이를 무시한다.
task2.shouldRunAfter task1
// 무조건 task1 -> task2 순서를 지킨다.
task2.mustRunAfter task1
===== tasks =====
* ''tasks''는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskContainer.html|TaksContainer]]의 인스턴스이며 이는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskCollection.html|TaskCollection]] 인터페이스를 상속한다.
* [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskCollection.html#withType%28java.lang.Class%29|TaskCollection.withType]] ''tasks.withType(TaskType) { ... }'' 을 사용하여 특정 태스크 타입에 대한 공통 설정을 수행할 수 있다.
===== UP-TO-Date upToDate 조건 =====
* [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskOutputs.html#upToDateWhen%28org.gradle.api.specs.Spec%29|TaskOutputs.upToDateWhen]]을 통해 upToDate 검사 조건을 변경할 수 있다.
* 태스크를 무조건 실행하게 만들고자 한다면 Up to date 검사를 안하게 만들면 된다.
// 태스크 선언부에서 아래와 같은 형태를 띄게 된다.
task someTask {
outputs.upToDateWhen { false }
doLast {
...
}
}
===== --rerun-tasks =====
* ''--rerun-tasks'' 옵션을 주면 up-to-date 상태와 무관하게 무조건 태스크를 실행한다.
===== Task 실행에서 제외 =====
* "aaa" 태스크 실행시 "bbb" 태스크가 의존성에 걸려있더라도 실행을 하지 않고 건너뛰게 해야하는 경우가 있다.
gradle.taskGraph.whenReady { taskGraph ->
def tasks = taskGraph.allTasks
// 태스크 실행 그래프에 'aaa'가 들어있으면
if (tasks.find { it.name.toLowerCase() == 'aaa'}) {
bbb.enabled = false // bbb 태스크를 skip 한다. 로그상에 SKIP으로 뜸
}
}
===== 참조 =====
* [[http://mrhaki.blogspot.com/2018/05/gradle-goodness-command-line-options.html|Gradle Goodness: Command Line Options For Custom Tasks - Messages from mrhaki]]