Attached is a CAB task I wrote some weeks ago to create Microsoft .cab
files.  I know, I know, boo, hiss, but I had no choice - really.  I have
to create these for one of my current projects, so I put this together.
The task syntax is just like jar or zip, since it really does the same
thing anyway.

Use it like this:

  <cab cabfile="filename" basedir="dir"/>

All of the optional parameters from MatchingTask are supported
(including the nested params):

    includes
    excludes
    items
    ignore
    defaultexcludes

This task contains OS checks and will only run on Windoze.  It is
harmlessly ignored on other OSes.  You must have the Microsoft CABARC
utility available in your executable path.  I have not been able to find
any Java classes for creating CAB files - if anyone knows of any, please
let me know.

I'm donating the source to the project - you will see that I borrowed
heavily from existing tasks anyway.

Roger Vaughn

package org.apache.tools.ant.taskdefs.optional;

import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;

import java.io.*;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * Create a CAB archive.
 *
 * @author Roger Vaughn <a href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
 */

public class Cab extends MatchingTask {

    private File cabFile;
    private File baseDir;
    protected String archiveType = "cab";
    
    /**
     * This is the name/location of where to 
     * create the .cab file.
     */
    public void setCabfile(String cabFilename) {
        cabFile = project.resolveFile(cabFilename);
    }
    
    /**
     * This is the base directory to look in for 
     * things to cab.
     */
    public void setBasedir(String baseDirname) {
        baseDir = project.resolveFile(baseDirname);
    }

    public void execute() throws BuildException {
        String myos = System.getProperty("os.name");
        log("Myos = " + myos, Project.MSG_VERBOSE);
        if (myos.toLowerCase().indexOf("windows") < 0){
            // this command will be executed only on the specified OS
            log("Can only run cab tasks on Windows", Project.MSG_VERBOSE);
            return;
        }

        if (baseDir == null) {
            throw new BuildException("basedir attribute must be set!");
        }
        if (!baseDir.exists()) {
            throw new BuildException("basedir does not exist!");
        }

        DirectoryScanner ds = super.getDirectoryScanner(baseDir);

        String[] files = ds.getIncludedFiles();
        String[] dirs  = ds.getIncludedDirectories();

        // quick exit if the target is up to date
        boolean upToDate = true;
        for (int i=0; i<files.length && upToDate; i++)
            if (new File(baseDir,files[i]).lastModified() > 
                cabFile.lastModified())
                upToDate = false;
        if (upToDate) return;

        log("Building "+ archiveType +": "+ cabFile.getAbsolutePath());

        try {
            File listFile = createListFile(files);
            try
            {
                createCabFile(
                    baseDir.getAbsolutePath(),
                    cabFile.getAbsolutePath(),
                    listFile.getAbsolutePath());
            }
            finally
            {
                listFile.delete();
            }
        } catch (IOException ioe) {
            String msg = "Problem creating " + archiveType + " " + 
ioe.getMessage();
            throw new BuildException(msg);
        }
    }

    protected File createListFile(String[] files)
        throws IOException
    {
        File listFile = File.createTempFile("ant", null);
        PrintWriter writer = new PrintWriter(new FileOutputStream(listFile));

        for (int i = 0; i < files.length; i++)
        {
            writer.println(files[i]);
        }
        writer.close();

        return listFile;
    }

    protected void createCabFile(String dir, String cabFile, String listFile)
        throws IOException
    {
        int err = -1; // assume the worst

        String command =
            "cmd /c cd " + project.resolveFile(dir) + " && " + 
            "cabarc -r -p n " + cabFile + " @" + listFile;
        
        try {
            // show the command
            log(command, Project.MSG_VERBOSE);

            // exec command on system runtime
            Process proc = Runtime.getRuntime().exec(command);

            // copy input and error to the output stream
            StreamPumper inputPumper =
                new StreamPumper(proc.getInputStream(), "exec", project, null);
            StreamPumper errorPumper =
                new StreamPumper(proc.getErrorStream(), "error", project, null);

            // starts pumping away the generated output/error
            inputPumper.start();
            errorPumper.start();

            // Wait for everything to finish
            proc.waitFor();
            inputPumper.join();
            errorPumper.join();
            proc.destroy();

            // check its exit value
            err = proc.exitValue();
            if (err != 0) {
                log("Result: " + err, Project.MSG_ERR);
            }
        } catch (InterruptedException ex) {}
    }
    
    // Inner class for continually pumping the input stream during
    // Process's runtime.
    class StreamPumper extends Thread {
        private BufferedReader din;
        private String name;
        private boolean endOfStream = false;
        private int SLEEP_TIME = 5;
        private Project project;
        private PrintWriter fos;
        private static final int BUFFER_SIZE = 512;

        public StreamPumper(InputStream is, String name, Project project, 
PrintWriter fos) {
            this.din     = new BufferedReader(new InputStreamReader(is));
            this.name    = name;
            this.project = project;
            this.fos     = fos;
        }

        public void pumpStream()
            throws IOException
        {
            byte[] buf = new byte[BUFFER_SIZE];
            if (!endOfStream) {
                String line = din.readLine();

                if (line != null) {
                    if (fos == null)
                        log(line, Project.MSG_INFO);
                    else
                        fos.println(line);
                } else {
                    endOfStream = true;
                }
            }
        }

        public void run() {
            try {
                try {
                    while (!endOfStream) {
                        pumpStream();
                        sleep(SLEEP_TIME);
                    }
                } catch (InterruptedException ie) {}
                din.close();
            } catch (IOException ioe) {}
        }
    }
}

Reply via email to