Gradle DefaultTask 클래스 사용

Gradle은 표준으로 DefaultTask 클래스가 준비되어 있으며,이를 상속한 Task 클래스가 준비되어 있다. 이러한 목적을 위해 테스크 생성에 대해 설명한다.

DefaultTask 상속 클래스

Gradle은 표준으로 다양한 테스크가 포함되어 있는데, 이것들은 “DefaultTask"라는 클래스를 상속한 클래스로 준비되어 있다. 이 DefaultTask 상속 클래스는 자신의 테스크을 만들어 커스텀 마이징을 할 수 있다.

우선은 “DefaultTask 상속 클래스"가 어떤 것인지 직접 만들어 본다. 이 클래스는 다음과 같은 형태로 정의된다.

class 클래스 extends DefaultTask {
    ...... 필드 ......

    void 메소드(인수) {
        ...... 처리 ......
    }

    @TaskAction
    void 메소드() {
        ...... 처리 ......
    }
}

클래스는 DefaultTask라는 클래스를 상속하여 만든다. 이 클래스 내에 테스크로 수행할 처리를 메소드로 제공한다. 이 메소드에는 @TaskAction 어노테이션을 붙여 둔다. 그러면 테스크로 실행되었을 때, 이 메소드가 호출된다.

테스크로 사용하는 각종의 값은 필드로 사용할 수 있어야 한다. 이것은 그대로 이용해도 되지만, 외부에서 사용하는 경우는 private 필드로 설정하여 접근을 위한 메소드를 따로 제공하는 것이 스마트하다.

다음에 간단한 클래스의 예제는 아래와 같다.

class Calc extends DefaultTask {
    private int num
    private String op
 
    void num(p1){
        num = p1
    }
 
    void op(p1){
        op = p1
    }
 
    @TaskAction 
    void calc() {
        switch(op) {
        case 'total':
            int total = 0
            for(def i in 1..num) {
                total += i
            }
            println("total: ${total}")
        break
 
        case 'count':
            for(def i in 1..num) {
                println("NO, ${i}")
            }
        break
 
        default:
            println('not found operator...')
        }
    }
}

Calc 클래스에는 calc 라는 테스크 액션을 준비하고 있다. 여기에서 num와 op의 값에 따라 총의 계산과 수치 계산을 하고 있다.

Calc 클래스를 지정한 테스크

그럼, DefaultTask 상속 클래스를 이용하는 테스크는 어떻게 작성할 수 있을까? 그 작성법은 아래와 같다.

task 테스크(type : 클래스) {
    ...... 수행할 처리 ......
}

테스크의 ()에는 인수로 ’type’ 값을 준비하고, 이 type에서 사용하는 클래스를 지정하다.

실제로 수행하는 처리에는 사용하는 클래스에 필드로 준비되어 있는 변수에 값을 할당하는 처리를 준비해 둔다. 이렇게 하면, 클래스의 각 필드의 값을 변경하여 테스크 메소드를 실행할 수 있다.

간단한 사용 예를 아래에 같다.

task total(type:Calc) {
    group 'devkuma'
    description 'Task for calculating total.'
    num 100
    op 'total'
}
 
task count(type:Calc) {
    group 'devkuma'
    description 'Task for count number.'
    num 10
    op 'count'
}

여기에서는 앞 전에 Calc 클래스를 type에 지정한 total, count라는 두 가지 테스크를 만들었다. gradle total라고 실행하면 100까지의 합계가 계산된다.

$ gradle total

> Task :total
total: 5050


BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

“gradle count"라고 실행하면 1 ~ 10까지의 숫자를 순서대로 출력한다.

$ gradle count

> Task :count
NO, 1
NO, 2
NO, 3
NO, 4
NO, 5
NO, 6
NO, 7
NO, 8
NO, 9
NO, 10


BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

여기에서는 테스크의 인수로 (type:Calc)을 지정하고 있다. 그러면 Calc 클래스의 테스크를 수행하는 테스크으로 정의될 수 있다. 여기에는 다음과 같은 문장이 작성되어 있다.

group 그룹명
description 설명
num 정수
op 조작의 유형

