Tuesday, September 20, 2011

Buckminster RCP build with independent features

Information:
Buckminster does not seem to be very active anymore. To build Eclipse products, update sites and similar have a look at my tycho tutorials. My Buckminster tutorials are no longer maintained and remein here as reference only.



When building an RCP application all features are typically part of the product. For example the product we built in my previous post contains the Eclipse Platform and a custom feature.


Now when it comes to updates P2 only regards its root nodes. So when you want to update your custom feature only you will soon run into problems. Andrew Niefer wrote a nice blog entry on this topic.

What we want to do is to install a core product only and afterwards install independent features that are not referenced from the base product. This way all these features can be updated independently.

Concept

We first will create a P2 update site containing everything our final installation might need. The product, RCP stuff like platform launchers and optional features. Afterwards we will use this update site to assemble independent features to our final RCP application.

Our final setup will include 6 Plug-ins/Features, 2 Plug-ins containing code, 2 Features each containing one of the Plug-ins and 2 assembly projects. You can see their dependencies on the diagram below:


 We will start by using the code from our previous examples for publishing an update site and for an RCP build as a basis.

Step 1: Updating the update site

The update site shall include code needed for the RCP Feature, so we need to add it to the Included Features. Open com.example.update.p2/features.xml and add com.example.rcp.feature to the list of Included Features.

This will trigger a build for the RCP core feature when the update site is built.

Step 2: Adapting target platform

If you only build for your development platform you can skip this step.

We need to add the Delta Pack to our target platform we defined for the RCP build. Download the delta pack from Eclipse. Go to http://download.eclipse.org/eclipse/downloads/, switch to the 3.x downloads. Afterwards select your release from Latest Releases, find and download the Delta Pack. This package contains platform specific executables so we can build eg a linux RCP on windows.
 Go to Window -> Preferences -> Plug-in Development -> Target Platform. Edit your custom Target Definition and add the location of the eclipse folder located inside the downloaded zip.

You can find a more detailed example on the Target Platform by Ralf Ebert.

Step 3: RCP Build Project

Our com.example.rcp.releng project needs some updates. First we update the ant file build/createProduct.ant.
<project>
     <pathconvert property="equinox.launcher.jar">
       <first count="1">
         <sort>
           <fileset dir="${eclipse.home}/plugins" includes="**/org.eclipse.equinox.launcher_*.jar"/>
           <reverse xmlns="antlib:org.apache.tools.ant.types.resources.comparators">
             <date/>
           </reverse>
         </sort>
       </first>
     </pathconvert>
    
    <target name="create.product">
        <property name="installableIUs" value="${iu},${features}" />        
        <property name="destination" location="${sp:destination}"/>
        <delete dir="${destination}"/>
        <mkdir dir="${destination}"/>
        <makeurl property="repository" file="${sp:updateSite}"/>
        <echoproperties/>
        <echo message="============================== RCP Settings =============================="/>
        <echo message="Repository:  ${repository}"/>
        <echo message="Destination: ${destination}"/>
        <echo message="Product:     ${iu}"/>
        <echo message="Features:    ${features}"/>
        <echo message="IUs:         ${installableIUs}"/>
        <echo message="target:      ${target.os}.${target.ws}.${target.arch}"/>
        <echo message="============================== Building RCP =============================="/>
        <java jar="${equinox.launcher.jar}" fork="true" failonerror="true" >
            <arg value="-application"/>
            <arg value="org.eclipse.equinox.p2.director"/>
            <arg value="-repository"/>
            <arg value="${repository}"/>
            <arg value="-destination"/>
            <arg value="${destination}"/>
            <arg value="-profile"/>
            <arg value="${product.profile}"/>
            <arg value="-profileProperties" />
            <arg value="org.eclipse.update.install.features=true" />
            <arg value="-installIU"/>
            <arg value="${installableIUs}"/>
            <arg value="-p2.os" />
            <arg value="${target.os}" />
            <arg value="-p2.ws" />
            <arg value="${target.ws}" />
            <arg value="-p2.arch" />
            <arg value="${target.arch}" />
            <arg value="-consoleLog"/>
            <arg value="-roaming"/>
        </java>
    </target>
