Automated Builds

How do you automate your build process with Java?

Previously, I was using a shareware text editor (with IDE-like syntax highlighting) called Textpad for writing code. To automate the build process, I started using Ant. That works fine except that I still have to use a freeware program called Inno Setup for creating the installer program for a game. And then I have to open up an FTP program to upload it to my website.

The FTP step isn’t such a big deal though since I have to post to the news page and edit version numbers when I upload a new version of program anyways.

Now, I’m using Eclipse to write code. It provides Ant support, but whenever I use Ant it screws up Eclipse’s build. And vice versa. The same thing happens when I use Ant outside of Eclipse. It’s easy to clean up their class files, but it’s annoying.

Optimally, what I would like to have is the following options within Eclipse: Run and Release. Run works fine, but there’s nothing like the Release option. What I want the Release option to do is create a demo and full version of the game (including the JVM) and package them in installer programs automatically. Uploading the files to my website automatically would be nice too, but I’m not that picky.

Does anyone else do something like this? Should I just use the Eclipse compilation and Ant script for the Release option? Is there some way to automate the installer packaging? Maybe I could just write a short Java program that opens up the Inno Setup scripts and changes the version number to update the version, but I would still need some way to compile the scripts with Inno Setup from within Ant.

I don’t have those problems with Ant. I can just be the directories you have set up and how your clean works.

Make sure you set Eclipse up to have separate source and class folders, such as the default src and bin.

Make sure your build script follows the same structure.

When you run a clean with your build script, do not delete the bin directory. Eclipse will complain.

Place any distribution files you create in a separate folder like dist or build.

Look at IzPack for an installer. It is free and integrates with Ant.

If you want to always run from a jar file, you can tell Eclipse to run from it instead of from the bin folder. Use Run->Run…->Classpath->User Entries->Add Jar. After you add the jar, move it to the top of the list.

Here is a build file that I use:


<project name="vector" default="shrink1">
    <taskdef resource="proguard/ant/task.properties" classpath="C:/Test/Java/proguard3.7beta2/lib/proguard.jar" />

    <property name="src" value="${basedir}/src"/>
    <property name="bin" value="${basedir}/bin"/>
    <property name="dist" value="${basedir}/dist"/>

    <target name="clean">
        <delete dir="${dist}" />
        <delete file="${bin}/V.class" />
    </target>
	
    <target name="init" depends="clean">
        <mkdir dir="${dist}"/>
    </target>
	
    <target name="compile" depends="init">
        <javac srcdir="${src}" destdir="${bin}"/>
    </target>

    <target name="jar" depends="compile">
        <zip destfile="${dist}/vector1.jar" basedir="${bin}"/>
    </target>
	
    <target name="shrink1" depends="jar">
        <proguard configuration="vector.pro"/>
    </target>
</project>

If this doesn’t help, post your build file.

I think I’m doing just about everything you mentioned. I’ll take a look at it tomorrow morning and see if I can figure out what’s going on. If not, I’ll post the build file here.

Izpack installers can only be used on computers with the JVM already installed, right? If that’s the case, I’m better off with Inno Setup because I can embed the JVM.

Correct. However, you could do both so people that already have Java can have a smaller download. Especially Linux and MacOS people.

I use innosetup in combination with ant to automatically generate an installer


<exec executable="_buildsys_/innosetup/ISCC.exe" dir="_buildsys_/innosetup">
    <arg line="../../etc/Setup.iss /dBINARY_VERSION=${version.binary} /dVERSION=${version}"/>
</exec>

As you can see, I map ant propperties to innosetup macros to change the version and binary version inside the script.

Another option would be to use a filter-set while preparing your setup script:


<copy file="etc/Setup.iss" todir="temp">
    <filterset>
        <filter token="VERSION" value="${version}"/>
        <filter token="BINARY_VERSION" value="${version.binary}"/>
    </filterset>
</copy>

<exec executable="_buildsys_/innosetup/ISCC.exe" dir="_buildsys_/innosetup">
    <arg line="../../tmp/Setup.iss"/>
</exec>

