Gradle Task 완벽 가이드 - 생성부터 최적화까지
Gradle Task는 빌드 프로세스의 기본 단위입니다. ANT의 target과 유사하며, 프로젝트 객체의 하위 객체입니다.
1. Task 기본 형식
기본 구조
task hello {
doLast {
println 'Hello World'
}
}
// String으로 이름 지정
task "hello" {
}
// 왼쪽 시프트 연산자 (deprecated)
task hello << {
println 'Hello World'
}
프로그래매틱 생성
project.tasks.create("copy", CopyTask.class)
2. 여러 Action 추가
task sampleTask {
println "Configuration" // 항상 실행
doFirst {
println "First action"
}
doLast {
println "Last action"
}
}
// 나중에 추가
sampleTask.doFirst { println "Added first action" }
sampleTask.doLast { println "Added last action" }
실행 순서: doFirst (역순) -> doLast (순서대로)
3. Task 속성
tasks // 태스크 리스트
name // 태스크 이름
path // 태스크 경로
description // 설명 (gradle tasks 출력 시 표시)
설명 추가
task copy(type: Copy) {
description 'Copies resources to target directory.'
from 'resources'
into 'target'
}
경로로 태스크 접근
tasks.getByPath('projectA:hello').path
4. 의존성 설정
기본 의존성
task taskX << {
println 'taskX'
}
task taskY(dependsOn: 'taskX') << {
println 'taskY'
}
// 여러 의존성
task task1(dependsOn: [task2, task3])
나중에 의존성 추가
taskY.dependsOn taskX
taskY.dependsOn taskX, taskZ
// 기존 의존성 덮어쓰기
classes { dependsOn = [task1, task2] }
// 조건부 의존성
taskX.dependsOn {
tasks.findAll { task -> task.name.startsWith('lib') }
}
5. Task 순서 제어
finalizedBy
태스크 실행 후 다른 태스크 실행:
task5.finalizedBy task6
mustRunAfter
실행할 태스크가 있으면 반드시 그 후에 실행:
task5.mustRunAfter task4
shouldRunAfter
mustRunAfter와 유사하지만 순환 의존성 시 무시됨:
task5.shouldRunAfter task4
6. Task 스킵
enabled 속성
sampleTask.enabled = false
onlyIf 조건
ext {
environment = 'prod'
}
task prodTask << {
println 'Executing prod tasks ' + environment
}
prodTask.onlyIf {
project.hasProperty('environment') && project.environment == 'prod'
}
StopExecutionException
eclipse.doFirst {
if (!usingEclipse) {
throw new StopExecutionException()
}
}
7. Task 최적화
입력과 출력이 변경되지 않으면 UP-TO-DATE로 스킵됩니다.
입출력 정의
task updateExample {
ext {
propXml = file('PropDetails.xml')
}
File envFile = file('envproperty.txt')
File sysFile = file('sysproperty.txt')
inputs.file propXml
outputs.files(envFile, sysFile)
doLast {
println "Generating Properties files"
// 처리 로직
}
}
최적화 무시
gradle --rerun-tasks taskName
8. 동적 Task (Rule)
tasks.addRule("Pattern: sync<repoServer>") { String taskName ->
if (taskName.startsWith("sync")) {
task(taskName) << {
println "Syncing from: " + (taskName - 'sync')
}
}
}
사용:
gradle syncProduction
gradle syncStaging
9. 내장 Task 타입
Copy
task copyTask(type: Copy) {
from "."
into "abc"
include('employees.xml')
}
task copyWithRename(type: Copy) {
from "."
into "dir1"
include('employees.xml')
rename { String fileName ->
fileName.replace("employees", "abc")
}
}
Zip
task zipTask(type: Zip) {
archiveName "sample.zip"
from "src"
destinationDir file("dest")
}
Delete
task clean(type: Delete) {
delete rootProject.buildDir
}
태스크 내에서 copy
variant.assemble.doLast {
copy {
from variant.mappingFile
into "${rootDir}/mappingFiles"
rename { String fileName ->
"mapping-${variant.name}.txt"
}
}
}
10. Custom Task 생성
같은 빌드 스크립트 내
class SampleTask extends DefaultTask {
String systemName = "DefaultMachineName"
String systemGroup = "DefaultSystemGroup"
@TaskAction
def action1() {
println "System Name is " + systemName + " and group is " + systemGroup
}
@TaskAction
def action2() {
println 'Adding multiple actions'
}
}
task hello(type: SampleTask)
hello {
systemName = 'MyDevelopmentMachine'
systemGroup = 'Development'
}
hello.doFirst { println "Executing first" }
hello.doLast { println "Executing last" }
실행 순서: doFirst -> TaskAction -> doLast
buildSrc에서 정의
{projectDir}/buildSrc/src/main/groovy/ch3/SampleTask.groovy:
package ch3
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class SampleTask extends DefaultTask {
String systemName = "DefaultMachineName"
@TaskAction
def action() {
println "System Name is " + systemName
}
}
build.gradle:
task hello(type: ch3.SampleTask) {
systemName = 'MyMachine'
}
별도 프로젝트로 분리
SampleTaskProj/build.gradle:
apply plugin: 'groovy'
version = 1.0
dependencies {
compile gradleApi()
compile localGroovy()
}
다른 프로젝트에서 사용:
buildscript {
repositories {
flatDir { dirs "../SampleTaskProj/build/libs" }
}
dependencies {
classpath group: 'ch3', name: 'SampleTaskProj', version: '1.0'
}
}
task hello(type: ch3.SampleTask)
11. 명령어 실행
exec
exec {
executable 'open'
args '-a', 'Safari', "http://localhost:$debug_port"
}
javaexec
javaexec {
main = "-jar"
args = [
"fitnesse-standalone.jar",
"-c", "FrontPage?suite&format=text"
]
}
task runJar(dependsOn: jar) << {
javaexec { main = "-jar"; args jar.archivePath }
}
12. Listener
project.gradle.addListener(new TimeTrace())
class TimeTrace implements TaskExecutionListener, BuildListener {
private Clock clock
private times = []
@Override
void buildStarted(Gradle gradle) {}
@Override
void settingsEvaluated(Settings settings) {}
@Override
void projectsLoaded(Gradle gradle) {}
@Override
void projectsEvaluated(Gradle gradle) {}
@Override
void buildFinished(BuildResult result) {
println "Task spend time:"
for (time in times) {
if (time[0] > 50) {
printf "%7sms %s\n", time
}
}
}
@Override
void beforeExecute(Task task) {
clock = new Clock()
}
@Override
void afterExecute(Task task, TaskState state) {
def ms = clock.timeInMs
times.add([ms, task.path])
task.project.logger.warn("${task.path} spend ${ms}ms")
}
}
13. 프로파일링
./gradlew assembleDebug --profile
결과: build/reports/profile-[date-of-your-build]
Comments