[gradle] provided compile

etc tools 2015. 11. 30. 11:40


gradle의 dependency scope는 compile, runtime, testCompile, testRuntime 만 있다.

https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html


그렇다면, web application 개발할 때 servlet과 같은 provided scope를 넣으려면, war plugin을 이용해야 한다.
(provided scope는 컴파일할 때는 함께 사용하고 war 압축에는 사용되지 않는 것을 의미한다.)


apply plugin: 'war'
dependencies {
providedCompile "javax.servlet:servlet-api:3.1.0" }



Posted by '김용환'
,


gradle 2.9가 2.8에 비해서 성능이 많아 좋아졌다고 해서 발표했다. 메모리를 적게 사용하고 증분 빌드 방식을 사용하여 엄청 빠르게 했다고 얘기했다.


실제로 2.7과 2.9 버전간의 테스트한 결과이다. 10.8초에서 4.4초로 50%이상 확 줄어들었다!!!! 헉~


<2.7>

$ gradle clean compileScala

Starting a new Gradle Daemon for this build (subsequent builds will be faster).

:clean

:compileJava UP-TO-DATE

:compileScala


BUILD SUCCESSFUL


Total time: 10.809 secs




<2.9>

$ gradle clean compileScala

:clean

:compileJava UP-TO-DATE

:compileScala


BUILD SUCCESSFUL


Total time: 4.456 secs





참조

https://docs.gradle.org/current/release-notes



Performance improvements for incremental builds

In many cases, Gradle 2.9 is much faster than Gradle 2.8 when performing incremental builds.

Very large builds (many thousands of source files) could see incremental build speeds up to 80% faster than 2.7 and up to 40% faster than 2.8.

Faster up-to-date checking for incremental builds

Gradle now uses a more efficient mechanism to scan the filesystem, making up-to-date checks significantly faster. This improvement is only available when running Gradle with Java 7 or newer.

Other improvements have been made to speed-up include and exclude pattern evaluation; these improvements apply to all supported Java versions.

No build script changes are needed to take advantage of these performance optimizations.

Reduced memory footprint for incremental builds

Gradle now uses much less memory than previous releases when performing incremental builds. By de-duplicating Strings used as file paths in internal caches, and by reducing the overhead of listing classes under test for Java projects, some builds use 30-70% less memory that Gradle 2.8.

Reduced memory consumption can translate into significant performance improvements when a build process is running low on memory.

No build script changes are needed to take advantage of these memory savings.





어떻게 한 것인지 자세한 내용을 보려면 다음을 참조한다. 아주 잘 나와 있다. (좀 봐야할듯.)


https://github.com/gradle/gradle/blob/master/design-docs/incremental-build.md


java.nio.file.Files.walkFileTree을 이용해서 메타 정보를 수집해서 다시 파일을 읽지 않도록 했다고 적혀 있고, Guava의 Interners.newWeakInterner()를 이용하여 메모리 최적화할 수 있게 했다.

Posted by '김용환'
,


git 에서 특이한 현상이 있다.


github A 프로젝트를 clone 후,  파일 수정/add/commit/push 한다. 그리고 push를 시도한다.

그러나, github B 프로젝트로 push하는 황당한(?)일이 벌어진다.


ERROR: Permission to ProjectA denied to ProjectB

fatal: The remote end hung up unexpectedly




SSH 디버그로 설정해도 특이한 현상이다. 

