Skip to content

Commit 2687a40

Browse files
author
Shinya Yamaoka
committed
Replace patches using sed and perl with pure php.
* Define PHPBREW_EXPECTED_PHP_DIR and PHPBREW_FIXTURES_PHP_DIR in phpunit.xml. * Add a common interface of patch utility classes. * Add a new class RegexpPatch which replaces a content of files using regexp. * Introduce PatchCollection class and it holds patch definitions now. * Add tests for Apxs2PatchTask, Patch64BitSupportTask, RegexpPatch, PatchCollection, and RegexpPatchRule. * Add an utility class which provides a way to create temprary files in tests.
1 parent 6e42441 commit 2687a40

22 files changed

+866
-48
lines changed

CONTRIBUTORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ Sort alphabatically:
2424
* rado-h
2525
* shelling
2626
* ujihisa
27+
* Shinya Yamaoka

phpunit.xml

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
<env name="PHPBREW_ROOT" value=".phpbrew"/>
1010
<env name="PHPBREW_HOME" value=".phpbrew"/>
1111
<env name="PHPBREW_EXTENSION_DIR" value="tests/fixtures/ext"/>
12+
<env name="PHPBREW_FIXTURES_PHP_DIR" value="tests/fixtures/php"/>
13+
<env name="PHPBREW_EXPECTED_PHP_DIR" value="tests/expected/php"/>
1214
</php>
1315

1416
<testsuites>

src/PhpBrew/Patch/Patch.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
namespace PhpBrew\Patch;
3+
4+
/**
5+
* A common interface of patch utility classes.
6+
*/
7+
interface Patch
8+
{
9+
/**
10+
* Enables a backup before applying patches.
11+
* Call this method when you want to preserve an original file.
12+
*/
13+
public function enableBackup();
14+
15+
/**
16+
* Applies patches to a file.
17+
*/
18+
public function apply();
19+
}

src/PhpBrew/Patch/PatchCollection.php

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
namespace PhpBrew\Patch;
3+
4+
use PhpBrew\Buildable;
5+
use CLIFramework\Logger;
6+
7+
/**
8+
* Aggregates pathes.
9+
*/
10+
class PatchCollection
11+
{
12+
public static function createPatchesFor64BitSupport(Logger $logger, Buildable $build)
13+
{
14+
return array(
15+
new RegexpPatch(
16+
$logger,
17+
$build,
18+
array('Makefile'),
19+
array(
20+
RegexpPatchRule::allOf(array('/^BUILD_/'), '/\$\(CC\)/', '$(CXX)'),
21+
RegexpPatchRule::allOf(array('/^EXTRA_LIBS =/'), '/^(.*)$/', '$1 -lstdc++')
22+
)
23+
)
24+
);
25+
}
26+
27+
public static function createPatchesForApxs2(Logger $logger, Buildable $build)
28+
{
29+
$rules = array(
30+
RegexpPatchRule::always(
31+
'#libphp\$\(PHP_MAJOR_VERSION\)\.#',
32+
'libphp$(PHP_VERSION).'
33+
),
34+
RegexpPatchRule::always(
35+
'#libs/libphp\$PHP_MAJOR_VERSION\.#',
36+
'libs/libphp$PHP_VERSION.'
37+
),
38+
RegexpPatchRule::always(
39+
'#libs/libphp5.so#',
40+
'libs/libphp$PHP_VERSION.so'
41+
),
42+
RegexpPatchRule::always(
43+
'#libs/libphp5.la#',
44+
'libs/libphp$PHP_VERSION.la'
45+
),
46+
RegexpPatchRule::always(
47+
'#libphp\$PHP_MAJOR_VERSION\.#',
48+
'libphp$PHP_VERSION.'
49+
)
50+
);
51+
return array(
52+
new RegexpPatch(
53+
$logger,
54+
$build,
55+
array('configure', 'Makefile.global'),
56+
$rules
57+
)
58+
);
59+
}
60+
}

