Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 360   Methods: 13
NCLOC: 192   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Cab.java 0% 0% 0% 0%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 package org.apache.tools.ant.taskdefs.optional;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileOutputStream;
 59   
 import java.io.IOException;
 60   
 import java.io.OutputStream;
 61   
 import java.io.PrintWriter;
 62   
 import java.util.Enumeration;
 63   
 import java.util.Vector;
 64   
 import org.apache.tools.ant.BuildException;
 65   
 import org.apache.tools.ant.DirectoryScanner;
 66   
 import org.apache.tools.ant.Project;
 67   
 import org.apache.tools.ant.taskdefs.ExecTask;
 68   
 import org.apache.tools.ant.taskdefs.Execute;
 69   
 import org.apache.tools.ant.taskdefs.LogOutputStream;
 70   
 import org.apache.tools.ant.taskdefs.MatchingTask;
 71   
 import org.apache.tools.ant.taskdefs.StreamPumper;
 72   
 import org.apache.tools.ant.taskdefs.condition.Os;
 73   
 import org.apache.tools.ant.types.Commandline;
 74   
 import org.apache.tools.ant.types.FileSet;
 75   
 import org.apache.tools.ant.util.FileUtils;
 76   
 
 77   
 
 78   
 /**
 79   
  * Create a CAB archive.
 80   
  *
 81   
  * @author Roger Vaughn <a href="mailto:rvaughn@seaconinc.com">rvaughn@seaconinc.com</a>
 82   
  * @author Jesse Stockall
 83   
  */
 84   
 
 85   
 public class Cab extends MatchingTask {
 86   
 
 87   
     private File cabFile;
 88   
     private File baseDir;
 89   
     private Vector filesets = new Vector();
 90   
     private boolean doCompress = true;
 91   
     private boolean doVerbose = false;
 92   
     private String cmdOptions;
 93   
 
 94   
     protected String archiveType = "cab";
 95   
 
 96   
     private FileUtils fileUtils = FileUtils.newFileUtils();
 97   
 
 98   
     /**
 99   
      * The name/location of where to create the .cab file.
 100   
      */
 101  0
     public void setCabfile(File cabFile) {
 102  0
         this.cabFile = cabFile;
 103   
     }
 104   
 
 105   
     /**
 106   
      * Base directory to look in for files to CAB.
 107   
      */
 108  0
     public void setBasedir(File baseDir) {
 109  0
         this.baseDir = baseDir;
 110   
     }
 111   
 
 112   
     /**
 113   
      * If true, compress the files otherwise only store them.
 114   
      */
 115  0
     public void setCompress(boolean compress) {
 116  0
         doCompress = compress;
 117   
     }
 118   
 
 119   
     /**
 120   
      * If true, display cabarc output.
 121   
      */
 122  0
     public void setVerbose(boolean verbose) {
 123  0
         doVerbose = verbose;
 124   
     }
 125   
 
 126   
     /**
 127   
      * Sets additional cabarc options that are not supported directly.
 128   
      */
 129  0
     public void setOptions(String options) {
 130  0
         cmdOptions = options;
 131   
     }
 132   
 
 133   
     /**
 134   
      * Adds a set of files to archive.
 135   
      */
 136  0
     public void addFileset(FileSet set) {
 137  0
         filesets.addElement(set);
 138   
     }
 139   
 
 140   
     /*
 141   
      * I'm not fond of this pattern: "sub-method expected to throw
 142   
      * task-cancelling exceptions".  It feels too much like programming
 143   
      * for side-effects to me...
 144   
      */
 145  0
     protected void checkConfiguration() throws BuildException {
 146  0
         if (baseDir == null && filesets.size() == 0) {
 147  0
             throw new BuildException("basedir attribute or at least one "
 148   
                                      + "nested filest is required!", 
 149   
                                      getLocation());
 150   
         }
 151  0
         if (baseDir != null && !baseDir.exists()) {
 152  0
             throw new BuildException("basedir does not exist!", getLocation());
 153   
         }
 154  0
         if (cabFile == null) {
 155  0
             throw new BuildException("cabfile attribute must be set!",
 156   
                                      getLocation());
 157   
         }
 158   
     }
 159   
 
 160   
     /**
 161   
      * Create a new exec delegate.  The delegate task is populated so that
 162   
      * it appears in the logs to be the same task as this one.
 163   
      */
 164  0
     protected ExecTask createExec() throws BuildException {
 165  0
         ExecTask exec = (ExecTask) getProject().createTask("exec");
 166  0
         exec.setOwningTarget(this.getOwningTarget());
 167  0
         exec.setTaskName(this.getTaskName());
 168  0
         exec.setDescription(this.getDescription());
 169   
 
 170  0
         return exec;
 171   
     }
 172   
 
 173   
     /**
 174   
      * Check to see if the target is up to date with respect to input files.
 175   
      * @return true if the cab file is newer than its dependents.
 176   
      */
 177  0
     protected boolean isUpToDate(Vector files) {
 178  0
         boolean upToDate = true;
 179  0
         for (int i = 0; i < files.size() && upToDate; i++) {
 180  0
             String file = files.elementAt(i).toString();
 181  0
             if (fileUtils.resolveFile(baseDir, file).lastModified() >
 182   
                 cabFile.lastModified()) {
 183  0
                 upToDate = false;
 184   
             }
 185   
         }
 186  0
         return upToDate;
 187   
     }
 188   
 
 189   
     /**
 190   
      * Creates a list file.  This temporary file contains a list of all files
 191   
      * to be included in the cab, one file per line.
 192   
      */
 193  0
     protected File createListFile(Vector files)
 194   
         throws IOException {
 195  0
         File listFile = fileUtils.createTempFile("ant", "", null);
 196   
 
 197  0
         PrintWriter writer = new PrintWriter(new FileOutputStream(listFile));
 198   
 
 199  0
         for (int i = 0; i < files.size(); i++) {
 200  0
             writer.println(files.elementAt(i).toString());
 201   
         }
 202  0
         writer.close();
 203   
 
 204  0
         return listFile;
 205   
     }
 206   
 
 207   
     /**
 208   
      * Append all files found by a directory scanner to a vector.
 209   
      */
 210  0
     protected void appendFiles(Vector files, DirectoryScanner ds) {
 211  0
         String[] dsfiles = ds.getIncludedFiles();
 212   
 
 213  0
         for (int i = 0; i < dsfiles.length; i++) {
 214  0
             files.addElement(dsfiles[i]);
 215   
         }
 216   
     }
 217   
 
 218   
     /**
 219   
      * Get the complete list of files to be included in the cab.  Filenames
 220   
      * are gathered from filesets if any have been added, otherwise from the
 221   
      * traditional include parameters.
 222   
      */
 223  0
     protected Vector getFileList() throws BuildException {
 224  0
         Vector files = new Vector();
 225   
 
 226  0
         if (baseDir != null) {
 227   
             // get files from old methods - includes and nested include
 228  0
             appendFiles(files, super.getDirectoryScanner(baseDir));
 229   
         }
 230   
 
 231   
         // get files from filesets
 232  0
         for (int i = 0; i < filesets.size(); i++) {
 233  0
             FileSet fs = (FileSet) filesets.elementAt(i);
 234  0
             if (fs != null) {
 235  0
                 appendFiles(files, fs.getDirectoryScanner(getProject()));
 236   
             }
 237   
         }
 238   
 
 239  0
         return files;
 240   
     }
 241   
 
 242  0
     public void execute() throws BuildException {
 243   
 
 244  0
         checkConfiguration();
 245   
 
 246  0
         Vector files = getFileList();
 247   
 
 248   
         // quick exit if the target is up to date
 249  0
         if (isUpToDate(files)) {
 250  0
             return;
 251   
         }
 252   
 
 253  0
         log("Building " + archiveType + ": " + cabFile.getAbsolutePath());
 254   
 
 255  0
         if (!Os.isFamily("windows")) {
 256  0
             log("Using listcab/libcabinet", Project.MSG_VERBOSE);
 257   
 
 258  0
             StringBuffer sb = new StringBuffer();
 259   
 
 260  0
             Enumeration fileEnum = files.elements();
 261   
 
 262  0
             while (fileEnum.hasMoreElements()) {
 263  0
                 sb.append(fileEnum.nextElement()).append("\n");
 264   
             }
 265  0
             sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");
 266   
 
 267  0
             try {
 268  0
                 Process p = Execute.launch(getProject(),
 269   
                                            new String[] {"listcab"}, null,
 270   
                                            baseDir != null ? baseDir 
 271   
                                                    : getProject().getBaseDir(),
 272   
                                            true);
 273  0
                 OutputStream out = p.getOutputStream();
 274   
 
 275   
                 // Create the stream pumpers to forward listcab's stdout and stderr to the log
 276   
                 // note: listcab is an interactive program, and issues prompts for every new line.
 277   
                 //       Therefore, make it show only with verbose logging turned on.
 278  0
                 LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
 279  0
                 LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
 280  0
                 StreamPumper    outPump = new StreamPumper(p.getInputStream(), outLog);
 281  0
                 StreamPumper    errPump = new StreamPumper(p.getErrorStream(), errLog);
 282   
 
 283   
                 // Pump streams asynchronously
 284  0
                 (new Thread(outPump)).start();
 285  0
                 (new Thread(errPump)).start();
 286   
 
 287  0
                 out.write(sb.toString().getBytes());
 288  0
                 out.flush();
 289  0
                 out.close();
 290   
 
 291  0
                 int result = -99; // A wild default for when the thread is interrupted
 292   
 
 293  0
                 try {
 294   
                     // Wait for the process to finish
 295  0
                     result = p.waitFor();
 296   
 
 297   
                     // Wait for the end of output and error streams
 298  0
                     outPump.waitFor();
 299  0
                     outLog.close();
 300  0
                     errPump.waitFor();
 301  0
                     errLog.close();
 302   
                 } catch (InterruptedException ie) {
 303  0
                     log("Thread interrupted: " + ie);
 304   
                 }
 305   
 
 306   
                 // Informative summary message in case of errors
 307  0
                 if (result != 0) {
 308  0
                     log("Error executing listcab; error code: " + result);
 309   
                 }
 310   
             } catch (IOException ex) {
 311  0
                 String msg = "Problem creating " + cabFile + " " + ex.getMessage();
 312  0
                 throw new BuildException(msg, getLocation());
 313   
             }
 314   
         } else {
 315  0
             try {
 316  0
                 File listFile = createListFile(files);
 317  0
                 ExecTask exec = createExec();
 318  0
                 File outFile = null;
 319   
 
 320   
                 // die if cabarc fails
 321  0
                 exec.setFailonerror(true);
 322  0
                 exec.setDir(baseDir);
 323   
 
 324  0
                 if (!doVerbose) {
 325  0
                     outFile = fileUtils.createTempFile("ant", "", null);
 326  0
                     exec.setOutput(outFile);
 327   
                 }
 328   
 
 329  0
                 exec.setExecutable("cabarc");
 330  0
                 exec.createArg().setValue("-r");
 331  0
                 exec.createArg().setValue("-p");
 332   
 
 333  0
                 if (!doCompress) {
 334  0
                     exec.createArg().setValue("-m");
 335  0
                     exec.createArg().setValue("none");
 336   
                 }
 337   
 
 338  0
                 if (cmdOptions != null) {
 339  0
                     exec.createArg().setLine(cmdOptions);
 340   
                 }
 341   
 
 342  0
                 exec.createArg().setValue("n");
 343  0
                 exec.createArg().setFile(cabFile);
 344  0
                 exec.createArg().setValue("@" + listFile.getAbsolutePath());
 345   
 
 346  0
                 exec.execute();
 347   
 
 348  0
                 if (outFile != null) {
 349  0
                     outFile.delete();
 350   
                 }
 351   
 
 352  0
                 listFile.delete();
 353   
             } catch (IOException ioe) {
 354  0
                 String msg = "Problem creating " + cabFile + " " + ioe.getMessage();
 355  0
                 throw new BuildException(msg, getLocation());
 356   
             }
 357   
         }
 358   
     }
 359   
 }
 360