AppendTask.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. /*
  3. * $Id: AppendTask.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. include_once 'phing/types/FileList.php';
  23. include_once 'phing/types/FileSet.php';
  24. /**
  25. * Appends text, contents of a file or set of files defined by a filelist to a destination file.
  26. *
  27. * <code>
  28. * <append text="And another thing\n" destfile="badthings.log"/>
  29. * </code>
  30. * OR
  31. * <code>
  32. * <append file="header.html" destfile="fullpage.html"/>
  33. * <append file="body.html" destfile="fullpage.html"/>
  34. * <append file="footer.html" destfile="fullpage.html"/>
  35. * </code>
  36. * OR
  37. * <code>
  38. * <append destfile="${process.outputfile}">
  39. * <filterchain>
  40. * <xsltfilter style="${process.stylesheet}">
  41. * <param name="mode" expression="${process.xslt.mode}"/>
  42. * <param name="file_name" expression="%{task.append.current_file.basename}"/> <!-- Example of using a RegisterSlot variable -->
  43. * </xsltfilter>
  44. * </filterchain>
  45. * <filelist dir="book/" listfile="book/PhingGuide.book"/>
  46. * </append>
  47. * </code>
  48. * @package phing.tasks.system
  49. * @version $Revision: 905 $
  50. */
  51. class AppendTask extends Task {
  52. /** Append stuff to this file. */
  53. private $to;
  54. /** Explicit file to append. */
  55. private $file;
  56. /** Any filesets of files that should be appended. */
  57. private $filesets = array();
  58. /** Any filelists of files that should be appended. */
  59. private $filelists = array();
  60. /** Any filters to be applied before append happens. */
  61. private $filterChains = array();
  62. /** Text to append. (cannot be used in conjunction w/ files or filesets) */
  63. private $text;
  64. /** Sets specific file to append. */
  65. function setFile(PhingFile $f) {
  66. $this->file = $f;
  67. }
  68. /**
  69. * Set target file to append to.
  70. * @deprecated Will be removed with final release.
  71. */
  72. function setTo(PhingFile $f) {
  73. $this->log("The 'to' attribute is deprecated in favor of 'destFile'; please update your code.", Project::MSG_WARN);
  74. $this->to = $f;
  75. }
  76. /**
  77. * The more conventional naming for method to set destination file.
  78. * @param PhingFile $f
  79. */
  80. function setDestFile(PhingFile $f) {
  81. $this->to = $f;
  82. }
  83. /**
  84. * Supports embedded <filelist> element.
  85. * @return FileList
  86. */
  87. function createFileList() {
  88. $num = array_push($this->filelists, new FileList());
  89. return $this->filelists[$num-1];
  90. }
  91. /**
  92. * Nested creator, adds a set of files (nested <fileset> attribute).
  93. * This is for when you don't care what order files get appended.
  94. * @return FileSet
  95. */
  96. function createFileSet() {
  97. $num = array_push($this->filesets, new FileSet());
  98. return $this->filesets[$num-1];
  99. }
  100. /**
  101. * Creates a filterchain
  102. *
  103. * @return FilterChain The created filterchain object
  104. */
  105. function createFilterChain() {
  106. $num = array_push($this->filterChains, new FilterChain($this->project));
  107. return $this->filterChains[$num-1];
  108. }
  109. /**
  110. * Sets text to append. (cannot be used in conjunction w/ files or filesets).
  111. * @param string $txt
  112. */
  113. function setText($txt) {
  114. $this->text = (string) $txt;
  115. }
  116. /**
  117. * Sets text to append. Supports CDATA.
  118. * @param string $txt
  119. */
  120. function addText($txt) {
  121. $this->text = (string) $txt;
  122. }
  123. /** Append the file(s). */
  124. function main() {
  125. if ($this->to === null) {
  126. throw new BuildException("You must specify the 'destFile' attribute");
  127. }
  128. if ($this->file === null && empty($this->filelists) && empty($this->filesets) && $this->text === null) {
  129. throw new BuildException("You must specify a file, use a filelist, or specify a text value.");
  130. }
  131. if ($this->text !== null && ($this->file !== null || !empty($this->filelists))) {
  132. throw new BuildException("Cannot use text attribute in conjunction with file or filelists.");
  133. }
  134. // create a filwriter to append to "to" file.
  135. $writer = new FileWriter($this->to, $append=true);
  136. if ($this->text !== null) {
  137. // simply append the text
  138. $this->log("Appending string to " . $this->to->getPath());
  139. // for debugging primarily, maybe comment
  140. // out for better performance(?)
  141. $lines = explode("\n", $this->text);
  142. foreach($lines as $line) {
  143. $this->log($line, Project::MSG_VERBOSE);
  144. }
  145. $writer->write($this->text);
  146. } else {
  147. // append explicitly-specified file
  148. if ($this->file !== null) {
  149. try {
  150. $this->appendFile($writer, $this->file);
  151. } catch (Exception $ioe) {
  152. $this->log("Unable to append contents of file " . $this->file->getAbsolutePath() . ": " . $ioe->getMessage(), Project::MSG_WARN);
  153. }
  154. }
  155. // append the files in the filelists
  156. foreach($this->filelists as $fl) {
  157. try {
  158. $files = $fl->getFiles($this->project);
  159. $this->appendFiles($writer, $files, $fl->getDir($this->project));
  160. } catch (BuildException $be) {
  161. $this->log($be->getMessage(), Project::MSG_WARN);
  162. }
  163. }
  164. // append any files in filesets
  165. foreach($this->filesets as $fs) {
  166. try {
  167. $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
  168. $this->appendFiles($writer, $files, $fs->getDir($this->project));
  169. } catch (BuildException $be) {
  170. $this->log($be->getMessage(), Project::MSG_WARN);
  171. }
  172. }
  173. } // if ($text ) {} else {}
  174. $writer->close();
  175. }
  176. /**
  177. * Append an array of files in a directory.
  178. * @param FileWriter $writer The FileWriter that is appending to target file.
  179. * @param array $files array of files to delete; can be of zero length
  180. * @param PhingFile $dir directory to work from
  181. */
  182. private function appendFiles(FileWriter $writer, $files, PhingFile $dir) {
  183. if (!empty($files)) {
  184. $this->log("Attempting to append " . count($files) . " files" .($dir !== null ? ", using basedir " . $dir->getPath(): ""));
  185. $basenameSlot = Register::getSlot("task.append.current_file");
  186. $pathSlot = Register::getSlot("task.append.current_file.path");
  187. foreach($files as $filename) {
  188. try {
  189. $f = new PhingFile($dir, $filename);
  190. $basenameSlot->setValue($filename);
  191. $pathSlot->setValue($f->getPath());
  192. $this->appendFile($writer, $f);
  193. } catch (Exception $ioe) {
  194. $this->log("Unable to append contents of file " . $f->getAbsolutePath() . ": " . $ioe->getMessage(), Project::MSG_WARN);
  195. }
  196. }
  197. } // if !empty
  198. }
  199. private function appendFile(FileWriter $writer, PhingFile $f) {
  200. $in = FileUtils::getChainedReader(new FileReader($f), $this->filterChains, $this->project);
  201. while(-1 !== ($buffer = $in->read())) { // -1 indicates EOF
  202. $writer->write($buffer);
  203. }
  204. $this->log("Appending contents of " . $f->getPath() . " to " . $this->to->getPath());
  205. }
  206. }