src/PhpBrew/Patch/RegexpPatch.php

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
namespace PhpBrew\Patch;
3+
4+
use PhpBrew\Patch\Patch;
5+
use PhpBrew\Buildable;
6+
use CLIFramework\Logger;
7+
8+
/**
9+
* Applies patches to a file using regexp.
10+
* You can customize replacement rules of a patch by passing
11+
* RegexpPatchRule objects to this class.
12+
*/
13+
class RegexpPatch implements Patch
14+
{
15+
/**
16+
* @var Logger
17+
*/
18+
private $logger;
19+
20+
/**
21+
* @var Buildable
22+
*/
23+
private $build;
24+
25+
/**
26+
* @var array
27+
*/
28+
private $paths;
29+
30+
/**
31+
* @var array
32+
*/
33+
private $rules;
34+
35+
/**
36+
* @var string
37+
*/
38+
private $backupFileSuffix;
39+
40+
public function __construct(Logger $logger, Buildable $build, array $paths, array $rules)
41+
{
42+
$this->logger = $logger;
43+
$this->build = $build;
44+
$this->paths = $paths;
45+
$this->rules = $rules;
46+
}
47+
48+
public function enableBackup()
49+
{
50+
$this->backupFileSuffix = '.bak';
51+
}
52+
53+
public function apply()
54+
{
55+
foreach ($this->paths as $relativePath) {
56+
$absolutePath = $this->build->getSourceDirectory() . DIRECTORY_SEPARATOR . $relativePath;
57+
$contents = $this->read($absolutePath);
58+
$this->backup($absolutePath, $contents);
59+
$newContents = $this->applyRules($contents);
60+
$this->write($absolutePath, $newContents);
61+
}
62+
}
63+
64+
private function read($path)
65+
{
66+
$contents = file_get_contents($path);
67+
68+
if ($contents === false) {
69+
throw new \RuntimeException('Failed to read '. $path);
70+
}
71+
72+
return $contents;
73+
}
74+
75+
protected function backup($path, $contents)
76+
{
77+
if ($this->backupFileSuffix && file_put_contents($path . $this->backupFileSuffix, $contents) === false) {
78+
throw new \RuntimeException('Failed to write ' . $path);
79+
}
80+
}
81+
82+
private function applyRules($contents)
83+
{
84+
foreach ($this->rules as $rule) {
85+
$contents = $rule->apply($contents);
86+
}
87+
return $contents;
88+
}
89+
90+
private function write($path, $contents)
91+
{
92+
if (file_put_contents($path, $contents) === false) {
93+
throw new \RuntimeException('Failed to write ' . $path);
94+
}
95+
}
96+
}
97+

src/PhpBrew/Patch/RegexpPatchRule.php

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
namespace PhpBrew\Patch;
3+
4+
/**
5+
* Defines a rule of a replacement using regexp.
6+
*/
7+
class RegexpPatchRule
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private $pattern;
13+
14+
/**
15+
* @var string
16+
*/
17+
private $replacement;
18+
19+
/**
20+
* @var Callable
21+
*/
22+
private $isReplacementRequired;
23+
24+
private function __construct($pattern, $replacement, $isReplacementRequired)
25+
{
26+
$this->pattern = $pattern;
27+
$this->replacement = $replacement;
28+
$this->isReplacementRequired = $isReplacementRequired;
29+
}
30+
31+
/**
32+
* Replaces always.
33+
*/
34+
public static function always($pattern, $replacement)
35+
{
36+
return new RegexpPatchRule($pattern, $replacement, function() {
37+
return true;
38+
});
39+
}
40+
41+
/**
42+
* Replaces if one of preconditions is satisfied.
43+
*/
44+
public static function anyOf($conditions, $pattern, $replacement)
45+
{
46+
return new RegexpPatchRule($pattern, $replacement, function($line) use ($conditions) {
47+
foreach ($conditions as $condition) {
48+
if (preg_match($condition, $line)) {
49+
return true;
50+
}
51+
}
52+
53+
return count($conditions) === 0 ? true : false;
54+
});
55+
}
56+
57+
/**
58+
* Replaces if all of preconditions are satisfied.
59+
*/
60+
public static function allOf($conditions, $pattern, $replacement)
61+
{
62+
return new RegexpPatchRule($pattern, $replacement, function($line) use ($conditions) {
63+
foreach ($conditions as $condition) {
64+
if (!preg_match($condition, $line)) {
65+
return false;
66+
}
67+
}
68+
return true;
69+
});
70+
}
71+
72+
public function apply($subject)
73+
{
74+
$lines = preg_split("/(?:\r\n|\n|\r)/", $subject);
75+
$size = count($lines);
76+
for ($i = 0; $i < $size; ++$i) {
77+
if (call_user_func($this->isReplacementRequired, $lines[$i])) {
78+
$lines[$i] = preg_replace($this->pattern, $this->replacement, $lines[$i]);
79+
}
80+
}
81+
return implode($lines, PHP_EOL);
82+
}
83+
}

