KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > Cab


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs.optional;
20
21 import java.io.File JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.PrintWriter JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Vector JavaDoc;
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.DirectoryScanner;
30 import org.apache.tools.ant.Project;
31 import org.apache.tools.ant.taskdefs.ExecTask;
32 import org.apache.tools.ant.taskdefs.Execute;
33 import org.apache.tools.ant.taskdefs.LogOutputStream;
34 import org.apache.tools.ant.taskdefs.MatchingTask;
35 import org.apache.tools.ant.taskdefs.StreamPumper;
36 import org.apache.tools.ant.taskdefs.condition.Os;
37 import org.apache.tools.ant.types.FileSet;
38 import org.apache.tools.ant.util.FileUtils;
39
40
41 /**
42  * Create a CAB archive.
43  *
44  */

45
46 public class Cab extends MatchingTask {
47
48     private File JavaDoc cabFile;
49     private File JavaDoc baseDir;
50     private Vector JavaDoc filesets = new Vector JavaDoc();
51     private boolean doCompress = true;
52     private boolean doVerbose = false;
53     private String JavaDoc cmdOptions;
54
55     // CheckStyle:VisibilityModifier OFF - bc
56
protected String JavaDoc archiveType = "cab";
57     // CheckStyle:VisibilityModifier ON
58

59     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
60
61     /**
62      * The name/location of where to create the .cab file.
63      * @param cabFile the location of the cab file.
64      */

65     public void setCabfile(File JavaDoc cabFile) {
66         this.cabFile = cabFile;
67     }
68
69     /**
70      * Base directory to look in for files to CAB.
71      * @param baseDir base directory for files to cab.
72      */

73     public void setBasedir(File JavaDoc baseDir) {
74         this.baseDir = baseDir;
75     }
76
77     /**
78      * If true, compress the files otherwise only store them.
79      * @param compress a <code>boolean</code> value.
80      */

81     public void setCompress(boolean compress) {
82         doCompress = compress;
83     }
84
85     /**
86      * If true, display cabarc output.
87      * @param verbose a <code>boolean</code> value.
88      */

89     public void setVerbose(boolean verbose) {
90         doVerbose = verbose;
91     }
92
93     /**
94      * Sets additional cabarc options that are not supported directly.
95      * @param options cabarc command line options.
96      */

97     public void setOptions(String JavaDoc options) {
98         cmdOptions = options;
99     }
100
101     /**
102      * Adds a set of files to archive.
103      * @param set a set of files to archive.
104      */

105     public void addFileset(FileSet set) {
106         if (filesets.size() > 0) {
107             throw new BuildException("Only one nested fileset allowed");
108         }
109         filesets.addElement(set);
110     }
111
112     /*
113      * I'm not fond of this pattern: "sub-method expected to throw
114      * task-cancelling exceptions". It feels too much like programming
115      * for side-effects to me...
116      */

117     /**
118      * Check if the attributes and nested elements are correct.
119      * @throws BuildException on error.
120      */

121     protected void checkConfiguration() throws BuildException {
122         if (baseDir == null && filesets.size() == 0) {
123             throw new BuildException("basedir attribute or one "
124                                      + "nested fileset is required!",
125                                      getLocation());
126         }
127         if (baseDir != null && !baseDir.exists()) {
128             throw new BuildException("basedir does not exist!", getLocation());
129         }
130         if (baseDir != null && filesets.size() > 0) {
131             throw new BuildException(
132                 "Both basedir attribute and a nested fileset is not allowed");
133         }
134         if (cabFile == null) {
135             throw new BuildException("cabfile attribute must be set!",
136                                      getLocation());
137         }
138     }
139
140     /**
141      * Create a new exec delegate. The delegate task is populated so that
142      * it appears in the logs to be the same task as this one.
143      * @return the delegate.
144      * @throws BuildException on error.
145      */

146     protected ExecTask createExec() throws BuildException {
147         ExecTask exec = new ExecTask(this);
148         return exec;
149     }
150
151     /**
152      * Check to see if the target is up to date with respect to input files.
153      * @param files the list of files to check.
154      * @return true if the cab file is newer than its dependents.
155      */

156     protected boolean isUpToDate(Vector JavaDoc files) {
157         boolean upToDate = true;
158         for (int i = 0; i < files.size() && upToDate; i++) {
159             String JavaDoc file = files.elementAt(i).toString();
160             if (FILE_UTILS.resolveFile(baseDir, file).lastModified()
161                     > cabFile.lastModified()) {
162                 upToDate = false;
163             }
164         }
165         return upToDate;
166     }
167
168     /**
169      * Creates a list file. This temporary file contains a list of all files
170      * to be included in the cab, one file per line.
171      *
172      * <p>This method expects to only be called on Windows and thus
173      * quotes the file names.</p>
174      * @param files the list of files to use.
175      * @return the list file created.
176      * @throws IOException if there is an error.
177      */

178     protected File JavaDoc createListFile(Vector JavaDoc files)
179         throws IOException JavaDoc {
180         File JavaDoc listFile = FILE_UTILS.createTempFile("ant", "", null);
181         listFile.deleteOnExit();
182
183         PrintWriter JavaDoc writer = new PrintWriter JavaDoc(new FileOutputStream JavaDoc(listFile));
184
185         int size = files.size();
186         for (int i = 0; i < size; i++) {
187             writer.println('\"' + files.elementAt(i).toString() + '\"');
188         }
189         writer.close();
190
191         return listFile;
192     }
193
194     /**
195      * Append all files found by a directory scanner to a vector.
196      * @param files the vector to append the files to.
197      * @param ds the scanner to get the files from.
198      */

199     protected void appendFiles(Vector JavaDoc files, DirectoryScanner ds) {
200         String JavaDoc[] dsfiles = ds.getIncludedFiles();
201
202         for (int i = 0; i < dsfiles.length; i++) {
203             files.addElement(dsfiles[i]);
204         }
205     }
206
207     /**
208      * Get the complete list of files to be included in the cab. Filenames
209      * are gathered from the fileset if it has been added, otherwise from the
210      * traditional include parameters.
211      * @return the list of files.
212      * @throws BuildException if there is an error.
213      */

214     protected Vector JavaDoc getFileList() throws BuildException {
215         Vector JavaDoc files = new Vector JavaDoc();
216
217         if (baseDir != null) {
218             // get files from old methods - includes and nested include
219
appendFiles(files, super.getDirectoryScanner(baseDir));
220         } else {
221             FileSet fs = (FileSet) filesets.elementAt(0);
222             baseDir = fs.getDir();
223             appendFiles(files, fs.getDirectoryScanner(getProject()));
224         }
225
226         return files;
227     }
228
229     /**
230      * execute this task.
231      * @throws BuildException on error.
232      */

233     public void execute() throws BuildException {
234
235         checkConfiguration();
236
237         Vector JavaDoc files = getFileList();
238
239         // quick exit if the target is up to date
240
if (isUpToDate(files)) {
241             return;
242         }
243
244         log("Building " + archiveType + ": " + cabFile.getAbsolutePath());
245
246         if (!Os.isFamily("windows")) {
247             log("Using listcab/libcabinet", Project.MSG_VERBOSE);
248
249             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
250
251             Enumeration JavaDoc fileEnum = files.elements();
252
253             while (fileEnum.hasMoreElements()) {
254                 sb.append(fileEnum.nextElement()).append("\n");
255             }
256             sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");
257
258             try {
259                 Process JavaDoc p = Execute.launch(getProject(),
260                                            new String JavaDoc[] {"listcab"}, null,
261                                            baseDir != null ? baseDir
262                                                    : getProject().getBaseDir(),
263                                            true);
264                 OutputStream JavaDoc out = p.getOutputStream();
265
266                 // Create the stream pumpers to forward listcab's stdout and stderr to the log
267
// note: listcab is an interactive program, and issues prompts for every new line.
268
// Therefore, make it show only with verbose logging turned on.
269
LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
270                 LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
271                 StreamPumper outPump = new StreamPumper(p.getInputStream(), outLog);
272                 StreamPumper errPump = new StreamPumper(p.getErrorStream(), errLog);
273
274                 // Pump streams asynchronously
275
(new Thread JavaDoc(outPump)).start();
276                 (new Thread JavaDoc(errPump)).start();
277
278                 out.write(sb.toString().getBytes());
279                 out.flush();
280                 out.close();
281
282                 int result = -99; // A wild default for when the thread is interrupted
283

284                 try {
285                     // Wait for the process to finish
286
result = p.waitFor();
287
288                     // Wait for the end of output and error streams
289
outPump.waitFor();
290                     outLog.close();
291                     errPump.waitFor();
292                     errLog.close();
293                 } catch (InterruptedException JavaDoc ie) {
294                     log("Thread interrupted: " + ie);
295                 }
296
297                 // Informative summary message in case of errors
298
if (Execute.isFailure(result)) {
299                     log("Error executing listcab; error code: " + result);
300                 }
301             } catch (IOException JavaDoc ex) {
302                 String JavaDoc msg = "Problem creating " + cabFile + " " + ex.getMessage();
303                 throw new BuildException(msg, getLocation());
304             }
305         } else {
306             try {
307                 File JavaDoc listFile = createListFile(files);
308                 ExecTask exec = createExec();
309                 File JavaDoc outFile = null;
310
311                 // die if cabarc fails
312
exec.setFailonerror(true);
313                 exec.setDir(baseDir);
314
315                 if (!doVerbose) {
316                     outFile = FILE_UTILS.createTempFile("ant", "", null);
317                     outFile.deleteOnExit();
318                     exec.setOutput(outFile);
319                 }
320
321                 exec.setExecutable("cabarc");
322                 exec.createArg().setValue("-r");
323                 exec.createArg().setValue("-p");
324
325                 if (!doCompress) {
326                     exec.createArg().setValue("-m");
327                     exec.createArg().setValue("none");
328                 }
329
330                 if (cmdOptions != null) {
331                     exec.createArg().setLine(cmdOptions);
332                 }
333
334                 exec.createArg().setValue("n");
335                 exec.createArg().setFile(cabFile);
336                 exec.createArg().setValue("@" + listFile.getAbsolutePath());
337
338                 exec.execute();
339
340                 if (outFile != null) {
341                     outFile.delete();
342                 }
343
344                 listFile.delete();
345             } catch (IOException JavaDoc ioe) {
346                 String JavaDoc msg = "Problem creating " + cabFile + " " + ioe.getMessage();
347                 throw new BuildException(msg, getLocation());
348             }
349         }
350     }
351 }
352
Popular Tags