Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 74
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConvertAllLqtPages
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 3
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
42
 buildIterator
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace Flow\Maintenance;
4
5use AppendIterator;
6use Flow\Container;
7use Flow\Import\Converter;
8use Flow\Import\LiquidThreadsApi\ConversionStrategy;
9use Flow\Import\LiquidThreadsApi\LocalApiBackend;
10use Flow\Import\SourceStore\FileImportSourceStore;
11use Flow\Import\SourceStore\FlowRevisionsDb;
12use Flow\OccupationController;
13use Flow\Utils\NamespaceIterator;
14use Flow\Utils\PagesWithPropertyIterator;
15use MediaWiki\Maintenance\Maintenance;
16use Psr\Log\AbstractLogger;
17use Psr\Log\LogLevel;
18use Wikimedia\Rdbms\IReadableDatabase;
19
20$IP = getenv( 'MW_INSTALL_PATH' );
21if ( $IP === false ) {
22    $IP = __DIR__ . '/../../..';
23}
24
25require_once "$IP/maintenance/Maintenance.php";
26
27/**
28 * Converts all LiquidThreads pages on a wiki to Flow. When using the logfile
29 * option this process is idempotent.It may be run many times and will only import
30 * one copy of each item.
31 */
32class ConvertAllLqtPages extends Maintenance {
33    public function __construct() {
34        parent::__construct();
35        $this->addDescription( "Converts LiquidThreads data to Flow data" );
36        $this->addOption( 'logfile', 'File to read and store associations between imported items ' .
37            'and their sources. This is required for the import to be idempotent.', false, true );
38        $this->addOption( 'force-recovery-conversion', 'If a previous logfile was lost, this ' .
39            'option can be set to attempt to map threads to topics that have already been ' .
40            'imported to prevent doubles.' );
41        $this->addOption( 'debug', 'Include debug information with progress report' );
42        $this->addOption( 'dryrun', 'Show what would be converted, but do not make any changes.' );
43        $this->addOption( 'ignoreflowreadonly', 'Ignore $wgFlowReadOnly if set, allowing boards to be created.' );
44        $this->addOption( 'convertempty', 'Convert pages even if they have no threads.' );
45        $this->addOption( 'insert-ignore', 'Ignore duplicate key insert errors.' );
46        $this->requireExtension( 'Flow' );
47    }
48
49    public function execute() {
50        global $wgFlowReadOnly;
51
52        if ( $wgFlowReadOnly ) {
53            if ( $this->getOption( 'ignoreflowreadonly', false ) ) {
54                // Make Flow writable for the duration of the script
55                $wgFlowReadOnly = false;
56            } else {
57                $this->error( 'Flow is in read-only mode. Use --ignoreflowreadonly to continue.' );
58                return;
59            }
60        }
61
62        $logfile = $this->getOption( 'logfile' );
63        if ( $logfile ) {
64            $sourceStore = new FileImportSourceStore( $logfile );
65        } elseif ( $this->getOption( 'force-recovery-conversion' ) ) {
66            // fallback: if we don't have a sourcestore to go on, at least look
67            // at DB to figure out what's already imported...
68            $dbr = Container::get( 'db.factory' )->getDB( DB_REPLICA );
69            $sourceStore = new FlowRevisionsDb( $dbr );
70        } else {
71            $this->error( 'Param logfile or force-recovery-conversion required!' );
72            $this->maybeHelp( true );
73            die( 1 );
74        }
75
76        $logger = new MaintenanceDebugLogger( $this );
77        if ( $this->getOption( 'debug' ) ) {
78            $logger->setMaximumLevel( LogLevel::DEBUG );
79        } else {
80            $logger->setMaximumLevel( LogLevel::INFO );
81        }
82
83        $importer = Container::get( 'importer' );
84        /** @var OccupationController $occupationController */
85        $occupationController = $this->getServiceContainer()->getService( 'FlowTalkpageManager' );
86        $talkpageManagerUser = $occupationController->getTalkpageManager();
87
88        $dbw = $this->getPrimaryDB();
89        $strategy = new ConversionStrategy(
90            $dbw,
91            $sourceStore,
92            new LocalApiBackend( $talkpageManagerUser ),
93            Container::get( 'url_generator' ),
94            $talkpageManagerUser,
95            Container::get( 'controller.notification' )
96        );
97
98        $converter = new Converter(
99            $dbw,
100            $importer,
101            $logger,
102            $talkpageManagerUser,
103            $strategy
104        );
105
106        $titles = $this->buildIterator( $logger, $dbw );
107        $dryRun = $this->getOption( 'dryrun', false );
108        $convertEmpty = $this->getOption( 'convertempty', false );
109
110        $logger->info( "Starting full wiki LQT conversion of all LiquidThreads pages" );
111        $converter->convertAll( $titles, $dryRun, $convertEmpty );
112
113        $logger->info( "Finished conversion" );
114    }
115
116    /**
117     * @param AbstractLogger $logger
118     * @param IReadableDatabase $db
119     *
120     * @return AppendIterator
121     */
122    private function buildIterator( $logger, $db ) {
123        global $wgLqtTalkPages;
124
125        $iterator = new AppendIterator();
126
127        $logger->info( "Considering for conversion: pages with the 'use-liquid-threads' property" );
128        $withProperty = new PagesWithPropertyIterator( $db, 'use-liquid-threads' );
129        $iterator->append( $withProperty->getIterator() );
130
131        if ( $wgLqtTalkPages ) {
132            foreach ( $this->getServiceContainer()->getNamespaceInfo()->getTalkNamespaces() as $ns ) {
133                $logger->info( "Considering for conversion: pages in namespace $ns" );
134                $it = new NamespaceIterator( $db, $ns );
135                $iterator->append( $it->getIterator() );
136            }
137        }
138
139        return $iterator;
140    }
141}
142
143$maintClass = ConvertAllLqtPages::class;
144require_once RUN_MAINTENANCE_IF_MAIN;