]> granicus.if.org Git - php/commitdiff
Add tidy.php to enforce formatting
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 10 Jan 2020 14:52:42 +0000 (15:52 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 3 Feb 2020 12:34:42 +0000 (13:34 +0100)
Many parts are disabled for the PHP-7.4 branch. We only strip
trailing whitespace in C files and reindent .php files to spaces.

scripts/dev/tidy.php [new file with mode: 0644]

diff --git a/scripts/dev/tidy.php b/scripts/dev/tidy.php
new file mode 100644 (file)
index 0000000..267f838
--- /dev/null
@@ -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;
+    }
+}