123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- <?php
- /**
- * PhpPatcher class
- * @author legolas558
- * @version 1.0
- *
- * improved, code cleanup and PHP5 done by jumpin.banana@gmail.com 2012
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
- *
- * You should have received a copy of the
- * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
- * along with this program. If not, see http://www.sun.com/cddl/cddl.html
- *
- *
- * Facility to merge unified diff files
- * First use Merge() and then ApplyPatch() to commit changes
- * files will be created, updated and/or deleted
- *
- */
- define('_PHPP_INVALID_INPUT', 'Invalid input');
- define('_PHPP_UNEXPECTED_EOF', 'Unexpected end of file');
- define('_PHPP_UNEXPECTED_ADD_LINE', 'Unexpected add line at line %d');
- define('_PHPP_UNEXPECTED_REMOVE_LINE', 'Unexpected remove line at line %d');
- define('_PHPP_INVALID_DIFF', 'Invalid unified diff block');
- define('_PHPP_FAILED_VERIFY', 'Failed source verification of file %s at line %d');
- class PhpPatcher {
-
- var $root;
- var $msg;
- var $sources = array();
- var $destinations = array();
- var $removals = array();
- var $newline = "\n";
-
- public function __construct($root_path) {
- // if you specify a root path all paths will be intended as relative to it (and not written, too)
- $this->root = $root_path;
- }
-
- public function Merge($udiff) {
- $lines = $this->_linesplit($udiff);
- if (!isset($lines)) {
- $this->msg = _PHPP_INVALID_INPUT;
- return false;
- }
- unset($udiff);
-
- $line = current($lines);
- do {
- if (strlen($line)<5) {
- continue;
- }
- // start recognition when a new diff block is found
- if (substr($line, 0, 4)!='--- ') {
- continue;
- }
- $p = strpos($line, "\t", 4);
- if ($p===false) $p = strlen($line);
- $src = $this->root.substr($line, 4, $p-4);
- $line = next($lines);
- if (!isset($line)) {
- $this->msg = _PHPP_UNEXPECTED_EOF;
- return false;
- }
- if (substr($line, 0, 4)!='+++ ') {
- $this->msg = _PHPP_INVALID_DIFF;
- return false;
- }
- $p = strpos($line, "\t", 4);
- if ($p===false) $p = strlen($line);
- $dst = $this->root.substr($line, 4, $p-4);
-
- $line = next($lines);
- if (!isset($line)) {
- $this->msg = _PHPP_UNEXPECTED_EOF;
- return false;
- }
-
- $done=0;
- while (preg_match('/@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@($)/A', $line, $m)) {
-
- if ($m[3]==='')
- $src_size = 1;
- else $src_size = (int)$m[3];
- if ($m[6]==='')
- $dst_size = 1;
- else $dst_size = (int)$m[6];
- if (!$this->_apply_diff($lines, $src, $dst,
- (int)$m[1], $src_size, (int)$m[4],
- $dst_size))
- return false;
- $done++;
- $line = next($lines);
- if ($line === FALSE)
- break 2;
- }
- if ($done==0) {
- $this->msg = _PHPP_INVALID_DIFF;
- return false;
- }
-
- } while (FALSE !== ($line = next($lines)));
-
- //NOTE: previously opened files are still cached
- return true;
- }
-
- function ClearCache() {
- $this->sources = array();
- $this->destinations = array();
- $this->removals = array();
- }
-
- function ApplyPatch() {
- if (empty($this->destinations))
- return 0;
- $done = 0;
- $files = array_keys($this->destinations);
- foreach($files as $file) {
- $f = @fopen($file, 'w');
- if ($f===null)
- continue;
- fwrite($f, implode($this->newline, $this->destinations[$file]));
- fclose($f);
- $done++;
- }
- foreach($this->removals as $file) {
- if (@unlink($file))
- $done++;
- if (isset($this->sources[$file]))
- unset($this->sources[$file]);
- }
- $this->destinations = array(); // clear the destinations cache
- $this->removals = array();
- return $done;
- }
-
- private function &_get_source($src) {
- if (isset($this->sources[$src]))
- return $this->sources[$src];
- if (!is_readable($src)) {
- return null;
- }
- $_data = file_get_contents($src);
- $this->sources[$src] = $this->_linesplit($_data);
- return $this->sources[$src];
- }
-
- private function &_get_destin($dst, $src) {
- if (isset($this->destinations[$dst]))
- return $this->destinations[$dst];
- $this->destinations[$dst] = $this->_get_source($src);
- return $this->destinations[$dst];
- }
- // separate CR or CRLF lines
- private function &_linesplit(&$data) {
- $lines = preg_split('/(\r\n)|(\r)|(\n)/', $data);
- return $lines;
- }
-
- private function _apply_diff(&$lines, $src, $dst, $src_line, $src_size, $dst_line, $dst_size) {
- $src_line--;
- $dst_line--;
- $line = next($lines);
- if ($line === false) {
- $this->msg = _PHPP_UNEXPECTED_EOF;
- return false;
- }
- $source = array(); // source lines (old file)
- $destin = array(); // new lines (new file)
- $src_left = $src_size;
- $dst_left = $dst_size;
- do {
- if (!isset($line{0})) {
- $source[] = '';
- $destin[] = '';
- $src_left--;
- $dst_left--;
- continue;
- }
- if ($line{0}=='-') {
- if ($src_left==0) {
- $this->msg = sprintf(_PHPP_UNEXPECTED_REMOVE_LINE, key($lines));
- return false;
- }
- $source[] = substr($line, 1);
- $src_left--;
- } else if ($line{0}=='+') {
- if ($dst_left==0) {
- $this->msg = sprintf(_PHPP_UNEXPECTED_ADD_LINE, key($lines));
- return false;
- }
- $destin[] = substr($line, 1);
- $dst_left--;
- } else {
- if (!isset($line{1}))
- $line = '';
- else if ($line{0}=='\\') {
- if ($line=='\\ No newline at end of file') {
- continue;
- }
- } else {
- $line = substr($line, 1);
- }
- $source[] = $line;
- $destin[] = $line;
- $src_left--;
- $dst_left--;
- }
-
- if (($src_left==0) && ($dst_left==0)) {
- // now apply the patch, finally!
- if ($src_size>0) {
- $src_lines =& $this->_get_source($src);
- if (!isset($src_lines)) {
- return false;
- }
- }
- if ($dst_size>0) {
- if ($src_size>0) {
- $dst_lines =& $this->_get_destin($dst, $src);
- if (!isset($dst_lines))
- return false;
- $src_bottom=$src_line+count($source);
- $dst_bottom=$dst_line+count($destin);
-
- for ($l=$src_line;$l<$src_bottom;$l++) {
- if ($src_lines[$l]!=$source[$l-$src_line]) {
- $this->msg = sprintf(_PHPP_FAILED_VERIFY, $src, $l);
- return false;
- }
- }
- array_splice($dst_lines, $dst_line, count($source), $destin);
- } else
- $this->destinations[$dst] = $destin;
- } else
- $this->removals[] = $src;
-
- return true;
- }
- } while (FALSE !== ($line = next($lines)));
- $this->msg = _PHPP_UNEXPECTED_EOF;
- return false;
- }
- }
- ?>
|