Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[linux-distros-dev] an easy way to build eclipse plugins

Hi, 

I cooked up a method for building Eclipse features or plugins in a
relatively easy way. We're currently using this build method in RHEL and
I'd like to move it over to Fedora. Before I do that, I wanted to get
comments from everybody here. 

The build method uses a set of generic releng or builder scripts that
builds a feature or plugin from a source archive which has been created
with a cvs checkout or has been exported by eclipse. I whipped up a
little page explaining how to export an appropriate source archive:

http://people.redhat.com/bkonrath/eclipse/exporting-buildable-source-archives.html

This is probably something that should be put on the wiki if everybody
agrees this build method is a good one to standardize on.

Attached is a patch to add these generic releng scripts to the templates
directory of pde.build. I called this build method package-build. If
we're all in agreement on this, we should request this patch be added to
pde.build.

Here's a quick overview of how this build method works works:

* The source is unpacked.
* Use the copy-platform script to setup a fake SDK root dir. (This is 
  needed because pde.build doesn't support building a feature if the 
  feature is already installed. Without it, it would not be possible to 
  build plugins of the same version more than once in a given build 
  root. IMHO this is a bug in pde.build and I may try to fix it so we 
  can get rid of this.)
* Call the builder with a line like this:

java -cp %{eclipse_base}/startup.jar                   \
     -Duser.home=$homedir                              \
     org.eclipse.core.launcher.Main                    \
     -application org.eclipse.ant.core.antRunner       \
     -Dtype=feature                                    \
     -Did=net.sourceforge.phpeclipse                   \
     -DsourceDirectory=$(pwd)                          \
     -DbaseLocation=$SDK                               \
     -Dbuilder=%{eclipse_base}/plugins/org.eclipse.pde.build_3.1.2/templates/package-build  \
     -f %{eclipse_base}/plugins/org.eclipse.pde.build_3.1.2/scripts/build.xml

  All that really has to be set is the id and the type. The rest is a 
  template.
* The builder will then call a shell script to create a 'plugins' and 
  'features' directory and will add appropriate symlinks to the plugins 
  and features inside these directories. This step just makes the 
  sources look as though they have been checked out by the fetch stage 
  of the releng process.   
* The build then proceeds through a normal releng build expect for the 
  small hack needed to get the assemble target called for an id 
  that has been defined on the command line. Details are in the 
  customTargets.xml in the patch if you're interested

This build method makes it possible to create an application to generate
templates for rpms. I don't know details of how the Debian rules and
Gentoo ebuilds work, but I imagine it would be possible to make backends
for this app that would work for rpm, deb and ebuilds. Thoughts?

We are currently using this package build stuff for a few plugins that
we will be shipping in RHEL. I'm attaching the PHPeclipse spec as a
complete example. Note that the interaction between PHPeclipse and
apache/mysql is not setup in this specfile because PHPeclispe uses XAMPP
instead of the system software. When I have time, I'm going to write a
fragment or two to address these short coming and then will put
PHPeclipse into Fedora Extras. I've also attached the script I used to
generate the PHPeclipse source archive - upstream didn't seem to
interested in providing such an archive. If anybody wants an srpm of
this version of PHPeclipse, let me know.

I guess that all I have to say for now. Any comments or suggestions
would be appreciated.

