diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-01-10 15:52:42 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-03 13:34:42 +0100 |
commit | 4fd63185803aad42790c0ac38c144b346e283009 (patch) | |
tree | 22de45dadbe5a5737352cd0b3620e31dcca6e9a4 /scripts | |
parent | 42e67881c9597681196f215c2122e90ee7427e7e (diff) | |
download | php-git-4fd63185803aad42790c0ac38c144b346e283009.tar.gz |
Add tidy.php to enforce formatting
Many parts are disabled for the PHP-7.4 branch. We only strip
trailing whitespace in C files and reindent .php files to spaces.
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/dev/tidy.php | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/scripts/dev/tidy.php b/scripts/dev/tidy.php new file mode 100644 index 0000000000..267f838a61 --- /dev/null +++ b/scripts/dev/tidy.php @@ -0,0 +1,145 @@ +<?php + +set_error_handler(function($_, $msg) { + throw new Exception($msg); +}); + +$rootDir = __DIR__ . '/../..'; +$it = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($rootDir), + RecursiveIteratorIterator::LEAVES_ONLY +); + +$excludes = [ + // Bundled libraries / files. + 'ext/bcmath/libbcmath/', + 'ext/date/lib/', + 'ext/fileinfo/data_file.c', + 'ext/fileinfo/libmagic/', + 'ext/gd/libgd/', + 'ext/hash/sha3/', + 'ext/hash/hash_whirlpool.c', + 'ext/hash/php_hash_whirlpool_tables.h', + 'ext/mbstring/libmbfl/', + 'ext/mbstring/unicode_data.h', + 'ext/pcre/pcre2lib/', + 'ext/standard/html_tables/html_table_gen.php', + 'ext/xmlrpc/libxmlrpc/', + 'sapi/cli/php_http_parser.c', + 'sapi/cli/php_http_parser.h', + 'sapi/litespeed/', + // Not a PHP file. + 'ext/zlib/tests/data.inc', + // Flexible HEREDOC/NOWDOC tests are likely whitespace sensitive. + // TODO: Properly classify them. + 'Zend/tests/flexible-', +]; + +foreach ($it as $file) { + if (!$file->isFile()) { + continue; + } + + $path = $file->getPathName(); + foreach ($excludes as $exclude) { + if (strpos($path, $exclude) !== false) { + continue 2; + } + } + + $lang = getLanguageFromExtension($file->getExtension()); + if ($lang === null) { + continue; + } + + $origCode = $code = file_get_contents($path); + + if ($lang === 'c') { + $code = stripTrailingWhitespace($code); + // TODO: Avoid this for now. + // $code = reindentToTabs($code); + } else if ($lang === 'php') { + $code = stripTrailingWhitespace($code); + $code = reindentToSpaces($code); + } else if ($lang === 'phpt') { + // TODO: Don't reformat .phpt on PHP-7.4. + /*$code = transformTestCode($code, function(string $code) { + $code = stripTrailingWhitespace($code); + $code = reindentToSpaces($code); + return $code; + });*/ + } + + if ($origCode !== $code) { + file_put_contents($path, $code); + } +} + +function stripTrailingWhitespace(string $code): string { + return preg_replace('/\h+$/m', '', $code); +} + +function reindentToTabs(string $code): string { + return preg_replace_callback('/^ +/m', function(array $matches) { + $tabSize = 4; + $spaces = strlen($matches[0]); + $tabs = intdiv($spaces, $tabSize); + $spaces -= $tabs * $tabSize; + return str_repeat("\t", $tabs) . str_repeat(" ", $spaces); + }, $code); +} + +function reindentToSpaces(string $code): string { + return preg_replace_callback('/^[ \t]+/m', function(array $matches) { + $tabSize = 4; + $indent = 0; + foreach (str_split($matches[0]) as $char) { + if ($char === ' ') { + $indent++; + } else { + $partialIndent = $indent % $tabSize; + if ($partialIndent === 0) { + $indent += $tabSize; + } else { + $indent += $tabSize - $partialIndent; + } + } + } + return str_repeat(" ", $indent); + }, $code); +} + +function transformTestCode(string $code, callable $transformer): string { + // Don't transform whitespace-sensitive tests. + if (strpos($code, '--WHITESPACE_SENSITIVE--') !== false) { + return $code; + } + + return preg_replace_callback( + '/(--FILE--)(.+?)(--[A-Z_]+--)/s', + function(array $matches) use($transformer) { + return $matches[1] . $transformer($matches[2]) . $matches[3]; + }, + $code + ); +} + +function getLanguageFromExtension(string $ext): ?string { + switch ($ext) { + case 'c': + case 'h': + case 'cpp': + case 'y': + case 'l': + case 're': + return 'c'; + case 'php': + // TODO: Reformat .inc files. + //case 'inc': + return 'php'; + case 'phpt': + return 'phpt'; + default: + return null; + } +} |