$ git clone git@github.xxxx.com:projectA.git Initialized empty Git repository in .... remote: Counting objects: 3194, done. remote: Total 3194 (delta 0), reused 0 (delta 0), pack-reused 3194 Receiving objects: 100% (3194/3194), 9.45 MiB, done. Resolving deltas: 100% (1415/1415), done. $ cd projectA $ vi test $ git status # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: test # no changes added to commit (use "git add" and/or "git commit -a") $ git add . $ git commit -m '11' [master 6d243f2] 11 1 files changed, 1 insertions(+), 0 deletions(-) $ git push debug1: Connecting to github.xxxx.com [1.1.1.1] port 22. debug1: Connection established. debug1: identity file /home/www/.ssh/identity type -1 debug1: identity file /home/www/.ssh/identity-cert type -1 debug1: identity file /home/www/.ssh/id_rsa type -1 debug1: identity file /home/www/.ssh/id_rsa-cert type -1 debug1: identity file /home/www/.ssh/id_dsa type -1 debug1: identity file /home/www/.ssh/id_dsa-cert type -1 debug1: Remote protocol version 2.0, remote software version libssh-0.6.0 debug1: no match: libssh-0.6.0 debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_5.3 debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: server->client aes128-ctr hmac-sha1 none debug1: kex: client->server aes128-ctr hmac-sha1 none debug1: sending SSH2_MSG_KEXDH_INIT debug1: expecting SSH2_MSG_KEXDH_REPLY debug1: Host 'github.xxx.com' is known and matches the RSA host key. debug1: Found key in /home/www/.ssh/known_hosts:8 debug1: ssh_rsa_verify: signature correct debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug1: SSH2_MSG_NEWKEYS received debug1: SSH2_MSG_SERVICE_REQUEST sent debug1: SSH2_MSG_SERVICE_ACCEPT received debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Trying private key: /home/www/.ssh/identity debug1: Trying private key: /home/www/.ssh/id_rsa debug1: read PEM private key done: type RSA debug1: Authentication succeeded (publickey). debug1: channel 0: new [client-session] debug1: Entering interactive session. debug1: Sending environment. debug1: Sending env LANG = ko_KR.UTF-8 debug1: Sending command: git-receive-pack 'projectA.git' debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 ERROR: Permission to ProjectA denied to ProjectB. debug1: channel 0: free: client-session, nchannels 1 debug1: fd 0 clearing O_NONBLOCK debug1: fd 1 clearing O_NONBLOCK Transferred: sent 2208, received 1680 bytes, in 0.1 seconds Bytes per second: sent 38768.0, received 29497.4 debug1: Exit status 1 fatal: The remote end hung up unexpectedly



git config --list 또는 cat .git/config 에서도 projectA.git로 제대로 나온다!!!


문제 해결은 ssh key를 삭제하고 다시 ssh gen을 하고 ssh key를 다시 등록하니 정상적으로 작동했다. 만약 주의 깊게 보지 않고 -f(force push)매개변수를 주었다면 민폐가 되었을 것이다.


아마도 '잘못된 SSH 키가 꼬이면, git push할 때 다른 프로젝트로 결합되어 엉뚱한 작업을 진행할 수 있다'라고 가정할 수 있는 환경을 공유한다.


따라서 git push -f는 정말 신중하게 써야 한다.!! 잘못하면 엉뚱한 github 프로젝트를 엉뚱하게 변경할 가능성이 존재한다.




참고

https://help.github.com/enterprise/2.4/user/articles/error-permission-to-user-repo-denied-to-user-other-repo/



Posted by '김용환'
,


gradle이 데몬으로 실행되어 있다면, 컴파일 속도가 엄청 빠를 수 있다. 

org.gradle.daemon=true



처음 실행할 때는 12초이다.

$ gradle compileScala

Starting a new Gradle Daemon for this build (subsequent builds will be faster).

:compileJava UP-TO-DATE

:compileScala


BUILD SUCCESSFUL


Total time: 12.809 secs





gradle 데몬이 실행한 후 컴파일하면 1.9초에 컴파일이 완료된다.


 $ gradle compileScala

:compileJava UP-TO-DATE

:compileScala UP-TO-DATE


BUILD SUCCESSFUL


Total time: 1.969 secs




Posted by '김용환'
,


gradle 은 groovy 기반이다.


