====== Gradle Task ====== * [[http://www.gradle.org/docs/current/dsl/index.html|DSL API에서 Task types]]를 확장해서 사용할 수 있다. * 빌드 파일에는 이미 수많은 gradle 관련 패키지가 기본 import 된 상태이다. 따라서 gradle 관련 클래스 사용시 import 할 필요가 없는 경우가 많다. [[http://www.gradle.org/docs/current/userguide/ide_support.html|Using Gradle without IDE support]] 참조. * [[http://www.gradle.org/docs/current/userguide/more_about_tasks.html|More about tasks]] ===== 선언 ===== task hello << { println "hello" } // 괄호하고 이름 task(hello) << { println "hello" } task(copy, type: Copy) { from(file('srcDir')) into(buildDir) } // 이름을 문자열로 task('hello') << { println "hello" } // tasks 에 추가 tasks.add(name: 'taskName', type: org.something.GradleTask, dependsOn: 'anotherTask') { // task 설정 println "hello" } // with create tasks.create(name: 'taskName', type: org.something.GradleTask, dependsOn: 'anotherTask') { // task 설정 } ===== 태스크 정보 설정 ===== * Task의 description과 group을 지정하면 ''gradle tasks'' 시에 정보를 표시해 준다. * group은 마음대로 정할 수 있지만, 기본적으로 ''build'' 등이 있다. dist { description = '태스크 설명' group = '태스크의 그룹' } // 혹은 dist.description = '태스크 설명' dist.group = '태스크의 그룹' * 동적 프라퍼티 설정 task something { ext.prop1 = 'xxx' ext.prop2 = 'yyy' } // 외부에서 something.prop1 으로 접근 가능 ===== task에 접근하기 ===== * ''task hello''가 있을 때, * ''hello.name'' * ''project.hello.name'' * ''tasks.hello.name'' * ''tasks['hello'].name'' * ''tasks.getByPath()''로 접근 project(':projectA') { task hello } task hello println tasks.getByPath('hello').path // :hello println tasks.getByPath(':hello').path // :hello println tasks.getByPath('projectA:hello').path // :projectA:hello println tasks.getByPath(':projectA:hello').path // :projectA:hello ===== task 설정 ===== * [[http://www.gradle.org/docs/current/dsl/index.html|DSL API에서 Task types]] 생성하기 * 설정하기 // 단일 선언 task myCopy(type: Copy) // 태스크의 메소드 호출 등으로 설정하기 1 Copy myCopy = task(myCopy, type: Copy) myCopy.from 'resources' myCopy.into 'target' myCopy.include('**/*.txt', '**/*.xml', '**/*.properties') // 설정 2 task(myCopy, type: Copy) .from('resources') .into('target') .include('**/*.txt', '**/*.xml', '**/*.properties') // 설정 3 task myCopy(type: Copy) myCopy { from 'resources' into 'target' include('**/*.txt', '**/*.xml', '**/*.properties') } // 설정 4, configure() 메소드 task myCopy(type: Copy) myCopy.configure { from('source') into('target') include('**/*.txt', '**/*.xml', '**/*.properties') } // 설정 5. 선언시 task copy(type: Copy) { from 'resources' into 'target' include('**/*.txt', '**/*.xml', '**/*.properties') } * 의존성 설정 // 다른 프로젝트의 태스크 project('projectA') { task taskX(dependsOn: ':projectB:taskY') << { println 'taskX' } } // 나중에 설정 taskX.dependsOn taskY // 여러 태스크에 의존 taskX.dependsOn ['taskY', 'taskZ'] // 이름을 리턴하는 클로저를 통한 다중 설정 taskX.dependsOn { tasks.findAll { task -> task.name.startsWith('lib') } } * 설명(description) 추가 : 태스크에 ''description'' 프라퍼티를 설정하면 ''gradle tasks''에서 볼 수 있게 된다. * 태스크 대체 : 플러그인에서 생성한 태스크를 개발자가 원하는 것으로 대체하길 원하거나 할 때 사용 ''overwrite: true'' task copy(type: Copy) task copy(overwrite: true) << { println('I am the new one.') } ===== 태스크 건너 뛰기 ===== * ''onlyIf'' // hello task에 대해 hello.onlyIf { !project.hasProperty('skipHello') } // 실행시 skipHello 프라퍼티 지정 gradle hello -PskipHello * [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/StopExecutionException.html|StopExecutionException]] 예외를 던지면, 해당 지점부터 그 태스크는 실행이 안되고 건너뛴다. 그 이후 실행할 태스크는 계속 실행된다. task compile << { println 'We are doing the compile.' } compile.doFirst { // if문에 원하는 조건을 지정한다. if (true) { throw new StopExecutionException() } } task myTask(dependsOn: 'compile') << { println 'I am not affected' } * ''task.enabled=true|false'' 이 값이 true여야만 해당 태스크가 실행된다. ===== 이미 최신으로 갱신된 태스크 건너뛰기 ===== * 자바 컴파일 태스크 같은 경우 이미 모든 최신 java 파일이 컴파일 돼 있다면 건너뛰는 기능이 있다. 이 같은 것을 구현하는 방법. * 모든 태스크에는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskInputs.html|TaskInputs]] ''inputs''와 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskOutputs.html|TaskOutputs]] ''outputs'' 프라퍼티가 있다. 이 값을 설정해주면 자동으로 UP-TO-DATE인지 검사하여 실행 여부를 결정한다. task transform { ext.srcFile = file('mountains.xml') ext.destDir = new File(buildDir, 'generated') inputs.file srcFile outputs.dir destDir doLast { println "Transforming source file." destDir.mkdirs() // outputs.dir 영역에 파일을 생성하는 코드.. } } * 작동방식 * 태스크 실행시작시 inputs에 있는 파일의 스냅샷을 찍는다. * 태스크 실행후 outputs에 있는 파일의 스냅샷을 찍는다. * 태스크를 재실행할 때 이전 inputs, outputs의 스냅샷과 현재 inputs와 outputs의 스냅샷을 비교하여 변경 사항이 없으면 해당 태스크를 건너뛴다. 아니면 태스크를 실행하고 모든 스냅샷을 다시 찍는다. ==== 멀티 프로젝트에서 각 프로젝트 별 최신 갱신 여부 검사 ==== inputs/outputs를 사용하여 VCS에서 받은 멀티 프로젝트의 프로젝트별 갱신 여부를 검사할 수 있다. task checkUpToDate { description = '프로젝트 최신 갱신 여부 검사' def checkFile = file(new File(tmpDir, "gradle_${project.name}_check_up_to_date").absoluteFile) FileTree projectFileTree = fileTree(dir: project.projectDir) projectFileTree.exclude "${builDir}/**/*" inputs.files projectFileTree outputs.file checkFile doLast { println "[${project.name}] needs refresh." if (checkFile.exists()) { checkFile.delete() } checkFile.createNewFile() } } ===== Task Rules ===== * ''tasks.addRule'' 태스크 생성 규칙을 통해 동적으로 태스크를 만들어낼 수 있다. tasks.addRule("Pattern: ping") { String taskName -> if (taskName.startsWith("ping")) { task(taskName) << { println "Pinging: " + (taskName - 'ping') } } } // Rule에 대해 의존성을 지정하는 것도 가능하다. task groupPing { dependsOn pingServer1, pingServer2 } ===== 태스크의 실행 순서 ===== * 태스크에 ''dependsOn [a, b]'' 형태로는 실행 순서를 지정할 수 없다. dependsOn 은 의존 대상을 명시할 뿐 의존 대상의 실행순서는 명시하지 않는다. * 기존방법 : 다음과 같은 방식으로 순서를 명확히 하는 것도 가능하다. task somethingLastTask << { tasks.somethingFirstTask.execute() tasks.somethingSecondTask.execute() .... // do somthing last } * 새로운 방법(2015년 1월 현재 incubating) : // 보통은 task1 -> task2 순서로 실행하지만 특정 상황에서는 이를 무시한다. task2.shouldRunAfter task1 // 무조건 task1 -> task2 순서를 지킨다. task2.mustRunAfter task1 ===== tasks ===== * ''tasks''는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskContainer.html|TaksContainer]]의 인스턴스이며 이는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskCollection.html|TaskCollection]] 인터페이스를 상속한다. * [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskCollection.html#withType%28java.lang.Class%29|TaskCollection.withType]] ''tasks.withType(TaskType) { ... }'' 을 사용하여 특정 태스크 타입에 대한 공통 설정을 수행할 수 있다. ===== UP-TO-Date upToDate 조건 ===== * [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/tasks/TaskOutputs.html#upToDateWhen%28org.gradle.api.specs.Spec%29|TaskOutputs.upToDateWhen]]을 통해 upToDate 검사 조건을 변경할 수 있다. * 태스크를 무조건 실행하게 만들고자 한다면 Up to date 검사를 안하게 만들면 된다. // 태스크 선언부에서 아래와 같은 형태를 띄게 된다. task someTask { outputs.upToDateWhen { false } doLast { ... } } ===== --rerun-tasks ===== * ''--rerun-tasks'' 옵션을 주면 up-to-date 상태와 무관하게 무조건 태스크를 실행한다. ===== Task 실행에서 제외 ===== * "aaa" 태스크 실행시 "bbb" 태스크가 의존성에 걸려있더라도 실행을 하지 않고 건너뛰게 해야하는 경우가 있다. gradle.taskGraph.whenReady { taskGraph -> def tasks = taskGraph.allTasks // 태스크 실행 그래프에 'aaa'가 들어있으면 if (tasks.find { it.name.toLowerCase() == 'aaa'}) { bbb.enabled = false // bbb 태스크를 skip 한다. 로그상에 SKIP으로 뜸 } } ===== 참조 ===== * [[http://mrhaki.blogspot.com/2018/05/gradle-goodness-command-line-options.html|Gradle Goodness: Command Line Options For Custom Tasks - Messages from mrhaki]]