</project>
The director used for the build process now gets a list of installable units (IUs). This list includes our product followed by all independent features we wish to install.

Now change buckminster.cspex to
<?xml version="1.0" encoding="UTF-8"?>
<cspecExtension xmlns:com="http://www.eclipse.org/buckminster/Common-1.0"
    xmlns="http://www.eclipse.org/buckminster/CSpec-1.0">

    <dependencies>
        <dependency name="com.example.update.p2" componentType="eclipse.feature" />
    </dependencies>
    <actions>
        <public name="create.product" actor="ant">
            <actorProperties>
                <property key="buildFile" value="build/createProduct.ant" />
                <property key="targets" value="create.product" />
            </actorProperties>
            <properties>
                <property key="profile" value="${product.profile}" />
                <property key="iu" value="${product.id}" />
                <property key="features" value="${product.features}" />
            </properties>
            <prerequisites alias="updateSite">
                <attribute name="site.p2.publish" component="com.example.update.p2" />
            </prerequisites>
            <products alias="destination" base="${product.destination}">
                <path path="${product.name}.${target.ws}.${target.os}.${target.arch}/" />
            </products>
        </public>

        <public name="create.product.zip" actor="ant">
            <actorProperties>
                <property key="buildFileId" value="buckminster.pdetasks" />
                <property key="targets" value="create.zip" />
            </actorProperties>
            <prerequisites alias="action.requirements">
                <attribute name="create.product" />
            </prerequisites>
            <products alias="action.output" base="${product.destination}">
                <path path="${product.name}.${target.ws}.${target.os}.${target.arch}.zip" />
            </products>
        </public>
    </actions>
</cspecExtension>
This will give us 2 new actions: 
  • create.product to build our RCP applicaton
  • create.product.zip which will build and zip our application.

Finally change buckminster_product.properties to
# Where all the output should go
buckminster.output.root=C:/Build/BuildArtifacts

# Where the temp files should go
buckminster.temp.root=${user.home}/tmp

# How .qualifier in versions should be replaced
qualifier.replacement.*=generator:lastRevision

# update site settings
updatesite.destination=C:/Build/UpdateSite

# rcp settings
product.id=com.example.rcp.core.myproduct
product.name=MyProduct

# leave empty when no features are needed, but do NOT comment this out
# multiple features can be defined as a comma separated list
product.features=com.example.myfeature.feature.group
product.profile=ExampleProfile

product.destination=C:/Build/Sample RCP

target.os=win32
target.ws=win32
target.arch=x86
This property file is used for building the update site and the product. Therefore we need some update site properties too.
  • product.name
    will be used for the product build folder and the zip file. It will not be used anywhere else.
  • product.features
    a comma separated list of all features that should be installed independently from the base product. So if your base product already includes FeatureA, do not add it here! The property may be left empty. In this case you will get the same results as from Buckminster RPC build.
     
  • product.profile
    name of the P2 profile to be created. This will be part of your final RPC application
  • target.X
    Needs to be set to a defined target platform. We cannot use * here anymore as we need to build an RCP dedicated to a specific platform.

    Building for a dedicated platform also influences the content of our update site. All Plug-ins/Features built using this properties file will be built for the defined target only. This might be of interest when you use code that is platform dependent. You still can build your update site only to keep it platform independent.

Step 4: Build the product

When you are done right click on your com.example.rcp.releng project and select Buckminster -> Invoke Action... 

Select create.product and enter the path to your buckminster_product.properties file. After hitting OK you can find your RCP product in C:\Build\Sample RCP.

Our product consists of the consists of the core product My RCP Example which includes the Platform and a custom made Feature My Base Features. Additionally it contains another feature Myfeature that is independent of the core product. Hence we can update Myfeature without updating My RCP Example.


No comments:

Post a Comment