KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > Delete


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;
20
21 import java.io.File JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.Vector JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Comparator JavaDoc;
26
27 import org.apache.tools.ant.Project;
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.taskdefs.condition.Os;
30 import org.apache.tools.ant.types.FileSet;
31 import org.apache.tools.ant.types.PatternSet;
32 import org.apache.tools.ant.types.ResourceCollection;
33 import org.apache.tools.ant.types.resources.Sort;
34 import org.apache.tools.ant.types.resources.Restrict;
35 import org.apache.tools.ant.types.resources.Resources;
36 import org.apache.tools.ant.types.resources.FileResource;
37 import org.apache.tools.ant.types.resources.FileResourceIterator;
38 import org.apache.tools.ant.types.resources.comparators.Reverse;
39 import org.apache.tools.ant.types.resources.comparators.FileSystem;
40 import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
41 import org.apache.tools.ant.types.resources.selectors.Exists;
42 import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
43 import org.apache.tools.ant.types.selectors.OrSelector;
44 import org.apache.tools.ant.types.selectors.AndSelector;
45 import org.apache.tools.ant.types.selectors.NotSelector;
46 import org.apache.tools.ant.types.selectors.DateSelector;
47 import org.apache.tools.ant.types.selectors.FileSelector;
48 import org.apache.tools.ant.types.selectors.NoneSelector;
49 import org.apache.tools.ant.types.selectors.SizeSelector;
50 import org.apache.tools.ant.types.selectors.DepthSelector;
51 import org.apache.tools.ant.types.selectors.DependSelector;
52 import org.apache.tools.ant.types.selectors.ExtendSelector;
53 import org.apache.tools.ant.types.selectors.SelectSelector;
54 import org.apache.tools.ant.types.selectors.PresentSelector;
55 import org.apache.tools.ant.types.selectors.ContainsSelector;
56 import org.apache.tools.ant.types.selectors.FilenameSelector;
57 import org.apache.tools.ant.types.selectors.MajoritySelector;
58 import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
59 import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
60
61 /**
62  * Deletes a file or directory, or set of files defined by a fileset.
63  * The original delete task would delete a file, or a set of files
64  * using the include/exclude syntax. The deltree task would delete a
65  * directory tree. This task combines the functionality of these two
66  * originally distinct tasks.
67  * <p>Currently Delete extends MatchingTask. This is intended <i>only</i>
68  * to provide backwards compatibility for a release. The future position
69  * is to use nested filesets exclusively.</p>
70  *
71  * @since Ant 1.2
72  *
73  * @ant.task category="filesystem"
74  */

