JarJar with Ant - how to use a Rule file - ant

I would like to know how to run JarJar with Ant, passing the rules in with an external Rules file.
1) I know I can pass the rules in one by one as below:
<jarjar destfile="B.jar" >
<zipfileset src="A.jar" />
<rule pattern="com.a.**" result="test.b.#1" />
</jarjar>
2) I know I can pass the rules in a file if I run it from the command line:
java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
3) I can use the above command line in an Ant <exec> task. (best workaround)
4) I found some reference to using a <rulesFile> tag in Maven.
The above options are not ideal for what I would like to do.
I want to run JarJar from an Ant task, passing in a rules file.

I have been unable to get any information about this, from any forum, or by mailing the developers of JarJar, so I have decided to answer this question with a workaround that I am using:
Use the DOCTYPE & ENTITY xml entities (as per suggestion on Ant website)
As an example, the below build.xml file includes the contents of another test.txt file inline. I import the text file using the tag include_this (this is my name - you can use any name here):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project [
<!ENTITY include_this SYSTEM "test.txt">
]>
<project name="Test" default="build" >
<target name="build" >
&include_this;
</target>
</project>
In this simple example, the contents of the test.txt file is:
<echo>This is a test.</echo>
So I've been using this workaround to replace the rules in the jarjar call. Putting the rules in the test.txt file:
<rule pattern="com.**" result="${project.output}.com.#1" />
<rule pattern="org.**" result="${project.output}.org.#1" />
My jarjar call then becomes:
<!-- jarjar uses the same syntax as the jar task -->
<jarjar destfile="${jarjar.output.dir}/${project.output}.jar" >
<!-- source files -->
<zipfileset src="${jar.output.dir}/${project.output}.jar" />
<!-- refactoring rules -->
&include_this;
</jarjar>

Related

Change baseDir attribute while using import tag

Let me first provide the background of the problem I'm facing.
I have a directory structure as below.
c:\myDirectory
c:\myDirectory\Project1
c:\myDirectory\Scripts
Under the c:\myDirectory\Scripts there is a script that download the source code (from svn) and creates the c:\myDirectory\Project1 directory.
I have another ant scripts ( c:\myDirectory\Scripts**compile-source.xml ) that compiles the Project1
from an ant script build.xml that is downloaded to c:\myDirectory\Project1
Snippet for c:\myDirectory\Scripts\compile-source.xml
<project name="compile" default="buildAll" basedir=".">
<property file=".\build.properties">
</property>
.......
<import file="${project.home.path}/${project.name}/build.xml"/>
<target name="buildAll">
<antcall target="jar-pack"/>
</target>
</project>
Snippet for c:\myDirectory\Project1\build.xml.
<project name="CommonFeatures" default="jar-pack" basedir=".">
<description>
A build file for the Common Features project
</description>
....
</project>
Note that the basedir for the project is set as "." for both the above ant scripts.
When I execute the script c:\myDirectory\Scripts\compile-source.xml from the c:\myDirectory\Scripts directory the target "jar-pack" present in the c:\myDirectory\Project1\build.xml gets executed.
However, the problem is that basedir attribude in build.xml ( basedir="." ) is the current working directory and in this case its c:\myDirectory\Scripts. Hence the script build.xml errors out since the basedir for build.xml is expected to be c:\myDirectory\Project1. The build.xml script would have worked, if basedir="." were set to "c:\myDirectory\Project1", but unfortunately build.xml file comes from the source code that is downloaded and I'm unable to edit.
So here's my question, Is it possible to do any of the following.
Override the value of the attribude basedir="." in build.xml when the is done in c:\myDirectory\Scripts\compile-source.xml ?
Is it possible to change the basedir in build.xml by any other mechanism so that the script c:\myDirectory\Project1\build.xml is executed under directory c:\myDirectory\Project1 ?
Any other way to resolve this issue?
Any help from Ant experts to overcome this issue is highly appreciated.
You can update basedir using subant task. Check this answer
Create the following build.xml file (assuming it is in Z:/any/folder):
<?xml version="1.0" encoding="UTF-8"?>
<project name="project">
<target name="mytarget">
<subant target="debug">
<property name="basedir" value="X:/any/dir/with/project"/>
<fileset dir="Y:/any/folder/with" includes="build.xml"/>
</subant>
</target>
</project>
The you can execute ant mytarget from Z:/any/folder
You can specifically reference the location of your build file, which is described in this stack overflow thread. This would allow you to get and use the directory your build file resides in as a reference point.
For your case the usage of the subant or ant tasks may be better suited, but nevertheless...
You can (but you should know/consider the side-effects!) extend ant with the common ant-contrib task definitions and use the var task which is able to override properties. Make sure to use the latest version (> 1.0b3).
<!-- adjust to your path and include it somewhere at the beginning of your project file -->
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="lib/ant-contrib-1.0b3.jar" />
<!-- works e.g. for basedir = /foo/bar to update it to /foo/bar/.. ~ /foo -->
<var name="basedir" value="${basedir}/.." />
update: but one has to be careful, because this does not change . (current working directory) (so <property name="x" location="tmp" /> would be relative to . and not to basedir anymore ; update: setting basedir outside of ant or via <project basedir= also sets . to basedir!). Here is some test target proving the effect on both:
<target name="tst.dummy.basedir-override">
<!-- example output:
tst.dummy.basedir-override:
[echo] basedir before: basedir=D:\tst, '.'=D:\tst\.
[echo] updating it via 'var' to '..'
[echo] basedir now: basedir=D:\tst/.., '.'=D:\tst\.
-->
<property name="cur" location="." /> <!-- makes the relative path absolute -->
<echo message="basedir before: basedir=${basedir}, '.'=${cur}" />
<echo message="updating it via 'var' to '..'" />
<var name="basedir" value="${basedir}/.." />
<property name="cur2" location="." /> <!-- makes the relative path absolute -->
<echo message="basedir now: basedir=${basedir}, '.'=${cur2}" />
</target>

