Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #240 from totten/master-misc
Upgrade - Fix cleanup logic for a few funny edge-cases
- Loading branch information
Showing
6 changed files
with
407 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
|
||
namespace CRM\CivixBundle\Utils; | ||
|
||
/** | ||
* Evil Expressions: What happens when you don't import nikic/php-parser. | ||
*/ | ||
class EvilEx { | ||
|
||
/** | ||
* Find a function-body, and run it through a filter. | ||
* | ||
* Limitation: This only matches top-level functions, where the `function x()` begins in the leftmost, | ||
* and where the closing `}` is als in the leftmost, and where the body is indented. | ||
* | ||
* @param string $body | ||
* Full-text file. | ||
* @param string $function | ||
* Name of the function to filter. | ||
* @param callable $filter | ||
* Filter the function-body; return new body. | ||
* function(string $body): string | ||
* @return string | ||
* Updated body. | ||
*/ | ||
public static function rewriteFunction(string $body, string $function, callable $filter): string { | ||
$pattern = "/(\nfunction " . $function . "\([^{]+\)\s*{\n)((\n| [^\n]*\n)*)(}\n)/m"; | ||
return preg_replace_callback($pattern, | ||
function ($m) use ($filter) { | ||
$body = $m[2]; | ||
$newBody = $filter($body); | ||
return $m[1] . $newBody . $m[4]; | ||
}, | ||
$body | ||
); | ||
} | ||
|
||
/** | ||
* Searches for a chunk of code - and replaces it. | ||
* | ||
* When matching the chunk of code, it specifically ignores whitespace and blank lines. | ||
* | ||
* @param string $body | ||
* @param array $matchChunk | ||
* A series of lines which should be found somewhere inside $body (modulo whitespace). | ||
* @param callable $filterChunk | ||
* Filter the matching lines; return new lines. | ||
* function(array $matchLines): array | ||
* @return string | ||
* Updated body. | ||
*/ | ||
public static function rewriteMultilineChunk(string $body, array $matchChunk, callable $filterChunk) { | ||
$expectLines = EvilEx::digestLines($matchChunk); | ||
$actualLines = EvilEx::digestLines(explode("\n", $body)); | ||
foreach (array_keys($actualLines) as $startOffset) { | ||
$endOffset = NULL; | ||
$expectLineNum = 0; | ||
for ($actualLineNum = $startOffset; $actualLineNum < count($actualLines); $actualLineNum++) { | ||
if (empty($actualLines[$actualLineNum]['dig'])) { | ||
continue; | ||
} | ||
if ($expectLines[$expectLineNum]['dig'] !== $actualLines[$actualLineNum]['dig']) { | ||
continue 2; | ||
} | ||
$expectLineNum++; | ||
if ($expectLineNum >= count($expectLines)) { | ||
$endOffset = $actualLineNum; | ||
break 2; | ||
} | ||
} | ||
} | ||
|
||
if ($endOffset === NULL) { | ||
return $body; | ||
} | ||
|
||
$rawActualLines = array_column($actualLines, 'raw'); | ||
$matchLines = array_slice($rawActualLines, $startOffset, $endOffset - $startOffset + 1, TRUE); | ||
$newLines = $filterChunk($matchLines); | ||
array_splice($rawActualLines, $startOffset, $endOffset - $startOffset + 1, $newLines); | ||
return implode("\n", $rawActualLines); | ||
} | ||
|
||
public static function digestLine(string $line): string { | ||
return mb_strtolower(preg_replace('/\s+/', '', $line)); | ||
} | ||
|
||
public static function digestLines($lines): array { | ||
$result = []; | ||
foreach ($lines as $line) { | ||
$result[] = ['raw' => $line, 'dig' => static::digestLine($line)]; | ||
} | ||
return $result; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<?php | ||
// [[ EX - Keep pure comment ]] | ||
|
||
// function civixcleanempty_civicrm_keepPureComment() { | ||
// foo | ||
// } | ||
|
||
// [[ EX - Removable 1 ]] | ||
|
||
function civixcleanempty_civicrm_removeOne() { | ||
} | ||
|
||
// [[ EX - Keepable 1 ]] | ||
|
||
function civixcleanempty_civicrm_keepOne() { | ||
stuff(); | ||
} | ||
|
||
// [[ EX - Removable 2 ]] | ||
|
||
/** | ||
* | ||
*/ | ||
function civixcleanempty_civicrm_removeTwo() { | ||
|
||
} | ||
|
||
// [[ EX - Keepable 2 ]] | ||
|
||
/** | ||
* @param $x | ||
*/ | ||
function civixcleanempty_civicrm_keepTwo($x) { | ||
stuff($x); | ||
} | ||
|
||
// [[ EX - Removable 3 ]] | ||
|
||
/** | ||
* | ||
*/ | ||
function civixcleanempty_civicrm_remove_three($x) { | ||
// Do nothing | ||
} | ||
|
||
// [[ EX - Keepable 3 ]] | ||
|
||
function civixcleanempty_civicrm_keepThree() { | ||
stuff(); // Comment | ||
} | ||
|
||
// [[ EX - Removable 4 ]] | ||
|
||
function civixcleanempty_civicrm_removeFour() {} | ||
|
||
// [[ EX - Keepable 4 ]] | ||
|
||
function civixcleanempty_civicrm_keepFour() { | ||
foreach ($a as $b) {} x(); | ||
} | ||
|
||
// [[ EX - Removable 5 ]] | ||
|
||
function civixcleanempty_civicrm_removeFive() { } | ||
|
||
// [[ EX - Keepable 5 ]] | ||
|
||
function civixcleanempty_civicrm_keepFive() { | ||
if (FOO) { | ||
x(); | ||
} | ||
y(); | ||
} | ||
|
||
// [[ EX - Removable 6 ]] | ||
|
||
function civixcleanempty_civicrm_removeSix() { | ||
return; | ||
} | ||
|
||
// [[ EX - Keepable 6 ]] | ||
|
||
function civixcleanempty_civicrm_keepSix() { | ||
return; | ||
$x++; | ||
} | ||
|
||
// [[ EX - Keepable 6a ]] | ||
|
||
function civixcleanempty_civicrm_keepSixA() { | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
// [[ EX - Keep pure comment ]] | ||
|
||
// function civixcleanempty_civicrm_keepPureComment() { | ||
// foo | ||
// } | ||
|
||
// [[ EX - Removable 1 ]] | ||
|
||
// [[ EX - Keepable 1 ]] | ||
|
||
function civixcleanempty_civicrm_keepOne() { | ||
stuff(); | ||
} | ||
|
||
// [[ EX - Removable 2 ]] | ||
|
||
|
||
|
||
// [[ EX - Keepable 2 ]] | ||
|
||
/** | ||
* @param $x | ||
*/ | ||
function civixcleanempty_civicrm_keepTwo($x) { | ||
stuff($x); | ||
} | ||
|
||
// [[ EX - Removable 3 ]] | ||
|
||
|
||
|
||
// [[ EX - Keepable 3 ]] | ||
|
||
function civixcleanempty_civicrm_keepThree() { | ||
stuff(); // Comment | ||
} | ||
|
||
// [[ EX - Removable 4 ]] | ||
|
||
// [[ EX - Keepable 4 ]] | ||
|
||
function civixcleanempty_civicrm_keepFour() { | ||
foreach ($a as $b) {} x(); | ||
} | ||
|
||
// [[ EX - Removable 5 ]] | ||
|
||
// [[ EX - Keepable 5 ]] | ||
|
||
function civixcleanempty_civicrm_keepFive() { | ||
if (FOO) { | ||
x(); | ||
} | ||
y(); | ||
} | ||
|
||
// [[ EX - Removable 6 ]] | ||
|
||
// [[ EX - Keepable 6 ]] | ||
|
||
function civixcleanempty_civicrm_keepSix() { | ||
return; | ||
$x++; | ||
} | ||
|
||
// [[ EX - Keepable 6a ]] | ||
|
||
function civixcleanempty_civicrm_keepSixA() { | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
namespace E2E; | ||
|
||
class CleanEmptyTest extends \PHPUnit\Framework\TestCase { | ||
|
||
use CivixProjectTestTrait; | ||
|
||
public static $key = 'civixcleanempty'; | ||
|
||
public function setUp(): void { | ||
chdir(static::getWorkspacePath()); | ||
static::cleanDir(static::getKey()); | ||
$this->civixGenerateModule(static::getKey()); | ||
chdir(static::getKey()); | ||
|
||
$this->assertFileExists('info.xml'); | ||
} | ||
|
||
public function testCleanup(): void { | ||
$mainPhp = static::getKey() . '.php'; | ||
copy(__DIR__ . '/CleanEmptyTest.in.txt', $mainPhp); | ||
$this->assertEquals(0, $this->civix('upgrade')->execute([])); | ||
$this->assertFileEquals(__DIR__ . '/CleanEmptyTest.out.txt', $mainPhp); | ||
} | ||
|
||
} |
Oops, something went wrong.