Much ado about scripting, Linux & Eclipse: card subject to change

2010-02-18

p2 Repository Association And The Fine Art Of Forceably Enabling Disabled Sites

This week I've spent some time exploring how to associate p2 repo sites with other sites. The reason for this is that we publish features which depend on other publishers' features, and so would like to be able to have our update site automatically enable sites on which we depend in the end user's Eclipse.

The first attempt to do this was by using p2.inf files. Based on examples on blogs and in newsgroups, I added this p2.inf file into our BIRT Integration feature:

instructions.configure=addRepository(location:http${#58}//download.eclipse.org/releases/galileo/,type:0,name:Eclipse Galileo,enabled:true); \
   addRepository(location:http${#58}//download.eclipse.org/releases/galileo/,type:1,name:Eclipse Galileo,enabled:true); \
   addRepository(location:http${#58}//download.eclipse.org/eclipse/updates/3.5/,type:0,name:Eclipse 3.5,enabled:true); \
   addRepository(location:http${#58}//download.eclipse.org/eclipse/updates/3.5/,type:1,name:Eclipse 3.5,enabled:true); \
   addRepository(location:http${#58}//download.eclipse.org/birt/update-site/2.5/,type:0,name:BIRT 2.5,enabled:true); \
   addRepository(location:http${#58}//download.eclipse.org/birt/update-site/2.5/,type:1,name:BIRT 2.5,enabled:true);
Unfortunately, this didn't work - I got this error while building:

 java.lang.IllegalArgumentException: No action found for: addRepository.

So, hoping that using a fully-qualified name for the action would help, I tried this:

instructions.configure=org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/releases/galileo/,type:0,name:Eclipse Galileo,enabled:true); \
   org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/releases/galileo/,type:1,name:Eclipse Galileo,enabled:true); \
   org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/eclipse/updates/3.5/,type:0,name:Eclipse 3.5,enabled:true); \
   org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/eclipse/updates/3.5/,type:1,name:Eclipse 3.5,enabled:true); \
   org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/birt/update-site/2.5/,type:0,name:BIRT 2.5,enabled:true); \
   org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(location:http${#58}//download.eclipse.org/birt/update-site/2.5/,type:1,name:BIRT 2.5,enabled:true);

Success! The build no longer complained. Of course I wasn't getting any associate sites enabled when I added the new repo into Eclipse. Why, I wondered?

Thankfully, I was told that the now-deprecated Metadata Generator (org.eclipse.equinox.p2.metadata.generator.EclipseGenerator) doesn't support p2.inf files, so it was finally time to switch to Eclipse 3.5's Update Site Publisher (org.eclipse.equinox.p2.publisher.UpdateSitePublisher), which can be run like this as a drop-in replacement for the above application:

<echo>Run p2.publisher.UpdateSitePublisher using launcherjar = @{launcherjar}</echo>
<java jar="@{launcherjar}"
      fork="true" timeout="10800000"
      jvm="${java.home}/bin/java"
      failonerror="false" maxmemory="256m" taskname="p2">
 <classpath>
  <fileset dir="${builder.build.path}/plugins"
           includes="org.eclipse.equinox.launcher_*.jar, org.eclipse.equinox.p2.publisher_*.jar, org.eclipse.equinox.p2.updatesite_*.jar"
  />
  <fileset dir="${clean.eclipse.home}/plugins"
           includes="org.eclipse.equinox.launcher_*.jar, org.eclipse.equinox.p2.publisher_*.jar, org.eclipse.equinox.p2.updatesite_*.jar"
  />
  <pathelement location="${builder.build.path}/plugins" />
  <pathelement location="${clean.eclipse.home}/plugins" />
 </classpath>
 <arg line=" org.eclipse.equinox.launcher.Main -application org.eclipse.equinox.p2.publisher.UpdateSitePublisher" />
 <arg line=" -metadataRepository file:${updateSiteJarDir}/ -metadataRepositoryName "${update.site.product.name} ${update.site.description} Update Site"" />
 <arg line=" -artifactRepository file:${updateSiteJarDir}/ -artifactRepositoryName "${update.site.product.name} ${update.site.description} Artifacts"" />
 <arg line=" -source ${updateSiteJarDir}/" />
 <arg line=" -compress -publishArtifacts -reusePack200Files -configs *,*,*" />
</java>

Having switched out the deprecated app for its successor, I then discovered that using the instructions.configure touchpoint was way too late in the process to be of any use; this information is only used when you install the feature, not when you poll the repo for metadata. So to add the BIRT 2.5 update site I'd have to install the BIRT integration feature... which depends on the BIRT 2.5 site. I needed to inject this requirement in at an earlier point in the process.

So, the next step was to hit up #equinox-dev and ask for help, which I got from Pascal "LeNettoyeur" Rapicault, fellow IBM alumnus. He suggested that I append into the content.xml file in my repo the following information. Note that type 0 and 1 represent metadata repo and artifact repo, and options=1 or 0 is used to mark the site enabled or disabled.

  <references size='2'>
    <repository uri='http://download.eclipse.org/birt/update-site/2.5/'
url='http://download.eclipse.org/birt/update-site/2.5/' type='0' options='1'/>
    <repository uri='http://download.eclipse.org/birt/update-site/2.5/'
url='http://download.eclipse.org/birt/update-site/2.5/' type='1' options='1'/>
  </references>
</repository>

Success, I again thought, since the associated sites were finally being added and enabled into Eclipse when the repo was scanned for metadata. I even scripted this process so that it could be integrated into our build process, or simply reused, eg., to merge two update sites and add some associate site for optional feature installs.

But alas, every step forward brings another step backward, as I discovered that available but disabled sites are NOT enabled despite the instructions in the repo. In other words, I cannot force an existing, yet disabled site to become enabled because my repo requires it. I can only document the requirement and hope that users will RTFM without getting too annoyed.

So, what's the solution? Well, there currently isn't one. But if this scenario seems like something you'd like to see improved, please cast your votes & comments in one of these bugs:

3 comments:

aniefer said...

Bug 291696 tracks the replacement of the metadata generator. If you had done this after M6 you probably would not have noticed that the old generator does not have full support for the p2.inf :).

nickb said...

Actually, I found a workaround. If you need to forceably enable http://somewhere.com/path/to/a/repo/ but that's already included in an upstream dependency (eg., the default-disabled BIRT site that comes with Helios), you can add an extra slash into the URL to convince p2 it's a new site and just add the new one. Thus:

http://somewhere.com/path/to/a/repo/

becomes

http://somewhere.com/path//to/a/repo/

and while the user will end up with two nearly-identical URLs in their list, at least they won't have to manually enable a site to install your goodies.

Jose Muñoz said...

I have followed the steps to associate a repository. I can see it now being added as part of the references in the metadata repository (content.xml), but when I select the feature to be installed. The dependencies discovering fails because the site is added but is not enabled. I double check that the parameter "enable:true" was set in the p2.inf instructions. So not sure what I'm missing. I tried the installation on a fresh eclipse, so no sites like mine are previously added.