Liferay SDK portlet plugin: use ant target to modify .war file after being created

In a liferay portlet, the autogenerated build.xml (created with the SDK in eclipse, autogenerated by the wizard) always looks like this
<?xml version="1.0"?>
<project name="my-service-portlet" basedir="." default="deploy">
<import file="../build-common-portlet.xml" />
</project>
Is it advisable to add custom targets to this? I want to modify the .war file after it is created. Like this:
Is there a way with Apache Ant to update a jar file after it's been built?
My war-file is huge because it is autocreated by Liferay's service builder, and it seems to be in need of a few optimizations. I want to remove the WEB-INF/src/.java files (and those WEB-INF/classes/.class files in the .war) that are also in the WEB-INF/lib/.jar. They seem to be duplicated. Can I do this to save space during deployment and to simplify and speed-up the deployment process.
How would such an ant-target look like?
Sure, that's totally possible:
<project name="MyPortlet" basedir="." default="updateWarAndDeploy">
<import file="../build-common-portlet.xml" />
<target name="updateWarAndDeploy">
<antcall target="war"/>
-- modify war file --
<copy file="${plugin.file}" todir="${auto.deploy.dir}" />
</target>
</project>

Location of xsd for ant ivy lib "antlib:org.apache.ivy.ant" for IDE autocomplete with xsd?

