Free Eclipse Classpath Ant Task

This software is no longer supported! I have neither used nor updated this software since I originally posted it, back in 2004. You are welcome to both the binary and source versions, but I no longer do anything with it or support it. If you need something changed, you will have to do it yourself, using the source. Sorry, but after I released it, I realized how little I really needed it, and thus stopped using it.

I’ve just released version 1.0 of a free Ant custom task to make it a little easier to work on a project using both Ant and Eclipse. What this task does is read the .classpath file that Eclipse uses to maintain your project’s classpath, combines that with your Eclipse preferences to expand classpath variables and then creates a path-like structure in your Ant project that you can compile against.

I wrote this because I use Eclipse and I always also have a build file. Keeping the two in sync, classpath-wise, was always a hassle. Now I can simply update the classpath inside Eclipse, and whenever I do an Ant build it will automatically be in sync.

I wrote it against Eclipse 3.0 M8 originally. Then I upgraded to M9 and it stopped working. So with a bit of futzing about, I got it to work with both 3.0 versions and 2.1.3, all three of which keep the preferences file in completely different places with completely different names. But that’s taken care of now. I have also tested on both WindowsXP and Linux, but more on XP than Linux.

To use it, drop the jar file (plus jdom.jar if you don’t already have it) in ANT_HOME/lib. Then taskdef the task

  <taskdef resource="com/joeygibson/ant/eclipseclasspath.properties"/>  

Then call the task. There are several optional attributes, but if you want the classpath to end up in a path called “classpath”, then you can probably get by with just this

  <eclipsecp workspace="/home/me/workspace"/>  

If you are on Windows, and using Eclipse 3.0 M8 or later and you keep your workspace in C:/Eclipse/workspace then you don’t even have to do that much. You can get by with

  <eclipsecp/>   

Once you’ve executed the task, just reference the newly-created path from your javac task or anything else that takes a path as an argument.

You can read more about it in the README.txt

I’ve got several downloadable versions available, in both zip and tar.gz formats, with and without source, and with and without jdom.jar. If you use it and like it/don’t like it/have suggestions, please let me know.

Downloads
Binary only ect.zip
ect.tar.gz
Binary w/ JDOM ect-with-jdom.zip
ect-with-jdom.tar.gz
Source only ect-src.zip
ect-src.tar.gz

I’ve heard there are other tools out there that do this, but I didn’t find them, so I wrote my own. Please email me with any comments you have about it.

Advertisements