gradle에서 dependency lib를 정의할 때, 아래와 같이 single 또는 double quotation (', ")을 사용할 수 있다. 

(대부분의 spring 데모가 single quotation, '으로 정의하고 있다.)


compile 'org.scala-lang:scala-library:2.11.5'

compile "org.scala-lang:scala-library:2.11.5"



두 예시 모두 잘 동작한다.
그러나, 변수를 사용하려면 single quoation(')을 사용하면 컴파일시 이상하다고 에러가 발생한다. double quoation(")을 써야 변수명을 확인하고 컴파일을 할 수 있다. (고급 용어로 String interpolation 이라고 한다.)


scala-version = "2.11.7"
org.scala-lang:scala-library:${scala-version}"



참조 : groovy 문서 


http://docs.groovy-lang.org/latest/html/documentation/index.html#all-strings

String interpolation

Any Groovy expression can be interpolated in all string literals, apart from single and triple single quoted strings. Interpolation is the act of replacing a placeholder in the string with its value upon evaluation of the string. The placeholder expressions are surrounded by ${} or prefixed with $ for dotted expressions. The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling toString() on that expression.

Here, we have a string with a placeholder referencing a local variable:

def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"
 

assert greeting.toString() == 'Hello Guillaume'


Posted by '김용환'
,

gradle에도 maven의 dependencies 명령과 동일한 기능이 있다.


$ gradle dependencies
...

+--- ch.qos.logback:logback-classic:1.1.2

|    +--- ch.qos.logback:logback-core:1.1.2

|    \--- org.slf4j:slf4j-api:1.7.6

+--- ch.qos.logback:logback-core:1.1.2

+--- org.slf4j:slf4j-api:1.7.6

+--- org.springframework.retry:spring-retry:1.1.2.RELEASE

|    \--- org.springframework:spring-core:4.0.4.RELEASE -> 4.2.2.BUILD-SNAPSHOT (*)

+--- org.springframework.boot:spring-boot-starter-test: -> 1.3.0.BUILD-SNAPSHOT

|    +--- junit:junit:4.12 (*)

|    +--- org.mockito:mockito-core:1.10.19

|    |    +--- org.hamcrest:hamcrest-core:1.1 -> 1.3

|    |    \--- org.objenesis:objenesis:2.1

|    +--- org.hamcrest:hamcrest-core:1.3

|    +--- org.hamcrest:hamcrest-library:1.3

|    |    \--- org.hamcrest:hamcrest-core:1.3

|    +--- org.springframework:spring-core:4.2.2.BUILD-SNAPSHOT (*)

|    \--- org.springframework:spring-test:4.2.2.BUILD-SNAPSHOT

|         \--- org.springframework:spring-core:4.2.2.BUILD-SNAPSHOT (*)

\--- org.aspectj:aspectjtools:1.8.7



(*) - dependencies omitted (listed previously)


BUILD SUCCESSFUL


Total time: 1.96 secs



테스트 라이브러리를 제외하고 실제 런타임과 관련된 것을 확인하려면 --configuration runtime을 추가한다.test관련 라이브러리는 보이지 않는다.


$ gradle dependencies --configuration runtime
...

+--- ch.qos.logback:logback-classic:1.1.2

|    +--- ch.qos.logback:logback-core:1.1.2

|    \--- org.slf4j:slf4j-api:1.7.6

+--- ch.qos.logback:logback-core:1.1.2

+--- org.slf4j:slf4j-api:1.7.6

\--- org.springframework.retry:spring-retry:1.1.2.RELEASE

     \--- org.springframework:spring-core:4.0.4.RELEASE -> 4.2.2.BUILD-SNAPSHOT (*)





Posted by '김용환'
,


capistrano 3에 배포 정책 (groups, sequence, parallel) 이 있다.


groups는 그룹단위로 병렬 배포를 할 수 있다. limit과 wait를 활용하여 배포할 수 있어서 서버가 많은 경우에 효과적이다.

sequence는 한대씩 배포하는 경우이다. 서버가 적은 경우 (3개 미만)일 때 효과적이다.

parallel은 동시에 배포하는 경우이다. 유틸리티나 스크립트 실행시 효과적일 수 있다. 


http://capistranorb.com/2013/06/01/release-announcement.html


# Capistrano 3.0.x
    on :all, in: :groups, limit: 3, wait: 5 do
      # Take all servers, in groups of three which execute in parallel
      # wait five seconds between groups of servers.
      # This is perfect for rolling restarts
    end

    on :all, in: :sequence, wait: 15 do
      # This takes all servers, in sequence and waits 15 seconds between
      # each server, this might be perfect if you are afraid about
      # overloading a shared resource, or want to defer the asset compilation
      # over your cluster owing to worries about load
    end

    on :all, in: :parallel do
      # This will simply try and execute the commands contained within
      # the block in parallel on all servers. This might be perfect for kicking
      # off something like a Git checkout or similar.
    end


Posted by '김용환'
,



intellij idea에서 build.gradle 에 dependency lib를 추가하면 자동으로 dependency lib를 다운받지 않는다.

Gradle Project 화면에서 좌측에 계속 돌아가는 아이콘을 클릭하면 dependency lib를 다운받는다. 






Posted by '김용환'
,



gradle는 dependency version을 자동화할 수 없고, 도 maven 처럼 수동으로 넣어줘야 한다.


예를 들어 guava 버전을 18.0으로 지정하면, compile시 ${guavaVersion}으로 입력하여 guava 정의와 함께 버전을 명시할 수 있다. 

def guavaVersion = '18.0'
dependencies {
compile("com.google.guava:guava:${guavaVersion}")
..
}



참고로 def로 property를 정의하지 않으면, 아래와 같은 에러가 발생한다.


> No such property: guavaVersion for class: org.gradle.api.internal.project.DefaultProject_Decorated

Posted by '김용환'
,




gradle 에서 scope 를 test로 하는 dependency 를 추가하려면, testCompile을 사용한다.


dependencies {
testCompile("org.springframework.boot:spring-boot-starter-test")
}

compile, runtime, testCompile, testRuntime 등이 더 있다. 



출처 : https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html

Posted by '김용환'
,