For some reason no WYSIWYG tool ever works for me, be it for writing texts or generating presentations. My workflow simply doesn't match the one of those tools, I end up spending too much time thinking about the look rather than the content.

In addition I like my work to be under version control and versioning big binary blobs (and gzip compressed XML isn't really better than that) isn't that cool. So I prefer tools that work on plain text.

Some time ago I tried S5 and liked it, except for the fact that I couldn't create a PDF of the real slides instead of the print view S5 provides.

Then I stumbled over the LaTeX Beamer Class and used it for an internal presentation I did this week. For somebody familiar with LaTeX this is really really great, I can only praise it. It is an "apt-get install latex-beamer" away from Debian/Ubuntu systems and I didn't have any trouble getting it to work on my Cygwin pdflatex installation at work either.

This is the example directly from the class's homepage

\documentclass{beamer}

\usepackage{beamerthemesplit}

\title{Example Presentation Created with the Beamer Package}
\author{Till Tantau}
\date{\today}

\begin{document}

\frame{\titlepage}

\section[Outline]{}
\frame{\tableofcontents}

\section{Introduction}
\subsection{Overview of the Beamer Class}
\frame
{
  \frametitle{Features of the Beamer Class}

  \begin{itemize}
  \item<1-> Normal LaTeX class.
  \item<2-> Easy overlays.
  \item<3-> No external programs needed.      
  \end{itemize}
}
\end{document}

which produces this PDF. In the end I had to select a nice theme and things looked better than anything I ever did in PowerPoint. And it certainly took me less time, was version controlled and all that.

path: /en/oss | #

I guess I've heard "Ant is an XML programming language" and "Ant would be fine wasn't it for all the XML" once too often. Last week I managed to free up a few hours to build a (probably completely useless) prototype to prove it doesn't have to be that way:

$ cat src/etc/examples/Simple2.java
package org.example;

import org.apache.ant.javafront.annotations.AntProject;
import org.apache.ant.javafront.annotations.AntTarget;

import org.apache.tools.ant.Project;

@AntProject()
public class Simple2 {
    private final Project p;

    public Simple2(Project p) {
        this.p = p;
    }

    @AntTarget(Name="hello", Description="says hello", Depends="nonsense")
    public void foo() {
        p.log("Hello, world!");
        p.log("This is " + p.getProperty("ant.version") + " calling.");
    }

    @AntTarget public void nonsense() {}
}
$ ant -lib build/lib/ant-javafront-0.1.jar -f src/etc/examples/Simple2.java -projecthelp
Buildfile: src/etc/examples/Simple2.java
[buildfile] Compiling 1 source file to /tmp/javafront
Main targets:

 hello  says hello
$ ant -lib build/lib/ant-javafront-0.1.jar -f src/etc/examples/Simple2.java hello
Buildfile: src/etc/examples/Simple2.java

nonsense:

hello:
Hello, world!
This is Apache Ant version 1.7.1 compiled on June 27 2008 calling.

BUILD SUCCESSFUL
Total time: 0 seconds

This is stock Ant 1.7.1 (should work with Ant 1.7.0 and probably 1.6.5 as well) and Java 5 together with a custom ProjectHelper (more on this later).

The build file is a Java source file that gets compiled on demand. Each public no-arg method that has the AntTarget annotation becomes a target where the method's name forms the default for the target name.

Ant provides an extension point, the ProjectHelper class which is responsible for configuring an Ant Project instance from a source (usually a File). My prototype extends Ant's built in ProjectHelper class and overrides a single method. The majority of that class is concerned with compiling the "build file" and performing some reflection. Apart from that, two trivial annotations and a very simple subclass of Ant's Target are all that it takes to replace XML with Java source code. Replacing XML with any custom format you can think up would be as straight forward, it's just that nobody seems to know you can plug in your own parser - maybe it's time for a "little known Ant extension points" article.

My experiment doesn't do all that its XML cousin can do, in particular it doesn't support <import>, but that can be faked to a certain extent by making the "build file" inherit from a base class. The other thing is automatic handling of IDs, but that is something you'd need when using Ant tasks and should probably go into the builder (see below). It does support <ant> and friends as well as namespaces, as demonstrated by an example of running AntUnit on the build file itself.

Inside your "target" you may perform any Java code as you see fit. Of course this means you'll only use the target execution engine of Ant. Reusing Ant tasks from Java might be pretty daunting, so I threw in a little Ant tag builder library based on the builder pattern and a fluent interface, not very complete and really just a teaser. For example:

$ cat src/etc/examples/Simple3.java
package org.example;

import org.apache.ant.javafront.annotations.AntProject;
import org.apache.ant.javafront.annotations.AntTarget;
import org.apache.tools.ant.Project;
import org.apache.ant.javafront.builder.TagBuilder;

@AntProject(Name="simple3", DefaultTarget="hello")
public class Simple3 {
    private Project p;

    public void setProject(Project p) {
        this.p = p;
    }

    @AntTarget(Name="-setup")
    public void setup() {
        TagBuilder.forProject(p)
            .property().withName("world").andValue("world").execute();
    }

    @AntTarget(Depends="-setup")
    public void hello() {
        TagBuilder.forProject(p).echo().message("Hello, ${world}!").execute();
    }
}
$ ant -lib build/lib/ant-javafront-0.1.jar -f src/etc/examples/Simple3.java
Buildfile: src/etc/examples/Simple3.java
[buildfile] Compiling 1 source file to /tmp/javafront

-setup:

hello:
     [echo] Hello, world!

BUILD SUCCESSFUL
Total time: 0 seconds

$ ant -lib build/lib/ant-javafront-0.1.jar -f src/etc/examples/Simple3.java -Dworld=reader
Buildfile: src/etc/examples/Simple3.java

-setup:

hello:
     [echo] Hello, reader!

BUILD SUCCESSFUL
Total time: 0 seconds

or

$ cat src/etc/examples/AntUnitTest.java
package org.apache.ant.javafront.example;

import org.apache.ant.javafront.BuildFileBase;
import org.apache.ant.javafront.annotations.AntProject;
import org.apache.ant.javafront.annotations.AntTarget;
import org.apache.tools.ant.Project;

import static org.apache.ant.javafront.builder.EchoBuilder.echoMessage;
import static org.apache.ant.javafront.builder.DeleteBuilder.deleteDir;
import static org.apache.ant.javafront.builder.MkdirBuilder.mkdir;

@AntProject(Name="example using AntUnit", BaseDir="../../..",
            DefaultTarget="antunit")
public class AntUnitTest extends BuildFileBase {
    private static final String FILE = "build.xml";
    private static final String OUTPUT = "${output}";

    public AntUnitTest(Project p) {
        super(p);
        build().property().withName("output").andLocation("build/testoutput")
            .execute();
    }

    @AntTarget(Description="describes this build file")
    public void describe() {
        echoMessage(getProject(), "${ant.version}");
        echoMessage(getProject(), "Demonstrates running an AntUnit test.");
    }

    @AntTarget
    public void setUp() {
        mkdir(getProject(), OUTPUT);
    }

    @AntTarget
    public void tearDown() {
        deleteDir(getProject(), OUTPUT);
    }

    @AntTarget
    public void testCopy() {
        build().copy().withAttribute("verbose", "true")
            .file(FILE).toDir(OUTPUT)
            .execute();
        build().tagWithNs("assertFileExists", "antlib:org.apache.ant.antunit")
            .withAttribute("file", OUTPUT + "/" + FILE)
            .execute();
    }

    @AntTarget(Description="runs the test")
    public void antunit() {
        build().tagWithNs("antunit", "antlib:org.apache.ant.antunit")
            .withChild(build().tagWithNs("plainlistener",
                                         "antlib:org.apache.ant.antunit"))
            .withChild(build().tag("file").withAttribute("file",
                                                         "${ant.file}"))
            .execute();
    }
}
$ ant -lib build/lib/ant-javafront-0.1.jar -lib ../ant-core/trunk/lib/optional/ant-antunit-1.1.jar -f src/etc/examples/AntUnitTest.java
Buildfile: src\etc\examples\AntUnitTest.java

antunit:
  [antunit] Build File: /home/stefan/dev/ASF/ant-javafront/src/etc/examples/AntUnitTest.java
  [antunit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0,062 sec
  [antunit] Target: testCopy took 0,031 sec

BUILD SUCCESSFUL
Total time: 0 seconds
$ ant -lib build/lib/ant-javafront-0.1.jar -lib ../ant/lib/optional/ant-antunit-1.1.jar\
 -f src/etc/examples/AntUnitTest.java setUp testCopy tearDown
Buildfile: src/etc/examples/AntUnitTest.java

setUp:
    [mkdir] Created dir: /home/stefan/dev/ASF/ant-javafront/build/testoutput

testCopy:
     [copy] Copying 1 file to /home/stefan/dev/ASF/ant-javafront/build/testoutput
     [copy] Copying /home/stefan/dev/ASF/ant-javafront/build.xml to /home/stefan/dev/ASF/ant-javafront/build/testoutput/build.xml

tearDown:
   [delete] Deleting directory /home/stefan/dev/ASF/ant-javafront/build/testoutput

BUILD SUCCESSFUL
Total time: 0 seconds

I must admit that I don't really see that much of a point in the experiment itself, other than proving that it can be done. The files I've presented so far are longer and more verbose than their XML equivalents would have been. There may be cases where you realy want some non-declarative stuff like performing a loop, here using Java may help, something like.

$ cat src/etc/examples/EchoExamples.java
package org.example;

import org.apache.ant.javafront.BuildFileBase;
import org.apache.ant.javafront.annotations.AntProject;
import org.apache.ant.javafront.annotations.AntTarget;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;

import static org.apache.ant.javafront.builder.EchoBuilder.echoMessage;

@AntProject(Description="lists all build files in the current directory",
            DefaultTarget="list")
public class EchoExamples extends BuildFileBase {
    public EchoExamples(Project p) {
        super(p);
    }

    @AntTarget(Description="list the files in the example dir")
    public void list() {
        FileSet fs = (FileSet)
            build().tag("fileset")
            .withAttribute("dir", ".")
            .withAttribute("includes", "*.java")
            .build();
        DirectoryScanner ds = fs.getDirectoryScanner();
        for (String file : ds.getIncludedFiles()) {
            echoMessage(getProject(), "found " + file);
        }
    }
}
$ ant -lib build/lib/ant-javafront-0.1.jar -f src/etc/examples/EchoExamples.java
Buildfile: src/etc/examples/EchoExamples.java
[buildfile] Compiling 1 source file to /tmp/javafront

list:
     [echo] found AntUnitTest.java
     [echo] found EchoExamples.java
     [echo] found Simple.java
     [echo] found Simple2.java
     [echo] found Simple3.java

BUILD SUCCESSFUL
Total time: 0 seconds

Right now I don't expect to put more work into the experiment. The tag builder library may be useful on its own, but what I've seen so far hasn't convinced my that Java would be a better language to describe your builds. What I have shown is that Ant doesn't need XML at all and now I feel better 8-).

path: /en/Apache/Ant | #

Like so many people I spent part of the last weekend upgrading my laptop from Hardy to Intrepid. I'm not sure whether the upgrade really downloaded too much like Steve has seen since I was fortunate enough to have a fast line (thanks, Mum). I'll probably know once I upgrade the desktop which is on my 1 MBit/s home connection.

Faced some issues, in particular alsa-utils hangs during shutdown. I got around it by manually removing alsa-utils from the shutdown scripts, but will try the "shutdown network before alsa-utils" fix suggested later. Right now I don't have any sound at all, while it used to work before I rebooted Intrepid and had alsa-utils hang for the first time.

My "user base" isn't too happy with the upgrade of KDE games from 3.x to 4.x because ksnake has gone and some of the user interface improvements in kpat and lskat are considered big steps backwards.

path: /en/personal/infra | #