Hi all,

Here is the code and a bit of documentation for RemoteAnt. Please let me
know if you have any questions or comments.

Sorry about the raw attachments, the mail list wouldn't allow a zip file.
You'll have to recreate the package structure to get a build.

Many thanks,

Robert

-----Original Message-----
From: Robert Smith [mailto:[EMAIL PROTECTED] 
Sent: 08 March 2004 20:30
To: '[EMAIL PROTECTED]'
Subject: Any interest in a remote Ant server?

Hi all,

I've written an add-on for Ant that allows for remote builds. It consists of
an RMI based server application and a handful of custom Ant tasks on the
client side. My motivation for this was to allow C/C++ code to be built on
remote machines for multiple architectures from the comfort of the
developer's Eclipse IDE on Windows. I tried Rant, but found it too limiting,
so I've done my own version, complete with file transfers and synchronous
logging (which took some work to make it all serialize/deserialize properly
across RMI!)

<snip>

<project name="RemoteAnt" default="jar">

    <!--========================================-->
    <!--=                 jar                  =-->
    <!--========================================-->

	<target name="jar" depends="rmic">
        <copy todir="${dir.classes}">
            <fileset dir="${dir.src}"
                     excludes="**/*.java,
                               **/*.html"/>
        </copy>
	
		<jar destfile="${dir.lib}/ant-remote.jar" 
		     basedir="${dir.classes}"/>
	</target>


    <!--========================================-->
    <!--=                 rmic                 =-->
    <!--========================================-->

	<target name="rmic" depends="compile">
        <rmic base         = "${dir.classes}"
              includes     = "${classes.stub}"
              classpathref = "path.classpath"
              stubversion  = "1.2"/>
	</target>

	
    <!--========================================-->
    <!--=               compile                =-->
    <!--========================================-->

    <target name="compile" depends="init">
        <mkdir dir="${dir.classes}"/>

        <!-- compile our source code -->
        <javac srcdir="${dir.src}"
               destdir="${dir.classes}"
               classpathref="path.classpath"/>
    </target>
	

    <!--========================================-->
    <!--=                clean                 =-->
    <!--========================================-->

	<target name="clean" depends="init">
        <delete includeEmptyDirs="true" quiet="true">
            <fileset dir="${dir.classes}"/>
        </delete>
        <delete file="${dir.lib}/ant-remote.jar" 
                quiet="true"/>
    </target>
    
    
    <!--========================================-->
    <!--=               javadoc                =-->
    <!--========================================-->

    <target name="javadoc" 
            depends="init"
            description="Generate JavaDocs">
    
        <mkdir dir="${dir.doc}"/>
        
        <javadoc packagenames="com.rjmpsmith.*"
                 sourcepath="${dir.src}"
                 classpathref="path.classpath"
                 destdir="${dir.doc}"
                 author="true"
                 version="true"
                 use="true"
                 windowtitle="Remote Ant API"/>
    </target>
    
        
    <!--========================================-->
    <!--=                 init                 =-->
    <!--========================================-->

	<target name="init">
	    <property name="dir.classes" value="classes"/>
	    <property name="dir.src"     value="src"/>
	    <property name="dir.lib"     value="lib"/>
	    <property name="dir.doc"     value="doc"/>
	    <property name="classes.stub" 
	              value="com/rjmpsmith/ant/taskdefs/RemoteTask.class 
	                     com/rjmpsmith/ant/RemoteBuildServices.class"/>

	    <path id="path.classpath">
	        <pathelement location="${dir.classes}"/>
            <pathelement path="${dir.lib}/log104j.jar"/>
            <pathelement path="${dir.lib}/ant.jar"/>
        </path>
	</target>

</project>
Building RemoteAnt
------------------

1. Modify the classpath in the build.xml file to point to your versions
   of ant.jar and log104j.jar, *or* copy these jars into the lib directory

2. type ant 

3. For javadocs, type ant javadocs



Using the RemoteAnt server
--------------------------

Note: My Unix scripting and knowledge of RMI security and configuration are 
somewhat limited, so I could seriously use some help standardising the launch
of the server

1. I am using Exception chaining in my code, so it's probably best if you use
   JDK1.4+.

2. Make certain that Ant is installed on the server.

3. Add ant-remote.jar to the lib directory of your ant installation(s)

4. In order for the server to work, You will need to provide two files 
somewhere on the 
   classpath - an RMI policy file, and a log4j configuration file. I've attached
   simple examples at the end of this file. I've also attached the bash script I
   use to kick things off - though I'm no Unix guru. I could really use some 
help

5. Start rmiregistry on your desired port.

6. Start the server. Command line arguments are:

      1. The RMI port from step 5
      2. Some location in the filesystem to store files to support the builds
      3. (optional) Default time to live (in minutes) for abandoned sessions 
            The default is 240 minutes. If the session hasn't been closed by 
then,
            a timer fires, and the server will close the session automatically,
            deleting all files stored on the session's behalf.


      example - see bellow for my sad attempt at a script
      ---------------------------------------------------
      % export CLASSPATH=<current dir and all ant jars>
      % rmiregistry 2020
      % java -Djava.security.policy=policy.txt 
com.rjmpsmith.ant.RemoteAntServer 2020 /tmp/builds 120




My first shot at a script to launch the server on Unix
------------------------------------------------------

I created a directory which contains the script, the policy.txt file, and 
log4j.properties.
I've always been a bit hazy on exactly what I have to make available to the 
rmiregistry and
the server class in order to avoid the dreaded unmarshaling exceptions, so I 
tend to
throw everything at them.

Here's the script - obviously the paths are for our own server

#
# This file starts an Ant build server on Unix
#

# Get the OS name
UNAME=`uname`

# set up the common environment
ANT_HOME=/usr/shared/scm/tools/apache-ant-1.6.1
RMI_PORT=2020
BUILD_DIR=/tmp/builds

# set up OS specific environment
if [ $UNAME == 'Linux' ]
then
    JAVA_HOME=/usr/shared/scm/tools/linux/j2sdk1.4.2_03
    PATH=$JAVA_HOME/bin:$ANT_HOME/bin:/usr/shared/scm/tools/linux/bin
else
    JAVA_HOME=/usr/shared/scm/tools/solaris/j2sdk1.4.2_03
    PATH=$JAVA_HOME/bin:$ANT_HOME/bin:/usr/shared/scm/tools/solaris/bin
fi

# set up the Java classpath
CLASSPATH=.
for jar in $ANT_HOME/lib/*.jar
do
    CLASSPATH=$CLASSPATH:$jar
done

# export our environment variables
export JAVA_HOME
export ANT_HOME
export PATH
export CLASSPATH

# start an RMI registry server
echo Starting RMI registry on port $RMI_PORT...
$JAVA_HOME/bin/rmiregistry $RMI_PORT&
echo PID=$!

# start the remote build server
echo Starting remote build server...
$JAVA_HOME/bin/java -classpath $CLASSPATH -Djava.security.policy=policy.txt 
com.rjmpsmith.ant.RemoteAntServer $RMI_PORT $BUILD_DIR 120 &
echo PID=$!


Sample policy file - not safe!
------------------------------
grant {
        permission java.security.AllPermission;
};

Sample log4j configuration - console only
-----------------------------------------

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n




Using the client
----------------

In your buildfile, import the task definitions:

    <taskdef resource="remoteant.taskdefs"/>

The following tasks are supported:

createSession=com.rjmpsmith.ant.taskdefs.CreateRemoteSessionTask
closeSession=com.rjmpsmith.ant.taskdefs.CloseRemoteSessionTask
remoteBuild=com.rjmpsmith.ant.taskdefs.RemoteBuildTask
putFiles=com.rjmpsmith.ant.taskdefs.RemotePutFileTask
getFile=com.rjmpsmith.ant.taskdefs.RemoteGetFileTask


Here's how to use them:


createSession
-------------

Creates a session for this build on the remote server. When a session is 
created,
A RemoteSession object is created and placed into a synchronized HashMap. This 
object maps a unique ID (String) to a location in the filesystem where files 
will
be stored on it's behalf. In order to prevent failed builds from causing 
sessions
to build up, it also contains the watchdog timer which will fire after a given 
length of time, removing the session.

        <createSession host="somehost" 
                       port="rmiregistryport" 
                       property="sessionname"
                       ttl="60"/>             <-- Optional. Overrides the 
default time to
                                                  live. Given In minutes.

If the tasks succedes, the property specified in the property attribute will be 
set
to the unique ID for the session. This property is then used with the other 
tasks.


CloseSession
------------

Pretty self explanitory  - removes all files associated with the session from 
the server, cancels the watchdog timer, and removes the RemoteSession object 
from
the HashMap.

        <closeSession session="${sessionname}"/>


putFiles
--------

Transfers files from the client to the server. Files on the server are placed 
into
a directory structure as follows. This location is stored in the RemoteSession
object.

    root build path (given as arg to server)
      |
      |_ hostname of the client
           |
           |_ timestamp of the session (This would be the project root of the 
ant build)
                 |
                 |_ dir structure given in remotedir attribute (if present)
                        |
                        |_ dir structure which mirrors the fileset, or none
                           if flatten attribute is set.



        <putFiles session="${sessionname}" 
                  remotedir="some/extra/dir" <-- optional. Applies to all 
filesets
                  flatten="true">            <-- optional. Applies to all 
filesets

            <fileset dir="cfg">
                    <include name="SolarisCBuild.xml"/>
            </fileset>
            <fileset dir="${basedir}"
                     includes="**/c/**"
                     excludes="**/Makefile"/>
            <fileset dir="src"/>                  
        </putFiles>

Through the use of remotedir and flatten attributes, you can easily create 
complex
file heirarchies on the server. However, you would probably need to use several 
calls
to putFiles. File transfer is blindingly fast, though, so no harm putting more 
than 
you really need if you wish to keep things simple.


remoteBuild
-----------

Kicks off an Ant build on the remote server. BuildEvents are captured by a 
custom
listener on the remote end and forwarded on in real time (via an RMI callback) 
to 
a custom listener on the local client (implemented by the RemoteTask base 
class),
which in turn publishes them on to all (standard) registered listeners in the 
local Ant process.

        <remoteBuild session="${sessionname}" 
                     buildfile="remotebuild.xml" <-- Optional. Defaults to 
build.xml
                     targets="build,deploy"/>    <-- Optional. Defaults to the 
default
                                                     target in the build file. 
Comma
                                                     seperated list.

getFile
-------

Retrieves a file from the remote session. Remote file is given relative to the 
project
root on the server side (see above). Local file is ABSOLUTE.

        <getFile session="${sessionname}" 
                 remoteFile="ctjava"
                 localFile="${basedir}/Configuration/bin/ctjava"/>


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to