Gradle build는 세 개의 명확한 단계를 가진다.
Initialization
Gradle은 single 혹은 multi-project build를 지원한다.
Initialization 단계동안, Gradle은 build에서 어떠한 프로젝트가 어떤 부분을 담당할지를 정하고, 각각의 프로젝트의 Project instance를 생성한다.
Configuration
이 단계동안 project object는 구성된다.
build의 부분을 담당하고 있는 모든 프로젝트의 build script는 실행된다.
Gradle 1.4는 configuration on demand라는 모드를 소개한다.
이 모드에서, Gradle은 오직 관련있는 프로젝트만 구성한다.
Execution
Gradle은 configuration 단계동안 앞으로 실행될 task의 집합을 결정하고, 생성하고 구성한다.
이 집합은 gradle command를 통해 넘겨진 task 이름변수와 현재 directory를 통해 결정된다.
그리고 나서 Gradle은 선택된 task들을 실행한다.
Settings file
build script files 외에, Gradle은 setting file을 정의한다.
settings file은 naming convention에 의해서 Gradle에 의해 정의된다.
이 파일을 위한 기본적인 이름은 settings.gradle이다.
settings file은 initialization 단계동안 실행된다.
multiproject build는 root project 안에 settings.gradle 이 존재하여야 한다.
어떤 project가 어떠한 부분을 담당하고 있는지 정의되어야 하기 때문이다.
single project build에서는, settings file은 선택적이다.
포함된 project를 정의하는 것 외에, 당신은 당신의 build script classpath에 library를 추가해야 할 경우가 있다.
자, 그럼 이제 single project build를 위한 소개를 보자.
ex) Single project build
settings.gradle
println 'This is executed during the initialization phase.'
build.gradle
println 'This is executed during the configuration phase.' task configured { println 'This is also executed during the configuration phase.' } task test << { println 'This is executed during the execution phase.' } task testBoth { doFirst { println 'This is executed first during the execution phase.' } doLast { println 'This is executed last during the execution phase.' } println 'This is executed during the configuration phase as well.' }
gradle test testBoth 의 실행 결과
> gradle test testBoth This is executed during the initialization phase. This is executed during the configuration phase. This is also executed during the configuration phase. This is executed during the configuration phase as well. :test This is executed during the execution phase. :testBoth This is executed first during the execution phase. This is executed last during the execution phase. BUILD SUCCESSFUL Total time: 1 secsbuild script에서, property 접근과 method 호출은 project object에 위임된다.
이와 비슷하게 settings file 안의 property 접근과 method 호출 역시 settings object에 위임된다.
Multi-project builds multi-project build는 Gradle의 한번의 실행동안 하나 이상의 project를 빌드하는 것이다.
당신은 settings file에서 각각의 project가 multiproject build 안에서 어떠한 부분을 담당하는지 선언하여야 한다.
Project locations Multi-project build는 항상 하나의 root가 있는 tree 형태로 표현된다. tree의 각각의 요소는 proejct를 나타낸다.
project는 multi-project build 안에서 project 의 위치를 나타내는 path를 가지고 있다.
대부분의 예에서, project path는 파일 시스템 내의 project의 물리적인 위치와 일관성을 가진다.
하지만, 이 것은 설정으로 변화시킬 수 있다.
project tree는 settings.gradle 파일 안에서 생성된다.
기본적으로 setting file의 위치는 root project의 위치로 가정된다.
하지만 setting file 안에서 당신은 root project의 위치를 재정의할 수 있다.
Building the tree settings file 안에서, 당신은 project tree를 build할 수 있는 method들을 사용할 수 있다.
Hierarchical layouts
ex) Hierarchical layout
settings.gradle
include 'project1', 'project2:child', 'project3:child1'include method 는 변수로써 project path를 가진다.
project path는 file system 상대 경로와 동일한 것으로 간주된다.
예를 들어, services:api 는 기본적으로 services/api 와 동일한 것으로 간주된다.
당신은 오직 나무의 잎사귀들만 명시하면 된다.
이 뜻은 service:hotels:api 라고 명시했다면 이 것은 services, service:hotels, services:hotels:api 의 3개 project를 생성할 것이라는 것이다.
Flat layouts
ex) Flat layout settings.gradle
includeFlat 'project3', 'project4'
includeFlat method는 변수로써 directory 이름을 가지게 된다.
이 디렉토리들은 project 디렉토리의 자식으로써 존재하여야 한다.
이 디렉토리들의 위치는 multi-project tree에서 root project의 child project로써 고려된다.
Modifying elements of the project tree settings file 안에서 생성된 multi-project tree는 project descriptors라고 불리는 것들로 이루어진다.
당신은 settings file 내의 이러한 descriptor를 언제든 수정할 수 있다.
이 descriptor에 접근하기 위해서 당신이 할 수 있는 것은 : descriptor를 사용하여 당신은 프로젝트의 이름, 디렉토리와 빌드 파일을 바꿀 수 있다.
ex) Modification of elements of the project tree
settings.gradle
println rootProject.name println project(':projectA').namesettings.gradle
rootProject.name = 'main' project(':projectA').projectDir = new File(settingsDir, '../my-project-a') project(':projectA').buildFileName = 'projectA.gradle'
Initialization
어떻게 gradle은 single 혹은 multiproject build를 할지 구분할 수 있을까?
당신이 multiproject build를 settings file이 존재하는 director에서 시작한다면, 그것은 간단하다.
하지만 Gradle은 build의 한 부분을 담당하고 있는 subproject에서 build를 실행하는 것 또한 허용한다.
만약 당신이 settings.gradle 파일이 없는 project에서 Gradle을 실행시킨다면, Gradle은 settings.gradle 파일을 아래 방법과 같이 찾을 것이다.
- 현재 디렉토리와 같은 level에서 master로 불리는 director
- 아직 찾지못했다면, parent directory - 아직 찾지못했다면, single project build로 실행된다.
- 만약 settings.gradle 파일을 찾았다면, Gradle은 settings.gradle 파일에서 현재의 project가 multiproject의 계층의 한 부분인지 체크한다. 만약 아니라면 build는 single project build로써 실행되고, 그렇다면 multiproject build로써 수행된다.
이 행위의 목적은 무엇인가?
Gradle은 현재의 project가 multiproject build의 subproject인지 아닌지 구분할 필요가 있다.
만약 subproject라면, subproject와 의존성있는 project들은 빌드될 것이지만, Gradle은 전체 multiproject build의 build 설정을 만들 필요가 있다.
당신은 -u command line option을 사용하여서 Gradle에게 parent 계층의 settings.gradle 파일을 찾지않을 것을 전할 수 있다.
그러면 현재 프로젝트는 single project로써 build될 것이다.
만약 현재 프로젝트가 settings.gradle 파일을 가지고 있다면 -u option은 의미가 없다.
아래 build들이 그러한 것처럼 :
- single project build, 만약 settings.gradle 파일이 multiproject 계층에서 정의되지 않다면
- multi project build, 만약 settings.gradle 파일이 multiproject 계층에서 정의되어 있다면
settings.gradle 파일을 위한 자동 검색은 오직 물리적으로 계층적이거나 평평한 구조에서면 효과가 있다.
평평한 구조에서는 당신은 추가적으로 "master" 라고 묘사되었던 naming convention을 따라야만 한다.
Gradle은 멋대로의 구조 역시 허용하지만, 그러한 그조에서 당신은 build를 settings file이 존재하는 곳에서 실행시켜야 한다.
Gradle은 build의 한 부분을 차지하고 있는 모든 프로젝트를 위해서 Project 객체를 생성한다.
multi-project build에서 이러한 것들은 Settings object 안에 명시되어 있는 project이다.
각각의 project object는 기본적으로 top level directory와 같은 이름을 가지고 있고, root project를 제외한 모든 project는 parent project를 가지고 있다.
어떠한 project도 child project를 가질 수 있다.
Configuration and execution of a single project build single project build에서, initialization 단계 이후의 흐름은 매우 단순하다.
build script는 initialization 단계동안 만들어졌던 project object에 대해 실행되게 된다.
그리고 나서 Gradle은 command line을 통해 전달된 변수와 같은 이름의 task를 찾게 되고, 변수를 넘겨준 순서대로 각각 실행되게 된다.
Responding to the lifecycle in the build script
당신의 build script는 lifecycle 동안 build 진행을 알림으로써 받을 수 있다.
이러한 알림은 보통 두가지 형태를 가진다.
당신은 특정한 listener 인터페이스를 구현하거나, 알림이 시작할 때 실행될 closure를 제공할 수도 있다.
아래는 clousure를 사용한 예제이다.
Project evaluation
당신은 project가 평가되기 전후로 즉시 알림을 받을 수 있다.
이 것은 build script나 custom된 logging 혹은 profiling에 전체적인 부분에 추가적인 설정을 해야할 때 쓰일 수 있다.
아래는 hasTests 속성이 true로 설정된 각각의 프로젝트에 test task를 추가하는 예제이다.
ex) Adding of test task to each project which has certain property set
build.gradle
allprojects { afterEvaluate { project -> if (project.hasTests) { println "Adding test task to $project" project.task('test') << { println "Running tests for $project" } } } }
projectA.gradle
hasTests = true
gradle -q test 의 실행 결과
> gradle -q test Adding test task to project ':projectA' Running tests for project ':projectA'
이 예제는 project가 평가된 이후에 실행되는 closure를 추가하기 위해 Project.afterEvaluate() 메서드를 사용한다.
project가 평가될 때 알림을 받는 것 또한 가능하다.
이 예제는 project evaluation의 몇몇 custom된 logging을 동작한다.
afterProject 알림은 project evaluation의 성공여부에 상관없이 받게된다.
ex) Notifications
build.gradle
gradle.afterProject {project, projectState -> if (projectState.failure) { println "Evaluation of $project FAILED" } else { println "Evaluation of $project succeeded" } }
gradle -q test 의 실행 결과
> gradle -q test Evaluation of root project 'buildProjectEvaluateEvents' succeeded Evaluation of project ':projectA' succeeded Evaluation of project ':projectB' FAILED
당신은 이러한 event를 받기위해서 Gradle에 ProjectEvaluationListener를 추가할 수도 있다.
Task creation
당신은 task가 project에 추가된 이후, 즉시 알림을 받을 수 있다.
이 것은 build file 내에서 task가 사용가능하게 만들어지기 전 몇몇 default value나 행위를 추가할 때에 사용된다.
아래 예제는 각각의 task에 scrDir 속성을 설정하는 에제이다.
ex) Setting of certain property to all tasks
build.gradle
tasks.whenTaskAdded { task -> task.ext.srcDir = 'src/main/java' } task a println "source dir is $a.srcDir"
gradle -q a 의 실행 결과
> gradle -q a source dir is src/main/java
당신은 이러한 event를 받기위해서 TaskContainer에 Action을 추가할 수도 있다.
Task execution
당신은 어떠한 task가 실행되기 전 혹은 후에 즉시 알림을 받을 수 있다.
아래 예제는 task 실행의 시작과 끝을 기록한다.
명심해야 할 것은 afterTask 알림은 task의 성공여부와 상관없이 받게된다는 것이다.
ex) Logging of start and end of each task execution
build.gradle
task ok task broken(dependsOn: ok) << { throw new RuntimeException('broken') } gradle.taskGraph.beforeTask { Task task -> println "executing $task ..." } gradle.taskGraph.afterTask { Task task, TaskState state -> if (state.failure) { println "FAILED" } else { println "done" } }
gradle -q broken 의 실행 결과
> gradle -q broken executing task ':ok' ... done executing task ':broken' ... FAILED
당신은 이러한 event를 받기위해서 TaskExecutionGraph에 TaskExecutionListener를 사용할 수도 있다.
댓글 없음 :
댓글 쓰기