이들은 모두 상속의 Calc 클래스에 있는 메소드를 호출하는 것이다. group과 description은 DefaultTask 클래스에 있는 것으로, 각 그룹명과 설명 텍스트를 설정한다.

그리고 Calc 클래스에 준비되어 있는 num와 op으로 계산의 정수 값와 작업의 유형을 지정하고 있다.

이런 식으로 task로 정의된 가운데, type 지정한 클래스의 메서드를 호출하여 필요한 설정을 한다. 그러면, 그 설정이 된 후에 태스크 액션이 수행된다.

JavaExec 클래스 이용

DefaultTask 상속 클래스를 사용한 테스크 작성의 기본이 알았으니, Gradle에 제공되는 주요 DefaultTask 상속 클래스에 대한 사용법을 살펴보기로 한다.

JavaExec 클래스

JavaExec는 Java 프로그램의 실행을 위한 테스크를 구현하는 클래스이다. 이 클래스에는 실행에 필요한 각종 메소드가 준비되어 있다. 중요한 것을 아래 정리해 두었다.

main "클래스"

실행하는 클래스를 지정하는 메소드이다. 클래스명을 텍스트로 인수로 지정하여 호출한다.

classpath "텍스트"

여기에서는 실행 시에 classpath로 지정하는 텍스트를 설정한다. 디폴트 classpath 로 좋다면, sourceSets.main.runtimeClasspath라는 값을 지정해 둔다.

args "Iterator"
args "값1, 값2, ..."

인수로 전달할 정보를 지정하는 것이다. 이것은 Iterator로 정리하여 준비할 수 있으며, 부정 인수로 필요한 값을 개별적으로 인수에 지정할 수도 있다.

jvmArgs "Iterator"
jvmArgs "값1, 값2, ..."

여기에서는 Java 가상 머신에 전달되는 인수를 지정한다. 이것도 역시 Iterator와 같은 이상한 인수가 준비되어 있다.

workingDir "텍스트"

작업 디렉터리를 지정하는 것이다. 인수에는 설정하고자 하는 디렉터리의 경로를 지정한다. 이것은 프로젝트 폴더에서의 상대 경로로 지정한다.

그럼, 이 JavaExec을 이용한 테스크의 예를 들어 둔다.

task appRun(type: JavaExec) {
    group 'devkuma'
    description 'exec App class.'
    main 'App'
    classpath sourceSets.main.runtimeClasspath
     
    doFirst {
        println()
        println('---------- Start ----------')
        println()
    }
    doLast {
        println()
        println('----------- end -----------')
        println()
    }
}

여기에서는 App 클래스를 실행하는 appRun 작업을 만들었다. gradle appRun라고 실행하면 콘솔에 다음과 같이 출력된다.

$ gradle appRun

> Task :appRun

---------- Start ----------

Hello world.

----------- end -----------

Gradle에서의 실행은 다양한 출력이 있어 실행 결과를 알아보기 어렵기에, doFirst과 doLast으로 텍스트를 출력해서 한눈에 “이것이 실행 내용"이라고 알 수 있도록 해본다. 여기에서는 다음과 같이 ExecJava 설정을 하고 있다.

main 'App'
classpath sourceSets.main.runtimeClasspath

일단 main과 classpath 만 준비한다. 이 2개는 디폴트로 값이 설정되어 있지 않아서 생략할 수도 없다. 그 외의 것은 디폴트인 상태로도 문제가 없을 것이다.

커멘드를 실행하는 Exec 이용

프로젝트에서 작성하고 있는 Java 프로그램이 아닌, 다른 프로그램을 실행하려는 경우도 있다. 이러한 경우에 사용되는 것이 Exec 클래스이다.

Exec 클래스는 커멘드 라인에서 명령을 실행하는 기능을 한다. 이에 몇 가지 메소드가 준비되어 있으며, 명령 실행에 관한 설정을 할 수 있게 되어 있다.

commandLine "실행 명령", "인수"...

실행할 명령의 내용을 지정한다. 첫번째 인수에 커멘드를 작성하고, 그 이후에 옵션 등을 인수로 지정한다.

workingDir "텍스트"

이것은 앞에서 이미 설명 했었다. 작업 디렉터리를 지정하는 것이다.

