Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.00% covered (success)
92.00%
46 / 50
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
MoveBatch
92.00% covered (success)
92.00%
46 / 50
50.00% covered (danger)
50.00%
1 / 2
14.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 execute
89.74% covered (warning)
89.74%
35 / 39
0.00% covered (danger)
0.00%
0 / 1
13.18
1<?php
2/**
3 * Move a batch of pages.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @ingroup Maintenance
8 * @author Tim Starling
9 *
10 *
11 * This will print out error codes from Title::moveTo() if something goes wrong,
12 * e.g. immobile_namespace for namespaces which can't be moved
13 */
14
15use MediaWiki\Maintenance\Maintenance;
16use MediaWiki\Title\Title;
17use MediaWiki\User\User;
18
19// @codeCoverageIgnoreStart
20require_once __DIR__ . '/Maintenance.php';
21// @codeCoverageIgnoreEnd
22
23/**
24 * Maintenance script to move a batch of pages.
25 *
26 * @ingroup Maintenance
27 */
28class MoveBatch extends Maintenance {
29    public function __construct() {
30        parent::__construct();
31        $this->addDescription( 'Moves a batch of pages' );
32        $this->addOption( 'u', "User to perform move", false, true );
33        $this->addOption( 'r', "Reason to move page", false, true );
34        $this->addOption( 'i', "Interval to sleep between moves" );
35        $this->addOption( 'noredirects', "Suppress creation of redirects" );
36        $this->addArg(
37            'listfile',
38            'List of pages to move (newline delimited) in the format <existing page name>|<new name>',
39            false
40        );
41    }
42
43    public function execute() {
44        # Options processing
45        $username = $this->getOption( 'u', false );
46        $reason = $this->getOption( 'r', '' );
47        $interval = $this->getOption( 'i', 0 );
48        $noRedirects = $this->hasOption( 'noredirects' );
49        if ( $this->hasArg( 0 ) ) {
50            $file = fopen( $this->getArg( 0 ), 'r' );
51        } else {
52            $file = $this->getStdin();
53        }
54
55        # Setup
56        if ( !$file ) {
57            $this->fatalError( "Unable to read file, exiting" );
58        }
59        if ( $username === false ) {
60            $user = User::newSystemUser( 'Move page script', [ 'steal' => true ] );
61        } else {
62            $user = User::newFromName( $username );
63        }
64        if ( !$user || !$user->isRegistered() ) {
65            $this->fatalError( "Invalid username" );
66        }
67
68        $movePageFactory = $this->getServiceContainer()->getMovePageFactory();
69
70        # Setup complete, now start
71        for ( $lineNum = 1; !feof( $file ); $lineNum++ ) {
72            $line = fgets( $file );
73            if ( $line === false ) {
74                break;
75            }
76            $parts = array_map( 'trim', explode( '|', $line ) );
77            if ( count( $parts ) !== 2 ) {
78                $this->error( "Error on line $lineNum, no pipe character" );
79                continue;
80            }
81            $source = Title::newFromText( $parts[0] );
82            $dest = Title::newFromText( $parts[1] );
83            if ( $source === null || $dest === null ) {
84                $this->error( "Invalid title on line $lineNum" );
85                continue;
86            }
87
88            $this->output( $source->getPrefixedText() . ' --> ' . $dest->getPrefixedText() );
89            $this->beginTransactionRound( __METHOD__ );
90            $mp = $movePageFactory->newMovePage( $source, $dest );
91            $status = $mp->move( $user, $reason, !$noRedirects );
92            if ( !$status->isOK() ) {
93                $this->output( " FAILED\n" );
94                $this->error( $status );
95            }
96            $this->commitTransactionRound( __METHOD__ );
97            $this->output( "\n" );
98
99            if ( $interval ) {
100                sleep( $interval );
101            }
102        }
103    }
104}
105
106// @codeCoverageIgnoreStart
107$maintClass = MoveBatch::class;
108require_once RUN_MAINTENANCE_IF_MAIN;
109// @codeCoverageIgnoreEnd