ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dominique Devienne" <DDevie...@lgc.com>
Subject RE: generate manifest.mf file
Date Fri, 20 Aug 2004 14:39:46 GMT
> From: Mark Lybarger [mailto:Mark.Lybarger@CBC-Companies.com]
> 
> is there a way to get ant to generate a manifest.mf file that'll
include a
> proper classpath entry?  we currently have an ejb-jar which is
packaged as
> part of an ear, and the ejb-jar uses libraries that are packaged in
the
> ear.  the ejb-jar's manifest includes a classpath entry that points to
> those 3rd party jars. the problem is that when ever a jar file is
modified
> (renamed or added) the manifest doesn't stay in sync.  it would be
nice if
> ant (or something) could generate the manifest based on fileset list
that
> it finds.

You mean something along the lines of this custom task ;-) --DD

PS: Should be a simple matter to replace the TaskUtils code
PPS: I've got good test coverage on this code, and it's used in
production
     so it should be fairly safe to use it as-is.
PPPS: I've posted the pure Ant equivalent (more verbose) in the past
      on this list. Search the archives if you don't want to compile
      the custom task below.

package com.lgc.buildmagic;

import java.io.File;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.types.Path;

/**
 * Converts a Path into a property suitable as a Manifest classpath.
 */
public class ManifestClassPath
             extends Task {

    /** The property name to hold the classpath value. */
    private String _name;

    /** The directory the classpath will be relative from. */
    private File _dir;

    /** The maximum parent directory level to traverse. */
    private int _maxParentLevels = 2;

    /** The classpath to convert. */
    private Path _path;

    /**
     * Sets a property, which must not already exists, with a space
     * separated list of files and directories relative to the jar
     * file's parent directory.
     */
    public void execute() {
        TaskUtils.assertAttributeSet(_name, "property");
        TaskUtils.assertAttributeSet(_dir, "jarfile");
        TaskUtils.assertPropertyNotSet(this, _name);
        if (_path == null) {
            throw new BuildException("Missing nested <classpath>!");
        }

        // Normalize the reference directory (containing the jar)
        final FileUtils fileUtils = FileUtils.newFileUtils();
        _dir = fileUtils.normalize(_dir.getAbsolutePath());

        // Create as many directory prefixes as parent levels to
traverse,
        // in addition to the reference directory itself
        File currDir = _dir;
        String[] dirs = new String[_maxParentLevels + 1];
        for (int i = 0; i < _maxParentLevels + 1; ++i) {
            dirs[i] = currDir.getAbsolutePath() + File.separatorChar;
            currDir = currDir.getParentFile();
            if (currDir == null) {
                _maxParentLevels = i + 1;
                break;
            }
        }

        String[] elements = _path.list();
        StringBuffer buffer = new StringBuffer();
        StringBuffer element = new StringBuffer();
        for (int i = 0; i < elements.length; ++i) {
            // Normalize the current file
            File pathEntry = new File(elements[i]);
            pathEntry =
fileUtils.normalize(pathEntry.getAbsolutePath());
            String fullPath = pathEntry.getAbsolutePath();

            // Find the longest prefix shared by the current file
            // and the reference directory.
            String relPath = null;
            for (int j = 0; j <= _maxParentLevels; ++j) {
                String dir = dirs[j];
                if (!fullPath.startsWith(dir)) {
                    continue;
                }

                // We have a match! Add as many ../ as parent
                // directory traversed to get the relative path
                element.setLength(0);
                for (int k = 0; k < j; ++k) {
                    element.append("..");
                    element.append(File.separatorChar);
                }
                element.append(fullPath.substring(dir.length()));
                relPath = element.toString();
                break;
            }

            // No match, so bail out!
            if (relPath == null) {
                throw new BuildException("No suitable relative path from
" +
                                         _dir + " to " + fullPath);
            }

            // Manifest's ClassPath: attribute always uses forward
            // slashes '/', and is space-separated. Ant will properly
            // format it on 72 columns with proper line continuation
            if (File.separatorChar != '/') {
                relPath = relPath.replace(File.separatorChar, '/');
            }
            buffer.append(relPath);
            if (pathEntry.isDirectory()) {
                buffer.append('/');
            }
            buffer.append(' ');
        }
        
        // Get rid of trailing space, if any
        if (buffer.length() > 0) {
            buffer.setLength(buffer.length() - 1);
        }

        // Finally assign the property with the manifest classpath
        getProject().setNewProperty(_name, buffer.toString());
    }

    /**
     * Sets the property name to hold the classpath value.
     *
     * @param  name the property name
     */
    public void setProperty(String name) {
        _name = name;
    }

    /**
     * The JAR file to contain the classpath attribute in its manifest.
     * 
     * @param  jarfile the JAR file. Need not exist yet, but its parent
     *         directory must exists on the other hand.
     */
    public void setJarFile(File jarfile) {
        File parent = jarfile.getParentFile();
        if (!parent.isDirectory()) {
            throw new BuildException("Jar's directory not found: " +
parent);
        }
        _dir = parent;
    }

    /**
     * Sets the maximum parent directory levels allowed when computing
     * a relative path.
     *
     * @param  levels the max level. Defaults to 2.
     */
    public void setMaxParentLevels(int levels) {
        _maxParentLevels = levels;
    }

    /**
     * Adds the classpath to convert.
     *
     * @param  path the classpath to convert.
     */
    public void addClassPath(Path path) {
        _path = path;
    }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Mime
View raw message