Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 80 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
PurgeList | |
0.00% |
0 / 80 |
|
0.00% |
0 / 5 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
doPurge | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
56 | |||
purgeNamespace | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
42 | |||
sendPurgeRequest | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /** |
3 | * Send purge requests for listed pages to CDN |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup Maintenance |
22 | */ |
23 | |
24 | use MediaWiki\Maintenance\Maintenance; |
25 | use MediaWiki\Title\Title; |
26 | |
27 | // @codeCoverageIgnoreStart |
28 | require_once __DIR__ . '/Maintenance.php'; |
29 | // @codeCoverageIgnoreEnd |
30 | |
31 | /** |
32 | * Maintenance script that sends purge requests for listed pages to CDN. |
33 | * |
34 | * @ingroup Maintenance |
35 | */ |
36 | class PurgeList extends Maintenance { |
37 | /** @var string|null */ |
38 | private $namespaceId; |
39 | /** @var bool */ |
40 | private $allNamespaces; |
41 | /** @var bool */ |
42 | private $doDbTouch; |
43 | /** @var int */ |
44 | private $delay; |
45 | |
46 | public function __construct() { |
47 | parent::__construct(); |
48 | $this->addDescription( "Send purge requests for listed pages to CDN.\n" |
49 | . "By default this expects a list of URLs or page names from STDIN. " |
50 | . "To query the database for input, use --namespace or --all-namespaces instead." |
51 | ); |
52 | $this->addOption( 'namespace', 'Purge pages with this namespace number', false, true ); |
53 | $this->addOption( 'all-namespaces', 'Purge pages in all namespaces', false, false ); |
54 | $this->addOption( 'db-touch', |
55 | "Update the page.page_touched database field.\n" |
56 | . "This is only considered when purging by title, not when purging by namespace or URL.", |
57 | false, |
58 | false |
59 | ); |
60 | $this->addOption( 'delay', 'Number of seconds to delay between each purge', false, true ); |
61 | $this->addOption( 'verbose', 'Show more output', false, false, 'v' ); |
62 | $this->setBatchSize( 100 ); |
63 | } |
64 | |
65 | public function execute() { |
66 | $this->namespaceId = $this->getOption( 'namespace' ); |
67 | $this->allNamespaces = $this->hasOption( 'all-namespaces' ); |
68 | $this->doDbTouch = $this->hasOption( 'db-touch' ); |
69 | $this->delay = intval( $this->getOption( 'delay', '0' ) ); |
70 | |
71 | if ( $this->allNamespaces ) { |
72 | $this->purgeNamespace( false ); |
73 | } elseif ( $this->namespaceId !== null ) { |
74 | $this->purgeNamespace( intval( $this->namespaceId ) ); |
75 | } else { |
76 | $this->doPurge(); |
77 | } |
78 | $this->output( "Done!\n" ); |
79 | } |
80 | |
81 | /** |
82 | * Purge URL coming from stdin |
83 | */ |
84 | private function doPurge() { |
85 | $stdin = $this->getStdin(); |
86 | $urls = []; |
87 | $htmlCacheUpdater = $this->getServiceContainer()->getHtmlCacheUpdater(); |
88 | |
89 | while ( !feof( $stdin ) ) { |
90 | $page = trim( fgets( $stdin ) ); |
91 | if ( preg_match( '%^https?://%', $page ) ) { |
92 | $urls[] = $page; |
93 | } elseif ( $page !== '' ) { |
94 | $title = Title::newFromText( $page ); |
95 | if ( $title ) { |
96 | $newUrls = $htmlCacheUpdater->getUrls( $title ); |
97 | |
98 | foreach ( $newUrls as $url ) { |
99 | $this->output( "$url\n" ); |
100 | } |
101 | |
102 | $urls = array_merge( $urls, $newUrls ); |
103 | |
104 | if ( $this->doDbTouch ) { |
105 | $title->invalidateCache(); |
106 | } |
107 | } else { |
108 | $this->output( "(Invalid title '$page')\n" ); |
109 | } |
110 | } |
111 | } |
112 | $this->output( "Purging " . count( $urls ) . " urls\n" ); |
113 | $this->sendPurgeRequest( $urls ); |
114 | } |
115 | |
116 | /** |
117 | * Purge a namespace or all pages |
118 | * |
119 | * @param int|bool $namespace |
120 | */ |
121 | private function purgeNamespace( $namespace = false ) { |
122 | if ( $this->doDbTouch ) { |
123 | // NOTE: If support for this is added in the future, |
124 | // it MUST NOT be allowed when $wgMiserMode is enabled. |
125 | // Change this to a check and error about instead! (T263957) |
126 | $this->fatalError( 'The --db-touch option is not supported when purging by namespace.' ); |
127 | } |
128 | |
129 | $dbr = $this->getReplicaDB(); |
130 | $htmlCacheUpdater = $this->getServiceContainer()->getHtmlCacheUpdater(); |
131 | $startId = 0; |
132 | if ( $namespace === false ) { |
133 | $conds = []; |
134 | } else { |
135 | $conds = [ 'page_namespace' => $namespace ]; |
136 | } |
137 | while ( true ) { |
138 | $res = $dbr->newSelectQueryBuilder() |
139 | ->select( [ 'page_id', 'page_namespace', 'page_title' ] ) |
140 | ->from( 'page' ) |
141 | ->where( $conds ) |
142 | ->andWhere( $dbr->expr( 'page_id', '>', $startId ) ) |
143 | ->orderBy( 'page_id' ) |
144 | ->limit( $this->getBatchSize() ) |
145 | ->caller( __METHOD__ )->fetchResultSet(); |
146 | if ( !$res->numRows() ) { |
147 | break; |
148 | } |
149 | $urls = []; |
150 | foreach ( $res as $row ) { |
151 | $title = Title::makeTitle( $row->page_namespace, $row->page_title ); |
152 | $urls = array_merge( $urls, $htmlCacheUpdater->getUrls( $title ) ); |
153 | $startId = $row->page_id; |
154 | } |
155 | $this->sendPurgeRequest( $urls ); |
156 | } |
157 | } |
158 | |
159 | /** |
160 | * Helper to purge an array of $urls |
161 | * @param array $urls List of URLS to purge from CDNs |
162 | */ |
163 | private function sendPurgeRequest( $urls ) { |
164 | $hcu = $this->getServiceContainer()->getHtmlCacheUpdater(); |
165 | if ( $this->delay > 0 ) { |
166 | foreach ( $urls as $url ) { |
167 | if ( $this->hasOption( 'verbose' ) ) { |
168 | $this->output( $url . "\n" ); |
169 | } |
170 | $hcu->purgeUrls( $url, $hcu::PURGE_NAIVE ); |
171 | sleep( $this->delay ); |
172 | } |
173 | } else { |
174 | if ( $this->hasOption( 'verbose' ) ) { |
175 | $this->output( implode( "\n", $urls ) . "\n" ); |
176 | } |
177 | $hcu->purgeUrls( $urls, $hcu::PURGE_NAIVE ); |
178 | } |
179 | } |
180 | } |
181 | |
182 | // @codeCoverageIgnoreStart |
183 | $maintClass = PurgeList::class; |
184 | require_once RUN_MAINTENANCE_IF_MAIN; |
185 | // @codeCoverageIgnoreEnd |