<?php
namespace PhpBrew\PatchKit;
use CLIFramework\Logger;
use PhpBrew\Buildable;
* RegExpPatchRule implements a pcre_replace based patch rule.
*/
class RegExpPatchRule implements PatchRule
{
private $files;
* @var string the regexp pattern
*/
private $pattern;
* @var string the replacement
*/
private $replacement;
* @param string $files
*/
public function __construct(array $files)
{
$this->files = $files;
}
* This method build up the predicator.
*/
public function allOf(array $patterns)
{
$this->predicator = function ($line) use ($patterns) {
foreach ($patterns as $pattern) {
if (!preg_match($pattern, $line)) {
return false;
}
}
return true;
};
return $this;
}
public function anyOf(array $patterns)
{
if (count($patterns) === 0) {
$this->predicator = true;
}
$this->predicator = function ($line) use ($patterns) {
foreach ($patterns as $pattern) {
if (preg_match($pattern, $line)) {
return true;
}
}
return false;
};
return $this;
}
public function always()
{
$this->predicator = true;
return $this;
}
public function replaces($pattern, $replacement)
{
$this->pattern = $pattern;
$this->replacement = $replacement;
return $this;
}
public static function files($files)
{
return new self((array) $files);
}
protected function applyLines(array $lines, &$patched)
{
$size = count($lines);
for ($i = 0; $i < $size; ++$i) {
if ($this->predicator === true || call_user_func($this->predicator, $lines[$i])) {
$lines[$i] = preg_replace($this->pattern, $this->replacement, $lines[$i], -1, $count);
$patched += $count;
}
}
return implode(PHP_EOL, $lines);
}
* This method can only be used for text format files.
*
* @param string $content the target of the text content.
*/
protected function applyTextContent($content, &$patched)
{
return $this->applyLines(preg_split("/(?:\r\n|\n|\r)/", $content), $patched);
}
public function backup(Buildable $build, Logger $logger)
{
foreach ($this->files as $file) {
$path = $build->getSourceDirectory() . DIRECTORY_SEPARATOR . $file;
if (!file_exists($path)) {
$logger->error("file $path doesn't exist in the build directory.");
continue;
}
$this->backupFile($path);
}
}
protected function backupFile($path)
{
$bakPath = $path . '.' . time() . '.bak';
copy($path, $bakPath);
}
public function apply(Buildable $build, Logger $logger)
{
$patched = 0;
foreach ($this->files as $file) {
$path = $build->getSourceDirectory() . DIRECTORY_SEPARATOR . $file;
if (!file_exists($path)) {
$logger->error("file $path doesn't exist in the build directory.");
continue;
}
if ($content = file_get_contents($path)) {
$content = $this->applyTextContent($content, $patched);
if (false === file_put_contents($path, $content)) {
$logger->error("Patch on $path write failed.");
}
}
}
return $patched;
}
}