75 public class Delete extends MatchingTask {
76     private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
77     private static final ResourceComparator REVERSE_FILESYSTEM = new Reverse(new FileSystem());
78     private static final ResourceSelector EXISTS = new Exists();
79
80     private static class ReverseDirs implements ResourceCollection {
81         static final Comparator JavaDoc REVERSE = new Comparator JavaDoc() {
82             public int compare(Object JavaDoc foo, Object JavaDoc bar) {
83                 return ((Comparable JavaDoc) foo).compareTo(bar) * -1;
84             }
85         };
86         private File JavaDoc basedir;
87         private String JavaDoc[] dirs;
88         ReverseDirs(File JavaDoc basedir, String JavaDoc[] dirs) {
89             this.basedir = basedir;
90             this.dirs = dirs;
91             Arrays.sort(this.dirs, REVERSE);
92         }
93         public Iterator JavaDoc iterator() {
94             return new FileResourceIterator(basedir, dirs);
95         }
96         public boolean isFilesystemOnly() { return true; }
97         public int size() { return dirs.length; }
98     }
99
100     // CheckStyle:VisibilityModifier OFF - bc
101
protected File JavaDoc file = null;
102     protected File JavaDoc dir = null;
103     protected Vector JavaDoc filesets = new Vector JavaDoc();
104     protected boolean usedMatchingTask = false;
105     // by default, remove matching empty dirs
106
protected boolean includeEmpty = false;
107
108     private int verbosity = Project.MSG_VERBOSE;
109     private boolean quiet = false;
110     private boolean failonerror = true;
111     private boolean deleteOnExit = false;
112     private Resources rcs = null;
113     // CheckStyle:VisibilityModifier ON
114

115     /**
116      * Set the name of a single file to be removed.
117      *
118      * @param file the file to be deleted
119      */

120     public void setFile(File JavaDoc file) {
121         this.file = file;
122     }
123
124     /**
125      * Set the directory from which files are to be deleted
126      *
127      * @param dir the directory path.
128      */

129     public void setDir(File JavaDoc dir) {
130         this.dir = dir;
131         getImplicitFileSet().setDir(dir);
132     }
133
134     /**
135      * If true, list all names of deleted files.
136      *
137      * @param verbose "true" or "on"
138      */

139     public void setVerbose(boolean verbose) {
140         if (verbose) {
141             this.verbosity = Project.MSG_INFO;
142         } else {
143             this.verbosity = Project.MSG_VERBOSE;
144         }
145     }
146
147     /**
148      * If true and the file does not exist, do not display a diagnostic
149      * message or modify the exit status to reflect an error.
150      * This means that if a file or directory cannot be deleted,
151      * then no error is reported. This setting emulates the
152      * -f option to the Unix &quot;rm&quot; command.
153      * Default is false meaning things are &quot;noisy&quot;
154      * @param quiet "true" or "on"
155      */

156     public void setQuiet(boolean quiet) {
157         this.quiet = quiet;
158         if (quiet) {
159             this.failonerror = false;
160         }
161     }
162
163     /**
164      * If false, note errors but continue.
165      *
166      * @param failonerror true or false
167      */

168      public void setFailOnError(boolean failonerror) {
169          this.failonerror = failonerror;
170      }
171
172     /**
173      * If true, on failure to delete, note the error and set
174      * the deleteonexit flag, and continue
175      *
176      * @param deleteOnExit true or false
177      */

178      public void setDeleteOnExit(boolean deleteOnExit) {
179          this.deleteOnExit = deleteOnExit;
180      }
181
182
183     /**
184      * If true, delete empty directories.
185      * @param includeEmpty if true delete empty directories (only
186      * for filesets). Default is false.
187      */

188     public void setIncludeEmptyDirs(boolean includeEmpty) {
189         this.includeEmpty = includeEmpty;
190     }
191
192    /**
193     * Adds a set of files to be deleted.
194     * @param set the set of files to be deleted
195     */

196     public void addFileset(FileSet set) {
197         filesets.addElement(set);
198     }
199
200     /**
201      * Add an arbitrary ResourceCollection to be deleted.
202      * @param rc the filesystem-only ResourceCollection.
203      */

204     public void add(ResourceCollection rc) {
205         if (rc == null) {
206             return;
207         }
208         rcs = (rcs == null) ? new Resources() : rcs;
209         rcs.add(rc);
210     }
211
212     /**
213      * add a name entry on the include list
214      * @return a NameEntry object to be configured
215      */

216     public PatternSet.NameEntry createInclude() {
217         usedMatchingTask = true;
218         return super.createInclude();
219     }
220
221     /**
222      * add a name entry on the include files list
223      * @return an NameEntry object to be configured
224      */

225     public PatternSet.NameEntry createIncludesFile() {
226         usedMatchingTask = true;
227         return super.createIncludesFile();
228     }
229
230     /**
231      * add a name entry on the exclude list
232      * @return an NameEntry object to be configured
233      */

234     public PatternSet.NameEntry createExclude() {
235         usedMatchingTask = true;
236         return super.createExclude();
237     }
238
239     /**
240      * add a name entry on the include files list
241      * @return an NameEntry object to be configured
242      */

243     public PatternSet.NameEntry createExcludesFile() {
244         usedMatchingTask = true;
245         return super.createExcludesFile();
246     }
247
248     /**
249      * add a set of patterns
250      * @return PatternSet object to be configured
251      */

252     public PatternSet createPatternSet() {
253         usedMatchingTask = true;
254         return super.createPatternSet();
255     }
256
257     /**
258      * Sets the set of include patterns. Patterns may be separated by a comma
259      * or a space.
260      *
261      * @param includes the string containing the include patterns
262      */

263     public void setIncludes(String JavaDoc includes) {
264         usedMatchingTask = true;
265         super.setIncludes(includes);
266     }
267
268     /**
269      * Sets the set of exclude patterns. Patterns may be separated by a comma
270      * or a space.
271      *
272      * @param excludes the string containing the exclude patterns
273      */

274     public void setExcludes(String JavaDoc excludes) {
275         usedMatchingTask = true;
276         super.setExcludes(excludes);
277     }
278
279     /**
280      * Sets whether default exclusions should be used or not.
281      *
282      * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
283      * should be used, "false"|"off"|"no" when they
284      * shouldn't be used.
285      */

286     public void setDefaultexcludes(boolean useDefaultExcludes) {
287         usedMatchingTask = true;
288         super.setDefaultexcludes(useDefaultExcludes);
289     }
290
291     /**
292      * Sets the name of the file containing the includes patterns.
293      *
294      * @param includesfile A string containing the filename to fetch
295      * the include patterns from.
296      */

297     public void setIncludesfile(File JavaDoc includesfile) {
298         usedMatchingTask = true;
299         super.setIncludesfile(includesfile);
300     }
301
302     /**
303      * Sets the name of the file containing the includes patterns.
304      *
305      * @param excludesfile A string containing the filename to fetch
306      * the include patterns from.
307      */

308     public void setExcludesfile(File JavaDoc excludesfile) {
309         usedMatchingTask = true;
310         super.setExcludesfile(excludesfile);
311     }
312
313     /**
314      * Sets case sensitivity of the file system
315      *
316      * @param isCaseSensitive "true"|"on"|"yes" if file system is case
317      * sensitive, "false"|"off"|"no" when not.
318      */

319     public void setCaseSensitive(boolean isCaseSensitive) {
320         usedMatchingTask = true;
321         super.setCaseSensitive(isCaseSensitive);
322     }
323
324     /**
325      * Sets whether or not symbolic links should be followed.
326      *
327      * @param followSymlinks whether or not symbolic links should be followed
328      */

329     public void setFollowSymlinks(boolean followSymlinks) {
330         usedMatchingTask = true;
331         super.setFollowSymlinks(followSymlinks);
332     }
333
334     /**
335      * add a "Select" selector entry on the selector list
336      * @param selector the selector to be added
337      */

338     public void addSelector(SelectSelector selector) {
339         usedMatchingTask = true;
340         super.addSelector(selector);
341     }
342
343     /**
344      * add an "And" selector entry on the selector list
345      * @param selector the selector to be added
346      */

347     public void addAnd(AndSelector selector) {
348         usedMatchingTask = true;
349         super.addAnd(selector);
350     }
351
352     /**
353      * add an "Or" selector entry on the selector list
354      * @param selector the selector to be added
355      */

356     public void addOr(OrSelector selector) {
357         usedMatchingTask = true;
358         super.addOr(selector);
359     }
360
361     /**
362      * add a "Not" selector entry on the selector list
363      * @param selector the selector to be added
364      */

365     public void addNot(NotSelector selector) {
366         usedMatchingTask = true;
367         super.addNot(selector);
368     }
369
370     /**
371      * add a "None" selector entry on the selector list
372      * @param selector the selector to be added
373      */

374     public void addNone(NoneSelector selector) {
375         usedMatchingTask = true;
376         super.addNone(selector);
377     }
378
379     /**
380      * add a majority selector entry on the selector list
381      * @param selector the selector to be added
382      */

383     public void addMajority(MajoritySelector selector) {
384         usedMatchingTask = true;
385         super.addMajority(selector);
386     }
387
388     /**
389      * add a selector date entry on the selector list
390      * @param selector the selector to be added
391      */

392     public void addDate(DateSelector selector) {
393         usedMatchingTask = true;
394         super.addDate(selector);
395     }
396
397     /**
398      * add a selector size entry on the selector list
399      * @param selector the selector to be added
400      */

401     public void addSize(SizeSelector selector) {
402         usedMatchingTask = true;
403         super.addSize(selector);
404     }
405
406     /**
407      * add a selector filename entry on the selector list
408      * @param selector the selector to be added
409      */

410     public void addFilename(FilenameSelector selector) {
411         usedMatchingTask = true;
412         super.addFilename(selector);
413     }
414
415     /**
416      * add an extended selector entry on the selector list
417      * @param selector the selector to be added
418      */

419     public void addCustom(ExtendSelector selector) {
420         usedMatchingTask = true;
421         super.addCustom(selector);
422     }
423
424     /**
425      * add a contains selector entry on the selector list
426      * @param selector the selector to be added
427      */

428     public void addContains(ContainsSelector selector) {
429         usedMatchingTask = true;
430         super.addContains(selector);
431     }
432
433     /**
434      * add a present selector entry on the selector list
435      * @param selector the selector to be added
436      */

437     public void addPresent(PresentSelector selector) {
438         usedMatchingTask = true;
439         super.addPresent(selector);
440     }
441
442     /**
443      * add a depth selector entry on the selector list
444      * @param selector the selector to be added
445      */

446     public void addDepth(DepthSelector selector) {
447         usedMatchingTask = true;
448         super.addDepth(selector);
449     }
450
451     /**
452      * add a depends selector entry on the selector list
453      * @param selector the selector to be added
454      */

455     public void addDepend(DependSelector selector) {
456         usedMatchingTask = true;
457         super.addDepend(selector);
458     }
459
460     /**
461      * add a regular expression selector entry on the selector list
462      * @param selector the selector to be added
463      */

464     public void addContainsRegexp(ContainsRegexpSelector selector) {
465         usedMatchingTask = true;
466         super.addContainsRegexp(selector);
467     }
468
469     /**
470      * add the modified selector
471      * @param selector the selector to add
472      * @since ant 1.6
473      */

474     public void addModified(ModifiedSelector selector) {
475         usedMatchingTask = true;
476         super.addModified(selector);
477     }
478
479     /**
480      * add an arbitrary selector
481      * @param selector the selector to be added
482      * @since Ant 1.6
483      */

484     public void add(FileSelector selector) {
485         usedMatchingTask = true;
486         super.add(selector);
487     }
488
489     /**
490      * Delete the file(s).
491      * @exception BuildException if an error occurs
492      */

493     public void execute() throws BuildException {
494         if (usedMatchingTask) {
495             log("DEPRECATED - Use of the implicit FileSet is deprecated. "
496                 + "Use a nested fileset element instead.", quiet ? Project.MSG_VERBOSE : verbosity);
497         }
498
499         if (file == null && dir == null && filesets.size() == 0 && rcs == null) {
500             throw new BuildException("At least one of the file or dir "
501                                      + "attributes, or a nested resource collection, "
502                                      + "must be set.");
503         }
504
505         if (quiet && failonerror) {
506             throw new BuildException("quiet and failonerror cannot both be "
507                                      + "set to true", getLocation());
508         }
509
510         // delete the single file
511
if (file != null) {
512             if (file.exists()) {
513                 if (file.isDirectory()) {
514                     log("Directory " + file.getAbsolutePath()
515                         + " cannot be removed using the file attribute. "
516                         + "Use dir instead.", quiet ? Project.MSG_VERBOSE : verbosity);
517                 } else {
518                     log("Deleting: " + file.getAbsolutePath());
519
520                     if (!delete(file)) {
521                         handle("Unable to delete file " + file.getAbsolutePath());
522                     }
523                 }
524             } else {
525                 log("Could not find file " + file.getAbsolutePath()
526                     + " to delete.", quiet ? Project.MSG_VERBOSE : verbosity);
527             }
528         }
529
530         // delete the directory
531
if (dir != null && dir.exists() && dir.isDirectory()
532             && !usedMatchingTask) {
533             /*
534                If verbosity is MSG_VERBOSE, that mean we are doing
535                regular logging (backwards as that sounds). In that
536                case, we want to print one message about deleting the
537                top of the directory tree. Otherwise, the removeDir
538                method will handle messages for _all_ directories.
539              */

540             if (verbosity == Project.MSG_VERBOSE) {
541                 log("Deleting directory " + dir.getAbsolutePath());
542             }
543             removeDir(dir);
544         }
545         Resources resourcesToDelete = new Resources();
546         resourcesToDelete.setProject(getProject());
547         Resources filesetDirs = new Resources();
548         filesetDirs.setProject(getProject());
549         FileSet implicit = null;
550         if (usedMatchingTask && dir != null && dir.isDirectory()) {
551             //add the files from the default fileset:
552
implicit = getImplicitFileSet();
553             implicit.setProject(getProject());
554             filesets.add(implicit);
555         }
556
557         for (int i = 0, size = filesets.size(); i < size; i++) {
558             FileSet fs = (FileSet) filesets.get(i);
559             if (fs.getProject() == null) {
560                 log("Deleting fileset with no project specified;"
561                     + " assuming executing project", Project.MSG_VERBOSE);
562                 fs = (FileSet) fs.clone();
563                 fs.setProject(getProject());
564             }
565             if (!fs.getDir().isDirectory()) {
566                 handle("Directory does not exist:" + fs.getDir());
567             } else {
568                 resourcesToDelete.add(fs);
569                 if (includeEmpty) {
570                     filesetDirs.add(new ReverseDirs(fs.getDir(), fs
571                             .getDirectoryScanner().getIncludedDirectories()));
572                 }
573             }
574         }
575         resourcesToDelete.add(filesetDirs);
576         if (rcs != null) {
577             // sort first to files, then dirs
578
Restrict exists = new Restrict();
579             exists.add(EXISTS);
580             exists.add(rcs);
581             Sort s = new Sort();
582             s.add(REVERSE_FILESYSTEM);
583             s.add(exists);
584             resourcesToDelete.add(s);
585         }
586         try {
587             if (resourcesToDelete.isFilesystemOnly()) {
588                 for (Iterator JavaDoc iter = resourcesToDelete.iterator(); iter.hasNext();) {
589                     FileResource r = (FileResource) iter.next();
590                     // nonexistent resources could only occur if we already
591
// deleted something from a fileset:
592
if (!r.isExists()) {
593                         continue;
594                     }
595                     if (!(r.isDirectory()) || r.getFile().list().length == 0) {
596                         log("Deleting " + r, verbosity);
597                         if (!delete(r.getFile()) && failonerror) {
598                             handle("Unable to delete "
599                                 + (r.isDirectory() ? "directory " : "file ") + r);
600                         }
601                     }
602                 }
603             } else {
604                  handle(getTaskName() + " handles only filesystem resources");
605             }
606         } catch (Exception JavaDoc e) {
607             handle(e);
608         } finally {
609             if (implicit != null) {
610                 filesets.remove(implicit);
611             }
612         }
613     }
614
615 //************************************************************************
616
// protected and private methods
617
//************************************************************************
618

619     private void handle(String JavaDoc msg) {
620         handle(new BuildException(msg));
621     }
622
623     private void handle(Exception JavaDoc e) {
624         if (failonerror) {
625             throw (e instanceof BuildException)
626                 ? (BuildException) e : new BuildException(e);
627         }
628         log(e, quiet ? Project.MSG_VERBOSE : verbosity);
629     }
630
631     /**
632      * Accommodate Windows bug encountered in both Sun and IBM JDKs.
633      * Others possible. If the delete does not work, call System.gc(),
634      * wait a little and try again.
635      */

636     private boolean delete(File JavaDoc f) {
637         if (!f.delete()) {
638             if (Os.isFamily("windows")) {
639                 System.gc();
640             }
641             try {
642                 Thread.sleep(DELETE_RETRY_SLEEP_MILLIS);
643             } catch (InterruptedException JavaDoc ex) {
644                 // Ignore Exception
645
}
646             if (!f.delete()) {
647                 if (deleteOnExit) {
648                     int level = quiet ? Project.MSG_VERBOSE : Project.MSG_INFO;
649                     log("Failed to delete " + f + ", calling deleteOnExit."
650                         + " This attempts to delete the file when the Ant jvm"
651                         + " has exited and might not succeed.", level);
652                     f.deleteOnExit();
653                     return true;
654                 }
655                 return false;
656             }
657         }
658         return true;
659     }
660
661     /**
662      * Delete a directory
663      *
664      * @param d the directory to delete
665      */

666     protected void removeDir(File JavaDoc d) {
667         String JavaDoc[] list = d.list();
668         if (list == null) {
669             list = new String JavaDoc[0];
670         }
671         for (int i = 0; i < list.length; i++) {
672             String JavaDoc s = list[i];
673             File JavaDoc f = new File JavaDoc(d, s);
674             if (f.isDirectory()) {
675                 removeDir(f);
676             } else {
677                 log("Deleting " + f.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
678                 if (!delete(f)) {
679                     handle("Unable to delete file " + f.getAbsolutePath());
680                 }
681             }
682         }
683         log("Deleting directory " + d.getAbsolutePath(), verbosity);
684         if (!delete(d)) {
685             handle("Unable to delete directory " + dir.getAbsolutePath());
686         }
687     }
688
689     /**
690      * remove an array of files in a directory, and a list of subdirectories
691      * which will only be deleted if 'includeEmpty' is true
692      * @param d directory to work from
693      * @param files array of files to delete; can be of zero length
694      * @param dirs array of directories to delete; can of zero length
695      */

696     protected void removeFiles(File JavaDoc d, String JavaDoc[] files, String JavaDoc[] dirs) {
697         if (files.length > 0) {
698             log("Deleting " + files.length + " files from "
699                 + d.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
700             for (int j = 0; j < files.length; j++) {
701                 File JavaDoc f = new File JavaDoc(d, files[j]);
702                 log("Deleting " + f.getAbsolutePath(),
703                         quiet ? Project.MSG_VERBOSE : verbosity);
704                 if (!delete(f)) {
705                     handle("Unable to delete file " + f.getAbsolutePath());
706                 }
707             }
708         }
709
710         if (dirs.length > 0 && includeEmpty) {
711             int dirCount = 0;
712             for (int j = dirs.length - 1; j >= 0; j--) {
713                 File JavaDoc currDir = new File JavaDoc(d, dirs[j]);
714                 String JavaDoc[] dirFiles = currDir.list();
715                 if (dirFiles == null || dirFiles.length == 0) {
716                     log("Deleting " + currDir.getAbsolutePath(),
717                             quiet ? Project.MSG_VERBOSE : verbosity);
718                     if (!delete(currDir)) {
719                         handle("Unable to delete directory "
720                                 + currDir.getAbsolutePath());
721                     } else {
722                         dirCount++;
723                     }
724                 }
725             }
726
727             if (dirCount > 0) {
728                 log("Deleted "
729                      + dirCount
730                      + " director" + (dirCount == 1 ? "y" : "ies")
731                      + " form " + d.getAbsolutePath(),
732                      quiet ? Project.MSG_VERBOSE : verbosity);
733             }
734         }
735     }
736 }
737
Popular Tags