I want create Ivy Ant tasks in xml editor in IDE (Intellij iDEA) with autocomplete based on xsd , but I cannot find xsd for register XML namespace xmlns:ivy="antlib:org.apache.ivy.ant"
Where I can find it?
I just copied the ivy jar to INTELLIJ_HOME/lib/ant and now intellij can resolve the ivy tasks.
Or import this ant file to your ant project, its actually the first ivy example in ivy documentation, make sure to always depend on install-ivy target, add your ant file to idea in the ant build window and you dont even have to install ivy and idea recognizes ivy tasks.
<property name="ivy.jar.dir" value="${user.home}/.ivy2/jars" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
<property name="ivy.install.version" value="2.2.0" />
<target name="check-ivy-installed" unless="INTERN-ivy.jar.exists">
<available property="INTERN-ivy.jar.exists" file="${ivy.jar.file}"/>
</target>
<target name="download-ivy" depends="check-ivy-installed" unless="INTERN-ivy.jar.exists">
<echo message="downloading and installing ivy"/>
<mkdir dir="${ivy.jar.dir}"/>
<!-- download Ivy from web site so that it can be used even without any special installation -->
<get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
<echo message="ivy installed"/>
</target>
<!-- =================================
target: install-ivy
this target is not necessary if you put ivy.jar in your ant lib directory
if you already have ivy in your ant lib, you can simply remove this
target and the dependency the 'go' target has on it
================================= -->
<target name="install-ivy" depends="download-ivy" description="--> install ivy">
<!-- try to load ivy here from local ivy dir, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<echo message="Installing ivy"/>
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>
To complete Shalom's answer, the location where to add the ivy.jar for the IntelliJ IDEA Community Edition is INTELLIJ_HOME/lib/ant/lib (one more folder to go).
Maybe it also apply to the full version.
might be, there was no xsd in the past time this discussion started, but at least since may 2011 the ivy scheme is well documented at
http://ant.apache.org/ivy/schemas/ivy.xsd
which is linked right from the documentation in http://ant.apache.org/ivy/
so, to start over using the scheme, you just need:
<?xml version="1.0" encoding="UTF-8"?>
<project name="yourproject"
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
>
<!-- … -->
I guess this discussion might help you. It appears that there is no xsd for the ivy ant tasks, but Eclipse does autocomplete.
yes, no xsd for ivy ant tasks avialable. but i found the way to make autocomplete in Intellij IDEA
in ant build file need to define additional task:
<property name="ivy.jar.dir" value="C:/Apache/apache-ivy-2.2.0/"/>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant">
<classpath>
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</classpath>
</taskdef>
XML plugin for jEdit defines AntCompleteTask (ant task) that produces an xml file called ant-complete.xml. The resulting file looks as follows:
<element-list>
<!-- ... -->
<element name="classpath"
content="(fileset|dirset|extdirs|existing|filelist|pathelement|path)">
<attribute name="id" type="ID" />
<attribute name="location" type="CDATA" />
<attribute name="cache" type="(true|false|on|off|yes|no)" />
<attribute name="refid" type="CDATA" />
<attribute name="description" type="CDATA" />
<attribute name="path" type="CDATA" />
</element>
<!-- ... -->
The generated file may be downloaded as XML plugin archive. Open XML.jar and browse to xml/completion directory. It's syntax is defined in xml-completion-info.dtd.
The task code does not contain an explicit license, but it's at least GPL. Anyway you probably don't need to distribute that task, only to use it and this doesn't require any license.
I can't assess the usability of the resulting xml file, but jEdit uses it for autocompletion.

ant: best way to setup system-dependent properties?