args "Iterator"
args "값1, 값2, ..."

이것도 앞에서 이미 등장 했었다. 인수로 전달할 정보를 지정하는 것이다. 이것은 Iterator로 정리하여 준비할 수 있으며, 부정 인수로 필요한 값을 개별적으로 인수 지정할 수도 있다.

Windows에서 실행

일단 이것만 알고 있으면 명령의 실행은 충분히 있을 것이다. 그러면 실제로 간단한 예를 들어 보겠다.

task javaVer(type:Exec) {
    group 'devkuma'
    description 'print java version.'
    workingDir '.'
    commandLine 'cmd'
    args '/c', 'java.bat'
    doFirst {
        println()
        println('***** Java Version *****')
    }
}

먼저 실행하는 명령으로 간단한 배치 파일을 만들어 둔다. 여기에서는 Windows에서 실행하기 위한 전제로 설명을 한다. 프로젝트 폴더에 “java.bat"라는 이름으로 파일을 준비한다. 그리고 다음과 같이 작성해 둔다.

java.exe -version

보면 알 수 있듯이 Java 버전을 출력하는 명령을 실행하고 있다. 이 배치 파일을 실행하는 작업을 만들 수 있다.

아래에 샘플을 올려 두었다.

> Task :javaVer

***** Java Version *****

C:\dev\GradleApp>java.exe -version
java version "9.0.1"
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)

작성한 후에 gradle javaVer라고 실행해 본다. 다음과 같이 버전이 출력된다.

설치된 JDK를 사용하여 표시는 달라질 것이지만, 대체로 이런 출력이 된다. 여기에서는 다음과 같이 실행 명령 설정을 한다.

workingDir '.'
commandLine 'cmd'
args '/c', 'javaver.bat'

이것으로 cmd /c java.bat라는 명령이 실행된다. 그러면 java.bat에 작성된 java.exe -version가 실행되어 Java 버전 정보가 출력된다.

Mac 및 리눅스 계열에서 실행

Window가 아닌 Mac 및 리눅스 계열에서 실행되는 예제는 아래와 같다.

task javaVer(type:Exec) {
    group 'devkuma'
    description 'print java version.'
    workingDir '.'
    commandLine './javaver'
    doFirst {
        println()
        println('***** Java Version *****')
    }
}

javaver 파일을 생성하여 아래와 같이 파일을 저장하고, chmod로 실행 권한을 부여한다.

java -version

출력은 Window와 동일하다.

파일을 복사하는 Copy 이용

프로그램 실행 관계 외에도, 비교적 기억해 두면 도움이 되는 것으로 파일 관련 클래스를 몇 가지 살펴 보고 설명한다.

Copy 클래스

Copy 클래스는 그 이름과 같이 파일을 복사할 수 있는 기능을 제공한다. 여기에는 다음과 같은 메소드가 준비되어 있다.

from "원본 경로"

복사할 원본 파일와 폴더의 경로를 텍스트로 지정한다.

into "대상 경로"

복사할 파일이나 폴더의 경로를 텍스트로 지정한다.

include "패턴", ...

복사 대상에 포함 할 파일을 ANT 스타일 패턴이라는 형식으로 지정한다. 이것은 와일드 카드로 지정되는 패턴이다.

exclude "패턴", ...

복사 대상에서 제외 파일을 ANT 스타일 패턴에서 지정하는 것이다.

그럼, Copy 간단한 사용 예를 아래에 들어 둔었다.

task copyJava(type: Copy) {
    group 'devkuma'
    description 'backup java files.'
    from 'src/main/java'
    into '../java_backup'
 }

이것은 main 안에 java 폴더를 프로젝트 폴더 외부에 복사한다. gradle copyJava라고 실행해 본다. java 폴더가 프로젝트 폴더와 같은 위치에 “java_backup"라는 이름으로 복사된다.

Delete 클래스

Delete 클래스는 파일과 폴더를 삭제하는 것이다. 여기에는 다음의 메소드가 준비되어 있다.

delete "파일", ...

삭제 대상 파일을 지정한다. 이것은 파일 경로 텍스트이다.




최종 수정 : 2017-12-22