持續集成包括軟件項目的持續構建與發佈,經過持續性地編譯與構建,完成項目的不斷集成。持續集成一般應用與WEB開發領域,對於RCP項目的持續集成目前業界較少。對於RCP項目的持續集成,就是經過按期執行項目自動構建程序來完成項目版本的集成與發佈,重點在於項目的自動化構建。通過筆者的研究與學習,經過本文向你們介紹一種基於PDE的RCP項目自動化構建方式,但願你們多多交流。php
1、簡介java
PDE (Plug-in Development Environment) headless-build是一種基於 Ant 腳本的構建方式,它主要適用於Eclipse plug-in與 Eclipse RCP項目的導出。因爲headless-build是特定於 Eclipse 插件的構建平臺,而 Eclipse 插件的編譯構建都離不開Eclipse自己的類庫與資源,於是運行headless-build以前,必須已經安裝好帶有PDE環境的Eclipse SDK以及相應的插件。PDE做爲Eclipse的一個插件項目存在於Eclipse中,且不一樣Eclipse下PDE實現的方式略有不一樣,本文以Eclipse3.5.1爲例,介紹PDE headless-build實現自動化構建的原理及示例。app
2、原理less
(一)headless-build核心庫文件eclipse
headless-build核心腳本文件都存儲於 Eclipse 的 PDE 插件中。以Eclipse3.5.1爲例,PDE build 插件位於 plugins 目錄下的 org.eclipse.pde.build 插件目錄中。在此目錄的 lib 文件夾中包含有 pde build 庫的核心類文件,其中包括了絕大多數和 PDE build 相關的 Ant task 的實現,有興趣的讀者能夠在 org.eclipse.pde.source 源代碼插件中看到相應的代碼。ide
對於咱們的 build 任務,PDE headless-build 的核心腳本文件位於 scripts 和 templates 兩個目錄下。工具
scripts 文件夾中提供了 headless-build 的基礎控制腳本。事實上不管是使用 headless-build 仍是IDE 導出,咱們都間接地經過執行這些腳本完成了一系列的過程。其中的 build.xml 文件是 build 過程的主腳本文件,在以前的啓動命令中的 –buildfile 後的值就是此 build.xml 文件的路徑。而 genericTargets.xml 則定義了在 build 過程的各個子過程的行爲。學習
templates 文件夾中則提供了一系列的模板庫。您可在 templates 下的 headless-build 目錄中找到前面所說的 allElements.xml、build.properties、customTargets.xml 文件的模板。您能夠方便地將其拷貝和修改,用做您本身的構建配置文件。fetch
(二)headless-build 的工做流程和通知機制ui
customTargets.xml 提供了對 headless-build 流程的多個節點的控制。而事實上 PDE 將 headless-build 分爲多個子過程。customTargets.xml 正是針對了此些子過程提供了回調接口,以通知和觸發用戶定製的腳本被執行。如下是 headless-build 總體流程的簡圖。
在其中,您須要提供的是最初的引入腳本(Ant 文件,批處理文件或命令行指令),以後 Eclipse 宿主會被啓動並調用您指定的一般位於 PDE 插件 scripts 目錄下的 build.xml,而此文件則會相應找到您在配置目錄中定義的 customTargets.xml 文件,執行用戶設定的回調腳本,並經過 customTargets.xml 調用 PDE 插件 scripts 下的 genericTargets.xml 啓動 PDE 內部的各項子過程的執行代碼。而在 genericTargets 中則定義了 headless-build 的4個子過程fetch、generate、process 和 assemble,下面咱們對他們作簡單的介紹。
(1)Fetch
Fetch負責從源控制中下載所需構建的插件項目的源文件。其過程以下:
正如前文所述,customTargets.xml中包含了headless build執行全部過程的預置以及回調接口,開發者能夠在其中本身編寫所需的自定義腳本。Fetch操做主要在於fetchElement操做,它會根據PreBuild中用戶定義的源文件庫的文件及地址映射的MAP來以次獲取須要構建的項目源碼。同時,fetch taeget中有一個unless=」skipFetch」的屬性,該屬性代表當shipFetch存在時,fetch過程能夠被跳過。
(2)Generate
Generate爲每一個插件分別生成自身的構建腳本。其過程以下:
一樣能夠自定義預置及回調操做,generate的主要過程在於generateScript操做。該操做使用eclipse.buildScript方法爲每一個插件分別生成自身的構建腳本。
(3)Process
process經過運行 generate 中生成的腳本,完成對每一個插件的構建。其過程以下:
Process過程主要調用prcessElement操做,該操做經過processViaFeature和processFlat兩個過程完成對各個插件以及依賴插件的構建。
(4)Assemble
assemble將 process 過程當中生成的插件打包。其過程以下:
調用了assembleElement過程,根據Manifest清單中的依賴,把相關的插件集成到一塊兒,打包發佈爲一個ZIP文件,該文件解壓後點擊.exe文件可運行。(打包後的的插件會被自動集成到宿主平臺中)
3、示例
瞭解了PDE headless build的實現原理,咱們能夠爲其量身打造本身的構建腳本。爲了直接突出核心,咱們對於獲取代碼管理工具上源碼的部分就取消了,在配置文件中將SkitFetch和skipMap設置爲true便可,接下來將把本地的RCP項目完成自動化構建。
(1)新建一個Plug-in Project,項目名稱爲com.rcpquickstart.helloworld,模板選擇「RCP Helloworld」,新建的步驟不作詳細講解,順着嚮導操做便可。
(2)新建一個Feature Project,名稱爲com.rcpquickstart.helloworld.feature,其插件選擇com.rcpquickstart.helloworld,新建的步驟不作詳細講解,順着嚮導操做便可,完成的Feature結構以下:
(3)在com.rcpquickstart.helloworld項目中新建一個Product Configratiuon,名稱爲helloworld.product,新建完之後打開文件進行以下配置。
接着爲product添加功能部件(Feature),點擊選項卡「Dependencies」,添加「com.rcpquickstart.helloworld.feature」和「org.eclipse.rcp」兩個功能部件便可。到目前爲止,咱們的RCP產品項目配置完畢。
(4)新建一個Java Project,名稱爲com.rcpquickstart.helloworld.build,接着再新建兩個文件「build.xml」和「build.properties」。該項目爲自動構建插件項目,使用ant腳本。
(5)編輯build.xml內容以下:
<projectname="com.rcpquickstart.helloworld.build"default="build"> <propertyfile="build.properties"/> <targetname="init"> <mkdirdir="${buildDirectory}"/> <mkdirdir="${buildDirectory}/plugins"/> <mkdirdir="${buildDirectory}/features"/> <copytodir="${buildDirectory}/plugins"> <filesetdir="../"> <includename="com.rcpquickstart.helloworld/**"/> </fileset> </copy> <copytodir="${buildDirectory}/features"> <filesetdir="../"> <includename="com.rcpquickstart.helloworld.feature/**"/> </fileset> </copy> </target> <targetname="pde-build"> <javaclassname="org.eclipse.equinox.launcher.Main"fork="true"failonerror="true"> <argvalue="-application"/> <argvalue="org.eclipse.ant.core.antRunner"/> <argvalue="-buildfile"/> <argvalue="${eclipseLocation}/plugins/org.eclipse.pde.build_${pdeBuildPluginVersion}/scripts/productBuild/productBuild.xml"/> <argvalue="-Dtimestamp=${timestamp}"/> <classpath> <pathelementlocation="${eclipseLocation}/plugins/org.eclipse.equinox.launcher_${equinoxLauncherPluginVersion}.jar"/> </classpath> </java> </target> <targetname="clean"> <deletedir="${buildDirectory}"/> </target> <targetname="build"depends="clean, init, pde-build"/> </project> |
從腳本能夠看出,執行過程分爲Clean、init、pde-build三部,Clean爲清理構建的目標目錄,即產品構建目錄,init爲新建構建目錄結構,同時,將所需構建的插件項目以及其feature拷貝到相應的目錄下(若是是依賴多個插件的話都須要執行拷貝)。Pde-build則是啓動一個Eclipse進程調用pde構建。
(6)build.properties內容以下:
# Version of org.ecilpse.pdebuild pdeBuildPluginVersion=3.5.1.R35x_20090820 # Version of org.eclipse.equinox.launcher equinoxLauncherPluginVersion=1.0.201.R35x_v20090715 base=c:/helloworld-build-target eclipseLocation=F:/Install/PDE/eclipse-SDK-3.5.1-win32/eclipse ############# PRODUCT/PACKAGING CONTROL ############# product=/com.rcpquickstart.helloworld/helloworld.product runPackager=true #Set the name of the archive that will result from the product build. #archiveNamePrefix= archivePrefix=helloworld # The location underwhich all of the build output will be collected. collectingFolder=${archivePrefix} configs=win32, win32, x86 allowBinaryCycles = true #Sort bundles depenedencies across all features instead of just within a given feature. flattenDependencies = true #Arguments to send to the zip executable zipargs= #Arguments to send to the tar executable tarargs= ############## BUILD NAMING CONTROL ################ # The directory into which the build elements are fetched and where # the build takes place. buildDirectory=c:/helloworld-build # Type of build. Used in naming the build output. Typically this value is # one of I, N, M, S, ... buildType=I # ID of the build. Used in naming the build output. buildId=HelloWorld # Label for the build. Used in naming the build output buildLabel=${buildType}.${buildId} # Timestamp for the build. Used in naming the build output timestamp=007 baseLocation=${base}/eclipse filteredDependencyCheck=false skipBase=true eclipseURL=<url for eclipse download site> eclipseBuildId=<Id of Eclipse build to get> eclipseBaseURL=${eclipseURL}/eclipse-platform-${eclipseBuildId}-win32.zip skipMaps=true mapsRepo=:pserver:anonymous@example.com/path/to/repo mapsRoot=path/to/maps mapsCheckoutTag=HEAD #tagMaps=true mapsTagTag=v${buildId} skipFetch=true ############# JAVA COMPILER OPTIONS ############## # Specify the output format of the compiler log when eclipse jdt is used logExtension=.log # Whether or not to include debug info in the output jars javacDebugInfo=false # Whether or not to fail the build if there are compiler errors javacFailOnError=true # Enable or disable verbose mode of the compiler javacVerbose=true |
須要注意幾個關鍵配置:
pdeBuildPluginVersion:
PDE BUILD的版本號,能夠在Eclipse目錄下的Plugin文件夾裏找到org.eclipse.pde.build_3.5.1.R35x_20090820文件夾,文件夾名後面的字符爲PDE版本;
equinoxLauncherPluginVersion:equinoxLauncher版本號,用於Eclipse項目構建的進程,其在Eclipse目錄下的Plugin文件夾裏找到
org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar ,後面字符爲其版本號;
Base:RCP runtime Binary和Delta Pack存放的目錄路徑,其兩者包括了RCP運行時環境所需插件以及大量跨平臺插件。
eclipseLocation:執行構建的Eclpise路徑
Product:須要發佈的Product文件
buildDirectory:執行構建的目標目錄,包括了構建時產生的文件
skipMaps:true,跳過源文件的MAP獲取。
skipFetch:true,跳過從源代碼管理工具獲取源文件。
(7)準備構建環境。根據配置文件中配置路徑,分別在C盤創建「helloworld-build」和「helloworld-build-target」兩個文件夾,同時,從eclipse官網上下載「eclipse-RCP-3.5.1-win32.zip」和「eclipse-3.5.1-delta-pack.zip」壓縮文件,將其解壓到剛纔的helloworld-build-target目錄下(相同的文件能夠覆蓋),下載地址:
http://archive.eclipse.org/eclipse/downloads/drops/R-3.5.1-200909170800/index.php
(8)執行build.xml,待構建完成後,在「/helloworld-build/I.HelloWorld」目錄下找到HelloWorld-win32.win32.x86.zip,其爲構建好的RCP項目,解壓後目錄結構以下:
雙擊helloworld.exe可運行程序。