I have a number of file/executable locations that are likely to be different depending on which computer I am running them on, and I would like to abstract these out through ant properties somehow. What's the best way to do this? Is there a system-wide ant setup script that gets called? Or can I make such a script?
In addition to Vladimir's solution you might have a default properties file for each of the OS or other you might deploy your build system on. Use the ${os.name} (and other Java system properties) to set up a path. For example
<property file="build-${os.name}.properties">
These files can be maintained and checked in into your version control system as well.
I use the more or less standard build.properties and build-local.properties files.
The first contains default values, common to all environments, the second only the exceptions. The first one is checked into subversion while the other is not.
EDIT : copy/pasting Akr's excellent idea
In addition you might have a default properties file for each of the OS or other you might deploy your build system on. These files can be checked in into your version control system as well.
The Ant script would then include all the files as follow (remember: in Ant the first definition wins):
<property file="build-local.properties"/>
<property file="build.properties"/>
<property file="build-${os.name}.properties">
Setup an ant build file called properties.xml, in which you should define the properties that you want to customize.
Here is properties.xml boilerplate I am using for my projects ( I've adapted it from one of the books on Ant ):
<?xml version="1.0" encoding="UTF-8"?>
<project
name="workspace-properties"
>
<dirname
property="workspace-properties.basedir"
file="${ant.file.workspace-properties}"
/>
<!--
==========================================================
Load Environment Variables
==========================================================
-->
<!-- #Load environment variables -->
<property environment="env" />
<!-- this is here to deal with the fact that an IntelliJ IDEA build
has no ant home
-->
<property
name="ant.home"
value="${env.ANT_HOME}"
/>
<!-- get Unix hostname, and set to Windows comparable name -->
<!-- #Trick to get host name x-platform -->
<property
name="env.COMPUTERNAME"
value="${env.HOSTNAME}"
/>
<!--
==========================================================
Load property files
Note: the ordering is VERY important.
==========================================================
-->
<!-- #Allow even users property file to relocate -->
<property
name="user.properties.file"
location="${user.home}/.build.properties"
/>
<!-- Load the application specific settings -->
<!-- #Project specific props -->
<property file="build.properties" />
<!--
==========================================================
Define your custom properties here.
You can overwrite them through build.properties and
${user.home}/.build.properties
==========================================================
-->
<property name="myexec1" location="/usr/bin/myexec1"/>
<property name="myexec2" location="/usr/bin/myexec2"/>
</project>
Important thing here is to come up with as many useful default property values as possible, then you may even never come up with custom build.properties files.
Then you just <import> this file in your project's build.xml.
<project
name="my-project"
>
<!-- this is done, so you may import my-project somewhere else -->
<dirname
property="my-project.basedir"
file="${ant.file.my-project}"
/>
<import file="${my-project.basedir}/relative/path/to/properties.xml"/>
<target name="using.myexec1">
<echo message="myexec1=${myexec1}"/>
</target>
</project>
If you want a custom value for myexec1 in my-project, just drop a custom flat build.properties file in the same directory where build.xml is located.
The build.properties file may look like this:
myexec1=c:/custom/path/to/myexec1.exe

How to get Flex Builder 3 to generate two builds: one "-use-network=true", another "-use-network=false"?

I'm building a Flex application that will need run under two different deployment scenarios:
First, the application will be hosted on the web. The SWF loads some external resources (images, text) so it requires network access, which is the Flex Builder 3 default build flag "-use-network=true". I don't need to do anything special; it just works.
Second, the application will be written to CD with autorun enabled to launch the index.html hosting the SWF. The SWF still needs to be able to load those same external resources, which reside on the CD in a subfolder. Since those files are on the CD, they are considered local, so Flash security requires the SWF to be built using a flag of "-use-network=false". I add that to the "Additional compiler arguments" text box found under "Flex Compiler" in the Flex project's Properties dialog.
That all works as expected, but it's tedious to have to manually modify the Flex Builder project settings to add or remove that flag as the case may be.
Ideally, I would like to just build the project once and have multiple output folders: one for the network deployment scenario, and another for the local deployment scenario.
What's the best way to do that? Is moving to an Ant build the way to go, or is there a simpler way? If an Ant build configuration is the correct way, do you have an example to share of such multiple build configurations?
Thanks for your help!
Once you get your head around the Ant build, it will make your life a lot easier. Building a multiple build file is no different from a single build file, you will just add an additional task inside of your build with the appropriate settings (you could also use a loop in ant, but that adds complexity)
So, expanding on the Flex Ant Tasks example from the docs, something like this should work (not-tested):
<?xml version="1.0" encoding="utf-8"?>
<!-- myMXMLCBuild.xml -->
<project name="My App Builder" basedir="." default="main">
<taskdef resource="flexTasks.tasks" classpath="${basedir}/flexTasks/lib/flexTasks.jar" />
<property name="FLEX_HOME" value="C:/flex/sdk"/>
<property name="APP_ROOT" value="apps"/>
<property name="DEPLOY_DIR" value="c:/jrun4/servers/default/default-war"/>
<target name="main" depends="clean, compile1, compile2">
</target>
<target name="compile1">
<mxmlc
file="${APP_ROOT}/Main.mxml"
output="${DEPLOY_DIR}/Main.swf"
actionscript-file-encoding="UTF-8"
keep-generated-actionscript="true"
incremental="true"
use-network="true"
>
<!-- Get default compiler options. -->
<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
<!-- List of path elements that form the roots of ActionScript
class hierarchies. -->
<source-path path-element="${FLEX_HOME}/frameworks"/>
<!-- List of SWC files or directories that contain SWC files. -->
<compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
<include name="libs" />
<include name="../bundles/{locale}" />
</compiler.library-path>
<!-- Set size of output SWF file. -->
<default-size width="500" height="600" />
</mxmlc>
</target>
<target name="compile2">
<mxmlc
file="${APP_ROOT}/Main.mxml"
output="${CD_DEPLOY_DIR}/Main.swf"
actionscript-file-encoding="UTF-8"
keep-generated-actionscript="true"
incremental="true"
use-network="false"
>
<!-- Get default compiler options. -->
<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
<!-- List of path elements that form the roots of ActionScript
class hierarchies. -->
<source-path path-element="${FLEX_HOME}/frameworks"/>
<!-- List of SWC files or directories that contain SWC files. -->
<compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
<include name="libs" />
<include name="../bundles/{locale}" />
</compiler.library-path>
<!-- Set size of output SWF file. -->
<default-size width="500" height="600" />
</mxmlc>
</target>
<target name="clean">
<delete dir="${APP_ROOT}/generated"/>
<delete>
<fileset dir="${DEPLOY_DIR}" includes="Main.swf"/>
</delete>
</target>
</project>
As a side note, if you are going to be running the Ant build in eclipse/Flash Builder you might as well increase the memory now.

Resources