持续集成包括软件项目的持续构建与发布,经过持续性地编译与构建,完成项目的不断集成。持续集成一般应用与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可运行程序。