13 thoughts on “Free Eclipse Classpath Ant Task

  1. I am using 3.0.1 and I had to do some additional steps from your readme.txt to get
    it to work in the Preferences->Ant to add your jars and the task to the runtime (apparently it doesn’t automatically pick them up from ANT_HOME/lib.
    Anyway,
    When I try to do a build I am getting:
    Buildfile: C:JavaArchivedWorkspacesAJContentServerbuild.xml
    [eclipsecp] Unable to map variable [JUNIT_HOME/junit.jar]
    [eclipsecp] Unable to map variable [AJCSLIB/slide-kernel-2.0.jar]
    [eclipsecp] Unable to map variable [AJCSLIB/slide-log4jlogger-2.0.jar]
    [eclipsecp] Unable to map variable [AJCSLIB/slide-roles-2.0.jar]
    [eclipsecp] Unable to map variable [AJCSLIB/slide-stores-2.0.jar]
    [eclipsecp] Unable to map variable [AJCSLIB/slide-webdavservlet-2.0.jar]
    The tags I used in the build.xml are:
    I can provide the whole build.xml on request.

  2. Yeah, variable expansion is a known problem with the task. As for running it under Eclipse, I never tried that, so I don’t think I knew about that problem.
    Perhaps at some point I’ll get around to fixing the variable expansion.

  3. I was able to get it to work, THANK YOU!
    However your readme.txt needs to be expanded to include the following:
    Your Ant->runtime classpath tab needs to have
    the EclipseClasspathTask.jar added to it.
    Your Ant->runtime tasks need to have the EclipseClasspathTask.class added to it.
    Your build.xml example
    *Note eclipse Preferences->Java->Build Path->classpath variables should be specific to the jar files and not folders that get extended or the task will not map them.

  4. Hi, I’ve installed eclipsecp as stated in the readme but at everybuild I get this error : [eclipsecp] Unable to find Eclipse preferences file at [D:JavaDeveclipse_projectsAnaemDir.metadata.pluginsorg.eclipse.jdt.corepref_store.ini]
    There is no file named “pref_store.ini” on d:eclipse or d:eclipse_projects directories
    What’s wrong ?
    Thank you

  5. Hi,
    I’m trying to copy all JARs required by an application to a particular directory. The classpath is specified in a .classpath file created by Eclipse and I used the ant task from http://www.joeygibson.com/blog/tech/java/Ant/EclipseClasspathTask.html to get the classpath in the build.xml as follows:
    But what I would like to do now that I have the classpath loaded from the .classpath file is to copy each of the JAR files in the classpath to a particular location.
    I think I need to create a filelist/fileset from the classpath but I don’t know how to do it?
    Could you please help me with this,
    Many thanks,
    Stefan

  6. mmm … site didn’t like the XML so here it is again with round brackets instead of angle brackets:
    (project name=”MyProject” default=”copy-libs” basedir=”.”)
    (taskdef resource=”com/joeygibson/ant/eclipseclasspath.properties”/)
    (target name=”copy-libs”)
    (eclipsecp pathid=”myclasspath” workspace=”D:Templibrary_builder” dir=”.” filename=”.classpath” verbose=”true”/)
    (/target)
    (/project)

  7. It would be much more useful if you could define filesets in Ant then have a task to generate the .classpath file for eclipse.

  8. Feel free to implement that, then. I did what was useful to me at the time. I released it in case other might find it useful. But I have no time any more to enhance or change it.

  9. First, thanks for this task.
    For a project that I am doing I needed to create an automatic build. Because we use WSAD/Eclipse as the main development tool, I wanted a simple way to create a classpath from the .classpath file, so an ant script can build the ear file.
    So thanks to your eclipsecp Ant task I could start straight away! Soon I found out I need some additional functionality, so I’ve extended your ant task as follows:
    * follows project references as well,
    * made it possible to run outside an eclipse environment (by dumping all variables in a properties file),
    * removed the dependency on jdom, so you only have to drop the eclipsecp jar in the lib dir of ant
    Please email me if your interested… can I publish this modified version in some way myself?

  10. // Added basic Expansion after reverseing in jad
    // might be useful to others, as it was for me
    /*jadclipse*/
    package com.joeygibson.ant;
    import java.io.*;
    import java.nio.channels.WritableByteChannel;
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import org.apache.tools.ant.*;
    import org.apache.tools.ant.types.Path;
    import org.jdom.*;
    import org.jdom.input.SAXBuilder;
    public class EclipseClasspathTask extends Task {
    private List pathElements = new ArrayList();
    public static final String DEFAULT_FILENAME = “.classpath”;
    public static final String DEFAULT_PATHID = “classpath”;
    public static final String DEFAULT_WORKSPACE = “c:/eclipse/workspace”;
    private List prefFiles;
    private File dir;
    private String pathId;
    private String classPathFileName;
    private boolean verbose;
    private File workspace;
    private String dumpFileName;
    public EclipseClasspathTask() {
    pathId = “classpath”;
    classPathFileName = “.classpath”;
    verbose = false;
    prefFiles = new ArrayList();
    prefFiles.add(“.metadata/.plugins/org.eclipse.jdt.core/prefs.ini”);
    prefFiles.add(“.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs”);
    prefFiles.add(“.metadata/.plugins/org.eclipse.jdt.core/pref_store.ini”);
    }
    public void execute() throws BuildException {
    if (workspace == null) {
    workspace = new File(“c:/eclipse/workspace”);
    }
    Map variables = getVariables();
    Document document = null;
    File inFile = null;
    try {
    if (dir == null) {
    dir = getProject().getBaseDir();
    }
    inFile = new File(dir, classPathFileName);
    SAXBuilder sax = new SAXBuilder();
    document = sax.build(inFile);
    } catch (FileNotFoundException e) {
    log(“Unable to open Eclipse classpath file [” + inFile.getAbsolutePath() + “]”);
    } catch (JDOMException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    if (document == null) {
    return;
    }
    Path classPath = new Path(getProject());
    Element root = document.getRootElement();
    Collection children = root.getChildren(“classpathentry”);
    if (children != null) {
    Iterator i = children.iterator();
    while (i.hasNext()) {
    Element element = (Element) i.next();
    Attribute kind = element.getAttribute(“kind”);
    Attribute path = element.getAttribute(“path”);
    String location = null;
    if (kind.getValue().equals(“var”)) {
    String name = path.getValue();
    location = (String) variables.get(name);
    boolean allowForExtension = true;
    String varname = null;
    if (allowForExtension && name != null) {
    if (verbose) {
    log(“Checking name:'” + name + “‘”);
    }
    if (name.indexOf(“/”) != -1) {
    // check that first path seperator is a var as path maybe extension.
    varname = name.substring(0, name.indexOf(“/”));
    if (varname != null && variables.get(varname) != null) {
    location = (String) variables.get(varname) + name.substring(varname.length(), name.length());
    }
    }
    }
    if (location == null) {
    log(“Unable to map variable [” + name + “]”);
    continue;
    }
    if (verbose) {
    log(“Varname ” + varname);
    log(“Adding ” + location + “, (” + name + “)”);
    }
    } else if (kind.getValue().equals(“lib”)) {
    location = path.getValue();
    if (verbose) {
    log(“Adding ” + location);
    }
    } else {
    if (verbose) {
    log(“Skipping entry of type: [” + kind.getValue() + “]”);
    }
    continue;
    }
    try {
    File file = new File(location);
    if (!file.isAbsolute()) {
    file = new File(dir, location);
    }
    pathElements.add(file);
    org.apache.tools.ant.types.Path.PathElement e = classPath.createPathElement();
    e.setLocation(file);
    } catch (Exception e) {
    log(“Error processing [” + location + “]: ” + e.getMessage());
    }
    }
    }
    getProject().addReference(pathId, classPath);
    if (dumpFileName != null && !pathElements.isEmpty()) {
    //@TODO use XML tools properly!!
    try {
    File dumpFile = new File(getProject().getBaseDir(), dumpFileName);
    PrintWriter writer = new PrintWriter(new FileOutputStream(dumpFile));
    writer.println(“”);
    writer.println(“”);
    Iterator iter = pathElements.iterator();
    while (iter.hasNext()) {
    File path = (File) iter.next();
    writer.println(“t”);
    }
    writer.println(“”);
    writer.flush();
    writer.close();
    } catch (FileNotFoundException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
    }
    }
    if (verbose) {
    log(“n” + pathId + “: ” + classPath.toString());
    }
    }
    private Map getVariables() {
    Map vars = new HashMap();
    File prefs = null;
    Iterator i = prefFiles.iterator();
    while (i.hasNext()) {
    String fileName = (String) i.next();
    prefs = new File(workspace, fileName);
    if (verbose) {
    log(“Checking ” + prefs.toString());
    }
    if (!prefs.exists()) {
    if (verbose) {
    log(“Cant find ‘” + prefs.toString() + “‘”);
    }
    } else {
    try {
    BufferedReader in = new BufferedReader(new FileReader(prefs));
    String line = null;
    Pattern valRegex = Pattern.compile(“/?(w).?:(.+)”);
    do {
    if ((line = in.readLine()) == null) {
    break;
    }
    int index = line.indexOf(“classpathVariable”);
    if (index >= 0) {
    String slice = line.substring(index);
    String chunks[] = slice.split(“=”);
    if (chunks.length == 2) {
    String name = chunks[0].substring(chunks[0].lastIndexOf(“.”) + 1);
    String value = null;
    Matcher valMatcher = valRegex.matcher(chunks[1]);
    if (valMatcher.matches()) {
    value = valMatcher.group(1) + “:” + valMatcher.group(2);
    } else {
    value = chunks[1];
    }
    if (verbose) {
    //log(“Adding to var lookup: (” + name + “,” + value + “)”);
    }
    vars.put(name, value);
    }
    }
    } while (true);
    } catch (FileNotFoundException e) {
    log(“Unable to find Eclipse preferences file at [” + prefs.getAbsolutePath() + “]”);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    return vars;
    }
    public void setDir(File directory) {
    dir = directory;
    }
    public void setPathId(String pathName) {
    pathId = pathName;
    }
    public void setFileName(String fileName) {
    this.classPathFileName = fileName;
    }
    public void setWorkspace(File workspace) {
    this.workspace = workspace;
    }
    public void setVerbose(boolean verbose) {
    this.verbose = verbose;
    }
    public void setDumpFileName(String string) {
    dumpFileName = string;
    }
    }
    /***** DECOMPILATION REPORT *****
    DECOMPILED FROM: C:ANTlibeclipseclasspathtask.jar
    TOTAL TIME: 80 ms
    JAD REPORTED MESSAGES/ERRORS:
    EXIT STATUS: 0
    CAUGHT EXCEPTIONS:
    ********************************/

  11. Great work Joe, thanks for the task. I found one bug while using it in an environment that uses Eclipse on Windows and Ant on linux. In such a scenario, the .classpath file stores relative paths in the form “/project/etc” which are correctly converted to absolute Windows paths (“C:/blah/project/etc”) using the following statement:
    if (!file.isAbsolute())
    {
    file = new File(dir, location);
    }
    Unfortunately, when this same classpath is read in Linux it recognizes “/project/etc” as an absolute path and fails to properly adjust it for the relative directory location.
    I fixed it by eliminating the absolute test (I only use relative paths for simplicity), but I’m sure there is a more general solution.
    Again, great work!

Comments are closed.