Pages

Monday, December 6, 2010

Ant macros for Flex, Part 2

While the first part was an introduction to Ant macros, this second part will show you some more macros for Flex/Actionscript projects.

The first one uses the compc task to compile all classes of a given source directory to a swc library:

<macrodef name="compile-lib">
  <attribute name="source-dir" default="${source.dir}"/>
  <attribute name="target-dir" default="${build.dir}"/>
  <attribute name="swc-name"/>
  <element name="args" optional="true"/>

  <sequential>
    <fileset id="sources" dir="@{source-dir}">
      <include name="**/*.as"/>
      <include name="**/*.mxml"/>
    </fileset>
    <pathconvert property="classes" pathsep=" " refid="sources">
      <compositemapper>
        <chainedmapper>
          <globmapper from="@{source-dir}/*" to="*" handledirsep="true" />
          <mapper type="package" from="*.as" to="*" />
        </chainedmapper>
        <chainedmapper>
          <globmapper from="@{source-dir}/*" to="*" handledirsep="true" />
          <mapper type="package" from="*.mxml" to="*" />
        </chainedmapper>
      </compositemapper>
    </pathconvert>
    
    <echo message="Compiling library @{swc-name} including classes: ${classes}"/>
    <compc
      output="@{target-dir}/@{swc-name}.swc"
      include-classes="${classes}"
      link-report="@{target-dir}/@{swc-name}-link-report.xml"
      keep-generated-actionscript="true"
      optimize="true"
      incremental="true">
        
      <source-path path-element="@{source-dir}"/>
      <external-library-path file="${libs.dir}/*.swc" append="false"/>
      <external-library-path file="${FLEX_HOME}/frameworks/libs/*.swc" append="false"/>
      <external-library-path file="${flex.playerglobal}" append="false"/>
      <args/>
    </compc>

  </sequential>
</macrodef>

In a first step the macro puts all *.as and *.mxml files in the source-dir into a fileset and then converts them to a comma separated list containing all qualified class names using pathconvert (for more on this see here and here and for an alternative approach see here).

After that it compiles the swc library using the compc task. Again you can pass additional compiler arguments using the args element (see part 1).

The second macro takes a swc library and creates an optimized runtime shared library out of it:

<macrodef name="create-rsl">
  <attribute name="source-dir" default="${build.dir}"/>
  <attribute name="target-dir" default="${build.dir}"/>
  <attribute name="swc-name"/>
  <sequential>
    <unzip src="@{source-dir}/@{swc-name}.swc" dest="@{target-dir}" overwrite="true">
      <patternset>
        <include name="library.swf"/>
      </patternset>
    </unzip>
    <move file="@{target-dir}/library.swf" tofile="@{target-dir}/@{swc-name}-library.swf"/>
    <exec executable="${flex.optimizer}" failonerror="true">
      <arg value="-input=@{target-dir}/@{swc-name}-library.swf"/>
      <arg value="-output=@{target-dir}/@{swc-name}.swf"/>
    </exec>
    <delete file="@{target-dir}/@{swc-name}-library.swf"/>
  </sequential>
</macrodef>

To do so, it first uses the unzip task to extract the library.swf, renames it using the move and then calls the flex optimizer using the exec task. The optimizer strips the swf file of all debugging code and metadata. With those two macros you can create runtime shared libraries with just two calls:

<target name="build-mylibrary">
  <compile-lib swc-name="MyLibrary" source-dir="${basedir}/src-mylibrary"/>
  <create-rsl swc-name="MyLibrary"/>
</target>

You can have macros for all kinds of things, be it running the flex unit test, building asdoc, running pmd or compiling locales. And once written you can move them from project to project.

More information on macros for Flex/Actionscript can be found here.

Sunday, December 5, 2010

Ant macros for Flex, Part 1

Ant macros are a nice way to reduce the size of build scripts, especially when you have lot's of modules and runtime shared libraries. The macrodef task always contains a sequential task containing all the actions to be done and multiple attributes and elements.

The first example is a macro for compiling modules using the mxmlc task (for applications you would not want use external libraries):

<macrodef name="compile-module">
  <attribute name="source-dir" default="${source.dir}"/>
  <attribute name="build-dir" default="${build.dir}"/>
  <attribute name="module-name"/>
  <element name="args" optional="true"/>
  <sequential>
    <echo message="Compiling module @{module-name}"/>
    <mxmlc debug="true" file="@{source-dir}/@{module-name}.mxml" incremental="true" link-report="@{build-dir}/@{module-name}-link-report.xml" locale="en_US" optimize="true" output="@{build-dir}/@{module-name}.swf">
      <source-path path-element="@{source-dir}"/>
      <external-library-path append="false" file="${libs.dir}/*.swc"/>
      <external-library-path append="false" file="${FLEX_HOME}/frameworks/locale/{locale}"/>
      <external-library-path append="false" file="${FLEX_HOME}/frameworks/libs/*.swc"/>
      <external-library-path file="${flex.playerglobal}"/>
      <args/>
    </mxmlc>
  </sequential>
</macrodef>

As you can see, the macro has three attributes, source-dir, build-dir and module-name as which get substituted in the sequential task. Additionally there is a args element which is also referenced in sequential task.

The following example shows how to use the macro:

<target name="compile-mymodule">
  <compile-module module-name="MyModule" source-dir="${source.dir}-mymodule">
    <args>
      <external-library-path file="${build.dir}/Core.swc" append="false"/>
    </args>
  </compile-module>
</target>

The macro compile-module is called with the attributes module-name and source-dir. All attributes with a default value can be left out, like build-dir. The args element is used to pass additional compiler arguments, like an external-library-path.

Macros are very useful for standardizing the build process. If you want to create link reports for all your modules and transform them using xslt for better readability, you can do all this in the macro definition.

The second part will cover macros for compiling libraries and creating runtime shared libraries.

Friday, December 3, 2010

Localization of Flex applications using ExcelAntTasks

ExcelAntTasks is a small tool which allows you to define all locales in an Excel file and to convert them automatically to *.properties files using Ant.

The following image shows locales defined in an Excel file:



The first column contains the keys and the second row contains the identifiers for the locales (en_US, de_DE and so on). Empty fields (see de_DE) mean that the value of a fallback locale (en_US) should be used. All blank fields won't show up in the *.properties files.

Now let's take a look at the build script to convert the locales:

<project default="buildLocales" name="ExcelAntTask Test">
  <taskdef classname="excelanttasks.ConvertExcel" classpath="build/excelAntTasks.jar" name="convert"/>
  <target name="buildLocales">
    <convert excelpath="Locale.xls" localepath="locale/"/>
  </target>
</project>

The ExcelAntTasks are made available using the taskdef tag. After that you can convert Excel files using the convert tag, which provides the following attributes:

- excelpath: The path to the excel file. Default is "Locale.xls".
- localepath: The path where to store the created property files. Default is "locale/".
- resourcename: The name of the created property file. Default is "Locale.properties".
- headerrownumber: The number of the header row. The header row contains the identifiers for the locales (en_US, de_DE and so on). Default is 2.
- keycolumnnumber: The number of the key column. The key column contains the keys used in Flex. Default is 1.
- keyLabel: The identifier of the key column. Default is "labelkey".

Running the build script creates a folder and a *.properties file for each locale identifier defined in the Excel file:



As you can see, there's one additional locales file called debug which maps the keys to the keys and which can be used to identify not yet localized string in the user interface.

Right now it is not possible to convert XML-based Excel files (XLSX, Excel 2007+), but this feature is definitely planned.