|
4 | 4 | * Textpattern Content Management System |
5 | 5 | * https://textpattern.com/ |
6 | 6 | * |
7 | | - * Copyright (C) 2022 The Textpattern Development Team |
8 | | - * |
9 | | - * This file is part of Textpattern. |
| 7 | + * Copyright (C) 2024 The Textpattern Development Team |
10 | 8 | * |
11 | 9 | * Textpattern is free software; you can redistribute it and/or |
12 | 10 | * modify it under the terms of the GNU General Public License |
|
18 | 16 | * GNU General Public License for more details. |
19 | 17 | * |
20 | 18 | * You should have received a copy of the GNU General Public License |
21 | | - * along with Textpattern. If not, see <https://www.gnu.org/licenses/>. |
| 19 | + * along with Textpattern. If not, see <http://www.gnu.org/licenses/>. |
22 | 20 | */ |
23 | 21 |
|
| 22 | +define('txpinterface', 'cli'); |
| 23 | + |
24 | 24 | if (php_sapi_name() !== 'cli') { |
25 | 25 | die('command line only'); |
26 | 26 | } |
27 | 27 |
|
28 | | -define('txpath', 'textpattern'); |
| 28 | +if (empty($argv[1])) { |
| 29 | + die("usage: {$argv[0]} <txpath> [update|rebuild]\n"); |
| 30 | +} |
| 31 | + |
| 32 | +$action = empty($argv[2]) ? 'update' : $argv[2]; |
| 33 | + |
| 34 | +define('txpath', rtrim(realpath($argv[1]), '/')); |
29 | 35 | define('n', "\n"); |
30 | 36 |
|
31 | | -// Find `.php` and `.js` files in `textpattern` directory. |
32 | | -$files = glob_recursive('textpattern/*\.{php,js}', GLOB_BRACE); |
33 | | -$files = preg_replace('%^textpattern%', '', $files); |
34 | | -$files = array_flip($files); |
| 37 | +$event = ''; |
| 38 | +$prefs['enable_xmlrpc_server'] = true; |
| 39 | +require_once(txpath.'/lib/constants.php'); |
| 40 | +require_once(txpath.'/lib/txplib_misc.php'); |
| 41 | +require_once(txpath.'/lib/txplib_admin.php'); |
| 42 | +$files = array(); |
| 43 | +$destination = txpath.DS.'checksums.txt'; |
35 | 44 |
|
36 | | -$cs = @file_get_contents(txpath.'/checksums.txt'); |
37 | | -if (preg_match_all('%^(\S+):\s+([\da-f]+)%im', $cs, $mm)) { |
38 | | - $out = ''; |
| 45 | +switch ($action) { |
| 46 | + case 'update': |
| 47 | + $files = calculate_checksums(); |
| 48 | + break; |
| 49 | + case 'rebuild': |
| 50 | + $files = files_to_checksum(txpath, '/.*\.(?:php|js)$/'); |
39 | 51 |
|
40 | | - foreach ($mm[1] as $key => $file) { |
41 | | - $md5 = md5_file(txpath.$file); |
42 | | - $out .= "$file: $md5".n; |
43 | | - unset($files[$file]); |
44 | | - } |
| 52 | + // Append root and rpc files. |
| 53 | + $files = array_merge($files, glob(txpath.DS.'..'.DS.'*.php')); |
| 54 | + $files = array_merge($files, glob(txpath.DS.'..'.DS.'rpc'.DS.'*.php')); |
| 55 | + |
| 56 | + // Remove setup and config-dist.php. |
| 57 | + $files = array_filter($files, function($e) { return (strpos($e, '/setup') === false); }); |
| 58 | + $files = array_filter($files, function($e) { return (strpos($e, '/config-dist') === false); }); |
45 | 59 |
|
46 | | - file_put_contents(txpath.'/checksums.txt', $out); |
47 | | - echo "Checksums updated.\n\n"; |
| 60 | + // Output list. |
| 61 | + if ($files) { |
| 62 | + $files = array_map(function ($str) { return str_replace(txpath, '', $str.": ".str_repeat('a', 32)); }, $files); |
| 63 | + file_put_contents($destination, implode(n, $files)); |
| 64 | + $files = calculate_checksums(); |
| 65 | + } |
| 66 | + break; |
48 | 67 | } |
49 | 68 |
|
50 | | -// New files. |
51 | | -$out = ''; |
| 69 | +if ($files) { |
| 70 | + file_put_contents($destination, implode(n, $files)); |
| 71 | + echo "Checksums updated in ".$destination.".\n"; |
| 72 | +} |
52 | 73 |
|
53 | | -foreach ($files as $file => $val) { |
54 | | - if (! preg_match('%^/(config-dist\.php|setup)%', $file)) { |
55 | | - $out .= "$file: ".md5_file(txpath.'/'.$file).n; |
| 74 | +/** |
| 75 | + * Recursively fetch files from the given root. |
| 76 | + * |
| 77 | + * Dot files and directories are skipped. |
| 78 | + * |
| 79 | + * @param string $folder Path to the start point (root directory to traverse) |
| 80 | + * @param string $pattern Full regex filter to apply |
| 81 | + * @return array List of files |
| 82 | + */ |
| 83 | +function files_to_checksum($folder, $pattern) |
| 84 | +{ |
| 85 | + $dir = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::SKIP_DOTS); |
| 86 | + $iter = new RecursiveIteratorIterator($dir); |
| 87 | + $files = new RegexIterator($iter, $pattern, RegexIterator::GET_MATCH); |
| 88 | + $fileList = array(); |
| 89 | + |
| 90 | + foreach ($files as $file) { |
| 91 | + $fileList = array_merge($fileList, $file); |
56 | 92 | } |
57 | | -} |
58 | 93 |
|
59 | | -if ($out) { |
60 | | - echo "New files without checksums:".n.$out.n; |
61 | | - echo "Add new files to 'checksums.txt' before release.".n.n; |
| 94 | + return $fileList; |
62 | 95 | } |
63 | 96 |
|
64 | | -exit; |
65 | | - |
66 | | -function glob_recursive($pattern, $flags = 0) |
| 97 | +/** |
| 98 | + * Recalculate checksums of all files in the destination file. |
| 99 | + * |
| 100 | + * @return array List of files and their checksums |
| 101 | + */ |
| 102 | +function calculate_checksums() |
67 | 103 | { |
68 | | - $files = glob($pattern, $flags); |
| 104 | + $fileList = array(); |
69 | 105 |
|
70 | | - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { |
71 | | - $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags)); |
| 106 | + foreach (check_file_integrity(INTEGRITY_MD5) as $file => $md5) { |
| 107 | + $fileList[] = "$file: $md5"; |
72 | 108 | } |
73 | 109 |
|
74 | | - return $files; |
| 110 | + return $fileList; |
75 | 111 | } |
0 commit comments