Gradle 테스크 생성
테스크 정의
Gradle은 명령에 의해 “테스크(task)“을 수행하는 프로그램이다. 지금까지 gradle compileJava
라든지 gradle run
와 같은 명령을 사용하였는데, 이들도 모두 “compileJava 테스크 수행”, “run 테스크 수행"이라는 것이다.
테스크 정의 기본
이 테스크는 사용자가 정의할 수 있다. 빌드 파일(build.gradle)에서 테스크의 처리를 기술해두면, 그것을 gradle 명령으로 호출 실행 시킬 수 있다.
테스크는 다음과 같은 형태로 정의한다.
task 테스크명 {
...... 수행할 처리 ......
}
테스크는 “task"라는 키워드를 사용하여 정의한다. 이 후에 테스크명을 작성하고, 그 다음에 {} 내에 테스크의 내용을 작성한다. 테스크 선언는 다른 작성법도 있는데, 다음과 같은 작성도 가능하다.
task (테스크명) {...}
task ('테스크명') {...}
이것으로 {} 안에 기술된 처리를 실행하는 작업을 정의할 수 있다. 그럼 실제로 해 보도록 하자.
build.gradle 아래 부분에, 아래와 같이 코드를 추가한다.
task hello {
println('이것은 hello 테스크 실행한 것이다')
}
그리고 파일을 저장하고, 명령 프롬프트 또는 터미널에서 다음과 같이 실행한다.
$ gradle hello
이것으로 hello 테스크가 실행된다. 실행해 보면, println으로 출력하는 문장 이외에도 다양한 문장이 출력된다.
Starting a Gradle Daemon (subsequent builds will be faster)
> Configure project :
이것은 hello 테스크 실행한 것이다
BUILD SUCCESSFUL in 16s
이는 “quiet 모드"로 테스크를 수행하면 많은 부분이 사라진다. -q
옵션을 지정하고 아래 같이 실행한다.
$ gradle -q hello
이로 표시되는 출력은 상당히 심플하게 될 것이다.
이것은 hello 테스크 실행한 것이다
doFirst와 doLast
테스크는 이렇게 task 후에 {} 부분에 처리를 쓰는 것만으로 만들 수 있다. 사실 보통은 이런 작성법은 많이 쓰지 않는다.
일반적인 테스크의 형태를 정리하면, 대체로 다음과 같은 형태가 된다.
task 테스크명 {
doFirst {
...... 수행할 처리 ......
}
doLast {
...... 수행할 처리 ......
}
}
태스크 {} 에는 doFirst, doLast 라는 것이 준비된다. 이것은 일종의 클로저이다. 이들은 각각 다음과 같은 기능을 한다.
- doFirst : 최초에 수행하는 액션이다.
- doLast : 최후에 수행 하는 액션이다.
테스크는 준비된 “액션"을 순서대로 실행해 나가는 역할을 한다. 액션이라는 것은 구체적으로 수행하는 처리의 “실행 단위” 같은 것이다. 테스크 중에는 여러 가지 액션이 준비되어 있고, 그것이 순차적으로 실행된다.
doFirst과 doLast는 그 액션의 최초, 최후에 실행한다. 즉, “테스크의 기본적인 처리 등이 있을 때는 그 전에 실행하는 것과 후에 실행하는 것"을 이렇게 준비한다.
이는 2개를 세트로 준비할 필요는 없다. 어느 한쪽만으로도 괜찮다.
그러면 실제로 간단한 예를 움직여 보자.
task hello {
doLast {
println('이것은 hello 태스크의 doLast이다.')
}
doFirst {
println('이것은 hello 태스크의 doFirst이다.')
}
}
아래 목록 아래처럼 hello 작업을 다시 시도한다. 그리고 gradle hello
를 실행한다. 그러면 다음과 같이 출력된다.
> Task :hello
이것은 hello 태스크의 doFirst이다.
이것은 hello 태스크의 doLast이다.
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
샘플은 doLast 먼저, doFirst가 후에 쓰여져 있지만, 실행 결과를 보면, 우선 doFirst이 실행된 후에 doLast가 실행되고 있는 것을 알 수 있다.
매개 변수 전달
태스크는 수행할 때 필요한 값을 매개 변수로 전달할 수 있다. 단순히 작업 처리 중 변수를 사용하면 된다. 예를 들어, 다음과 같다.
task msg {
println("you typed: " + x)
}
여기에서는 println으로 변수 x의 값을 표시하고 있다. 이 변수 x에 값을 설정하려면 gradle 명령을 실행시에 다음과 같이 입력한다.
$ gradle msg -Px=값
이렇게 -P
후에 변수명을 지정하고 그 뒤에 등호로 값을 지정한다. 변수 hoge에 123 값을 전달 싶다면 -Phoge=123
식으로 기술하면 된다.
사용 예제는 아래와 같다. 이는 숫자를 전달하여 그 숫자까지를 더하는 예제이다.
task hello {
doLast {
def n = max.toInteger()
for(def i in 1..n){
println("No," + i + " count.")
}
println("--end.")
}
}
테스크는 “max"라는 변수를 사용하여 최대 값을 지정한다. 예를 들어,
$ gradle hello -Pmax=5
이렇게 실행하면, 다음과 같이 메시지가 출력된다.
> Task :hello
No,1 count.
No,2 count.
No,3 count.
No,4 count.
No,5 count.
--end.
여기에서는 def n = max.toInteger()
와 같이 하여 변수 max를 정수 값으로 변환한 것을 변수 n에 대입하고 있다. 그리고 이 n 값을 이용하여 for으로 반복 계산을 실시하고 있다. 이런 상태로 매개 변수를 사용하여 쉽게 값을 변수로 전달할 수 있다.
다른 테스크 호출 및 종속
다른 테스크 호출
테스크에서 다른 테스크를 호출해야 하는 경우도 있다. 예를 들어 아래와 같은 테스크가 있다고 해보자.
task a {...}
task b {...}
a와 b라는 테스크가 있을 때, 테스크 a에서 테스크 b를 호출하려면 어떻게 해야 하는가? Java적으로 생각한다면 아래와 같이 호출하면 될거라 생각할 것이다.
b()
하지만 이렇게는 작동을 하지 않는다. 그럼 어떻게 해야 하는가? 그것은 “tasks"에 있는 작업 객체 안의 메소드를 호출하여 수행한다.
작업하는 것은 모든 tasks라고 객체에 정리하고 있다. 이것은 예를 들어 a, b라는 테스크가 있다면 tasks.a과 tasks.b로 지정할 수 있다. 이 테스크 객체 안에 있는 “execute"라는 메소드를 호출하여 테스크를 수행할 수 있다.
tasks.a.execute()
tasks.b.execute()
이런 식으로 실행하여 테스크 a, b를 호출한다.
간단한 사용 예제는 아래와 같다.
task hello {
doFirst {
println("*** start:hello task ***")
tasks.aaa.execute()
}
doLast {
tasks.bbb.execute()
println("*** end:hello task ***")
}
}
task aaa {
doLast {
println("<< This is A task! >>")
}
}
task bbb {
doLast {
println("<< I'm task B!! >>")
}
}
gradle hello
와 같이 hello 태스크를 실행해 보면, 아래와 같이 출력이 된다.
> Task :hello
*** start:hello task ***
<< This is A task! >>
<< I'm task B!! >>
*** end:hello task ***
여기에서는 hello의 doFirst 안에서 aaa, doLast에서 bbb를 호출하고 있다. 출력되는 텍스트가 호출되는 순서를 잘 확인한다.
종속 테스크 지정
어떤 테스크를 수행할 때, 다른 작업 수행이 필수적인 경우도 있다. 이러한 경우에는 “dependsOn ‘라는 기능을 사용할 수 있다. 이는 다음과 같이 작성한다.
task 테스크명 (dependsOn : '테스크') {
...... 중략 ......
}
또는 다음과 같은 작성도 가능하다.
task 테스크명 {
dependsOn : '테스크'
...... 중략 ......
}
이와 같이 기술해 두면 작업이 호출될 때, 먼저 dependsOn에 지정된 작업을 수행하고 그것이 끝난 후에 테스크의 본 처리를 수행한다.
여러 테스크를 지정해야 하는 경우는 테스크명을 배열로 지정한다. [ ‘a’, ‘b’, ‘c’]와 같은 식이다. 이 경우 최초에 작성한 테스크부터 실행된다.
아래 목록 필드에 사용할 예제는 아래와 같다.
task hello(dependsOn:['aaa', 'bbb']) {
doFirst {
println("*** start:hello task ***")
}
doLast {
println("*** end:hello task ***")
}
}
task aaa {
doLast {
println("<< This is A task! >>")
}
}
task bbb {
doLast {
println("<< I'm task B!! >>")
}
}
이를 “gradle hello"로 실행한다. 다음과 같이 출력이 된다.
> Task :aaa
<< This is A task! >>
> Task :bbb
<< I'm task B!! >>
> Task :hello
*** start:hello task ***
*** end:hello task ***
최초에 aaa 테스크, bbb 테스크이 실행되면, 이후에 hello 태스크가 호출되었는지 알 수 있다. dependsOn에 의해, aaa, bbb가 종속 테스크가 되는 테스크가 실행된 후가 아니면 hello가 실행되지 않게 된다.