Setting up a Local p2 Repository

I’m currently working on an Eclipse RCP application that uses PAX Logging. The easiest way to use the required bundles is to put them in a folder referenced by your Target Platform Definition. However, there are a couple of major drawbacks to this approach:

  1. Tycho requires p2 metadata in order to resolve dependencies, so the local folder approach won’t work if you’re using Tycho for a headless build
  2. Log4j Import-Package failures. Every time I started Eclipse I had to reset my target platform because Import-Package: org.apache.log4j;version="1.2.15";provider=paxlogging was failing

Based on the Equinox documentation I created the following ant build file to publish a local p2 repository. The only prerequisite is that all the required PAX Logging bundles are placed in a folder, relative to the build file, called lib/plugins (see p2-build.xml in-line comments). Once you’ve created your repository you can use your favourite web server to make it available to Tycho.

p2-build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="local-p2" default="create-p2" basedir=".">

    <!-- 3rd party bundles should be placed in
         a subdirectory called 'plugins' -->
    <property name="source.dir" location="${basedir}/lib" />
    <!-- the directory the repository will be
         created in -->
    <property name="repo.dir" value="${basedir}/repository" />

    <target name="clean">
        <delete dir="${repo.dir}" />
        <mkdir dir="${repo.dir}" />
    </target>

    <target name="create-p2" depends="clean">
        
        <makeurl file="${repo.dir}" property="repo.url" />
        <echo message="Repository URL: ${repo.url}"/>
        <makeurl file="${basedir}/category.xml" property="category.file.url" />

        <!-- Use a fileset include to avoid hard-coding
             the equinox launcher jar filename -->
        <pathconvert property="launcher.jar">
            <fileset dir="${eclipse.home}/plugins/">
                <include name="org.eclipse.equinox.launcher_*.jar" />
            </fileset>
        </pathconvert>
        <echo message="Using Equinox launcher: ${launcher.jar}"/>

        <!-- Assumes 3rd party bundles are located in
             ${source.dir}/plugins -->
        <p2.publish.featuresAndBundles
            repository="${repo.url}"
            publishArtifacts="true"
            compress="false"
            source="${source.dir}" />

        <!-- See category.xml -->
        <exec executable="java">
            <arg value="-jar" />
            <arg value="${launcher.jar}" />
            <arg value="-console" />
            <arg value="-consolelog" />
            <arg value="-application" />
            <arg value="org.eclipse.equinox.p2.publisher.CategoryPublisher" />
            <arg value="-metadataRepository" />
            <arg value="${repo.url}" />
            <arg value="-categoryDefinition" />
            <arg value="${category.file.url}" />
            <arg value="-categoryQualifier" />
        </exec>
    </target>

</project>

category.xml

<?xml version="1.0" encoding="UTF-8"?>
<site>
    <bundle id="org.ops4j.pax.configmanager" version="0.2.2">
        <category name="ops4j" />
    </bundle>
   <bundle id="org.ops4j.pax.logging.pax-logging-api" version="1.7.3">
      <category name="ops4j"/>
   </bundle>
   <bundle id="org.ops4j.pax.logging.pax-logging-service" version="1.7.3">
      <category name="ops4j"/>
   </bundle>
   <category-def name="ops4j" label="ops4j"/>
</site>