src/PhpBrew/Tasks/Apxs2PatchTask.php

+6-43
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use RuntimeException;
55
use PhpBrew\Utils;
6+
use PhpBrew\Patch\PatchCollection;
67

78
class Apxs2PatchTask extends BaseTask
89
{
@@ -14,48 +15,10 @@ public function patch($build, $options)
1415
return;
1516
}
1617

17-
// patch for libphp$(PHP_MAJOR_VERSION).so
18-
$patch=<<<'EOS'
19-
perl -i.bak -pe 's#
20-
libphp\$\(PHP_MAJOR_VERSION\)\.#libphp\$\(PHP_VERSION\)\.#gx' configure Makefile.global
21-
EOS;
22-
23-
if(Utils::system($patch) !== 0) $this->fail();
24-
25-
$patch=<<<'EOS'
26-
perl -i.bak -pe 's#
27-
libs/libphp\$PHP_MAJOR_VERSION\.
28-
#libs/libphp\$PHP_VERSION\.#gx' configure Makefile.global
29-
EOS;
30-
if(Utils::system($patch) !== 0) $this->fail();
31-
32-
// replace .so files
33-
$patch=<<<'EOS'
34-
perl -i.bak -pe 's#
35-
libs/libphp5.so
36-
#libs/libphp\$PHP_VERSION\.so#gx' configure Makefile.global
37-
EOS;
38-
if(Utils::system($patch) !== 0) $this->fail();
39-
40-
// patch for OVERALL_TARGET=libphp$PHP_MAJOR_VERSION.la
41-
// libphp$(PHP_VERSION).la:
42-
// replace .la files
43-
$patch=<<<'EOS'
44-
perl -i.bak -pe 's#
45-
libs/libphp5.la
46-
#libs/libphp\$PHP_VERSION\.la#gx' configure Makefile.global
47-
EOS;
48-
if(Utils::system($patch) !== 0) $this->fail();
49-
50-
$patch=<<<'EOS'
51-
perl -i.bak -pe 's#
52-
libphp\$PHP_MAJOR_VERSION\.#libphp\$PHP_VERSION\.#gx' configure Makefile.global
53-
EOS;
54-
if(Utils::system($patch) !== 0) $this->fail();
55-
}
56-
57-
public function fail()
58-
{
59-
throw new RuntimeException('apxs2 patch failed.');
18+
$patches = PatchCollection::createPatchesForApxs2($this->logger, $build);
19+
foreach ($patches as $patch) {
20+
$patch->enableBackup();
21+
$patch->apply();
22+
}
6023
}
6124
}

src/PhpBrew/Tasks/Patch64BitSupportTask.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use PhpBrew\Build;
55
use PhpBrew\Utils;
6+
use PhpBrew\Patch\PatchCollection;
67

78
class Patch64BitSupportTask extends BaseTask
89
{
@@ -23,11 +24,11 @@ public function patch(Build $build)
2324
$this->info("===> Applying patch file for php5.3.x on 64bit machine.");
2425

2526
if (!$this->options->dryrun) {
26-
$this->logger->debug('sed -i.bak \'/^BUILD_/ s/\$(CC)/\$(CXX)/g\' Makefile');
27-
system('sed -i.bak \'/^BUILD_/ s/\$(CC)/\$(CXX)/g\' Makefile');
28-
29-
$this->logger->debug('sed -i.bak \'/EXTRA_LIBS = /s|$| -lstdc++|\' Makefile');
30-
system('sed -i.bak \'/EXTRA_LIBS = /s|$| -lstdc++|\' Makefile');
27+
$patches = PatchCollection::createPatchesFor64BitSupport($this->logger, $build);
28+
foreach ($patches as $patch) {
29+
$patch->enableBackup();
30+
$patch->apply();
31+
}
3132
}
3233
}
3334
}

0 commit comments

Comments
 (0)