Cheers, Ben
Index: templates/package-build/build.properties
===================================================================
RCS file: templates/package-build/build.properties
diff -N templates/package-build/build.properties
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/package-build/build.properties	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,12 @@
+buildDirectory=${sourceDirectory}/build
+buildLabel=rpmBuild
+archivePrefix=eclipse
+skipFetch=true
+javacFailOnError=true
+collectingFolder=eclipse
+archivesFormat=*,*,*-zip
+zipargs=-y
+javacDebugInfo=true
+archiveName=${id}.zip
+runPackager=false
+baseLocation=@eclipse_base@
Index: templates/package-build/customTargets-assemble-target.xml
===================================================================
RCS file: templates/package-build/customTargets-assemble-target.xml
diff -N templates/package-build/customTargets-assemble-target.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/package-build/customTargets-assemble-target.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,12 @@
+<project>
+	<!-- ===================================================================== -->
+	<!-- Targets to assemble the built elements for particular configurations  -->
+	<!-- These generally call the generated assemble scripts (named in -->
+	<!-- ${assembleScriptName}) but may also add pre and post processing -->
+	<!-- Add one target for each root element and each configuration -->
+	<!-- ===================================================================== -->
+
+	<target name="assemble.@id@">
+		<ant antfile="${assembleScriptName}" dir="${buildDirectory}"/>
+	</target>
+</project>
Index: templates/package-build/customTargets.xml
===================================================================
RCS file: templates/package-build/customTargets.xml
diff -N templates/package-build/customTargets.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/package-build/customTargets.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,144 @@
+<project name="Build specific targets and properties" default="noDefault">
+
+	<fail unless="type" message="Please set the ${type} property to 'feature', 'plugin' or 'fragment'." />
+	<fail unless="id" message="Please set the ${id} property to the feature, plugin or fragment id of the plugin you are building." />
+	<fail unless="sourceDirectory" message="Please set the ${sourceDirectory} property to the directory that has the source plugins." />
+
+	<!-- we need to do this because you can't expand variables in target names -->	
+	<copy file="${builder}/customTargets-assemble-target.xml" tofile="${buildDirectory}/customTargets-${id}-assemble-target.xml" /> 
+	<replace file="${buildDirectory}/customTargets-${id}-assemble-target.xml" token="@id@" value="${id}" />
+	<import file="${buildDirectory}/customTargets-${id}-assemble-target.xml" />
+
+	<!-- ===================================================================== -->
+	<!-- Run a given ${target} on all elements being built -->
+	<!-- Add on <ant> task for each top level element being built. -->
+	<!-- ===================================================================== -->
+	<target name="allElements">
+		<ant antfile="${genericTargets}" target="${target}">
+			<property name="type" value="${type}" />
+			<property name="id" value="${id}" />
+		</ant>
+	</target>
+
+	
+	<!-- ===================================================================== -->
+	<!-- Check out map files from correct repository -->
+	<!-- ===================================================================== -->
+	<target name="getMapFiles">
+	</target>
+
+	<!-- ===================================================================== -->
+
+	<target name="clean" unless="noclean">
+		<antcall target="allElements">
+			<param name="target" value="cleanElement" />
+		</antcall>
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before setup -->
+	<!-- ===================================================================== -->
+	<target name="preSetup">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after setup but before starting the build proper -->
+	<!-- ===================================================================== -->
+	<target name="postSetup">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before fetching the build elements -->
+	<!-- ===================================================================== -->
+	<target name="preFetch">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after fetching the build elements -->
+	<!-- ===================================================================== -->
+	<target name="postFetch">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before generating the build scripts. -->
+	<!-- ===================================================================== -->
+	<target name="preGenerate">
+		<!-- Eclipse expects the feature projects to be in the 'features' directory and 
+   		plugin projects to be in the 'plugins' directory. The build infrastructure 
+		normally arranges the projects during the fetch stage. Since we aren't doing
+ 		the fetch stage, we have to manually arrange the files -->
+		<exec dir="${builder}" executable="/bin/sh">
+			<arg line="prepare-build-dir.sh ${sourceDirectory} ${buildDirectory}" />
+		</exec> 
+
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after generating the build scripts. -->
+	<!-- ===================================================================== -->
+	<target name="postGenerate">
+		<antcall target="clean" />
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before running the build.xmls for the elements being built. -->
+	<!-- ===================================================================== -->
+	<target name="preProcess">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after running the build.xmls for the elements being built. -->
+	<!-- ===================================================================== -->
+	<target name="postProcess">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before running assemble. -->
+	<!-- ===================================================================== -->
+	<target name="preAssemble">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after  running assemble. -->
+	<!-- ===================================================================== -->
+	<target name="postAssemble">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do before running package. -->
+	<!-- ===================================================================== -->
+	<target name="prePackage">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after  running package. -->
+	<!-- ===================================================================== -->
+	<target name="postPackage">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do after the build is done. -->
+	<!-- ===================================================================== -->
+	<target name="postBuild">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do to test the build results -->
+	<!-- ===================================================================== -->
+	<target name="test">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Steps to do to publish the build results -->
+	<!-- ===================================================================== -->
+	<target name="publish">
+	</target>
+
+	<!-- ===================================================================== -->
+	<!-- Default target                                                        -->
+	<!-- ===================================================================== -->
+	<target name="noDefault">
+		<echo message="You must specify a target when invoking this file" />
+	</target>
+
+</project>
Index: templates/package-build/prepare-build-dir.sh
===================================================================
RCS file: templates/package-build/prepare-build-dir.sh
diff -N templates/package-build/prepare-build-dir.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ templates/package-build/prepare-build-dir.sh	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+
+make_links()
+{
+  TYPE=$1
+  TYPEDIR=$2
+  shift; shift;
+  XMLFILES=$@
+  
+  CURBUILDFILE=$BUILDDIR/tmp/$TYPE-build.xml
+  cat $BUILDFILE | sed "s|@type@|$TYPE|" > $CURBUILDFILE
+
+  for f in $XMLFILES; do
+    PROJECTDIR=$(dirname $f)
+    PROJECTNAME=$(ant -Dbasedir=$PROJECTDIR -f $CURBUILDFILE 2>&1 | grep echo | cut --delimiter=' ' -f 7)
+    if [ -z $PROJECTNAME ]; then
+      if [ ! -e $PROJECTDIR/META-INF/MANIFEST.MF ]; then
+        echo "ERROR: could not determine the feature id for $PROJECTDIR"
+        exit 1
+      fi
+      PROJECTNAME=$(grep Bundle-SymbolicName $PROJECTDIR/META-INF/MANIFEST.MF | cut --delimiter=';' -f 1 | cut --delimiter=' ' -f 2)
+      if [ -z $PROJECTNAME  ]; then
+        echo "ERROR: could not determine the feature id for $PROJECTDIR"
+        exit 1
+      fi
+    fi
+    
+    echo "  making symlink: $BUILDDIR/$TYPEDIR/$PROJECTNAME -> $PROJECTDIR"
+    ln -sf $PROJECTDIR $BUILDDIR/$TYPEDIR/$PROJECTNAME 
+
+  done
+}
+
+
+if [ $# -ne 2 ]; then 
+  echo "usage: $0 <path to source dir> <path to build dir>"
+  exit 1
+fi
+
+if [ ! -d $1 ]; then
+  echo "usage: $0 <path to source dir> <path to build dir>"
+  exit 1
+fi
+
+SOURCEDIR=$1
+BUILDDIR=$2
+
+echo "preparing files in $1 for buildfile generation ..."
+mkdir -p $BUILDDIR
+
+# make some ant build files to extract the id from the feature.xml, plugin.xml or the fragment.xml
+mkdir -p $BUILDDIR/tmp
+BUILDFILE=$BUILDDIR/tmp/build.xml
+
+echo "<project default=\"main\">
+	<target name=\"main\">
+               	<xmlproperty file=\"@type@.xml\" collapseAttributes=\"true\"/>
+		<fail unless=\"@type@.id\" message=\"feature.id not set\"/>
+               	<echo message=\"\${@type@.id}\" />
+        </target>
+</project>" > $BUILDFILE
+
+# find the feature.xml, plugin.xml and fragment.xml files
+FEATURES=$(find $SOURCEDIR -name feature.xml)
+PLUGINS=$(find $SOURCEDIR -name plugin.xml) 
+FRAGMENTS=$(find $SOURCEDIR -name fragment.xml) 
+
+# make the directories eclipse is expecting 
+echo "  making the 'features' and 'plugins' directories"
+mkdir -p $BUILDDIR/features $BUILDDIR/plugins
+
+# make symlinks for the features
+make_links feature features $FEATURES
+
+# make the symlinks for plugins
+make_links plugin plugins $PLUGINS
+
+# make the symlinks for fragments - they go in the plugins directory as well
+make_links fragment plugins $FRAGMENTS
+
+rm -rf $BUILDDIR/tmp
+echo done 

Attachment: make-phpeclipse-source-archive.sh
Description: application/shellscript

%define fedora          0
%define redhat          1
%if %{fedora}
%define gcj_support     1
%else
%define gcj_support     0
%endif

%define eclipse_name	eclipse
%define eclipse_base	%{_datadir}/%{eclipse_name}

Name:           eclipse-phpeclipse
Version:        1.1.8
Release:        3
Summary:        PHP Eclipse plugin

Group:          Text Editors/Integrated Development Environments (IDE)
License:        Common Public License (CPL) 1.0
URL:            http://phpeclipse.net
Source0:        phpeclipse-%{version}.tar.gz
Source1:        make-phpeclipse-source-archive.sh 
Source2:	default_linux.properties
Source3:	README-php-browser.txt
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

BuildRequires:		eclipse-pde
%if %{gcj_support}
BuildRequires:		gcc-java >= 4.0.2
BuildRequires:		java-gcj-compat-devel >= 1.0.33
Requires(post):		java-gcj-compat >= 1.0.33
Requires(postun):	java-gcj-compat >= 1.0.33
%else
BuildRequires:		java-devel >= 1.4.2
%endif

%if %{gcj_support}
ExclusiveArch:		%{ix86} x86_64 ppc ia64
%else
BuildArch:		noarch
%endif

Requires:		eclipse-platform >= 1:3.1.2
Requires:		eclipse-platform < 1:3.1.3
Requires: 		eclipse-pde-runtime >= 1:3.1.2
Requires: 		php 
#Requires:		httpd
#Requires: 		php-mysql 
#Requires:		mysql

%description
The PHPeclipse plugin allows developers to write PHP webpages and scripts in Eclipse. 

%prep
%setup -q -n phpeclipse-1.1.8

%build
# See comments in the script to understand this.
/bin/sh -x %{eclipse_base}/buildscripts/copy-platform SDK %{eclipse_base}
SDK=$(cd SDK > /dev/null && pwd)

# Eclipse may try to write to the home directory.
mkdir home
homedir=$(cd home > /dev/null && pwd)

# build the main phpeclipse feature
java -cp %{eclipse_base}/startup.jar                   \
     -Duser.home=$homedir                              \
     org.eclipse.core.launcher.Main                    \
     -application org.eclipse.ant.core.antRunner       \
     -Dtype=feature                                    \
     -Did=net.sourceforge.phpeclipse                   \
     -DsourceDirectory=$(pwd)                          \
     -DbaseLocation=$SDK                               \
     -Dbuilder=%{eclipse_base}/plugins/org.eclipse.pde.build_3.1.2/templates/package-build  \
     -f %{eclipse_base}/plugins/org.eclipse.pde.build_3.1.2/scripts/build.xml

%install
rm -rf $RPM_BUILD_ROOT
install -d -m 755 $RPM_BUILD_ROOT%{eclipse_base}
unzip -q -d $RPM_BUILD_ROOT%{eclipse_base}/.. build/rpmBuild/net.sourceforge.phpeclipse.zip
rm $RPM_BUILD_ROOT/%{eclipse_base}/plugins/org.eclipse.pde.runtime_3.1.1.jar

# put the preferences in the right place
mkdir $RPM_BUILD_ROOT/%{eclipse_base}/plugins/net.sourceforge.phpeclipse.externaltools_%{version}/prefs/ 
cp %{SOURCE2} $RPM_BUILD_ROOT%{eclipse_base}/plugins/net.sourceforge.phpeclipse.externaltools_%{version}/prefs/

# put the README in the PHPeclipse feature directory
cp %{SOURCE3} $RPM_BUILD_ROOT%{eclipse_base}/features/net.sourceforge.phpeclipse_%{version}

%if %{gcj_support}
  aot-compile-rpm
%endif

%clean
rm -rf $RPM_BUILD_ROOT

%if %{gcj_support}
%post
%{_bindir}/rebuild-gcj-db
%postun
%{_bindir}/rebuild-gcj-db
%endif

%files
%defattr(-,root,root)
%{eclipse_base}/features/net.sourceforge.phpeclipse_*
%{eclipse_base}/plugins/net.sourceforge.phpdt.smarty.ui_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.core_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.debug.core_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.debug.ui_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.externaltools_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.launching_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.phphelp_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.ui_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.webbrowser_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.xml.core_*
%{eclipse_base}/plugins/net.sourceforge.phpeclipse.xml.ui_*
%if %{gcj_support}
%{_libdir}/gcj/%{name}/* 
%endif

%changelog
* Mon May 15 2006 Ben Konrath <bkonrath@xxxxxxxxxx> 1.1.8-3
- Add preferences for the external tools on linux.
- Add README for httpd integration.

* Fri May 12 2006 Ben Konrath <bkonrath@xxxxxxxxxx> 1.1.8-2
- Add requires.

* Wed Apr 26 2006 Ben Konrath <bkonrath@xxxxxxxxxx> 1.1.8-1
- initial version

Back to the top