내용으로 건너뛰기
권남
사용자 도구
로그인
사이트 도구
검색
도구
문서 보기
이전 판
역링크
최근 바뀜
미디어 관리자
사이트맵
로그인
>
최근 바뀜
미디어 관리자
사이트맵
추적:
gradle:organizing_build_logic
이 문서는 읽기 전용입니다. 원본을 볼 수는 있지만 바꿀 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요.
====== Gradle Organizing Build Logic ====== * [[http://www.gradle.org/docs/current/userguide/organizing_build_logic.html|Organizing Build Logic]] * Gradle에는 빌드 스크립트 로직을 구성하는 여러 가지 방법이 있다. * 태스크 클로저에 직접 넣기. * 여러 태스크가 동일 로직을 사용한다면 메소드로 빼서 호출한다. 멀티 프로젝트에서 이 로직을 사용한다면 부모 프로젝트에 메소드를 선언한다. * 메소드로 빼 빌드로직이 너무 복잡하다면 OO 모델로 바꿀 수 있다. 특정 디렉토리에 클래스를 넣어두면 Gradle이 자동으로 컴파일하여 빌드 스크립트 클래스패스에 추가한다. ===== 프라퍼티와 메소드 상속 ===== 부모 프로젝트에 정의된 모든 메소드와 프라퍼티는 서브 프로젝트에서도 접근 가능하다. 이를 통해 공통 구성을 정의하고 빌드 로직을 메소드로 만들어서 서브 프로젝트에서 사용하도록 하면 된다. * ''build.gradle'' <code groovy> srcDirName = 'src/java' def getSrcDir(project) { return project.file(srcDirName) } </code> * ''child/build.gradle'' <code groovy> task show << { // 상속받은 프라퍼티 사용 println 'srcDirName: ' + srcDirName File srcDir = getSrcDir(project) println 'srcDir: ' + rootProject.relativePath(srcDir) } </code> * 실행하면 <code> > gradle -q show srcDirName: src/java srcDir: child/src/java </code> ===== 구성 주입(Injected configuration) ===== 상속보다는 [[gradle:multiproject|Gradle Multi Project]]에 나온 교차 프로젝트 구성방식과 서브프로젝트 구성 방식이 더 좋다. 이유는 주입방식은 빌드 스크립트에서 명백하게 일어나고 서로 다른 프로젝트에 다른 로직을 주입할 수 있다. 그리고 리포지토리, 플러그인, 태스크와 기타 등등 모든 종류의 구성을 주입할 수 있다. * ''build.gradle'' <code groovy> subprojects { // 프라퍼티와 메소드를 주입한다. srcDirName = 'src/java' // 프라퍼티 srcDir = { file(srcDirName) } // 메소드 // Inject a task task show << { println 'project: ' + project.path println 'srcDirName: ' + srcDirName File srcDir = srcDir() println 'srcDir: ' + rootProject.relativePath(srcDir) } } // 특정 프로젝트에는 특수한 경우의 구성을 주입한다. project(':child2') { srcDirName = "$srcDirName/legacy" } </code> * ''child1/build.gradle'' <code groovy> // 주입된 프라퍼티와 메소드를 사용하지만, 값은 덮어 쓴다. srcDirName = 'java' def dir = srcDir() </code> * 실행하면<code> > gradle -q show project: :child1 srcDirName: java srcDir: child1/java project: :child2 srcDirName: src/java/legacy srcDir: child2/src/java/legacy </code> ===== buildSrc 프로젝트의 소스 빌드하기 ===== Gradle을 실행하면 ''buildSrc''라는 디렉토리가 존재하는지 검사한다. 존재한다면 자동으로 이 코드를 컴파일하고 테스트한 뒤에 빌드 스크립트의 클래스패스에 집어 넣는다. 그 외에 다른 것을 할 필요가 없다. 여기에 [[gradle:customtask|Custom Task]]와 [[gradle:customplugins|Gradle Custom Plugins]]을 넣으면 된다. 멀티 프로젝트에서는 최상위 프로젝트에만 ''buildSrc''를 둘 수 있다. * ''buildSrc''의 기본 빌드 스크립트<code groovy> // --build.gralde이 없어도 아래 빌드 스크립트가 존재하는 것으로 간주한다.-- // 1.6 버전에서는 명시적으로 필요한 것으로 보인다. apply plugin: 'groovy' dependencies { compile gradleApi() groovy localGroovy() } </code> 이 말은 ''buildSrc''에 기본 Java/Groovy 프로젝트를 구성할 수 있다는 뜻이다. [[gradle:java|Gradle Java Plugin]], [[gradle:groovy|Gradle Groovy Plugin]] 좀 더 복잡한 것이 필요하다면 자신만의 ''build.gradle''을 만들면 된다. <del>Gradle은 기본 빌드 스크립트를 ''build.gradle''이 있건 없건 무조건 적용한다. 즉, 빌드 스크립트에는 기본값 외에 다른 것만 정의하면 된다.</del> 1.6 버전에서는 기본 설정도 함께 넣어야 하게 바뀐 것 같다. * ''buildSrc/build.gradle''<code groovy> apply plugin: 'groovy' repositories { mavenCentral() } // gradle과 groovy에 관한 의존성은 추가할 필요가 없다. dependencies { compile gradleApi() groovy localGroovy() testCompile group: 'junit', name: 'junit', version: '4.8.2' } </code> ''buildSrc'' 프로젝트도 멀티 프로젝트 빌드가 될 수 있다. 하지만 실제 빌드의 클래스패스에 넣고자 하는 ''buildSrc'' 서브 프로젝트는 최상위 ''buildSrc'' 프로젝트의 ''runtime'' 의존성에 설정해야 한다. * 서브프로젝트를 최상위 ''buildSrc''프로젝트에 넣기 ''build.gradle''<code groovy> rootProject.dependencies { runtime project(path) } </code> ===== JDBC Driver 로딩 못하는 문제 ===== * Gradle 1.6에서 ''buildSrc''의 커스텀 태스크/플러그인 프로젝트에 지정된 JDBC Driver 클래스를 못 찾는 문제가 있다.(''No suitable driver found for jdbc:...'') * http://stackoverflow.com/questions/6329872/how-to-add-external-jar-files-to-gradle-build-script ''buildSrc/build.gradle'' <code groovy> repositories { mavenCentral() } configurations { driver } dependencies { driver group: 'mysql', name: 'mysql-connector-java', version: '5.1.16' } URLClassLoader loader = GroovyObject.class.classLoader configurations.driver.each {File file -> loader.addURL(file.toURL()) } // JDBC Driver 사용하는 코드 혹은 custom task/plugin 제작 </code> ===== 공유 스크립트 ===== [[:gradle|gradle]]에서 "외부 빌드 스크립트로 프로젝트 구성하기" 참조. ===== 커스텀 태스크 ===== [[gradle:customtask|Gradle Custom Task]] 참조. ===== 커스텀 플러그인 ===== [[gradle:customplugins|Gradle Custom Plugins]] 참조. ===== 외부 빌드 실행 ===== [[http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.GradleBuild.html|GradleBuild]] 태스크를 를 사용하여 다른 빌드의 태스크를 실행할 수 있다. ''dir'' 혹은 ''buildFile'' 프라퍼티로 실행할 빌드를 지정하고 ''tasks'' 프라퍼티로 실행할 태스크를 지정할 수 있다. * 다른 빌드를 실행하기 ''build.gradle'' <code groovy> task build(type: GradleBuild) { buildFile = 'other.gradle' tasks = ['hello'] } </code> * ''other.gradle'' <code groovy> task hello << { println "hello from the other build." } </code> * 실행하면 <code> > gradle -q build hello from the other build. </code> ===== 빌드 스크립트 전용 외부 라이브러리 ===== 빌드 스크립트가 외부 라이브러리를 필요로 한다면 ''buildScript()'' 메소드를 사용하여 빌드 스크립트 자체의 스크립트 클래스패스에 추가하면 된다. 빌드 스크립트 클래스패스를 지정하는 클로저를 인자로 전달한다. * 빌드 스크립트의 외부 의존성 지정하기 ''build.gradle'' <code groovy> buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' // classpath 구성 사용 } } </code> ''buildScript()''메소드에 전달된 클로저는 [[http://www.gradle.org/docs/current/javadoc/org/gradle/api/initialization/dsl/ScriptHandler.html|ScriptHandler]]의 인스턴스를 구성한다. 빌드 스크립트의 클래스패스는 **''classpath''** 구성을 사용하여 지정한다. 여기서는 프로젝트 의존성을 제외한 모든 의존성을 지정할 수 있다. 빌드 스크립트 클래스패스를 지정한 위에는 빌드스크립트에서 해당 클래스를 마음대로 사용할 수 있다. * 외부 의존 클래스 사용하는 빌드 스크립트 ''build.gradle'' <code groovy> import org.apache.commons.codec.binary.Base64 buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' } } task encode << { def byte[] encodedString = new Base64().encode('hello world\n'.getBytes()) println new String(encodedString) } </code> * 실행하면 <code> > gradle -q encode aGVsbG8gd29ybGQK </code> * 멀티 프로젝트에서는 프로젝트 빌드 스크립트의 의존성이 모든 서브프로젝트에도 적용된다. * 멀티 프로젝트에서 최상위 프로젝트의 ''buildscript''에 repository를 추가해도, 하위 프로젝트에서 다시 ''buildscript'' 구문을 넣고 의존성을 지정하면 하위 프로젝트의 **buildscriptt** 구문에 repository를 재지정해야 한다. ===== Ant 의존성 추가 ===== 빌드 스크립트의 외부 의존성 추가 방식으로는 Ant에 의존성을 추가할 수 없다. * Ant에 의존성 추가 ''build.gradle'' <code groovy> configurations { ftpAntTask } dependencies { // ant-commons-net의 maven pom.xml이 잘못돼 있어서 ant-commons-net의 추가 의존성을 직접 지정해줬다. ftpAntTask("org.apache.ant:ant-commons-net:1.8.4") { module("commons-net:commons-net:1.4.1") { dependencies "oro:oro:2.0.8:jar" } } } task ftp << { ant { taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) // 여기서 추가된 클래스패스 사용! ftp(server: "ftp.apache.org", userid: "anonymous", password: "me@myorg.com") { fileset(dir: "htdocs/manual") } } } </code> ===== apply ===== ''apply from: 'some.gradle'''로 외부 Gradle 스크립트를 적용할 수 있다. 이때 파일 대신 URL을 적어도 된다. [[http://mrhaki.blogspot.kr/2012/10/gradle-goodness-init-script-for-adding.html|인트라넷 URL을 통해 전사 공통 자바 소스 스타일 검사기능 추가하는 방법]] <code groovy> apply from: 'http://intranet/source/quality.gradle' </code> 이 방식을 사용할 경우 [[ci:jenkins|Jenkins]]등의 CI에서 동시 빌드시에 외부 리소스에 대한 락이 걸리는 상황이 발생한다.[[http://issues.gradle.org/browse/GRADLE-2795|[GRADLE-2795] Gradle locks the global script cache during the entire build, causing subsequent builds to fail if scripts change]] 아래와 유사한 오류가 발생할 것이다. <code> A problem occurred evaluating script. Could not open buildscript class cache for script 'http://.../?p=build-core;a=blob_plain;f=repository-utils.gradle;hb=HEAD' (/home/build/.gradle/caches/1.6/scripts/_p_build_core_a_blob_plain_f_r_4n9gdhqrjd4inp4c6jive7ql9c/DefaultScript/buildscript). Timeout waiting to lock buildscript class cache for script 'http://.../?p=build-core;a=blob_plain;f=repository-utils.gradle;hb=HEAD' (/home/build/.gradle/caches/1.6/scripts/_p_build_core_a_blob_plain_f_r_4n9gdhqrjd4inp4c6jive7ql9c/DefaultScript/buildscript). It is currently in use by another Gradle instance. Owner PID: unknown Our PID: 15314 Owner Operation: unknown Our operation: Lock file: /home/build/.gradle/caches/1.6/scripts/_p_build_core_a_blob_plain_f_r_4n9gdhqrjd4inp4c6jive7ql9c/DefaultScript/buildscript/cache.properties.lock </code> 이 때 해결책은 빌드 스크립트 URL의 맨 뒤에 Jenkins Job의 이름을 넣어주는 것이다. 마지막의 ''**${java.net.URLEncoder.encode(System.getenv()['JOB_NAME'] ?: 'NOJOB', 'UTF-8')}**'' Job 마다 서로 다른 build script Cache를 생성하여 Lock 충돌이 방지된다. <code groovy> apply from: "http://server/epository-utils.gradle?jn=${java.net.URLEncoder.encode(System.getenv()['JOB_NAME'] ?: 'NOJOB', 'UTF-8')}" </code> ''JOB_NAME'' 대신 ''Math.random()''사용시 계속해서 빌드 스크립트 캐시가 서로 다른이름으로 생성되어 파일 갯수가 증가하게 된다. ''/home/[username]/.gradle/caches/[version]/scripts/*'' 디렉토리를 cron 등으로 주기적으로 정리해줘야한다. 아래는 하루에 한 번씩 어제날짜의 캐시 디렉토리를 삭제하는 Unix script. <code sh> find /home/[user]/.gradle/caches/*/scripts -maxdepth 1 -mindepth 1 -mtime +1 -type d -exec rm -rf {} \; </code>
gradle/organizing_build_logic.txt
· 마지막으로 수정됨: 2015/09/22 17:54 저자
kwon37xi
문서 도구
문서 보기
이전 판
역링크
맨 위로