프로필

프로필 사진
Popomon
Frontend Developer
(2020/12 ~)

    카테고리

    포스트

    [Gradle - Basic] 빌드 스크립트 기초 - (2)

    2020. 2. 29. 19:12

    꿈가게: To Do List - iOS

    꿈가게: To Do List - Android

     

    Gradle - 고급 작업 (Enhanced Task)

    Gradle은 자체 속성과 메서드가있는 작업  고급 작업을 지원 합니다. 이것은 Ant 대상에 익숙한 것과는 실제로 다릅니다. 이러한 고급 작업은 귀하가 제공하거나 Gradle에 내장되어 있습니다.

    이번 포스팅에서는 Gradle에서 제공하는 조금 더 업그레이드 된 작업(Enhanced Task) 에 대해, 예제를 통해 알아보겠습니다.

     

     

    Gradle - 작업 결과 (Task outcomes)

    상태 내용
    (no label) or EXECUTED 작업이 실행되었습니다.
    UP-TO-DATE 작업의 출력은 변경되지 않았습니다.
    FROM-CACHE 작업의 출력은 이전 실행에서 찾을 수 있습니다.
    SKIPPED 작업이 해당 작업을 실행하지 않았습니다.
    NO-SOURCE 작업은 해당 작업을 실행할 필요가 없습니다.

     

     

    Gradle Build Script - 작업 정의

    # Ex 1

    task('작업이름')의 형태로 작업 이름에 문자열을 사용하여 정의합니다.

     

    << Groovy >>

    task('hello') {
        doLast {
            println "hello"
        }
    }
    
    task('copy', type: Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

    # Ex 2

    tasks 컨테이너를 이용하여 tasks.create('작업이름') 의 형태로 작업을 정의합니다.

     

    << Groovy >>

    tasks.create('hello') {
        doLast {
            println "hello"
        }
    }
    
    tasks.create('copy', Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

    # Ex 3

    task(작업이름) 형태의 DSL 구문을 사용하여 작업을 정의합니다.

     

    << Groovy >>

    task(hello) {
        doLast {
            println "hello"
        }
    }
    
    task(copy, type: Copy) {
        from(file('srcDir'))
        into(buildDir)
    }

     

     

     Gradle Build Script - 작업 찾기

    # Ex 1

    DSL 구문을 사용하여 작업에 접근하기

     

    << Groovy >>

    task hello
    task copy(type: Copy)
    
    // Access tasks using Groovy dynamic properties on Project
    
    println hello.name
    println project.hello.name
    
    println copy.destinationDir
    println project.copy.destinationDir

     


    # Ex 2

    tasks 컬렉션을 이용하여 작업에 접근하기

     

    << Groovy >>

    task hello
    task copy(type: Copy)
    
    println tasks.hello.name
    println tasks.named('hello').get().name
    
    println tasks.copy.destinationDir
    println tasks.named('copy').get().destinationDir

    # Ex 3

    tasks.getByPath() 를 사용하여 모든 프로젝트에서 작업에 액세스 할 수 있습니다.

    getByPath() 는 작업 이름, 상대 경로 또는 절대 경로로 메소드를 호출 할 수 있습니다 .

     

    << Groovy >>

    project(':projectA') {
        task hello
    }
    
    task hello
    
    println tasks.getByPath('hello').path
    println tasks.getByPath(':hello').path
    println tasks.getByPath('projectA:hello').path
    println tasks.getByPath(':projectA:hello').path

     

    << Command >>

    > gradle -q hello 
    : hello 
    : hello 
    : projectA : hello 
    : projectA : hello

     

     

     Gradle Build Script - 작업 구성

    # Ex 1

    type: Copy 로 선언해 주면, Copy (복사하는 작업) 생성을 할 수 있습니다.

     

    << Groovy >>

    task myCopy(type: Copy)

    # Ex 2

    명확하게하기 위해이 작업의 이름은 " myCopy"이지만 유형은 " Copy"입니다. 유형 은 같지만 이름이 다른 여러 작업을 수행 할 수 있습니다.

    API 를 사용하여 작업을 구성하는 방법입니다.

     

    << Groovy >>

    Copy myCopy = tasks.getByName("myCopy")
    myCopy.from 'resources'
    myCopy.into 'target'
    myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

     


    # Ex 3

    DSL 특정 구문을 사용하여 작업 구성하는 방법입니다.

    컨텍스트를 유지하며 가장 읽기 쉽습니다.

     

    << Groovy >>

    // Configure task using Groovy dynamic task configuration block
    myCopy {
       from 'resources'
       into 'target'
    }
    myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

    # Ex 4

    구성 블록으로 작업을 정의

     

    << Groovy >>

    task copy(type: Copy) {
       from 'resources'
       into 'target'
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

     

     

     Gradle Build Script - 작업 생성자에 인수 전달

    # Ex 1

    작업을 생성한 후 변수를 정의하는 것과 달리 인수 값을 작업 클래스의 생성자에 전달할 수 있습니다.

    Task생성자에 값을 전달 하려면 관련 생성자에 주석을 달아야합니다 @Inject

     

    << Groovy >>

    // 작업 형태를 클래스로 정의
    class CustomTask extends DefaultTask {
        final String message
        final int number
    
        @Inject
        CustomTask(String message, int number) {
            this.message = message
            this.number = number
        }
    }
    
    // 작업작성 - TaskContainer를 사용하여 생성자 인수가있는 작업작성
    tasks.create('myTask', CustomTask, 'hello', 42)
    
    // 작업작성 - 맵을 사용하여 생성자 인수가있는 작업 작성
    task myTask(type: CustomTask, constructorArgs: ['hello', 42])

     

     

     Gradle Build Script - 작업에 종속성 추가

    # Ex 1

    다른 프로젝트의 작업에 대한 종속성을 추가하는 방법입니다.

    dependsOn ':[프로젝트명]:[작업명]' 의 형태로 참조할 수 있습니다.

     

    << Groovy >>

    project('projectA') {
        task taskX {
            dependsOn ':projectB:taskY'
            doLast {
                println 'taskX'
            }
        }
    }
    
    project('projectB') {
        task taskY {
            doLast {
                println 'taskY'
            }
        }
    }

     

    << Command >>

    > gradle -q taskX 
    taskY 
    taskX

    # Ex 2

    작업 이름을 사용하는 대신 객체를 사용하여 종속성을 정의 할 수 있습니다.

     

    << Groovy >>

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    
    task taskY {
        doLast {
            println 'taskY'
        }
    }
    
    taskX.dependsOn taskY

     

    << Command >>

    > gradle -q taskX 
    taskY 
    taskX

    # Ex 3

    보다 고급 사용을 위해 지연 블록을 사용하여 작업 종속성을 정의 할 수 있습니다.

    lib1, lib2 와 같이 lib 로 시작하는 작업을 taskX 에 추가할 수 있습니다.

     

    << Groovy >>

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    
    // Using a Groovy Closure
    taskX.dependsOn {
        tasks.findAll { task -> task.name.startsWith('lib') }
    }
    
    task lib1 {
        doLast {
            println 'lib1'
        }
    }
    
    task lib2 {
        doLast {
            println 'lib2'
        }
    }
    
    task notALib {
        doLast {
            println 'notALib'
        }
    }

     

    << Command >>

    > gradle -q taskX 
    lib1 
    lib2 
    taskX

     

     

     Gradle Build Script - 순서가 있는 작업

    작업 순서는 여러 시나리오에서 유용 할 수 있습니다.

    - 작업의 순서를 'clean'전에 'build'가 실행되지 않도록 지정

    - 빌드 초기에 빌드 유효성 검사

    - 통합 테스트 전에 단위 테스트를 실행

    - 특정 유형의 모든 작업 결과를 집계하는 작업


    # Ex 1

    mustRunAfter를 사용하여 taskY 작업이 taskX 이후에 실행되도록 정의합니다.

     

    << Groovy >>

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    task taskY {
        doLast {
            println 'taskY'
        }
    }
    taskY.mustRunAfter taskX

     

    << Command >>

    > gradle -q taskY taskX
    taskX
    taskY

    # Ex 2

    shouldRunAfter를 사용하여 taskY 작업이 taskX 이후에 실행되도록 정의합니다.

     

    << Groovy >>

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    task taskY {
        doLast {
            println 'taskY'
        }
    }
    taskY.shouldRunAfter taskX

     

    << Command >>

    > gradle -q taskY taskX
    taskX
    taskY

    # Ex 3

    아래와 같이 dependsOn 을 통해 종속관계로서 순서가 정해져 있는 경우에는 작업의 순서를 지정하더라도 무시됩니다.

     

    << Groovy >>

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    task taskY {
        doLast {
            println 'taskY'
        }
    }
    task taskZ {
        doLast {
            println 'taskZ'
        }
    }
    taskX.dependsOn taskY
    taskY.dependsOn taskZ
    taskZ.shouldRunAfter taskX

     

    << Command >>

    > gradle -q taskX
    taskZ
    taskY
    taskX

     

     

     Gradle Build Script - 작업에 설명을 추가

    # Ex 1

    작업에 대한 설명을 description 을 통해서 추가할 수 있습니다.

     

    << Groovy >>

    task copy(type: Copy) {
       description 'Copies the resource directory to the target directory.'
       from 'resources'
       into 'target'
       include('**/*.txt', '**/*.xml', '**/*.properties')
    }

     

     

     Gradle Build Script - 작업 스킵하기

    # Ex 1

    onlyIf 예약어를 활용하여, skipHello 프로퍼티가 없는 경우에만 실행하도록 합니다.

     

    << Groovy >>

    task hello {
        doLast {
            println 'hello world'
        }
    }
    
    hello.onlyIf { !project.hasProperty('skipHello') }

     

    << Command >>

    > gradle hello -PskipHello
    > Task :hello SKIPPED
    
    BUILD SUCCESSFUL in 0s

    # Ex 2

    위의 방법으로 스킵 조건을 표현할 수 없는 경우에는 StopExecutionException 을 사용합니다. 아래의 코드에서는 compile 을 스킵하였습니다.

    이 기능은 Gradle에서 제공하는 작업을 수행 할 때 유용합니다. 그러한 작업의 내장 동작에 대한 조건부 실행 을 추가 할 수 있습니다

     

    << Groovy >>

    task compile {
        doLast {
            println 'We are doing the compile.'
        }
    }
    
    compile.doFirst {
        // Here you would put arbitrary conditions in real life.
        // But this is used in an integration test so we want defined behavior.
        if (true) { throw new StopExecutionException() }
    }
    task myTask {
        dependsOn('compile')
        doLast {
            println 'I am not affected'
        }
    }

     

    << Command >>

    > gradle -q myTask
    I am not affected

     

     

     Gradle Build Script - 작업 활성화 및 비활성화

    모든 작업에는 기본적으로 enabled 플래그가 true 입니다.

    이 속성을 false 로 바꾸어 주면 작업이 비활성화 됩니다.


    # Ex 1

    [작업이름].enabled = false 를 통해서 작업을 비활성화합니다.

     

    << Groovy >>

    task disableMe {
        doLast {
            println 'This should not be printed if the task is disabled.'
        }
    }
    disableMe.enabled = false

     

    << Command >>

    > gradle disableMe
    > Task :disableMe SKIPPED
    
    BUILD SUCCESSFUL in 0s

     

     

     Gradle Build Script - 작업 타임아웃

    모든 작업은 timeout 속성을 가지고 있습니다. timeout의 시간동안 작업이 완료되지 못한다면 작업이 마무리되고 실패로 처리됩니다.

     

    # Ex 1

    Duration.ofMillis(500) 을 통해서 500 밀리초(=0.5초) 안에 작업이 완료되지 않으면 실패로 처리됩니다.

     

    << Groovy >>

    task hangingTask() {
        doLast {
            Thread.sleep(100000)
        }
        timeout = Duration.ofMillis(500)
    }

    'Build > Gradle' 카테고리의 다른 글

    [Gradle - Basic] 로깅  (0) 2020.03.06
    [Gradle - Basic] 빌드 라이프 사이클  (0) 2020.03.05
    [Gradle - Basic] 플러그인  (0) 2020.03.05
    [Gradle - Basic] 파일 관련 API  (0) 2020.03.01
    [Gradle - Basic] 빌드 스크립트 기초 - (1)  (0) 2020.02.29