Re: [工具] 想將一些靜態檔案包在 JAR 裡

作者: qrtt1 (有些事,有時候。。。)   2016-04-15 18:46:58
※ 引述《Neisseria (Neisseria)》之銘言:
: 小弟用 gradle 想包一些 groovy 命令稿和靜態檔案
: build.gradle 如網址:https://pastebin.com/EUGbHCmg
: 目前可以順利產生 JAR,該 JAR 也可以順利執行
: 不過 靜態檔案會跑到其他的資料夾
: 結構大致如下:
: ├── classes
: │ └── main
: │ └── SomeClass.class
: ├── libs
: │ └── SomeClass-1.0.jar
: ├── resources
: │ └── main
: │ └── static-file
: └── tmp
: ├── compileGroovy
: │ └── groovy-java-stubs
: └── uberjar
: └── MANIFEST.MF
: 我覺得我可能是誤會了
: static-file 不會跑進 JAR 裡
: 不過我不確定 所以 po 上來請各位大大解惑
: 感恩
我建了一些 sample class 與靜態檔:
qty:t qrtt1$ tree
.
├── build
│ ├── classes
│ │ └── main
│ │ └── Hello.class
│ ├── libs
│ │ └── t-1.0.jar
│ ├── resources
│ │ └── main
│ │ └── foo.txt
│ └── tmp
│ ├── compileGroovy
│ │ └── groovy-java-stubs
│ ├── jar
│ │ └── MANIFEST.MF
│ └── uberjar
│ └── MANIFEST.MF
├── build.gradle
└── src
├── groovy
│ └── Hello.groovy
└── resources
└── foo.txt
14 directories, 8 files
摘錄會用到的部分如下:
sourceSets {
main {
groovy {
srcDir 'src/groovy'
}
resources {
srcDir 'src/resources'
}
}
}
task uberjar(type: Jar, dependsOn:[':compileJava', ':compileGroovy', ':processResources']) {
from files(sourceSets.main.output.classesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
manifest {
attributes 'Main-Class': 'SomeClass'
}
}
若是懷疑檔案沒進去,那就檢查一下源頭吧!
很明顯地黃字部分是源頭,綠字部分是其它 library 檔
那麼就來研究黃子部分的 code 吧。
沒頭緒!沒關係!gradle script 就是 groovy script
把它的類別印出來研究一下,在 build.gradle 最後面加上:
println sourceSets.main.output.class
println sourceSets.main.output.classesDir.class
執行一下:
# gradle -q
class org.gradle.api.internal.tasks.DefaultSourceSetOutput_Decorated
class java.io.File
classesDir 是個 File 物件,依它的命名猜是個錄目
DefaultSourceSetOutput 就是某個 gradle 的物件,先不知道它做什用的。
先不理它,來研究一下 classesDir 目錄內有什麼:
再加印一下它的內容:
println "files in classesDir"
sourceSets.main.output.classesDir.eachFile { println it }
/Users/qrtt1/t/build/classes/main/Hello.class
你發會現它沒有 靜態檔 只有 .class。
看來得換一條路來查了,如果在
sourceSets.main.output.classesDir
沒有我們期待的檔,那在它的上一層會不會有呢?
不確定要怎麼查但它是個 groovy object 先用 each 看看運氣:
sourceSets.main.output.each { println it }
/Users/qrtt1/t/build/classes/main
/Users/qrtt1/t/build/resources/main
你會發現它印出了二個目錄,依剛剛變數的名字來看
sourceSets.main.output.classesDir
就會是
/Users/qrtt1/t/build/classes/main
那麼代表目錄
/Users/qrtt1/t/build/resources/main
的變數叫什麼?
沒頭緒沒關係,找一下 property 有 Dir 的看看。
加 build.gradle 印一下:
println sourceSets.main.output.properties.grep {
it.key.contains("Dir")
}
只要沒有被 MOP 動手腳,groovy object 都有 properties
只要是 groovy object 就有基 grep 能用囉
qty:t qrtt1$ gradle
[classesDir=/Users/qrtt1/t/build/classes/main,
resourcesDir=/Users/qrtt1/t/build/resources/main]
========================================================
以上是簡單的野外求生過程,
不過先前其實有查到是哪個類別了,直接看 source code 比較快
https://github.com/gradle/gradle/blob/master/subprojects/
plugins/src/main/groovy/
org/gradle/api/internal/tasks/DefaultSourceSetOutput.java
縮:http://bit.ly/1SPm1Ke
所以,由上述的歷程可以知道你根本缺少了 resources 檔的位置。
依直覺可以這麼寫:
task uberjar(type: Jar, dependsOn:[':compileJava', ':compileGroovy', ':processResources']) {
from files(sourceSets.main.output.classesDir)
from files(sourceSets.main.output.resourcesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
manifest {
attributes 'Main-Class': 'SomeClass'
}
}
你就得到了有 resources file 的 uberjar
qty:t qrtt1$ unzip -l build/libs/t-1.0.jar |grep foo
0 04-15-16 18:01 foo.txt
不過依手冊與 source code 的明示、暗示,
它是一個 Composite Pattern
public class DefaultSourceSetOutput extends
CompositeFileCollection implements SourceSetOutput { }
通俗一點的叫『樹』,簡單地說應該要有獲得 parent 就得到它包含物的效果
你可以改寫成:
from files(sourceSets.main.output)
再加上 CopySpec 手冊說明 http://bit.ly/1VtZKbl ,
from (...) 它會自動呼叫 project.files,所以又能再簡化成:
from sourceSets.main.output
於是開心地打完收工,謝謝收看。
作者: Neisseria (Neisseria)   2016-04-15 22:32:00
感謝大大回得那麼認真,我會再試試看

Links booklink

Contact Us: admin [ a t ] ucptt.com