DeleteTask.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /*
  3. * $Id: DeleteTask.php 905 2010-10-05 16:28:03Z mrook $
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information please see
  19. * <http://phing.info>.
  20. */
  21. require_once 'phing/Task.php';
  22. /**
  23. * Deletes a file or directory, or set of files defined by a fileset.
  24. *
  25. * @version $Revision: 905 $
  26. * @package phing.tasks.system
  27. */
  28. class DeleteTask extends Task {
  29. protected $file;
  30. protected $dir;
  31. protected $filesets = array();
  32. protected $includeEmpty = false;
  33. protected $quiet = false;
  34. protected $failonerror = true;
  35. protected $verbosity = Project::MSG_VERBOSE;
  36. /** Any filelists of files that should be deleted. */
  37. private $filelists = array();
  38. /**
  39. * Set the name of a single file to be removed.
  40. * @param PhingFile $file
  41. */
  42. function setFile(PhingFile $file) {
  43. $this->file = $file;
  44. }
  45. /**
  46. * Set the directory from which files are to be deleted.
  47. * @param PhingFile $dir
  48. */
  49. function setDir(PhingFile $dir) {
  50. $this->dir = $dir;
  51. }
  52. /**
  53. * Used to force listing of all names of deleted files.
  54. * @param boolean $verbosity
  55. */
  56. function setVerbose($verbosity) {
  57. if ($verbosity) {
  58. $this->verbosity = Project::MSG_INFO;
  59. } else {
  60. $this->verbosity = Project::MSG_VERBOSE;
  61. }
  62. }
  63. /**
  64. * If the file does not exist, do not display a diagnostic
  65. * message or modify the exit status to reflect an error.
  66. * This means that if a file or directory cannot be deleted,
  67. * then no error is reported. This setting emulates the
  68. * -f option to the Unix rm command. Default is false
  69. * meaning things are verbose
  70. */
  71. function setQuiet($bool) {
  72. $this->quiet = $bool;
  73. if ($this->quiet) {
  74. $this->failonerror = false;
  75. }
  76. }
  77. /** this flag means 'note errors to the output, but keep going' */
  78. function setFailOnError($bool) {
  79. $this->failonerror = $bool;
  80. }
  81. /** Used to delete empty directories.*/
  82. function setIncludeEmptyDirs($includeEmpty) {
  83. $this->includeEmpty = (boolean) $includeEmpty;
  84. }
  85. /** Nested creator, adds a set of files (nested fileset attribute). */
  86. function createFileSet() {
  87. $num = array_push($this->filesets, new FileSet());
  88. return $this->filesets[$num-1];
  89. }
  90. /** Nested creator, adds a set of files (nested fileset attribute). */
  91. function createFileList() {
  92. $num = array_push($this->filelists, new FileList());
  93. return $this->filelists[$num-1];
  94. }
  95. /** Delete the file(s). */
  96. function main() {
  97. if ($this->file === null && $this->dir === null && count($this->filesets) === 0 && count($this->filelists) === 0) {
  98. throw new BuildException("At least one of the file or dir attributes, or a fileset element, or a filelist element must be set.");
  99. }
  100. if ($this->quiet && $this->failonerror) {
  101. throw new BuildException("quiet and failonerror cannot both be set to true", $this->location);
  102. }
  103. // delete a single file
  104. if ($this->file !== null) {
  105. if ($this->file->exists()) {
  106. if ($this->file->isDirectory()) {
  107. $this->log("Directory " . $this->file->__toString() . " cannot be removed using the file attribute. Use dir instead.");
  108. } else {
  109. $this->log("Deleting: " . $this->file->__toString());
  110. try {
  111. $this->file->delete();
  112. } catch(Exception $e) {
  113. $message = "Unable to delete file " . $this->file->__toString() .": " .$e->getMessage();
  114. if($this->failonerror) {
  115. throw new BuildException($message);
  116. } else {
  117. $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  118. }
  119. }
  120. }
  121. } else {
  122. $this->log("Could not find file " . $this->file->getAbsolutePath() . " to delete.",Project::MSG_VERBOSE);
  123. }
  124. }
  125. // delete the directory
  126. if ($this->dir !== null && $this->dir->exists() && $this->dir->isDirectory()) {
  127. if ($this->verbosity === Project::MSG_VERBOSE) {
  128. $this->log("Deleting directory " . $this->dir->__toString());
  129. }
  130. $this->removeDir($this->dir);
  131. }
  132. // delete the files in the filelists
  133. foreach($this->filelists as $fl) {
  134. try {
  135. $files = $fl->getFiles($this->project);
  136. $this->removeFiles($fl->getDir($this->project), $files, $empty=array());
  137. } catch (BuildException $be) {
  138. // directory doesn't exist or is not readable
  139. if ($this->failonerror) {
  140. throw $be;
  141. } else {
  142. $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  143. }
  144. }
  145. }
  146. // delete the files in the filesets
  147. foreach($this->filesets as $fs) {
  148. try {
  149. $ds = $fs->getDirectoryScanner($this->project);
  150. $files = $ds->getIncludedFiles();
  151. $dirs = $ds->getIncludedDirectories();
  152. $this->removeFiles($fs->getDir($this->project), $files, $dirs);
  153. } catch (BuildException $be) {
  154. // directory doesn't exist or is not readable
  155. if ($this->failonerror) {
  156. throw $be;
  157. } else {
  158. $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  159. }
  160. }
  161. }
  162. }
  163. /**
  164. * Recursively removes a directory.
  165. * @param PhingFile $d The directory to remove.
  166. */
  167. private function removeDir($d) {
  168. $list = $d->listDir();
  169. if ($list === null) {
  170. $list = array();
  171. }
  172. foreach($list as $s) {
  173. $f = new PhingFile($d, $s);
  174. if ($f->isDirectory()) {
  175. $this->removeDir($f);
  176. } else {
  177. $this->log("Deleting " . $f->__toString(), $this->verbosity);
  178. try {
  179. $f->delete();
  180. } catch (Exception $e) {
  181. $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage();
  182. if($this->failonerror) {
  183. throw new BuildException($message);
  184. } else {
  185. $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  186. }
  187. }
  188. }
  189. }
  190. $this->log("Deleting directory " . $d->getAbsolutePath(), $this->verbosity);
  191. try {
  192. $d->delete();
  193. } catch (Exception $e) {
  194. $message = "Unable to delete directory " . $d->__toString() . ": " . $e->getMessage();
  195. if($this->failonerror) {
  196. throw new BuildException($message);
  197. } else {
  198. $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  199. }
  200. }
  201. }
  202. /**
  203. * remove an array of files in a directory, and a list of subdirectories
  204. * which will only be deleted if 'includeEmpty' is true
  205. * @param PhingFile $d directory to work from
  206. * @param array &$files array of files to delete; can be of zero length
  207. * @param array &$dirs array of directories to delete; can of zero length
  208. */
  209. private function removeFiles(PhingFile $d, &$files, &$dirs) {
  210. if (count($files) > 0) {
  211. $this->log("Deleting " . count($files) . " files from " . $d->__toString());
  212. for ($j=0,$_j=count($files); $j < $_j; $j++) {
  213. $f = new PhingFile($d, $files[$j]);
  214. $this->log("Deleting " . $f->getAbsolutePath(), $this->verbosity);
  215. try {
  216. $f->delete();
  217. } catch (Exception $e) {
  218. $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage();
  219. if($this->failonerror) {
  220. throw new BuildException($message);
  221. } else {
  222. $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  223. }
  224. }
  225. }
  226. }
  227. if (count($dirs) > 0 && $this->includeEmpty) {
  228. $dirCount = 0;
  229. for ($j=count($dirs)-1; $j>=0; --$j) {
  230. $dir = new PhingFile($d, $dirs[$j]);
  231. $dirFiles = $dir->listDir();
  232. if ($dirFiles === null || count($dirFiles) === 0) {
  233. $this->log("Deleting " . $dir->__toString(), $this->verbosity);
  234. try {
  235. $dir->delete();
  236. $dirCount++;
  237. } catch (Exception $e) {
  238. $message="Unable to delete directory " . $dir->__toString();
  239. if($this->failonerror) {
  240. throw new BuildException($message);
  241. } else {
  242. $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
  243. }
  244. }
  245. }
  246. }
  247. if ($dirCount > 0) {
  248. $this->log("Deleted $dirCount director" . ($dirCount==1 ? "y" : "ies") . " from " . $d->__toString());
  249. }
  250. }
  251. }
  252. }