* @version 0.01 * @package phing.tasks.ext */ require_once 'phing/Task.php'; /** * Patches a file by applying a 'diff' file to it * * Requires "patch" to be on the execution path. * * @package phing.tasks.ext */ class PatchTask extends Task { /** * Base command to be executed * @var string */ const CMD = 'patch --batch '; /** * File to be patched * @var string */ private $originalFile; /** * Patch file * * @var string */ private $patchFile; /** * Value for a "-p" option * @var int */ private $strip; /** * Command line arguments for patch binary * @var array */ private $cmdArgs = array(); /** * Halt on error return value from patch invocation. * @var bool */ private $haltOnFailure = false; /** * The file containing the diff output * * Required. * * @param string $file File containing the diff output * @return void * @throws BuildException if $file not exists */ public function setPatchFile($file) { if (!is_file($file)) throw new BuildException(sprintf('Patchfile %s doesn\'t exist', $file)); $this->patchFile = $file; } /** * The file to patch * * Optional if it can be inferred from the diff file. * * @param string $file File to patch * @return void */ public function setOriginalFile($file) { $this->originalFile = $file; } /** * The name of a file to send the output to, instead of patching * the file(s) in place * * Optional. * * @param string $file File to send the output to * @return void */ public function setDestFile($file) { if ($file !== null) $this->cmdArgs []= "--output=$file"; } /** * Flag to create backups * * Optional, default - false * * @param bool $backups If true create backups * @return void */ public function setBackups($backups) { if ($backups) $this->cmdArgs []= '--backup'; } /** * Flag to ignore whitespace differences; * * Default - false * * @param bool $ignore If true ignore whitespace differences * @return void */ public function setIgnoreWhiteSpace($ignore) { if ($ignore) $this->cmdArgs []= '--ignore-whitespace'; } /** * Strip the smallest prefix containing num leading slashes * from filenames. * * patch's --strip option. * * @param int $num number of lines to strip * @return void * @throws BuildException if num is < 0, or other errors */ public function setStrip($num) { if ($num < 0) throw new BuildException('strip has to be >= 0'); $this->strip = $num; } /** * Work silently unless an error occurs * * Optional, default - false * @param bool $flag If true suppress set the -s option on the patch command * @return void */ public function setQuiet($flag) { if ($flag) $this->cmdArgs []= '--silent'; } /** * Assume patch was created with old and new files swapped * * Optional, default - false * * @param bool $flag If true set the -R option on the patch command * @return void */ public function setReverse($flag) { if ($flag) $this->cmdArgs []= '--reverse'; } /** * The directory to run the patch command in * * Defaults to the project's base directory. * * @param string $directory Directory to run the patch command in * @return void */ public function setDir($directory) { $this->cmdArgs []= "--directory=$directory"; } /** * Ignore patches that seem to be reversed or already applied * * @param bool $flag If true set the -N (--forward) option * @return void */ public function setForward($flag) { if ($flag) $this->cmdArgs []= "--forward"; } /** * Set the maximum fuzz factor * * Defaults to 0 * * @param string $value Value of a fuzz factor * @return void */ public function setFuzz($value) { $this->cmdArgs []= "--fuzz=$value"; } /** * If true, stop the build process if the patch command * exits with an error status. * * The default is "false" * * @param bool $value "true" if it should halt, otherwise "false" * @return void */ public function setHaltOnFailure($value) { $this->haltOnFailure = $value; } /** * Main task method * * @return void * @throws BuildException when it all goes a bit pear shaped */ public function main() { if ($this->patchFile == null) throw new BuildException('patchfile argument is required'); // Define patch file $this->cmdArgs []= '-i ' . $this->patchFile; // Define strip factor if ($this->strip != null) $this->cmdArgs []= '--strip=' . $this->strip; // Define original file if specified if ($this->originalFile != null) $this->cmdArgs []= $this->originalFile; $cmd = self::CMD . implode(' ', $this->cmdArgs); $this->log('Applying patch: ' . $this->patchFile); exec($cmd, $output, $exitCode); foreach ($output as $line) $this->log($line, Project::MSG_VERBOSE); if ($exitCode != 0 && $this->haltOnFailure) throw new BuildException( "Task exited with code $exitCode" ); } }