Actions

Difference between revisions of "Building Joomla Extensions with Apache Ant"

From Joomla! Documentation

(Using Apache Ant to build Joomla extensions)
 
(13 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 +
This page will make an effort to provide a both consistent and flexible extensions structure, in addition to give a short explanation on how to use the included ant scripts to build and package extensions.
 +
 
== Environment ==
 
== Environment ==
  
The build scripts depend on three environment variables, these values can either be set in the environment, or you can edit common.xml and set them manually
+
The build scripts depend on three environment variables, these values can either be set in the environment, you can tell your IDE to set them when running the script or as a last resort, you can edit common.xml and set them manually. Setting them manually is not recommended for projects with multiple participants or testing environments as the paths have to match.
  
 
'''SOURCEDIR'''
 
'''SOURCEDIR'''
Line 8: Line 10:
 
:This is the path to a temporary directory used to build packages, can be a relative or an absolute path  
 
:This is the path to a temporary directory used to build packages, can be a relative or an absolute path  
 
'''RELEASEDIR'''
 
'''RELEASEDIR'''
:This is the folder in which to put the packaged extensions when script is invoked with the 'package' target  
+
:This is the folder in which to put the packaged extensions when script is invoked with the 'package' target
  
 
== Build Targets ==
 
== Build Targets ==
Line 41: Line 43:
 
   <param name="PREFIX" value="system"/>
 
   <param name="PREFIX" value="system"/>
 
  </antcall>
 
  </antcall>
 
== Extension structure ==
 
=== Component ===
 
=== Module ===
 
=== Plugin ===
 
=== Template ===
 
  
 
== Scripts ==
 
== Scripts ==
Line 52: Line 48:
 
=== build.xml ===
 
=== build.xml ===
  
This file is per project or per extension, whatever the user sees fit, it includes the common.xml file and specifies which extensions to build. You can have one build file per extension or you can use one build file to build many extensions. I prefer having one build file for each extension named by the extension, so the build file for a helloworld component would be build_com_helloworld.xml or simply com_helloworld.xml. This is shown in the downloadable test packages.
+
This file is per project or per extension, whatever the user sees fit, it includes the common.xml file and specifies which extensions to build. You can have one build file per extension or you can use one build file to build many extensions. It is, however, preferable to have one build file for each extension named by the extension, so the build file for a helloworld component would be build_com_helloworld.xml or simply com_helloworld.xml. This is shown in the downloadable example packages.
  
 
  <?xml version="1.0" encoding="UTF-8"?>
 
  <?xml version="1.0" encoding="UTF-8"?>
Line 75: Line 71:
 
         </target>
 
         </target>
 
  </project>
 
  </project>
 
  
 
=== common.xml ===
 
=== common.xml ===
Line 100: Line 95:
 
         </loadfile>
 
         </loadfile>
 
   
 
   
        <property name="version" value="${NOW}"/>
+
         <condition property="version" value="${NOW}_r${dist.revision}" else="${NOW}">
         <condition property="version" value="${NOW}_r${dist.revision}">
+
                <isset property="dist.revision"/>
                <isset property="dist.revision"/>
+
 
         </condition>
 
         </condition>
 
   
 
   
Line 188: Line 182:
 
         </target>
 
         </target>
 
  </project>
 
  </project>
 +
 +
== Example workflow ==
 +
 +
* Test install of Joomla 1.5
 +
* Local svn checkout of your extension repository containing extensions in a structure like the attached example
 +
* Run 'ant -f com_helloworld.xml package' which builds the extension in the specified release directory
 +
* Install the extension on Joomla test site
 +
* Use the test site project to develop the extension and debug it
 +
* When changes are made, run 'ant -f com_helloworld.xml build sync' to first build a temporary tree in the specified build folder, then the 'sync' target will synchronize the changes between the build directory and the extension directory in the repository
 +
* Inspect the changes and do a svn commit
 +
* Now you can either package the extension with the 'package target' or continue development on the test site until a new commit is to be made
 +
 +
<noinclude>
 +
[[Category:Development]]
 +
</noinclude>
 +
[[Category:Tutorials]][[Category:Component Development]]

Revision as of 11:37, 16 August 2011

This page will make an effort to provide a both consistent and flexible extensions structure, in addition to give a short explanation on how to use the included ant scripts to build and package extensions.

Contents

Environment

The build scripts depend on three environment variables, these values can either be set in the environment, you can tell your IDE to set them when running the script or as a last resort, you can edit common.xml and set them manually. Setting them manually is not recommended for projects with multiple participants or testing environments as the paths have to match.

SOURCEDIR

This is the absolute path to the Joomla installation you are testing the extension on

BUILDDIR

This is the path to a temporary directory used to build packages, can be a relative or an absolute path

RELEASEDIR

This is the folder in which to put the packaged extensions when script is invoked with the 'package' target

Build Targets

NOTE: The PREFIX property in the build targets has different meaning depending on the extension type, for plugins it is used to determine the plugin group, and for other types it is used to determine whether the extension is for the site or for the administrator. To make a build target with an admin extension set PREFIX to "administrator"

buildcomponent

The target to build a component takes the component name and prefix, prefix is either empty or "administrator" if we are building a component for the backend
<antcall target="buildcomponent">
  <param name="NAME" value="com_helloworld"/>
  <param name="PREFIX" value=""/>
</antcall>

buildmodule

The target to build a module takes the module name and prefix, prefix is either empty or "administrator" if we are building a module for the backend
<antcall target="buildmodule">
  <param name="NAME" value="module_helloworld"/>
  <param name="PREFIX" value=""/>
</antcall>

buildtemplate

The target to build a template takes the template name and prefix, prefix is either empty or "administrator" if we are building a template for the backend
<antcall target="buildtemplate">
  <param name="NAME" value="helloworld"/>
  <param name="PREFIX" value=""/>
</antcall>

buildplugin

The target to build a plugin takes the template name and prefix, prefix is the plugin group to which the plugin belongs
<antcall target="buildplugin">
  <param name="NAME" value="plg_helloworld"/>
  <param name="PREFIX" value="system"/>
</antcall>

Scripts

build.xml

This file is per project or per extension, whatever the user sees fit, it includes the common.xml file and specifies which extensions to build. You can have one build file per extension or you can use one build file to build many extensions. It is, however, preferable to have one build file for each extension named by the extension, so the build file for a helloworld component would be build_com_helloworld.xml or simply com_helloworld.xml. This is shown in the downloadable example packages.

<?xml version="1.0" encoding="UTF-8"?>
<project name="helloworld" default="all" basedir=".">
       <import file="common.xml"/>
       <target name="all" depends="build,sync,package"/>
       <target name="package">
               <antcall target="_package">
                       <param name="NAME" value="com_helloworld"/>
               </antcall>
       </target>
       <target name="build">
               <antcall target="buildcomponent">
                       <param name="NAME" value="com_helloworld"/>
                       <param name="PREFIX" value=""/>
               </antcall>
       </target>
       <target name="sync">
               <antcall target="_sync">
                       <param name="NAME" value="com_helloworld"/>
               </antcall>
       </target>
</project>

common.xml

This is where the magic happens, this file contains build targets to build any module, plugin, template or component. You should normally not have to modify this file unless you need to manually set the environment variables or change the overall structure of an extension.

<?xml version="1.0" encoding="UTF-8"?>
<project>
       <property environment="env"/>
       <property name="source" value="${env.SOURCEDIR}"/>
       <property name="release" value="${env.RELEASEDIR}"/>
       <property name="builddir" value="${env.BUILDDIR}"/>
       <property name="verbose" value="false"/>

       <tstamp>
               <format property="NOW" pattern="yyyyMMdd"/>
       </tstamp>

       <loadfile property="dist.revision" srcFile="./.svn/entries" failonerror="false">
               <filterchain>
                       <headfilter lines="1" skip="3"/>
                       <deletecharacters chars="\n"/>
               </filterchain>
       </loadfile>

       <condition property="version" value="${NOW}_r${dist.revision}" else="${NOW}">
                <isset property="dist.revision"/>
       </condition>

       <target name="_clean">
               <delete dir="${builddir}/${NAME}" verbose="${verbose}"/>
       </target>

       <target name="_sync">
               <sync todir="${NAME}" includeemptydirs="true">
                       <fileset dir="${builddir}/${NAME}"/>
                       <preserveintarget>
                               <include name="**/.svn/**"/>
                       </preserveintarget>
               </sync>
       </target>

       <target name="_package">
               <zip destfile="${release}/${NAME}_${version}.zip" basedir="${NAME}" excludes=".svn"/>
       </target>

       <target name="buildplugin" depends="_clean">
               <copy todir="${builddir}/${NAME}" overwrite="true" verbose="${verbose}" failonerror="false">
                       <fileset dir="${source}/plugins/${PREFIX}">
                               <include name="*${NAME}*"/>
                       </fileset>
               </copy>
       </target>
       <target name="buildmodule" depends="_clean">
               <copy todir="${builddir}/${NAME}" overwrite="true" verbose="${verbose}" failonerror="false">
                       <fileset dir="${source}/${PREFIX}/modules/${NAME}"/>
               </copy>
               <copy todir="${builddir}/${NAME}/media" overwrite="true" verbose="${verbose}"  failonerror="false">
                       <fileset dir="${source}/media/${NAME}"/>
               </copy>
               <copy todir="${builddir}/${NAME}/language" overwrite="true" verbose="${verbose}"  failonerror="false" flatten="true">
                       <fileset dir="${source}/${PREFIX}/language">
                               <include name="*/*${NAME}.ini" />
                       </fileset>
               </copy>
       </target>
       <target name="buildtemplate" depends="_clean">
               <copy todir="${builddir}/${NAME}" overwrite="true" verbose="${verbose}" failonerror="false">
                       <fileset dir="${source}/${PREFIX}/templates/${NAME}"/>
               </copy>
       </target>
       <target name="buildcomponent" depends="_clean">
               <mkdir dir="${builddir}/${NAME}/site"/>
               <mkdir dir="${builddir}/${NAME}/admin"/>
               <mkdir dir="${builddir}/${NAME}/admin/sql"/>
               <mkdir dir="${builddir}/${NAME}/media"/>
               <mkdir dir="${builddir}/${NAME}/language"/>
               <mkdir dir="${builddir}/${NAME}/language/admin"/>
               <mkdir dir="${builddir}/${NAME}/language/site"/>
               <copy todir="${builddir}/${NAME}/media" overwrite="true" verbose="${verbose}" failonerror="false">
                       <fileset dir="${source}/media/${NAME}"/>
               </copy>
               <copy todir="${builddir}/${NAME}/admin" overwrite="true" verbose="${verbose}">
                       <fileset dir="${source}/administrator/components/${NAME}"/>
               </copy>
               <copy todir="${builddir}/${NAME}/language/admin" overwrite="true" verbose="${verbose}" flatten="true">
                       <fileset dir="${source}/administrator/language">
                               <exclude name="overrides/*"/>
                               <exclude name="pdf_fonts/*"/>
                               <include name="**/*${NAME}*.ini"/>
                       </fileset>
               </copy>
               <copy todir="${builddir}/${NAME}/site" overwrite="true" verbose="${verbose}">
                       <fileset dir="${source}/components/${NAME}"/>
               </copy>
               <copy todir="${builddir}/${NAME}/language/site" overwrite="true" verbose="${verbose}" flatten="true">
                       <fileset dir="${source}/language">
                               <exclude name="overrides/*"/>
                               <exclude name="pdf_fonts/*"/>
                               <include name="**/*${NAME}*.ini" />
                       </fileset>
               </copy>
               <move file="${builddir}/${NAME}/admin/${NAME}.xml" todir="${builddir}/${NAME}" verbose="${verbose}"/>
               <move file="${builddir}/${NAME}/admin/uninstall.${NAME}.php" todir="${builddir}/${NAME}" verbose="${verbose}" failonerror="false"/>
               <move file="${builddir}/${NAME}/admin/install.${NAME}.php" todir="${builddir}/${NAME}" verbose="${verbose}" failonerror="false"/>
               <move todir="${builddir}/${NAME}/admin/sql" verbose="${verbose}">
                       <fileset dir="${builddir}/${NAME}/admin">
                               <include name="*.sql"/>
                       </fileset>
               </move>
       </target>
</project>

Example workflow

  • Test install of Joomla 1.5
  • Local svn checkout of your extension repository containing extensions in a structure like the attached example
  • Run 'ant -f com_helloworld.xml package' which builds the extension in the specified release directory
  • Install the extension on Joomla test site
  • Use the test site project to develop the extension and debug it
  • When changes are made, run 'ant -f com_helloworld.xml build sync' to first build a temporary tree in the specified build folder, then the 'sync' target will synchronize the changes between the build directory and the extension directory in the repository
  • Inspect the changes and do a svn commit
  • Now you can either package the extension with the 'package target' or continue development on the test site until a new commit is to be made