to replace all occurences of @VERSION@ with the value of the ant property “version” and @BINARY_VERSION@ with the value of the ant property “version.binary” before compiling. This way your argline will not get too long.

At work we generate all changing information (e.g. the file-list to include in the installer) with the ant script and use a preprocessor step (velocity vpp-copy) to insert them at the right places.

I believe I figured out what the Ant/Eclipse conflict was. I have Eclipse set on automated build, and I have Ant set up so it cleans up the old class files before compiling. I guess Eclipse still thinks the files are compiled but can’t find them because they’ve been deleted.

What I’ve been doing to fix this is cleaning my project in Eclipse, and this must cause it to rebuild. So long as I’m only using Ant to create backups and set up releases, this shouldn’t be a big deal. I just wanted to know what was going on.

I will try out ant code similar to cylab’s when I build the next release. Thank you for posting that. I may take a look at IzPack later, but the game I’m working on now is targetted at Windows machines anyways.

I started having another strange problem with Ant today. Here’s the part of my build script that creates the files for the release:

<target name="release" depends="compile">
	<mkdir dir="${release.dir}"/>
	<jar destfile="${jar.path}">
		<fileset dir="${build.dir}" includes="**/*.class"/>

		<manifest>
			<attribute name="Built-By" value="${user.name}"/>
			<attribute name="Main-Class" value="${mainclass}"/>

			<section name="common">
			<attribute name="Specification-Title" value="${ant.project.name}"/>
			<attribute name="Specification-Version" value="${version}"/>
			<attribute name="Specification-Vendor" value="Cow God Games"/>
			<attribute name="Implementation-Title" value="common"/>
			<attribute name="Implementation-Version" value="${version} ${TODAY}"/> 
			<attribute name="Implementation-Vendor" value="Cow God Games"/>
			</section>
			
			<section name="${mainclass}">
			<attribute name="Sealed" value="false"/>
			</section>
		</manifest>
	</jar>

	<copy todir="${release.dir}" includeEmptyDirs="false">
		<fileset dir="${build.dir}"
			excludes="demo license.txt,error.log,**/*.class,**/Thumbs.db" />
	</copy>

	<copy todir="${release.embeddedjre.dir}" includeEmptyDirs="false">
		<fileset dir="${jrebundle.dir}" excludes="**/Thumbs.db" />
	</copy>

	<mkdir dir="${demo.dir}"/>
	<copy todir="${demo.dir}" includeEmptyDirs="false">
		<fileset dir="${release.dir}" excludes="full license.txt" />
		<fileset file="${build.dir}/demo license.txt" />
	</copy>
</target>

Since the code is already compiled, this snippet does the following: create the release directory, create the jar file, copy the “build” files (e.g. art, music, etc.) into the release directory, copy the JVM into the release directory, create the demo directory, and copy the entire release into the demo directory.

The issue is that the demo and release versions are supposed to include different licenses (demo license and full license, respectively). I believe I have the file sets set up that way, but both licenses appear in both versions.

One option would be to copy all the files and then delete the appropriate files, but that seems like too much of a hack.

I will insert the Inno Setup execution in there before the next release.

Don’t use the excludes attribute in the fileset, it doesn’t like spaces in the filenames. Lookkup a nested exclude tag in the ant user manual.

And don’t clean the build directory while compiling classes, it’s unnecessary (ant takes care of changed files) most of the time. Make a dedicated “clean” target, if you really need that.

It may not be your problem, but I highly recommend never having spaces in file names. Use an underscore or camel naming.

What you describe as your problem should only occur if the build failed. This would leave the directory empty while Eclipse expects files to be there. If there are no errors, the class directory will have all the files after the build finishes, unless you mapped ant to a different destination directory.

EDIT: As cylab pointed out, spaces in file names are bad.

I used the nested excludes, and I’m getting the right files now. It just seems a little odd that it handles spaces properly when done with nesting but not when done with an argument in the fileset tag.

I will work on setting up Ant to automate installer generation when I get time. I will have to alter my Inno Setup scripts as well because I have the version number hardcoded in a couple of places.

The excludes attribute is deprecated (maybe because of this) and afaik uses komma and/or space separated list of files to exclude.