Merge maintenance-work branch (now with less errors!):
authorChad Horohoe <demon@users.mediawiki.org>
Sun, 2 Aug 2009 19:35:17 +0000 (19:35 +0000)
committerChad Horohoe <demon@users.mediawiki.org>
Sun, 2 Aug 2009 19:35:17 +0000 (19:35 +0000)
* Docs have been updated to indicate the standard on how to write maintenance scripts (MW.org docs will follow) Have ported vast majority of maintenance scripts to new format. Remaining ones (mostly FiveUpgrade-related) are a bit more tricky. commandLine.inc is untouched for now. Many have gotten code-style updates as well. Deleted .inc files were only used by their .php counterparts, and have been merged into single files.
* (bug 11867) Lock error on redirect table when running orphans.php
* (bug 16322) Allow maintenance scripts to accept DB user/pass over input or params
* (bug 18566) Maintenance script to un/protect pages
* initStats overhaul, now uses class SiteStatsInit. Also fixes bug 18930

106 files changed:
RELEASE-NOTES
docs/maintenance.txt [new file with mode: 0644]
includes/AutoLoader.php
includes/DefaultSettings.php
includes/SiteStats.php
maintenance/Maintenance.php [new file with mode: 0644]
maintenance/addwiki.php
maintenance/archives/rebuildRecentchanges.inc [deleted file]
maintenance/archives/upgradeWatchlist.php [deleted file]
maintenance/attachLatest.php
maintenance/attribute.php [deleted file]
maintenance/benchmarkPurge.php
maintenance/cdb-test.php
maintenance/changePassword.php
maintenance/checkAutoLoader.php
maintenance/checkBadRedirects.php
maintenance/checkImages.php
maintenance/checkUsernames.php
maintenance/cleanupSpam.php
maintenance/clear_interwiki_cache.php
maintenance/clear_stats.php
maintenance/convertLinks.inc [deleted file]
maintenance/convertLinks.php
maintenance/convertUserOptions.php
maintenance/createAndPromote.php
maintenance/deleteArchivedFiles.inc [deleted file]
maintenance/deleteArchivedFiles.php
maintenance/deleteArchivedRevisions.inc [deleted file]
maintenance/deleteArchivedRevisions.php
maintenance/deleteBatch.php
maintenance/deleteDefaultMessages.php
maintenance/deleteImageMemcached.php
maintenance/deleteOldRevisions.inc [deleted file]
maintenance/deleteOldRevisions.php
maintenance/deleteOrphanedRevisions.inc [deleted file]
maintenance/deleteOrphanedRevisions.php
maintenance/deleteRevision.php
maintenance/doMaintenance.php [new file with mode: 0644]
maintenance/dumpLinks.php
maintenance/dumpSisterSites.php
maintenance/dumpUploads.php
maintenance/edit.php
maintenance/eval.php
maintenance/fetchText.php
maintenance/findhooks.php
maintenance/fixSlaveDesync.php
maintenance/fixTimestamps.php
maintenance/fixUserRegistration.php
maintenance/generateSitemap.php
maintenance/getLagTimes.php
maintenance/getSlaveServer.php
maintenance/initEditCount.php
maintenance/initStats.inc [deleted file]
maintenance/initStats.php
maintenance/language/alltrans.php
maintenance/mctest.php
maintenance/moveBatch.php
maintenance/namespaceDupes.php
maintenance/nextJobDB.php
maintenance/nukeNS.php
maintenance/nukePage.inc [deleted file]
maintenance/nukePage.php
maintenance/orphans.php
maintenance/patchSql.php
maintenance/populateCategory.php
maintenance/populateLogSearch.inc [deleted file]
maintenance/populateLogSearch.php
maintenance/populateLogUsertext.inc [deleted file]
maintenance/populateLogUsertext.php
maintenance/populateParentId.inc [deleted file]
maintenance/populateParentId.php
maintenance/protect.php [new file with mode: 0644]
maintenance/purgeList.php
maintenance/purgeOldText.php
maintenance/reassignEdits.inc [deleted file]
maintenance/reassignEdits.php
maintenance/rebuildFileCache.php
maintenance/rebuildLocalisationCache.php
maintenance/rebuildall.php
maintenance/rebuildmessages.php
maintenance/rebuildrecentchanges.inc [deleted file]
maintenance/rebuildrecentchanges.php
maintenance/rebuildtextindex.inc [deleted file]
maintenance/rebuildtextindex.php
maintenance/refreshImageCount.php
maintenance/refreshLinks.inc [deleted file]
maintenance/refreshLinks.php
maintenance/removeUnusedAccounts.inc [deleted file]
maintenance/removeUnusedAccounts.php
maintenance/renameDbPrefix.php
maintenance/renamewiki.php
maintenance/renderDump.php
maintenance/runJobs.php
maintenance/showJobs.php
maintenance/showStats.php
maintenance/sql.php
maintenance/stats.php
maintenance/undelete.php
maintenance/updateArticleCount.inc [deleted file]
maintenance/updateArticleCount.php
maintenance/updateRestrictions.php
maintenance/updateSearchIndex.inc [deleted file]
maintenance/updateSearchIndex.php
maintenance/updateSpecialPages.php
maintenance/updaters.inc
maintenance/waitForSlave.php

index a486ff4..7f2a67a 100644 (file)
@@ -78,6 +78,7 @@ this. Was used when mwEmbed was going to be an extension.
   GO button is pressed, in addition to the main namespace.
 * (bug 19907) $wgCrossSiteAJAXdomains and $wgCrossSiteAJAXdomainsRegex added 
   to control which external domains may access the API via cross-site AJAX.
+* $wgMaintenanceScripts for extensions to add their scripts to the default list
 
 === New features in 1.16 ===
 
@@ -176,6 +177,8 @@ this. Was used when mwEmbed was going to be an extension.
 * The description message in $wgExtensionCredits can be an array with parameters
 * (bug 12920) New CoreParserFunction {{nse:...}} as an url-friendly equivalent
   to {{ns:...}}
+* (bug 16322) Allow maintenance scripts to accept DB user/pass over input or params
+* (bug 18566) Maintenance script to un/protect pages
 
 === Bug fixes in 1.16 ===
 
@@ -367,6 +370,8 @@ this. Was used when mwEmbed was going to be an extension.
   (eg Newuser, Userrights) are no longer broken
 * (bug 17395) Remote file descriptions use user language ($wgLang), not wiki
   language ($wgContLang)
+* (bug 11867) Lock error on redirect table when running orphans.php
+* (bug 18930) initStats.php now refreshes active users count
 
 == API changes in 1.16 ==
 
diff --git a/docs/maintenance.txt b/docs/maintenance.txt
new file mode 100644 (file)
index 0000000..9128768
--- /dev/null
@@ -0,0 +1,57 @@
+Prior to version 1.16, maintenance scripts were a hodgepodge of code that
+had no cohesion or formal method of action. Beginning in 1.16, maintenance
+scripts have been cleaned up to use a unified class.
+
+1. Directory structure
+2. How to run a script
+3. How to write your own
+
+1. DIRECTORY STRUCTURE
+  The /maintenance directory of a MediaWiki installation contains several
+subdirectories, all of which have unique purposes.
+
+2. HOW TO RUN A SCRIPT
+  Ridiculously simple, just call 'php someScript.php' that's in the top-
+level /maintenance directory.
+
+Example:
+  php clear_stats.php
+  
+The following parameters are available to all maintenance scripts
+--help   : Print a help message
+--quiet  : Quiet non-error output
+--dbuser : The database user to use for the script (if needed)
+--dbpass : Same as above (if needed)
+--conf   : Location of LocalSettings.php, if not default
+--wiki   : For specifying the wiki ID
+--batch-size : If the script supports batch operations, do this many per batch
+
+3. HOW TO WRITE YOUR OWN
+Make a file in the maintenance directory called myScript.php or something.
+In it, write the following:
+
+==BEGIN==
+
+<?php
+
+require_once( "Maintenance.php" );
+
+class DemoMaint extends Maintenance {
+
+  public function __construct() {
+    parent::__construct();
+  }
+
+  protected function execute() {
+  }
+}
+
+$maintClass = "DemoMaint";
+require_once( DO_MAINTENANCE );
+
+==END==
+
+That's it. In the execute() method, you have access to all of the normal
+MediaWiki functions, so you can get a DB connection, use the cache, etc.
+For full docs on the Maintenance class, see the auto-generated docs at
+http://svn.wikimedia.org/doc/classMaintenance.html
index 50902c9..a984ba1 100644 (file)
@@ -186,6 +186,7 @@ $wgAutoloadLocalClasses = array(
        'Sanitizer' => 'includes/Sanitizer.php',
        'SiteConfiguration' => 'includes/SiteConfiguration.php',
        'SiteStats' => 'includes/SiteStats.php',
+       'SiteStatsInit' => 'includes/SiteStats.php',
        'SiteStatsUpdate' => 'includes/SiteStats.php',
        'Skin' => 'includes/Skin.php',
        'SkinTemplate' => 'includes/SkinTemplate.php',
index c08cafc..fe142ae 100644 (file)
@@ -2266,6 +2266,13 @@ if( !isset( $wgCommandLineMode ) ) {
 /** For colorized maintenance script output, is your terminal background dark ? */
 $wgCommandLineDarkBg = false;
 
+/**
+ * Array for extensions to register their maintenance scripts with the
+ * system. The key is the name of the class and the value is the full
+ * path to the file
+ */
+$wgMaintenanceScripts = array();
+
 #
 # Recent changes settings
 #
index 337ea6e..591f57c 100644 (file)
@@ -49,12 +49,7 @@ class SiteStats {
                        // clean schema with mwdumper.
                        wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
 
-                       global $IP;
-                       require_once "$IP/maintenance/initStats.inc";
-
-                       ob_start();
-                       wfInitStats();
-                       ob_end_clean();
+                       SiteStatsInit::doAllAndCommit( false );
 
                        $row = self::doLoad( wfGetDB( DB_MASTER ) );
                }
@@ -242,5 +237,149 @@ class SiteStatsUpdate {
                        array( 'ss_active_users' => intval($activeUsers) ),
                        array( 'ss_row_id' => 1 ), __METHOD__
                );
+               return $activeUsers;
+       }
+}
+
+/**
+ * Class designed for counting of stats.
+ */
+class SiteStatsInit {
+
+       // Db connection
+       private $db;
+
+       // Various stats
+       private $mEdits, $mArticles, $mPages, $mUsers, $mViews, $mFiles = 0;
+
+       /**
+        * Constructor
+        * @param $useMaster bool Whether to use the master db
+        */
+       public function __construct( $useMaster = false ) {
+               $this->db = wfGetDB( $useMaster ? DB_MASTER : DB_SLAVE );
+       }
+
+       /**
+        * Count the total number of edits
+        * @return int
+        */
+       public function edits() {
+               $this->mEdits = $this->db->selectField( 'revision', 'COUNT(*)', '', __METHOD__ );
+               $this->mEdits += $this->db->selectField( 'archive', 'COUNT(*)', '', __METHOD__ );
+               return $this->mEdits;
+       }
+
+       /**
+        * Count pages in article space
+        * @return int
+        */
+       public function articles() {
+               global $wgContentNamespaces;
+               $this->mArticles = $this->db->selectField( 'page', 'COUNT(*)', array( 'page_namespace' => $wgContentNamespaces, 'page_is_redirect' => 0, 'page_len > 0' ), __METHOD__ );
+               return $this->mArticles;
+       }
+
+       /**
+        * Count total pages
+        * @return int
+        */
+       public function pages() {
+               $this->mPages = $this->db->selectField( 'page', 'COUNT(*)', '', __METHOD__ );
+               return $this->mPages;
+       }
+       
+       /**
+        * Count total users
+        * @return int
+        */
+       public function users() {
+               $this->mUsers = $this->db->selectField( 'user', 'COUNT(*)', '', __METHOD__ );
+               return $this->mUsers;
+       }
+       
+       /**
+        * Count views
+        * @return int
+        */
+       public function views() {
+               $this->mViews = $this->db->selectField( 'page', 'SUM(page_counter)', '', __METHOD__ );
+               return $this->mViews;
+       }
+
+       /**
+        * Count total files
+        * @return int
+        */
+       public function files() {
+               $this->mFiles = $this->db->selectField( 'image', 'COUNT(*)', '', __METHOD__ );
+               return $this->mFiles;
+       }
+
+       /**
+        * Do all updates and commit them. More or less a replacement
+        * for the original initStats, but without the calls to wfOut()
+        * @param $update bool Whether to update the current stats or write fresh
+        * @param $noViews bool When true, do not update the number of page views
+        * @param $activeUsers Whether to update the number of active users
+        */
+       public static function doAllAndCommit( $update, $noViews = false, $activeUsers = false ) {
+               // Grab the object and count everything
+               $counter = new InitStats( false );
+               $counter->edits();
+               $counter->articles();
+               $counter->pages();
+               $counter->users();
+               $counter->files();
+
+               // Only do views if we don't want to not count them
+               if( !$noViews )
+                       $counter->views();
+
+               // Update/refresh
+               if( $update )
+                       $counter->update();
+               else
+                       $counter->refresh();
+
+               // Count active users if need be
+               if( $activeUsers )
+                       SiteStatsUpdate::cacheUpdate( wfGetDB( DB_MASTER ) );
+       }
+
+       /**
+        * Update the current row with the selected values
+        */
+       public function update() {
+               list( $values, $conds ) = $this->getDbParams();
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update( 'site_stats', $values, $conds, __METHOD__ );
+       }
+
+       /**
+        * Refresh site_stats. Erase the current record and save all
+        * the new values.
+        */
+       public function refresh() {
+               list( $values, $conds, $views ) = $this->getDbParams();
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->delete( 'site_stats', $conds, __METHOD__ );
+               $dbw->insert( 'site_stats', array_merge( $values, $conds, $views ), __METHOD__ );
+       }
+
+       /**
+        * Return three arrays of params for the db queries
+        * @return array
+        */
+       private function getDbParams() {
+               $values = array( 'ss_total_edits' => $this->mEdits,
+                                               'ss_good_articles' => $this->mArticles,
+                                               'ss_total_pages' => $this->mPages,
+                                               'ss_users' => $this->mUsers,
+                                               'ss_admins' => SiteStats::numberingroup( 'sysop' ), // @todo make this go away
+                                               'ss_images' => $this->mFiles );
+               $conds = array( 'ss_row_id' => 1 );
+               $views = array( 'ss_total_views' => $this->mViews );
+               return array( $values, $conds, $views );
        }
 }
diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php
new file mode 100644 (file)
index 0000000..a18376b
--- /dev/null
@@ -0,0 +1,804 @@
+<?php
+// Define this so scripts can easily find doMaintenance.php
+define( 'DO_MAINTENANCE', dirname(__FILE__) . '/doMaintenance.php' );
+
+// Make sure we're on PHP5 or better
+if( version_compare( PHP_VERSION, '5.0.0' ) < 0 ) {
+       echo( "Sorry! This version of MediaWiki requires PHP 5; you are running " .
+               PHP_VERSION . ".\n\n" .
+               "If you are sure you already have PHP 5 installed, it may be installed\n" .
+               "in a different path from PHP 4. Check with your system administrator.\n" );
+       die();
+}
+
+/**
+ * Abstract maintenance class for quickly writing and churning out
+ * maintenance scripts with minimal effort. All that _must_ be defined
+ * is the execute() method. See docs/maintenance.txt for more info
+ * and a quick demo of how to use it.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @author Chad Horohoe <chad@anyonecanedit.org>
+ * @since 1.16
+ * @ingroup Maintenance
+ */
+abstract class Maintenance {
+
+       /**
+        * Constants for DB access type
+        * @see Maintenance::getDbType()
+        */
+       const DB_NONE  = 0;
+       const DB_STD   = 1;
+       const DB_ADMIN = 2;
+
+       // This is the desired params
+       private $mParams = array();
+       
+       // Array of desired args
+       private $mArgList = array();
+
+       // This is the list of options that were actually passed
+       private $mOptions = array();
+
+       // This is the list of arguments that were actually passed
+       protected $mArgs = array();
+       
+       // Name of the script currently running
+       protected $mSelf;
+
+       // Special vars for params that are always used
+       private $mQuiet = false;
+       private $mDbUser, $mDbPass;
+
+       // A description of the script, children should change this
+       protected $mDescription = '';
+       
+       // Have we already loaded our user input?
+       private $mInputLoaded = false;
+       
+       // Batch size. If a script supports this, they should set
+       // a default with setBatchSize()
+       protected $mBatchSize = null;
+       
+       /**
+        * List of all the core maintenance scripts. This is added
+        * to scripts added by extensions in $wgMaintenanceScripts
+        * and returned by getMaintenanceScripts()
+        */
+       protected static $mCoreScripts = null;
+
+       /**
+        * Default constructor. Children should call this if implementing
+        * their own constructors
+        */
+       public function __construct() {
+               $this->addDefaultParams();
+       }
+
+       /**
+        * Do the actual work. All child classes will need to implement this
+        */
+       abstract public function execute();
+
+       /**
+        * Add a parameter to the script. Will be displayed on --help
+        * with the associated description
+        *
+        * @param $name String The name of the param (help, version, etc)
+        * @param $description String The description of the param to show on --help
+        * @param $required boolean Is the param required?
+        * @param $withArg Boolean Is an argument required with this option?
+        */
+       protected function addOption( $name, $description, $required = false, $withArg = false ) {
+               $this->mParams[ $name ] = array( 'desc' => $description, 'require' => $required, 'withArg' => $withArg );
+       }
+       
+       /**
+        * Checks to see if a particular param exists.
+        * @param $name String The name of the param
+        * @return boolean
+        */
+       protected function hasOption( $name ) {
+               return isset( $this->mOptions[ $name ] );
+       }
+       
+       /**
+        * Get an option, or return the default
+        * @param $name String The name of the param
+        * @param $default mixed Anything you want, default null
+        * @return mixed
+        */
+       protected function getOption( $name, $default = null ) {
+               if( $this->hasOption($name) ) {
+                       return $this->mOptions[$name];
+               } else {
+                       // Set it so we don't have to provide the default again
+                       $this->mOptions[$name] = $default;
+                       return $this->mOptions[$name];
+               }
+       }
+       
+       /**
+        * Add some args that are needed. Used in formatting help
+        */
+       protected function addArgs( $args ) {
+               $this->mArgList = array_merge( $this->mArgList, $args );
+       }
+       
+       /**
+        * Does a given argument exist?
+        * @param $argId int The integer value (from zero) for the arg
+        * @return boolean
+        */
+       protected function hasArg( $argId = 0 ) {
+               return isset( $this->mArgs[ $argId ] ) ;
+       }
+
+       /**
+        * Get an argument.
+        * @param $argId int The integer value (from zero) for the arg
+        * @param $default mixed The default if it doesn't exist
+        * @return mixed
+        */
+       protected function getArg( $argId = 0, $default = null ) {
+               return $this->hasArg($argId) ? $this->mArgs[$argId] : $default;
+       }
+
+       /**
+        * Set the batch size.
+        * @param $s int The number of operations to do in a batch
+        */
+       protected function setBatchSize( $s = 0 ) {
+               $this->mBatchSize = $s;
+       }
+
+       /**
+        * Get the script's name
+        * @return String
+        */
+       public function getName() {
+               return $this->mSelf;
+       }
+
+       /**
+        * Return input from stdin.
+        * @param $length int The number of bytes to read. If null,
+        *        just return the handle
+        * @return mixed
+        */
+       protected function getStdin( $len = null ) {
+               $f = fopen( 'php://stdin', 'rt' );
+               if( !$len ) {
+                       return $f;
+               }
+               $input = fgets( $f, $len );
+               fclose ( $f );
+               return rtrim( $input );
+       }
+
+       /**
+        * Throw some output to the user. Scripts can call this with no fears,
+        * as we handle all --quiet stuff here
+        * @param $out String The text to show to the user
+        */
+       protected function output( $out ) {
+               if( $this->mQuiet ) {
+                       return;
+               }
+               $f = fopen( 'php://stdout', 'w' );
+               fwrite( $f, $out );
+               fclose( $f );
+       }
+
+       /**
+        * Throw an error to the user. Doesn't respect --quiet, so don't use
+        * this for non-error output
+        * @param $err String The error to display
+        * @param $die boolean If true, go ahead and die out.
+        */
+       protected function error( $err, $die = false ) {
+               $f = fopen( 'php://stderr', 'w' ); 
+               fwrite( $f, $err );
+               fclose( $f );
+               if( $die ) die();
+       }
+
+       /**
+        * Does the script need normal DB access? By default, we give Maintenance
+        * scripts admin rights to the DB (when available). Sometimes, a script needs
+        * normal access for a reason and sometimes they want no access. Subclasses 
+        * should override and return one of the following values, as needed:
+        *    Maintenance::DB_NONE  -  For no DB access at all
+        *    Maintenance::DB_STD   -  For normal DB access
+        *    Maintenance::DB_ADMIN -  For admin DB access, default
+        * @return int
+        */
+       protected function getDbType() {
+               return Maintenance :: DB_ADMIN;
+       }
+
+       /**
+        * Add the default parameters to the scripts
+        */
+       private function addDefaultParams() {
+               $this->addOption( 'help', "Display this help message" );
+               $this->addOption( 'quiet', "Whether to supress non-error output" );
+               $this->addOption( 'conf', "Location of LocalSettings.php, if not default", false, true );
+               $this->addOption( 'wiki', "For specifying the wiki ID", false, true );
+               $this->addOption( 'globals', "Output globals at the end of processing for debugging" );
+               // If we support a DB, show the options
+               if( $this->getDbType() > 0 ) {
+                       $this->addOption( 'dbuser', "The DB user to use for this script", false, true );
+                       $this->addOption( 'dbpass', "The password to use for this script", false, true );
+               }
+               // If we support $mBatchSize, show the option
+               if( $this->mBatchSize ) {
+                       $this->addOption( 'batch-size', 'Run this many operations ' .
+                               'per batch, default: ' . $this->mBatchSize , false, true );
+               }
+       }
+
+       /**
+        * Spawn a child maintenance script. Pass all of the current arguments
+        * to it.
+        * @param $maintClass String A name of a child maintenance class
+        * @param $classFile String Full path of where the child is
+        * @return Maintenance child
+        */
+       protected function spawnChild( $maintClass, $classFile = null ) {
+               // If we haven't already specified, kill setup procedures
+               // for child scripts, we've already got a sane environment
+               if( !defined( 'MW_NO_SETUP' ) ) {
+                       define( 'MW_NO_SETUP', true );
+               }
+               
+               // Make sure the class is loaded first
+               if( !class_exists( $maintClass ) ) {
+                       if( $classFile ) {
+                               require_once( $classFile );
+                       }
+                       if( !class_exists( $maintClass ) ) {
+                               $this->error( "Cannot spawn child: $maintClass\n" );
+                       }
+               }
+               
+               $child = new $maintClass();
+               $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
+               return $child;
+       }
+
+       /**
+        * Do some sanity checking and basic setup
+        */
+       public function setup() {
+               global $IP, $wgCommandLineMode, $wgUseNormalUser, $wgRequestTime;
+
+               # Abort if called from a web server
+               if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
+                       $this->error( "This script must be run from the command line\n", true );
+               }
+
+               # Make sure we can handle script parameters
+               if( !ini_get( 'register_argc_argv' ) ) {
+                       $this->error( "Cannot get command line arguments, register_argc_argv is set to false", true );
+               }
+
+               if( version_compare( phpversion(), '5.2.4' ) >= 0 ) {
+                       // Send PHP warnings and errors to stderr instead of stdout.
+                       // This aids in diagnosing problems, while keeping messages
+                       // out of redirected output.
+                       if( ini_get( 'display_errors' ) ) {
+                               ini_set( 'display_errors', 'stderr' );
+                       }
+
+                       // Don't touch the setting on earlier versions of PHP,
+                       // as setting it would disable output if you'd wanted it.
+
+                       // Note that exceptions are also sent to stderr when
+                       // command-line mode is on, regardless of PHP version.
+               }
+
+               # Set the memory limit
+               ini_set( 'memory_limit', -1 );
+
+               $wgRequestTime = microtime(true);
+
+               # Define us as being in Mediawiki
+               define( 'MEDIAWIKI', true );
+
+               # Setup $IP, using MW_INSTALL_PATH if it exists
+               $IP = strval( getenv('MW_INSTALL_PATH') ) !== ''
+                       ? getenv('MW_INSTALL_PATH')
+                       : realpath( dirname( __FILE__ ) . '/..' );
+               
+               $wgCommandLineMode = true;
+               # Turn off output buffering if it's on
+               @ob_end_flush();
+
+               if (!isset( $wgUseNormalUser ) ) {
+                       $wgUseNormalUser = false;
+               }
+
+               $this->loadParamsAndArgs();
+               $this->maybeHelp();
+               $this->validateParamsAndArgs();
+       }
+
+       /**
+        * Clear all params and arguments.
+        */
+       public function clearParamsAndArgs() {
+               $this->mOptions = array();
+               $this->mArgs = array();
+               $this->mInputLoaded = false;
+       }
+
+       /**
+        * Process command line arguments
+        * $mOptions becomes an array with keys set to the option names
+        * $mArgs becomes a zero-based array containing the non-option arguments
+        *
+        * @param $self String The name of the script, if any
+        * @param $opts Array An array of options, in form of key=>value
+        * @param $args Array An array of command line arguments
+        */
+       public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
+               # If we were given opts or args, set those and return early
+               if( $self ) {
+                       $this->mSelf = $self;
+                       $this->mInputLoaded = true;
+               }
+               if( $opts ) {
+                       $this->mOptions = $opts;
+                       $this->mInputLoaded = true;
+               }
+               if( $args ) {
+                       $this->mArgs = $args;
+                       $this->mInputLoaded = true;
+               }
+
+               # If we've already loaded input (either by user values or from $argv)
+               # skip on loading it again. The array_shift() will corrupt values if
+               # it's run again and again
+               if( $this->mInputLoaded ) {
+                       $this->loadSpecialVars();
+                       return;
+               }
+
+               global $argv;
+               $this->mSelf = array_shift( $argv );
+
+               $options = array();
+               $args = array();
+
+               # Parse arguments
+               for( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) {
+                       if ( $arg == '--' ) {
+                               # End of options, remainder should be considered arguments
+                               $arg = next( $argv );
+                               while( $arg !== false ) {
+                                       $args[] = $arg;
+                                       $arg = next( $argv );
+                               }
+                               break;
+                       } elseif ( substr( $arg, 0, 2 ) == '--' ) {
+                               # Long options
+                               $option = substr( $arg, 2 );
+                               if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) {
+                                       $param = next( $argv );
+                                       if ( $param === false ) {
+                                               $this->error( "$arg needs a value after it\n", true );
+                                       }
+                                       $options[$option] = $param;
+                               } else {
+                                       $bits = explode( '=', $option, 2 );
+                                       if( count( $bits ) > 1 ) {
+                                               $option = $bits[0];
+                                               $param = $bits[1];
+                                       } else {
+                                               $param = 1;
+                                       }
+                                       $options[$option] = $param;
+                               }
+                       } elseif ( substr( $arg, 0, 1 ) == '-' ) {
+                               # Short options
+                               for ( $p=1; $p<strlen( $arg ); $p++ ) {
+                                       $option = $arg{$p};
+                                       if ( $this->mParams[$option]['withArg'] ) {
+                                               $param = next( $argv );
+                                               if ( $param === false ) {
+                                                       $this->error( "$arg needs a value after it\n", true );
+                                               }
+                                               $options[$option] = $param;
+                                       } else {
+                                               $options[$option] = 1;
+                                       }
+                               }
+                       } else {
+                               $args[] = $arg;
+                       }
+               }
+
+               $this->mOptions = $options;
+               $this->mArgs = $args;
+               $this->loadSpecialVars();
+               $this->mInputLoaded = true;
+       }
+
+       /**
+        * Run some validation checks on the params, etc
+        */
+       private function validateParamsAndArgs() {
+               # Check to make sure we've got all the required ones
+               foreach( $this->mParams as $opt => $info ) {
+                       if( $info['require'] && !$this->hasOption($opt) ) {
+                               $this->error( "Param $opt required.\n", true );
+                       }
+               }
+
+               # Also make sure we've got enough arguments
+               if ( count( $this->mArgs ) < count( $this->mArgList ) ) {
+                       $this->error( "Not enough arguments passed", true );
+               }
+       }
+       
+       /**
+        * Handle the special variables that are global to all scripts
+        */
+       private function loadSpecialVars() {
+               if( $this->hasOption( 'dbuser' ) )
+                       $this->mDbUser = $this->getOption( 'dbuser' );
+               if( $this->hasOption( 'dbpass' ) )
+                       $this->mDbPass = $this->getOption( 'dbpass' );
+               if( $this->hasOption( 'quiet' ) )
+                       $this->mQuiet = true;
+               if( $this->hasOption( 'batch-size' ) )
+                       $this->mBatchSize = $this->getOption( 'batch-size' );
+       }
+
+       /**
+        * Maybe show the help.
+        * @param $force boolean Whether to force the help to show, default false
+        */
+       private function maybeHelp( $force = false ) {
+               if( $this->hasOption('help') || in_array( 'help', $this->mArgs ) || $force ) {
+                       $this->mQuiet = false;
+                       if( $this->mDescription ) {
+                               $this->output( "\n" . $this->mDescription . "\n" );
+                       }
+                       $this->output( "\nUsage: php " . $this->mSelf );
+                       if( $this->mParams ) {
+                               $this->output( " [--" . implode( array_keys( $this->mParams ), "|--" ) . "]" );
+                       }
+                       if( $this->mArgList ) {
+                               $this->output( " <" . implode( $this->mArgList, "> <" ) . ">" );
+                       }
+                       $this->output( "\n" );
+                       foreach( $this->mParams as $par => $info ) {
+                               $this->output( "\t$par : " . $info['desc'] . "\n" );
+                       }
+                       die( 1 );
+               }
+       }
+       
+       /**
+        * Handle some last-minute setup here.
+        */
+       private function finalSetup() {
+               global $wgCommandLineMode, $wgUseNormalUser, $wgShowSQLErrors;
+               global $wgTitle, $wgProfiling, $IP, $wgDBadminuser, $wgDBadminpassword;
+               global $wgDBuser, $wgDBpassword, $wgDBservers, $wgLBFactoryConf;
+               
+               # Turn off output buffering again, it might have been turned on in the settings files
+               if( ob_get_level() ) {
+                       ob_end_flush();
+               }
+               # Same with these
+               $wgCommandLineMode = true;
+
+               # If these were passed, use them
+               if( $this->mDbUser )
+                       $wgDBadminuser = $this->mDbUser;
+               if( $this->mDbPass )
+                       $wgDBadminpass = $this->mDbPass;
+
+               if ( empty( $wgUseNormalUser ) && isset( $wgDBadminuser ) ) {
+                       $wgDBuser = $wgDBadminuser;
+                       $wgDBpassword = $wgDBadminpassword;
+       
+                       if( $wgDBservers ) {
+                               foreach ( $wgDBservers as $i => $server ) {
+                                       $wgDBservers[$i]['user'] = $wgDBuser;
+                                       $wgDBservers[$i]['password'] = $wgDBpassword;
+                               }
+                       }
+                       if( isset( $wgLBFactoryConf['serverTemplate'] ) ) {
+                               $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser;
+                               $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword;
+                       }
+               }
+       
+               if ( defined( 'MW_CMDLINE_CALLBACK' ) ) {
+                       $fn = MW_CMDLINE_CALLBACK;
+                       $fn();
+               }
+       
+               $wgShowSQLErrors = true;
+               @set_time_limit( 0 );
+       
+               $wgProfiling = false; // only for Profiler.php mode; avoids OOM errors
+       }
+
+       /**
+        * Potentially debug globals. Originally a feature only
+        * for refreshLinks
+        */
+       public function globals() {
+               if( $this->hasOption( 'globals' ) ) {
+                       print_r( $GLOBALS );
+               }
+       }
+
+       /**
+        * Do setup specific to WMF
+        */
+       public function loadWikimediaSettings() {
+               global $IP, $wgNoDBParam, $wgUseNormalUser, $wgConf;
+
+               if ( empty( $wgNoDBParam ) ) {
+                       # Check if we were passed a db name
+                       if ( isset( $this->mOptions['wiki'] ) ) {
+                               $db = $this->mOptions['wiki'];
+                       } else {
+                               $db = array_shift( $this->mArgs );
+                       }
+                       list( $site, $lang ) = $wgConf->siteFromDB( $db );
+       
+                       # If not, work out the language and site the old way
+                       if ( is_null( $site ) || is_null( $lang ) ) {
+                               if ( !$db ) {
+                                       $lang = 'aa';
+                               } else {
+                                       $lang = $db;
+                               }
+                               if ( isset( $this->mArgs[0] ) ) {
+                                       $site = array_shift( $this->mArgs );
+                               } else {
+                                       $site = 'wikipedia';
+                               }
+                       }
+               } else {
+                       $lang = 'aa';
+                       $site = 'wikipedia';
+               }
+       
+               # This is for the IRC scripts, which now run as the apache user
+               # The apache user doesn't have access to the wikiadmin_pass command
+               if ( $_ENV['USER'] == 'apache' ) {
+               #if ( posix_geteuid() == 48 ) {
+                       $wgUseNormalUser = true;
+               }
+       
+               putenv( 'wikilang=' . $lang );
+       
+               $DP = $IP;
+               ini_set( 'include_path', ".:$IP:$IP/includes:$IP/languages:$IP/maintenance" );
+       
+               if ( $lang == 'test' && $site == 'wikipedia' ) {
+                       define( 'TESTWIKI', 1 );
+               }
+       }
+
+       /**
+        * Generic setup for most installs. Returns the location of LocalSettings
+        * @return String
+        */
+       public function loadSettings() {
+               global $wgWikiFarm, $wgCommandLineMode, $IP, $DP;
+
+               $wgWikiFarm = false;
+               if ( isset( $this->mOptions['conf'] ) ) {
+                       $settingsFile = $this->mOptions['conf'];
+               } else {
+                       $settingsFile = "$IP/LocalSettings.php";
+               }
+               if ( isset( $this->mOptions['wiki'] ) ) {
+                       $bits = explode( '-', $this->mOptions['wiki'] );
+                       if ( count( $bits ) == 1 ) {
+                               $bits[] = '';
+                       }
+                       define( 'MW_DB', $bits[0] );
+                       define( 'MW_PREFIX', $bits[1] );
+               }
+       
+               if ( ! is_readable( $settingsFile ) ) {
+                       $this->error( "A copy of your installation's LocalSettings.php\n" .
+                                               "must exist and be readable in the source directory.\n", true );
+               }
+               $wgCommandLineMode = true;
+               $DP = $IP;
+               $this->finalSetup();
+               return $settingsFile;
+       }
+       
+       /**
+        * Support function for cleaning up redundant text records
+        * @param $delete boolean Whether or not to actually delete the records
+        * @author Rob Church <robchur@gmail.com>
+        */
+       protected function purgeRedundantText( $delete = true ) {
+               # Data should come off the master, wrapped in a transaction
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+
+               $tbl_arc = $dbw->tableName( 'archive' );
+               $tbl_rev = $dbw->tableName( 'revision' );
+               $tbl_txt = $dbw->tableName( 'text' );
+
+               # Get "active" text records from the revisions table
+               $this->output( "Searching for active text records in revisions table..." );
+               $res = $dbw->query( "SELECT DISTINCT rev_text_id FROM $tbl_rev" );
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $cur[] = $row->rev_text_id;
+               }
+               $this->output( "done.\n" );
+
+               # Get "active" text records from the archive table
+               $this->output( "Searching for active text records in archive table..." );
+               $res = $dbw->query( "SELECT DISTINCT ar_text_id FROM $tbl_arc" );
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $cur[] = $row->ar_text_id;
+               }
+               $this->output( "done.\n" );
+
+               # Get the IDs of all text records not in these sets
+               $this->output( "Searching for inactive text records..." );
+               $set = implode( ', ', $cur );
+               $res = $dbw->query( "SELECT old_id FROM $tbl_txt WHERE old_id NOT IN ( $set )" );
+               $old = array();
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $old[] = $row->old_id;
+               }
+               $this->output( "done.\n" );
+
+               # Inform the user of what we're going to do
+               $count = count( $old );
+               $this->output( "$count inactive items found.\n" );
+
+               # Delete as appropriate
+               if( $delete && $count ) {
+                       $this->output( "Deleting..." );
+                       $set = implode( ', ', $old );
+                       $dbw->query( "DELETE FROM $tbl_txt WHERE old_id IN ( $set )" );
+                       $this->output( "done.\n" );
+               }
+
+               # Done
+               $dbw->commit();
+       }
+       
+       /**
+        * Get the maintenance directory.
+        */
+       protected function getDir() {
+               return dirname( __FILE__ );
+       }
+
+       /**
+        * Get the list of available maintenance scripts. Note
+        * that if you call this _before_ calling doMaintenance
+        * you won't have any extensions in it yet
+        * @return array
+        */
+       public static function getMaintenanceScripts() {
+               global $wgMaintenanceScripts;
+               return $wgMaintenanceScripts + self::getCoreScripts();
+       }
+       
+       /**
+        * Return all of the core maintenance scripts
+        * @todo Don't make this list, maybe just scan all the files in /maintenance?
+        * @return array
+        */
+       private static function getCoreScripts() {
+               if( !self::$mCoreScripts ) {
+                       $d = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
+                       self::$mCoreScripts = array(
+                               # Main script list
+                               'AddWiki'                  => $d . 'addwiki.php',
+                               'AttachLatest'             => $d . 'attachLatest.php',
+                               'BenchmarkPurge'           => $d . 'benchmarkPurge.php',
+                               'ChangePassword'           => $d . 'changePassword.php',
+                               'CheckAutoLoader'          => $d . 'checkAutoLoader.php',
+                               'CheckBadRedirects'        => $d . 'checkBadRedirects.php',
+                               'CheckImages'              => $d . 'checkImages.php',
+                               'CheckSyntax'              => $d . 'checkSyntax.php',
+                               'CheckUsernames'           => $d . 'checkUsernames.php',
+                               'CleanupSpam'              => $d . 'cleanupSpam.php',
+                               'ClearInterwikiCache'      => $d . 'clear_interwiki_cache.php',
+                               'clear_stats'              => $d . 'clear_stats.php',
+                               'ConvertLinks'             => $d . 'convertLinks.php',
+                               'ConvertUserOptions'       => $d . 'convertUserOptions.php',
+                               'CreateAndPromote'         => $d . 'createAndPromote.php',
+                               'DeleteArchivedFiles'      => $d . 'deleteArchivedFiles.php',
+                               'DeleteArchivedRevisions'  => $d . 'deleteArchivedRevisions.php',
+                               'DeleteBatch'              => $d . 'deleteBatch.php',
+                               'DeleteDefaultMessages'    => $d . 'deleteDefaultMessages.php',
+                               'DeleteImageCache'         => $d . 'deleteImageMemcached.php',
+                               'DeleteOldRevisions'       => $d . 'deleteOldRevisions.php',
+                               'DeleteOrphanedRevisions'  => $d . 'deleteOrphanedRevisions.php',
+                               'DeleteRevision'           => $d . 'deleteRevision.php',
+                               'DumpLinks'                => $d . 'dumpLinks.php',
+                               'DumpSisterSites'          => $d . 'dumpSisterSites.php',
+                               'UploadDumper'             => $d . 'dumpUploads.php',
+                               'EditCLI'                  => $d . 'edit.php',
+                               'EvalPrompt'               => $d . 'eval.php',
+                               'FetchText'                => $d . 'fetchText.php',
+                               'FindHooks'                => $d . 'findhooks.php',
+                               'FixSlaveDesync'           => $d . 'fixSlaveDesync.php',
+                               'FixTimestamps'            => $d . 'fixTimestamps.php',
+                               'FixUserRegistration'      => $d . 'fixUserRegistration.php',
+                               'GenerateSitemap'          => $d . 'generateSitemap.php',
+                               'GetLagTimes'              => $d . 'getLagTimes.php',
+                               'GetSlaveServer'           => $d . 'getSlaveServer.php',
+                               'InitEditCount'            => $d . 'initEditCount.php',
+                               'InitStats'                => $d . 'initStats.php',
+                               'mcTest'                   => $d . 'mctest.php',
+                               'MoveBatch'                => $d . 'moveBatch.php',
+                               'nextJobDb'                => $d . 'nextJobDB.php',
+                               'NukeNS'                   => $d . 'nukeNS.php',
+                               'NukePage'                 => $d . 'nukePage.php',
+                               'Orphans'                  => $d . 'orphans.php',
+                               'PopulateCategory'         => $d . 'populateCategory.php',
+                               'PopulateLogSearch'        => $d . 'populateLogSearch.php',
+                               'PopulateParentId'         => $d . 'populateParentId.php',
+                               'Protect'                  => $d . 'protect.php',
+                               'PurgeList'                => $d . 'purgeList.php',
+                               'PurgeOldText'             => $d . 'purgeOldText.php',
+                               'ReassignEdits'            => $d . 'reassignEdits.php',
+                               'RebuildAll'               => $d . 'rebuildall.php',
+                               'RebuildFileCache'         => $d . 'rebuildFileCache.php',
+                               'RebuildLocalisationCache' => $d . 'rebuildLocalisationCache.php',
+                               'RebuildMessages'          => $d . 'rebuildmessages.php',
+                               'RebuildRecentchanges'     => $d . 'rebuildrecentchanges.php',
+                               'RebuildTextIndex'         => $d . 'rebuildtextindex.php',
+                               'RefreshImageCount'        => $d . 'refreshImageCount.php',
+                               'RefreshLinks'             => $d . 'refreshLinks.php',
+                               'RemoveUnusedAccounts'     => $d . 'removeUnusedAccounts.php',
+                               'RenameDbPrefix'           => $d . 'renameDbPrefix.php',
+                               'RenameWiki'               => $d . 'renamewiki.php',
+                               'DumpRenderer'             => $d . 'renderDump.php',
+                               'RunJobs'                  => $d . 'runJobs.php',
+                               'ShowJobs'                 => $d . 'showJobs.php',
+                               'ShowStats'                => $d . 'showStats.php',
+                               'MwSql'                    => $d . 'sql.php',
+                               'CacheStats'               => $d . 'stats.php',
+                               'Undelete'                 => $d . 'undelete.php',
+                               'UpdateArticleCount'       => $d . 'updateArticleCount.php',
+                               'UpdateRestrictions'       => $d . 'updateRestrictions.php',
+                               'UpdateSearchIndex'        => $d . 'updateSearchIndex.php',
+                               'UpdateSpecialPages'       => $d . 'updateSpecialPages.php',
+                               'WaitForSlave'             => $d . 'waitForSlave.php',
+
+                               # Language scripts
+                               'AllTrans' => $d . 'language/alltrans.php',
+                       );
+               }
+               return self::$mCoreScripts;
+       }
+}
index 8b82017..e721014 100644 (file)
  * Add a new wiki
  * Wikimedia specific!
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$wgNoDBParam = true;
+require_once( "Maintenance.php" );
 
-require_once( "commandLine.inc" );
-require_once( "rebuildInterwiki.inc" );
-require_once( "languages/Names.php" );
-if ( count( $args ) != 3 ) {
-       wfDie( "Usage: php addwiki.php <language> <site> <dbname>\nThe site for Wikipedia is 'wikipedia'.\n" );
-}
+class AddWiki extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Add a new wiki to the family. Wikimedia specific!";
+               $this->addArgs( 'language', 'site', 'dbname' );
+       }
+       
+       public function execute() {
+               global $IP, $wgLanguageNames, $wgDefaultExternalStore, $wgNoDBParam;
 
-addWiki( $args[0], $args[1], $args[2] );
+               $wgNoDBParam = true;
+               $lang = $this->getArg(0);
+               $site = $this->getArg(1);
+               $dbName = $this->getArg(2);
 
-# -----------------------------------------------------------------
+               if ( !isset( $wgLanguageNames[$lang] ) ) {
+                       $this->error( "Language $lang not found in \$wgLanguageNames\n", true );
+               }
+               $name = $wgLanguageNames[$lang];
 
-function addWiki( $lang, $site, $dbName )
-{
-       global $IP, $wgLanguageNames, $wgDefaultExternalStore;
+               $dbw = wfGetDB( DB_MASTER );
+               $common = "/home/wikipedia/common";
 
-       if ( !isset( $wgLanguageNames[$lang] ) ) {
-               print "Language $lang not found in \$wgLanguageNames\n";
-               return;
-       }
-       $name = $wgLanguageNames[$lang];
+               $this->output( "Creating database $dbName for $lang.$site ($name)\n" );
 
-       $dbw = wfGetDB( DB_MASTER );
-       $common = "/home/wikipedia/common";
-       $maintenance = "$IP/maintenance";
+               # Set up the database
+               $dbw->query( "SET table_type=Innodb" );
+               $dbw->query( "CREATE DATABASE $dbName" );
+               $dbw->selectDB( $dbName );
 
-       print "Creating database $dbName for $lang.$site ($name)\n";
-       
-       # Set up the database
-       $dbw->query( "SET table_type=Innodb" );
-       $dbw->query( "CREATE DATABASE $dbName" );
-       $dbw->selectDB( $dbName );
+               $this->output( "Initialising tables\n" );
+               $dbw->sourceFile( $this->getDir() . '/tables.sql' );
+               $dbw->sourceFile( "$IP/extensions/OAI/update_table.sql" );
+               $dbw->sourceFile( "$IP/extensions/AntiSpoof/sql/patch-antispoof.mysql.sql" );
+               $dbw->sourceFile( "$IP/extensions/CheckUser/cu_changes.sql" );
+               $dbw->sourceFile( "$IP/extensions/CheckUser/cu_log.sql" );
+               $dbw->sourceFile( "$IP/extensions/TitleKey/titlekey.sql" );
+               $dbw->sourceFile( "$IP/extensions/Oversight/hidden.sql" );
+               $dbw->sourceFile( "$IP/extensions/GlobalBlocking/localdb_patches/setup-global_block_whitelist.sql" );
+               $dbw->sourceFile( "$IP/extensions/AbuseFilter/abusefilter.tables.sql" );
 
-       print "Initialising tables\n";
-       dbsource( "$maintenance/tables.sql", $dbw );
-       dbsource( "$IP/extensions/OAI/update_table.sql", $dbw );
-       dbsource( "$IP/extensions/AntiSpoof/sql/patch-antispoof.mysql.sql", $dbw );
-       dbsource( "$IP/extensions/CheckUser/cu_changes.sql", $dbw );
-       dbsource( "$IP/extensions/CheckUser/cu_log.sql", $dbw );
-       dbsource( "$IP/extensions/TitleKey/titlekey.sql", $dbw );
-       dbsource( "$IP/extensions/Oversight/hidden.sql", $dbw );
-       dbsource( "$IP/extensions/GlobalBlocking/localdb_patches/setup-global_block_whitelist.sql", $dbw );
-       dbsource( "$IP/extensions/AbuseFilter/abusefilter.tables.sql", $dbw );
+               $dbw->query( "INSERT INTO site_stats(ss_row_id) VALUES (1)" );
 
-       $dbw->query( "INSERT INTO site_stats(ss_row_id) VALUES (1)" );
+               # Initialise external storage
+               if ( is_array( $wgDefaultExternalStore ) ) {
+                       $stores = $wgDefaultExternalStore;
+               } elseif ( $stores ) {
+                       $stores = array( $wgDefaultExternalStore );
+               } else {
+                       $stores = array();
+               }
+               if ( count( $stores ) ) {
+                       global $wgDBuser, $wgDBpassword, $wgExternalServers;
+                       foreach ( $stores as $storeURL ) {
+                               $m = array();
+                               if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) {
+                                       continue;
+                               }
 
-       # Initialise external storage
-       if ( is_array( $wgDefaultExternalStore ) ) {
-               $stores = $wgDefaultExternalStore;
-       } elseif ( $stores ) {
-               $stores = array( $wgDefaultExternalStore );
-       } else {
-               $stores = array();
-       }
-       if ( count( $stores ) ) {
-               require_once( 'ExternalStoreDB.php' );
-               global $wgDBuser, $wgDBpassword, $wgExternalServers;
-               foreach ( $stores as $storeURL ) {
-                       $m = array();
-                       if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) {
-                               continue;
-                       }
-                       
-                       $cluster = $m[1];
-                       print "Initialising external storage $cluster...\n";
-                       
-                       # Hack
-                       $wgExternalServers[$cluster][0]['user'] = $wgDBuser;
-                       $wgExternalServers[$cluster][0]['password'] = $wgDBpassword;
+                               $cluster = $m[1];
+                               $this->output( "Initialising external storage $cluster...\n" );
 
-                       $store = new ExternalStoreDB;
-                       $extdb = $store->getMaster( $cluster );
-                       $extdb->query( "SET table_type=InnoDB" );
-                       $extdb->query( "CREATE DATABASE $dbName" );
-                       $extdb->selectDB( $dbName );
+                               # Hack
+                               $wgExternalServers[$cluster][0]['user'] = $wgDBuser;
+                               $wgExternalServers[$cluster][0]['password'] = $wgDBpassword;
 
-                       # Hack x2
-                       $blobsTable = $store->getTable( $extdb );
-                       $blobsFile = popen( "sed s/blobs\\\\\\>/$blobsTable/ $maintenance/storage/blobs.sql", 'r' );
-                       $extdb->sourceStream( $blobsFile );
-                       pclose( $blobsFile );
-                       $extdb->immediateCommit();
+                               $store = new ExternalStoreDB;
+                               $extdb = $store->getMaster( $cluster );
+                               $extdb->query( "SET table_type=InnoDB" );
+                               $extdb->query( "CREATE DATABASE $dbName" );
+                               $extdb->selectDB( $dbName );
+
+                               # Hack x2
+                               $blobsTable = $store->getTable( $extdb );
+                               $sedCmd = "sed s/blobs\\\\\\>/$blobsTable/ " . $this->getDir() . "/storage/blobs.sql";
+                               $blobsFile = popen( $sedCmd, 'r' );
+                               $extdb->sourceStream( $blobsFile );
+                               pclose( $blobsFile );
+                               $extdb->immediateCommit();
+                       }
                }
-       }
 
-       global $wgTitle, $wgArticle;
-       $wgTitle = Title::newFromText( wfMsgWeirdKey( "mainpage/$lang" ) );
-       print "Writing main page to " . $wgTitle->getPrefixedDBkey() . "\n";
-       $wgArticle = new Article( $wgTitle );
-       $ucsite = ucfirst( $site );
+               global $wgTitle, $wgArticle;
+               $wgTitle = Title::newFromText( wfMsgWeirdKey( "mainpage/$lang" ) );
+               $this->output( "Writing main page to " . $wgTitle->getPrefixedDBkey() . "\n" );
+               $wgArticle = new Article( $wgTitle );
+               $ucsite = ucfirst( $site );
 
-       $wgArticle->insertNewArticle( <<<EOT
-==This subdomain is reserved for the creation of a [[wikimedia:Our projects|$ucsite]] in '''[[w:en:{$name}|{$name}]]''' language==
+               $wgArticle->insertNewArticle( $this->getFirstArticle( $ucsite, $name ), '', false, false );
 
-* Please '''do not start editing''' this new site. This site has a test project on the [[incubator:|Wikimedia Incubator]] (or on the [[betawikiversity:|BetaWikiversity]] or on the [[oldwikisource:|Old Wikisource]]) and it will be imported to here.
+               $this->output( "Adding to dblists\n" );
 
-* If you would like to help translating the interface to this language, please do not translate here, but go to [[betawiki:|Betawiki]], a special wiki for translating the interface. That way everyone can use it on every wiki using the [[mw:|same software]].
+               # Add to dblist
+               $file = fopen( "$common/all.dblist", "a" );
+               fwrite( $file, "$dbName\n" );
+               fclose( $file );
 
-* For information about how to edit and for other general help, see [[m:Help:Contents|Help on Wikimedia's Meta-Wiki]] or [[mw:Help:Contents|Help on MediaWiki.org]].
+               # Update the sublists
+               shell_exec("cd $common && ./refresh-dblist");
 
-== Sister projects ==
-<span class="plainlinks">
-[http://www.wikipedia.org Wikipedia] |
-[http://www.wiktionary.org Wiktonary] |
-[http://www.wikibooks.org Wikibooks] |
-[http://www.wikinews.org Wikinews] |
-[http://www.wikiquote.org Wikiquote] |
-[http://www.wikisource.org Wikisource]
-[http://www.wikiversity.org Wikiversity]
-</span>
+               #print "Constructing interwiki SQL\n";
+               # Rebuild interwiki tables
+               #passthru( '/home/wikipedia/conf/interwiki/update' );
 
-See Wikimedia's [[m:|Meta-Wiki]] for the coordination of these projects.
+               $this->output( "Script ended. You still have to:
+       * Add any required settings in InitialiseSettings.php
+       * Run sync-common-all
+       * Run /home/wikipedia/conf/interwiki/update
+       " );
+       }
+       
+       private function getFirstArticle( $ucsite, $name ) {
+               return <<<EOT
+       ==This subdomain is reserved for the creation of a [[wikimedia:Our projects|$ucsite]] in '''[[w:en:{$name}|{$name}]]''' language==
 
-[[aa:]]
-[[af:]]
-[[als:]]
-[[ar:]]
-[[de:]]
-[[en:]]
-[[as:]]
-[[ast:]]
-[[ay:]]
-[[az:]]
-[[bcl:]]
-[[be:]]
-[[bg:]]
-[[bn:]]
-[[bo:]]
-[[bs:]]
-[[cs:]]
-[[co:]]
-[[cs:]]
-[[cy:]]
-[[da:]]
-[[el:]]
-[[eo:]]
-[[es:]]
-[[et:]]
-[[eu:]]
-[[fa:]]
-[[fi:]]
-[[fr:]]
-[[fy:]]
-[[ga:]]
-[[gl:]]
-[[gn:]]
-[[gu:]]
-[[he:]]
-[[hi:]]
-[[hr:]]
-[[hsb:]]
-[[hy:]]
-[[ia:]]
-[[id:]]
-[[is:]]
-[[it:]]
-[[ja:]]
-[[ka:]]
-[[kk:]]
-[[km:]]
-[[kn:]]
-[[ko:]]
-[[ks:]]
-[[ku:]]
-[[ky:]]
-[[la:]]
-[[ln:]]
-[[lo:]]
-[[lt:]]
-[[lv:]]
-[[hu:]]
-[[mi:]]
-[[mk:]]
-[[ml:]]
-[[mn:]]
-[[mr:]]
-[[ms:]]
-[[mt:]]
-[[my:]]
-[[na:]]
-[[nah:]]
-[[nds:]]
-[[ne:]]
-[[nl:]]
-[[no:]]
-[[oc:]]
-[[om:]]
-[[pa:]]
-[[pl:]]
-[[ps:]]
-[[pt:]]
-[[qu:]]
-[[ro:]]
-[[ru:]]
-[[sa:]]
-[[si:]]
-[[sk:]]
-[[sl:]]
-[[sq:]]
-[[sr:]]
-[[sv:]]
-[[sw:]]
-[[ta:]]
-[[te:]]
-[[tg:]]
-[[th:]]
-[[tk:]]
-[[tl:]]
-[[tr:]]
-[[tt:]]
-[[ug:]]
-[[uk:]]
-[[ur:]]
-[[uz:]]
-[[vi:]]
-[[vo:]]
-[[xh:]]
-[[yo:]]
-[[za:]]
-[[zh:]]
-[[zu:]]
+       * Please '''do not start editing''' this new site. This site has a test project on the [[incubator:|Wikimedia Incubator]] (or on the [[betawikiversity:|BetaWikiversity]] or on the [[oldwikisource:|Old Wikisource]]) and it will be imported to here.
 
-EOT
-, '', false, false );
+       * If you would like to help translating the interface to this language, please do not translate here, but go to [[betawiki:|Betawiki]], a special wiki for translating the interface. That way everyone can use it on every wiki using the [[mw:|same software]].
 
-       print "Adding to dblists\n";
+       * For information about how to edit and for other general help, see [[m:Help:Contents|Help on Wikimedia's Meta-Wiki]] or [[mw:Help:Contents|Help on MediaWiki.org]].
 
-       # Add to dblist
-       $file = fopen( "$common/all.dblist", "a" );
-       fwrite( $file, "$dbName\n" );
-       fclose( $file );
+       == Sister projects ==
+       <span class="plainlinks">
+       [http://www.wikipedia.org Wikipedia] |
+       [http://www.wiktionary.org Wiktonary] |
+       [http://www.wikibooks.org Wikibooks] |
+       [http://www.wikinews.org Wikinews] |
+       [http://www.wikiquote.org Wikiquote] |
+       [http://www.wikisource.org Wikisource]
+       [http://www.wikiversity.org Wikiversity]
+       </span>
 
-       # Update the sublists
-       shell_exec("cd $common && ./refresh-dblist");
+       See Wikimedia's [[m:|Meta-Wiki]] for the coordination of these projects.
 
-       #print "Constructing interwiki SQL\n";
-       # Rebuild interwiki tables
-       #passthru( '/home/wikipedia/conf/interwiki/update' );
+       [[aa:]]
+       [[af:]]
+       [[als:]]
+       [[ar:]]
+       [[de:]]
+       [[en:]]
+       [[as:]]
+       [[ast:]]
+       [[ay:]]
+       [[az:]]
+       [[bcl:]]
+       [[be:]]
+       [[bg:]]
+       [[bn:]]
+       [[bo:]]
+       [[bs:]]
+       [[cs:]]
+       [[co:]]
+       [[cs:]]
+       [[cy:]]
+       [[da:]]
+       [[el:]]
+       [[eo:]]
+       [[es:]]
+       [[et:]]
+       [[eu:]]
+       [[fa:]]
+       [[fi:]]
+       [[fr:]]
+       [[fy:]]
+       [[ga:]]
+       [[gl:]]
+       [[gn:]]
+       [[gu:]]
+       [[he:]]
+       [[hi:]]
+       [[hr:]]
+       [[hsb:]]
+       [[hy:]]
+       [[ia:]]
+       [[id:]]
+       [[is:]]
+       [[it:]]
+       [[ja:]]
+       [[ka:]]
+       [[kk:]]
+       [[km:]]
+       [[kn:]]
+       [[ko:]]
+       [[ks:]]
+       [[ku:]]
+       [[ky:]]
+       [[la:]]
+       [[ln:]]
+       [[lo:]]
+       [[lt:]]
+       [[lv:]]
+       [[hu:]]
+       [[mi:]]
+       [[mk:]]
+       [[ml:]]
+       [[mn:]]
+       [[mr:]]
+       [[ms:]]
+       [[mt:]]
+       [[my:]]
+       [[na:]]
+       [[nah:]]
+       [[nds:]]
+       [[ne:]]
+       [[nl:]]
+       [[no:]]
+       [[oc:]]
+       [[om:]]
+       [[pa:]]
+       [[pl:]]
+       [[ps:]]
+       [[pt:]]
+       [[qu:]]
+       [[ro:]]
+       [[ru:]]
+       [[sa:]]
+       [[si:]]
+       [[sk:]]
+       [[sl:]]
+       [[sq:]]
+       [[sr:]]
+       [[sv:]]
+       [[sw:]]
+       [[ta:]]
+       [[te:]]
+       [[tg:]]
+       [[th:]]
+       [[tk:]]
+       [[tl:]]
+       [[tr:]]
+       [[tt:]]
+       [[ug:]]
+       [[uk:]]
+       [[ur:]]
+       [[uz:]]
+       [[vi:]]
+       [[vo:]]
+       [[xh:]]
+       [[yo:]]
+       [[za:]]
+       [[zh:]]
+       [[zu:]]
 
-       print "Script ended. You still have to:
-* Add any required settings in InitialiseSettings.php
-* Run sync-common-all
-* Run /home/wikipedia/conf/interwiki/update
-";
+EOT;
+       }
 }
 
+$maintClass = "AddWiki";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/archives/rebuildRecentchanges.inc b/maintenance/archives/rebuildRecentchanges.inc
deleted file mode 100644 (file)
index 65ba560..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/**
- * Rebuild recent changes table
- *
- * @file
- * @deprecated
- * @ingroup MaintenanceArchive
- * @defgroup MaintenanceArchive MaintenanceArchive
- */
-
-/** */
-function rebuildRecentChangesTable()
-{
-       $sql = "DROP TABLE IF EXISTS recentchanges";
-       wfQuery( $sql );
-
-       $sql = "CREATE TABLE recentchanges (
-  rc_timestamp varchar(14) binary NOT NULL default '',
-  rc_cur_time varchar(14) binary NOT NULL default '',
-  rc_user int(10) unsigned NOT NULL default '0',
-  rc_user_text varchar(255) binary NOT NULL default '',
-  rc_namespace tinyint(3) unsigned NOT NULL default '0',
-  rc_title varchar(255) binary NOT NULL default '',
-  rc_comment varchar(255) binary NOT NULL default '',
-  rc_minor tinyint(3) unsigned NOT NULL default '0',
-  rc_new tinyint(3) unsigned NOT NULL default '0',
-  rc_cur_id int(10) unsigned NOT NULL default '0',
-  rc_this_oldid int(10) unsigned NOT NULL default '0',
-  rc_last_oldid int(10) unsigned NOT NULL default '0',
-  INDEX rc_cur_id (rc_cur_id),
-  INDEX rc_cur_time (rc_cur_time),
-  INDEX rc_timestamp (rc_timestamp),
-  INDEX rc_namespace (rc_namespace),
-  INDEX rc_title (rc_title)
-) ENGINE=MyISAM PACK_KEYS=1;";
-       wfQuery( $sql );
-
-       print( "Loading from CUR table...\n" );
-
-       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,rc_user," .
-         "rc_user_text,rc_namespace,rc_title,rc_comment,rc_minor,rc_new," .
-         "rc_cur_id,rc_this_oldid,rc_last_oldid) SELECT cur_timestamp," .
-         "cur_timestamp,cur_user,cur_user_text,cur_namespace,cur_title," .
-         "cur_comment,cur_minor_edit,cur_is_new,cur_id,0,0 FROM cur " .
-         "ORDER BY cur_timestamp DESC LIMIT 5000";
-       wfQuery( $sql );
-
-       print( "Loading from OLD table...\n" );
-
-       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,rc_user," .
-      "rc_user_text,rc_namespace,rc_title,rc_comment,rc_minor,rc_new," .
-      "rc_cur_id,rc_this_oldid,rc_last_oldid) SELECT old_timestamp,''," .
-         "old_user,old_user_text,old_namespace,old_title,old_comment," .
-         "old_minor_edit,0,0,old_id,0 FROM old ORDER BY old_timestamp " .
-         "DESC LIMIT 5000";
-       wfQuery( $sql );
-
-       $sql = "SELECT rc_timestamp FROM recentchanges " .
-         "ORDER BY rc_timestamp DESC LIMIT 5000,1";
-       $res = wfQuery( $sql );
-       $obj = wfFetchObject( $res );
-       $ts = $obj->rc_timestamp;
-
-       $sql = "DELETE FROM recentchanges WHERE rc_timestamp < '{$ts}'";
-       wfQuery( $sql );
-
-       rebuildRecentChangesTablePass2();
-}
-
-function rebuildRecentChangesTablePass2()
-{
-       $ns = $id = $count = 0;
-       $title = $ct =  "";
-
-       print( "Updating links...\n" );
-
-       $sql = "SELECT rc_namespace,rc_title,rc_timestamp FROM recentchanges " .
-         "ORDER BY rc_namespace,rc_title,rc_timestamp DESC";
-       $res = wfQuery( $sql );
-
-       while ( $obj = wfFetchObject( $res ) ) {
-               if ( ! ( $ns == $obj->rc_namespace &&
-                          0 == strcmp( $title, wfStrencode( $obj->rc_title ) ) ) ) {
-
-                       $ns = $obj->rc_namespace;
-                       $title = wfStrencode( $obj->rc_title );
-
-                       $sql = "SELECT cur_id,cur_timestamp FROM cur WHERE " .
-                         "cur_namespace={$ns} AND cur_title='{$title}'";
-                       $res2 = wfQuery( $sql );
-                       $obj2 = wfFetchObject( $res2 );
-
-                       $id = $obj2->cur_id;
-                       $ct = $obj2->cur_timestamp;
-               }
-               $sql = "SELECT old_id FROM old WHERE old_namespace={$ns} " .
-                 "AND old_title='{$title}' AND old_timestamp < '" .
-                 "{$obj->rc_timestamp}' ORDER BY old_timestamp DESC LIMIT 1";
-               $res2 = wfQuery( $sql );
-
-               if ( 0 != wfNumRows( $res2 ) ) {
-                       $obj2 = wfFetchObject( $res2 );
-
-                       $sql = "UPDATE recentchanges SET rc_cur_id={$id},rc_cur_time=" .
-                         "'{$ct}',rc_last_oldid={$obj2->old_id} WHERE " .
-                         "rc_namespace={$ns} AND rc_title='{$title}' AND " .
-                         "rc_timestamp='{$obj->rc_timestamp}'";
-                       wfQuery( $sql );
-               } else {
-                       $sql = "UPDATE recentchanges SET rc_cur_id={$id},rc_cur_time=" .
-                         "'{$ct}' WHERE rc_namespace={$ns} AND rc_title='{$title}' " .
-                         "AND rc_timestamp='{$obj->rc_timestamp}'";
-                       wfQuery( $sql );
-               }
-
-               if ( 0 == ( ++$count % 500 ) ) {
-                       printf( "%d records processed.\n", $count );
-               }
-       }
-}
-
-
-?>
diff --git a/maintenance/archives/upgradeWatchlist.php b/maintenance/archives/upgradeWatchlist.php
deleted file mode 100644 (file)
index ee01673..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
- * @file
- * @deprecated
- * @ingroup MaintenanceArchive
- */
-
-/** */
-print "This script is obsolete!";
-print "It is retained in the source here in case some of its
-code might be useful for ad-hoc conversion tasks, but it is
-not maintained and probably won't even work as is.";
-exit(1);
-
-# Convert watchlists to new format
-
-global $IP;
-require_once( "../LocalSettings.php" );
-require_once( "$IP/Setup.php" );
-
-$wgTitle = Title::newFromText( "Rebuild links script" );
-set_time_limit(0);
-
-$wgDBuser                      = "wikiadmin";
-$wgDBpassword          = $wgDBadminpassword;
-
-$sql = "DROP TABLE IF EXISTS watchlist";
-wfQuery( $sql, DB_MASTER );
-$sql = "CREATE TABLE watchlist (
-  wl_user int(5) unsigned NOT NULL,
-  wl_page int(8) unsigned NOT NULL,
-  UNIQUE KEY (wl_user, wl_page)
-) ENGINE=MyISAM PACK_KEYS=1";
-wfQuery( $sql, DB_MASTER );
-
-$lc = new LinkCache;
-
-# Now, convert!
-$sql = "SELECT user_id,user_watch FROM user";
-$res = wfQuery( $sql, DB_SLAVE );
-$nu = wfNumRows( $res );
-$sql = "INSERT into watchlist (wl_user,wl_page) VALUES ";
-$i = $n = 0;
-while( $row = wfFetchObject( $res ) ) {
-       $list = explode( "\n", $row->user_watch );
-       $bits = array();
-       foreach( $list as $title ) {
-               if( $id = $lc->addLink( $title ) and ! $bits[$id]++) {
-                       $sql .= ($i++ ? "," : "") . "({$row->user_id},{$id})";
-               }
-       }
-       if( ($n++ % 100) == 0 ) echo "$n of $nu users done...\n";
-}
-echo "$n users done.\n";
-if( $i ) {
-       wfQuery( $sql, DB_MASTER );
-}
-
-
-# Add index
-# is this necessary?
-$sql = "ALTER TABLE watchlist
-  ADD INDEX wl_user (wl_user),
-  ADD INDEX wl_page (wl_page)";
-#wfQuery( $sql, DB_MASTER );
-
-
index 8d680af..71d5c79 100644 (file)
@@ -1,8 +1,8 @@
 <?php
-// quick hackjob to fix damages imports on wikisource
-// page records have page_latest wrong
-
 /**
+ * quick hackjob to fix damages imports on wikisource
+ * page records have page_latest wrong
+ *
  * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
  * http://www.mediawiki.org/
  *
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
  * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
-
-$fixit = isset( $options['fix'] );
-$fname = 'attachLatest';
-
-echo "Looking for pages with page_latest set to 0...\n";
-$dbw = wfGetDB( DB_MASTER );
-$result = $dbw->select( 'page',
-       array( 'page_id', 'page_namespace', 'page_title' ),
-       array( 'page_latest' => 0 ),
-       $fname );
+require_once( "Maintenance.php" );
 
-$n = 0;
-while( $row = $dbw->fetchObject( $result ) ) {
-       $pageId = intval( $row->page_id );
-       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-       $name = $title->getPrefixedText();
-       $latestTime = $dbw->selectField( 'revision',
-               'MAX(rev_timestamp)',
-               array( 'rev_page' => $pageId ),
-               $fname );
-       if( !$latestTime ) {
-               echo wfWikiID()." $pageId [[$name]] can't find latest rev time?!\n";
-               continue;
+class AttachLatest extends Maintenance {
+       
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( "fix", "Actually fix the entries, will dry run otherwise" );
+               $this->mDescription = "Fix page_latest entries in the page table";
        }
+       
+       public function execute() {
+               $this->output( "Looking for pages with page_latest set to 0...\n" );
+               $dbw = wfGetDB( DB_MASTER );
+               $result = $dbw->select( 'page',
+                       array( 'page_id', 'page_namespace', 'page_title' ),
+                       array( 'page_latest' => 0 ),
+                       __METHOD__ );
 
-       $revision = Revision::loadFromTimestamp( $dbw, $title, $latestTime );
-       if( is_null( $revision ) ) {
-               echo wfWikiID()." $pageId [[$name]] latest time $latestTime, can't find revision id\n";
-               continue;
+               $n = 0;
+               while( $row = $dbw->fetchObject( $result ) ) {
+                       $pageId = intval( $row->page_id );
+                       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+                       $name = $title->getPrefixedText();
+                       $latestTime = $dbw->selectField( 'revision',
+                               'MAX(rev_timestamp)',
+                               array( 'rev_page' => $pageId ),
+                               __METHOD__ );
+                       if( !$latestTime ) {
+                               $this->output( wfWikiID()." $pageId [[$name]] can't find latest rev time?!\n" );
+                               continue;
+                       }
+       
+                       $revision = Revision::loadFromTimestamp( $dbw, $title, $latestTime );
+                       if( is_null( $revision ) ) {
+                               $this->output( wfWikiID()." $pageId [[$name]] latest time $latestTime, can't find revision id\n" );
+                               continue;
+                       }
+                       $id = $revision->getId();
+                       $this->output( wfWikiID()." $pageId [[$name]] latest time $latestTime, rev id $id\n" );
+                       if( $this->hasOption('fix') ) {
+                               $article = new Article( $title );
+                               $article->updateRevisionOn( $dbw, $revision );
+                       }
+                       $n++;
+               }
+               $dbw->freeResult( $result );
+               $this->output( "Done! Processed $n pages.\n" );
+               if( !$this->hasOption('fix') ) {
+                       $this->output( "This was a dry run; rerun with --fix to update page_latest.\n" );
+               }
        }
-       $id = $revision->getId();
-       echo wfWikiID()." $pageId [[$name]] latest time $latestTime, rev id $id\n";
-       if( $fixit ) {
-               $article = new Article( $title );
-               $article->updateRevisionOn( $dbw, $revision );
-       }
-       $n++;
-}
-$dbw->freeResult( $result );
-echo "Done! Processed $n pages.\n";
-if( !$fixit ) {
-       echo "This was a dry run; rerun with --fix to update page_latest.\n";
 }
 
-
+$maintClass = "AttachLatest";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/attribute.php b/maintenance/attribute.php
deleted file mode 100644 (file)
index 5461d41..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-/**
- * Script for re-attributing edits
- * Use reassignEdits.php
- *
- * @file
- * @ingroup Maintenance
- */
-
-/** */
-require_once( "commandLine.inc" );
-
-# Parameters
-if ( count( $args ) < 2 ) {
-       print "Not enough parameters\n";
-       if ( $wgWikiFarm ) {
-               print "Usage: php attribute.php <language> <site> <source> <destination>\n";
-       } else {
-               print "Usage: php attribute.php <source> <destination>\n";
-       }
-       exit;
-}
-
-$source = $args[0];
-$dest = $args[1];
-
-$dbr = wfGetDB( DB_SLAVE );
-extract( $dbr->tableNames( 'page', 'revision','user' ));
-$eSource = $dbr->strencode( $source );
-$eDest = $dbr->strencode( $dest );
-
-# Get user id
-$res = $dbr->query( "SELECT user_id FROM $user WHERE user_name='$eDest'" );
-$row = $dbr->fetchObject( $res );
-if ( !$row ) {
-       print "Warning: the target name \"$dest\" does not exist";
-       $uid = 0;
-} else {
-       $uid = $row->user_id;
-}
-
-# Initialise files
-$logfile = fopen( "attribute.log", "a" );
-$sqlfile = fopen( "attribute.sql", "a" );
-
-fwrite( $logfile, "* $source &rarr; $dest\n" );
-
-fwrite( $sqlfile,
-"-- Changing attribution SQL file
--- Generated with attribute.php
--- $source -> $dest ($uid)
-");
-
-$omitTitle = "Wikipedia:Changing_attribution_for_an_edit";
-
-# Get revisions
-print "\nPage revisions\n\n";
-
-$res = $dbr->query( "SELECT page_namespace, page_title, rev_id, rev_timestamp
-FROM $revision,$page
-WHERE rev_user_text='$eSource' and rev_page=page_id" );
-$row = $dbr->fetchObject( $res );
-
-if ( $row ) {
-/*
-       if ( $row->old_title=='Votes_for_deletion' && $row->old_namespace == 4 ) {
-               # We don't have that long
-               break;
-       }
-*/
-       fwrite( $logfile, "**Revision IDs: " );
-       fwrite( $sqlfile, "UPDATE $revision SET rev_user=$uid, rev_user_text='$eDest' WHERE rev_id IN (\n" );
-
-       for ( $first=true; $row; $row = $dbr->fetchObject( $res ) ) {
-               $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-               $fullTitle = $title->getPrefixedDbKey();
-               if ( $fullTitle == $omitTitle ) {
-                       continue;
-               }
-
-               print "$fullTitle\n";
-               $url = $title->getFullUrl( "oldid={$row->rev_id}" );
-
-               # Output
-               fwrite( $sqlfile, "      " );
-               if ( $first ) {
-                       $first = false;
-               } else {
-                       fwrite( $sqlfile, ", " );
-                       fwrite( $logfile, ", " );
-               }
-
-               fwrite( $sqlfile, "{$row->rev_id} -- $url\n" );
-               fwrite( $logfile, "[$url {$row->rev_id}]" );
-
-       }
-       fwrite( $sqlfile, ");\n" );
-       fwrite( $logfile, "\n" );
-}
-
-print "\n";
-
-fclose( $sqlfile );
-fclose( $logfile );
-
-
index 796e1da..c0c635f 100644 (file)
 /**
  * Squid purge benchmark script
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-/** */
-require_once( "commandLine.inc" );
+require_once( "Maintenance.php" );
 
-/** 
- * Run a bunch of URLs through SquidUpdate::purge()
- * to benchmark Squid response times.
- * @param $urls array A bunch of URLs to purge
- * @param $trials int How many times to run the test?
- */
-function benchSquid( $urls, $trials = 1 ) {
-       $start = wfTime();
-       for( $i = 0; $i < $trials; $i++) {
-               SquidUpdate::purge( $urls );
+class BenchmarkPurge extends Maintenance {
+       
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( "count", "How many URLs to feed to Squid for purging", false, true );
+               $this->mDescription = "Benchmark the Squid purge functions.";
        }
-       $delta = wfTime() - $start;
-       $pertrial = $delta / $trials;
-       $pertitle = $pertrial / count( $urls );
-       return sprintf( "%4d titles in %6.2fms (%6.2fms each)",
-               count( $urls ), $pertrial * 1000.0, $pertitle * 1000.0 );
-}
-
-/** 
- * Get an array of randomUrl()'s.
- * @param $length int How many urls to add to the array
- */
-function randomUrlList( $length ) {
-       $list = array();
-       for( $i = 0; $i < $length; $i++ ) {
-               $list[] = randomUrl();
+       
+       public function execute() {
+               global $wgUseSquid;
+               if( !$wgUseSquid ) {
+                       $this->error( "Squid purge benchmark doesn't do much without squid support on.\n". true );
+               } else {
+                       $this->output( "There are " . count( $wgSquidServers ) . " defined squid servers:\n" );
+                       if( $this->hasOption( 'count' ) ) {
+                               $lengths = array( intval( $this->getOption('count') ) );
+                       } else {
+                               $lengths = array( 1, 10, 100 );
+                       }
+                       foreach( $lengths as $length ) {
+                               $urls = $this->randomUrlList( $length );
+                               $trial = $this->benchSquid( $urls );
+                               $this->output( $trial . "\n" );
+                       }
+               }
        }
-       return $list;
-}
-
-/** 
- * Return a random URL of the wiki. Not necessarily an actual title in the
- * database, but at least a URL that looks like one. 
- */
-function randomUrl() {
-       global $wgServer, $wgArticlePath;
-       return $wgServer . str_replace( '$1', randomTitle(), $wgArticlePath );
-}
-
-/** 
- * Create a random title string (not necessarily a Title object). 
- * For use with randomUrl().
- */
-function randomTitle() {
-       $str = '';
-       $length = mt_rand( 1, 20 );
-       for( $i = 0; $i < $length; $i++ ) {
-               $str .= chr( mt_rand( ord('a'), ord('z') ) );
+       
+       /** 
+        * Run a bunch of URLs through SquidUpdate::purge()
+        * to benchmark Squid response times.
+        * @param $urls array A bunch of URLs to purge
+        * @param $trials int How many times to run the test?
+        */
+       private function benchSquid( $urls, $trials = 1 ) {
+               $start = wfTime();
+               for( $i = 0; $i < $trials; $i++) {
+                       SquidUpdate::purge( $urls );
+               }
+               $delta = wfTime() - $start;
+               $pertrial = $delta / $trials;
+               $pertitle = $pertrial / count( $urls );
+               return sprintf( "%4d titles in %6.2fms (%6.2fms each)",
+                       count( $urls ), $pertrial * 1000.0, $pertitle * 1000.0 );
        }
-       return ucfirst( $str );
-}
-
-if( !$wgUseSquid ) {
-       wfDie( "Squid purge benchmark doesn't do much without squid support on.\n" );
-} else {
-       printf( "There are %d defined squid servers:\n", count( $wgSquidServers ) );
-       #echo implode( "\n", $wgSquidServers ) . "\n";
-       if( isset( $options['count'] ) ) {
-               $lengths = array( intval( $options['count'] ) );
-       } else {
-               $lengths = array( 1, 10, 100 );
+       
+       /** 
+        * Get an array of randomUrl()'s.
+        * @param $length int How many urls to add to the array
+        */
+       private function randomUrlList( $length ) {
+               $list = array();
+               for( $i = 0; $i < $length; $i++ ) {
+                       $list[] = $this->randomUrl();
+               }
+               return $list;
        }
-       foreach( $lengths as $length ) {
-               $urls = randomUrlList( $length );
-               $trial = benchSquid( $urls );
-               print "$trial\n";
+       
+       /** 
+        * Return a random URL of the wiki. Not necessarily an actual title in the
+        * database, but at least a URL that looks like one. 
+        */
+       private function randomUrl() {
+               global $wgServer, $wgArticlePath;
+               return $wgServer . str_replace( '$1', $this->randomTitle(), $wgArticlePath );
+       }
+       
+       /** 
+        * Create a random title string (not necessarily a Title object). 
+        * For use with randomUrl().
+        */
+       private function randomTitle() {
+               $str = '';
+               $length = mt_rand( 1, 20 );
+               for( $i = 0; $i < $length; $i++ ) {
+                       $str .= chr( mt_rand( ord('a'), ord('z') ) );
+               }
+               return ucfirst( $str );
        }
 }
+
+$maintClass = "BenchmarkPurge";
+require_once( DO_MAINTENANCE );
index 84e7f94..b980541 100644 (file)
@@ -1,65 +1,83 @@
 <?php
-require( 'commandLine.inc' );
-function randomString() {
-       $len = mt_rand( 0, 10 );
-       $s = '';
-       for ( $j = 0; $j < $len; $j++ ) {
-               $s .= chr( mt_rand( 0, 255 ) );
-       }
-       return $s;
-}
-function cdbAssert( $msg, $key, $v1, $v2 ) {
-       if ( $v1 !== $v2 ) {
-               echo $msg . ', k=' . bin2hex( $key ) . 
-                       ', v1=' . bin2hex( $v1 ) . 
-                       ', v2=' . bin2hex( $v2 ) . "\n";
-               return false;
-       } else {
-               return true;
+
+/**
+ * Test the CDB reader/writer
+ */
+
+require_once( "Maintenance.php" );
+
+class CdbTest extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "CDB read/write test";
        }
-}
 
+       public function execute() {
+               $this->output( "Write test...\n" );
 
-echo "Write test...\n";
+               $w1 = new CdbWriter_PHP( 'php.cdb' );
+               $w2 = new CdbWriter_DBA( 'dba.cdb' );
 
-$w1 = new CdbWriter_PHP( 'php.cdb' );
-$w2 = new CdbWriter_DBA( 'dba.cdb' );
+               $data = array();
+               for ( $i = 0; $i < 100000; $i++ ) {
+                       $key = $this->randomString();
+                       $value = $this->randomString();
+                       $w1->set( $key, $value );
+                       $w2->set( $key, $value );
 
-$data = array();
-for ( $i = 0; $i < 100000; $i++ ) {
-       $key = randomString();
-       $value = randomString();
-       $w1->set( $key, $value );
-       $w2->set( $key, $value );
+                       if ( !isset( $data[$key] ) ) {
+                               $data[$key] = $value;
+                       }
+               }
 
-       if ( !isset( $data[$key] ) ) {
-               $data[$key] = $value;
-       }
-}
+               $w1->close();
+               $w2->close();
+
+               passthru( 'md5sum php.cdb dba.cdb' );
 
-$w1->close();
-$w2->close();
+               $this->output( "Read test...\n" );
 
-passthru( 'md5sum php.cdb dba.cdb' );
+               $r1 = new CdbReader_PHP( 'php.cdb' );
+               $r2 = new CdbReader_DBA( 'dba.cdb' );
 
-echo "Read test...\n";
+               foreach ( $data as $key => $value ) {
+                       if ( $key === '' ) {
+                               // Known bug
+                               continue;
+                       }
+                       $v1 = $r1->get( $key );
+                       $v2 = $r2->get( $key );
 
-$r1 = new CdbReader_PHP( 'php.cdb' );
-$r2 = new CdbReader_DBA( 'dba.cdb' );
+                       $v1 = $v1 === false ? '(not found)' : $v1;
+                       $v2 = $v2 === false ? '(not found)' : $v2;
 
-foreach ( $data as $key => $value ) {
-       if ( $key === '' ) {
-               // Known bug
-               continue;
+                       #cdbAssert( 'Mismatch', $key, $v1, $v2 );
+                       $this->cdbAssert( "PHP error", $key, $v1, $value );
+                       $this->cdbAssert( "DBA error", $key, $v2, $value );
+               }
+               $this->output( "Done.\n" );
        }
-       $v1 = $r1->get( $key );
-       $v2 = $r2->get( $key );
 
-       $v1 = $v1 === false ? '(not found)' : $v1;
-       $v2 = $v2 === false ? '(not found)' : $v2;
+       private function randomString() {
+               $len = mt_rand( 0, 10 );
+               $s = '';
+               for ( $j = 0; $j < $len; $j++ ) {
+                       $s .= chr( mt_rand( 0, 255 ) );
+               }
+               return $s;
+       }
 
-       #cdbAssert( 'Mismatch', $key, $v1, $v2 );
-       cdbAssert( "PHP error", $key, $v1, $value );
-       cdbAssert( "DBA error", $key, $v2, $value );
+       private function cdbAssert( $msg, $key, $v1, $v2 ) {
+               if ( $v1 !== $v2 ) {
+                       $this->output( $msg . ', k=' . bin2hex( $key ) . 
+                               ', v1=' . bin2hex( $v1 ) . 
+                               ', v2=' . bin2hex( $v2 ) . "\n" );
+                       return false;
+               } else {
+                       return true;
+               }
+       }
 }
-echo "Done.\n";
+
+$maintClass = "CdbTest";
+require_once( DO_MAINTENANCE );
index 0fe8c0b..5f840f0 100644 (file)
@@ -2,55 +2,50 @@
 /**
  * Change the password of a given user
  *
- * @file
- * @ingroup Maintenance
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
  *
  * @author Ã†var Arnfjörð Bjarmason <avarab@gmail.com>
  * @copyright Copyright Â© 2005, Ã†var Arnfjörð Bjarmason
  * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
- */
-
-$optionsWithArgs = array( 'user', 'password' );
-require_once 'commandLine.inc';
-
-$USAGE =
-       "Usage: php changePassword.php [--user=user --password=password | --help]\n" .
-       "\toptions:\n" .
-       "\t\t--help      show this message\n" .
-       "\t\t--user      the username to operate on\n" .
-       "\t\t--password  the password to use\n";
-
-if( in_array( '--help', $argv ) )
-       wfDie( $USAGE );
-
-$cp = new ChangePassword( @$options['user'], @$options['password'] );
-$cp->main();
-
-/**
  * @ingroup Maintenance
  */
-class ChangePassword {
-       var $dbw;
-       var $user, $password;
-
-       function ChangePassword( $user, $password ) {
-               global $USAGE;
-               if( !strlen( $user ) or !strlen( $password ) ) {
-                       wfDie( $USAGE );
-               }
-
-               $this->user = User::newFromName( $user );
-               if ( !$this->user->getId() ) {
-                       die ( "No such user: $user\n" );
-               }
 
-               $this->password = $password;
+require_once( "Maintenance.php" );
 
-               $this->dbw = wfGetDB( DB_MASTER );
+class ChangePassword extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( "user", "The username to operate on", true, true );
+               $this->addOption( "password", "The password to use", true, true );
+               $this->mDescription = "Change a user's password";
        }
-
-       function main() {
-               $this->user->setPassword( $this->password );
-               $this->user->saveSettings();
+       
+       public function execute() {
+               $user = User::newFromName( $this->getOption('user') );
+               if( !$user->getId() ) {
+                       $this->error( "No such user: " . $this->getOption('user') . "\n", true );
+               }
+               try {
+                       $user->setPassword( $this->getOption('password') );
+                       $user->saveSettings();
+               } catch( PasswordError $pwe ) {
+                       $this->error( $pwe->getText(), true );
+               }
        }
 }
+
+$maintClass = "ChangePassword";
+require_once( DO_MAINTENANCE );
index 554395c..90ef996 100644 (file)
@@ -1,29 +1,57 @@
 <?php
-if ( php_sapi_name() != 'cli' ) exit;
+/**
+ * Check the autoloader
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
+ */
 
-$IP = dirname(__FILE__) .'/..';
-require( "$IP/includes/AutoLoader.php" );
-$files = array_unique( $wgAutoloadLocalClasses );
+require_once( "Maintenance.php" );
 
-foreach ( $files as $file ) {
-       if( function_exists( 'parsekit_compile_file' ) ){
-               $parseInfo = parsekit_compile_file( "$IP/$file" );
-               $classes = array_keys( $parseInfo['class_table'] );
-       } else {
-               $contents = file_get_contents( "$IP/$file" );
-               $m = array();
-               preg_match_all( '/\n\s*class\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
-               $classes = $m[1];
+class CheckAutoLoader extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "AutoLoader sanity checks";
        }
-       foreach ( $classes as $class ) {
-               if ( !isset( $wgAutoloadLocalClasses[$class] ) ) {
-                       //printf( "%-50s Unlisted, in %s\n", $class, $file );
-                       echo "          '$class' => '$file',\n";
-               } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) {
-                       echo "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n";
+       public function execute() {
+               global $wgAutoloadLocalClasses, $IP;
+               $files = array_unique( $wgAutoloadLocalClasses );
+
+               foreach( $files as $file ) {
+                       if( function_exists( 'parsekit_compile_file' ) ){
+                               $parseInfo = parsekit_compile_file( "$IP/$file" );
+                               $classes = array_keys( $parseInfo['class_table'] );
+                       } else {
+                               $contents = file_get_contents( "$IP/$file" );
+                               $m = array();
+                               preg_match_all( '/\n\s*class\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER );
+                               $classes = $m[1];
+                       }
+                       foreach ( $classes as $class ) {
+                               if ( !isset( $wgAutoloadLocalClasses[$class] ) ) {
+                                       //printf( "%-50s Unlisted, in %s\n", $class, $file );
+                                       $this->output( "\t'$class' => '$file',\n" );
+                               } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) {
+                                       $this->output( "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n" );
+                               }
+                       }
                }
        }
-
 }
 
-
+$maintClass = "CheckAutoLoader";
+require_once( DO_MAINTENANCE );
index 48a4b0e..87ecaae 100644 (file)
@@ -1,30 +1,59 @@
 <?php
+/**
+ * CheckBadRedirects - See if pages marked as being redirects
+ * really are.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
+ */
+require_once( "Maintenance.php" );
 
-require "commandLine.inc";
-
-echo "Fetching redirects...\n";
-$dbr = wfGetDB( DB_SLAVE );
-$result = $dbr->select(
-       array( 'page' ),
-       array( 'page_namespace','page_title', 'page_latest' ),
-       array( 'page_is_redirect' => 1 ) );
-
-$count = $result->numRows();
-echo "Found $count total redirects.\n";
-echo "Looking for bad redirects:\n";
-echo "\n";
+class CheckBadRedirects extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Look for bad redirects";
+       }
 
-foreach( $result as $row ) {
-       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-       $rev = Revision::newFromId( $row->page_latest );
-       if( $rev ) {
-               $target = Title::newFromRedirect( $rev->getText() );
-               if( !$target ) {
-                       echo $title->getPrefixedText();
-                       echo "\n";
+       public function execute() {
+               $this->output( "Fetching redirects...\n" );
+               $dbr = wfGetDB( DB_SLAVE );
+               $result = $dbr->select(
+                       array( 'page' ),
+                       array( 'page_namespace','page_title', 'page_latest' ),
+                       array( 'page_is_redirect' => 1 ) );
+       
+               $count = $result->numRows();
+               $this->output( "Found $count total redirects.\n" .
+                                               "Looking for bad redirects:\n\n" );
+       
+               foreach( $result as $row ) {
+                       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+                       $rev = Revision::newFromId( $row->page_latest );
+                       if( $rev ) {
+                               $target = Title::newFromRedirect( $rev->getText() );
+                               if( !$target ) {
+                                       $this->output( $title->getPrefixedText() . "\n" );
+                               }
+                       }
                }
+               $this->output( "\ndone.\n" );
        }
 }
 
-echo "\n";
-echo "done.\n";
+$maintClass = "CheckBadRedirects";
+require_once( DO_MAINTENANCE );
index 378caa3..71743dc 100644 (file)
@@ -1,51 +1,82 @@
 <?php
+/**
+ * Check images to see if they exist, are readable, etc etc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
+ */
+require_once( "Maintenance.php" );
 
-require( 'commandLine.inc' );
+class CheckImages extends Maintenance {
 
-$batchSize = 1000;
-$start = '';
-$dbr = wfGetDB( DB_SLAVE );
-$localRepo = RepoGroup::singleton()->getLocalRepo();
-
-$numImages = 0;
-$numGood = 0;
-
-do {
-       $res = $dbr->select( 'image', '*', array( 'img_name > ' . $dbr->addQuotes( $start ) ), 
-               'checkImages.php', array( 'LIMIT' => $batchSize ) );
-       foreach ( $res as $row ) {
-               $numImages++;
-               $start = $row->img_name;
-               $file = $localRepo->newFileFromRow( $row );
-               $path = $file->getPath();
-               if ( !$path ) {
-                       echo "{$row->img_name}: not locally accessible\n";
-                       continue;
-               }
-               $stat = @stat( $file->getPath() );
-               if ( !$stat ) {
-                       echo "{$row->img_name}: missing\n";
-                       continue;
-               }
-
-               if ( $stat['mode'] & 040000 ) {
-                       echo "{$row->img_name}: is a directory\n";
-                       continue;
-               }
-
-               if ( $stat['size'] == 0 && $row->img_size != 0 ) {
-                       echo "{$row->img_name}: truncated, was {$row->img_size}\n";
-                       continue;
-               }
-
-               if ( $stat['size'] != $row->img_size ) {
-                       echo "{$row->img_name}: size mismatch DB={$row->img_size}, actual={$stat['size']}\n";
-                       continue;
-               }
-
-               $numGood++;
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Check images to see if they exist, are readable, etc";
+               $this->setBatchSize( 1000 );
        }
+       
+       public function execute() {
+               $start = '';
+               $dbr = wfGetDB( DB_SLAVE );
 
-} while ( $res->numRows() );
+               $numImages = 0;
+               $numGood = 0;
+       
+               do {
+                       $res = $dbr->select( 'image', '*', array( 'img_name > ' . $dbr->addQuotes( $start ) ), 
+                               __METHOD__, array( 'LIMIT' => $this->mBatchSize ) );
+                       foreach ( $res as $row ) {
+                               $numImages++;
+                               $start = $row->img_name;
+                               $file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
+                               $path = $file->getPath();
+                               if ( !$path ) {
+                                       $this->output( "{$row->img_name}: not locally accessible\n" );
+                                       continue;
+                               }
+                               $stat = @stat( $file->getPath() );
+                               if ( !$stat ) {
+                                       $this->output( "{$row->img_name}: missing\n" );
+                                       continue;
+                               }
+       
+                               if ( $stat['mode'] & 040000 ) {
+                                       $this->output( "{$row->img_name}: is a directory\n" );
+                                       continue;
+                               }
+       
+                               if ( $stat['size'] == 0 && $row->img_size != 0 ) {
+                                       $this->output( "{$row->img_name}: truncated, was {$row->img_size}\n" );
+                                       continue;
+                               }
+       
+                               if ( $stat['size'] != $row->img_size ) {
+                                       $this->output( "{$row->img_name}: size mismatch DB={$row->img_size}, actual={$stat['size']}\n" );
+                                       continue;
+                               }
+       
+                               $numGood++;
+                       }
+       
+               } while ( $res->numRows() );
+       
+               $this->output( "Good images: $numGood/$numImages\n" );
+       }
+}
 
-echo "Good images: $numGood/$numImages\n";
+$maintClass = "CheckImages";
+require_once( DO_MAINTENANCE );
index 77565b9..7b7f11f 100644 (file)
@@ -3,40 +3,52 @@
  * This script verifies that database usernames are actually valid.
  * An existing usernames can become invalid if User::isValidUserName()
  * is altered or if we change the $wgMaxNameChars
- * @file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-error_reporting(E_ALL ^ E_NOTICE);
-require_once 'commandLine.inc';
 
-class checkUsernames {
-       var $stderr, $log;
+require_once( "Maintenance.php" );
 
-       function checkUsernames() {
-               $this->stderr = fopen( 'php://stderr', 'wt' );
+class CheckUsernames extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Verify that database usernames are actually valid";
        }
-       function main() {
-               $fname = 'checkUsernames::main';
 
+       function execute() {
                $dbr = wfGetDB( DB_SLAVE );
 
                $res = $dbr->select( 'user',
                        array( 'user_id', 'user_name' ),
                        null,
-                       $fname
+                       __METHOD__
                );
 
                while ( $row = $dbr->fetchObject( $res ) ) {
                        if ( ! User::isValidUserName( $row->user_name ) ) {
-                               $out = sprintf( "%s: %6d: '%s'\n", wfWikiID(), $row->user_id, $row->user_name );
-                               fwrite( $this->stderr, $out );
+                               $this->error( sprintf( "%s: %6d: '%s'\n", wfWikiID(), $row->user_id, $row->user_name ) );
                                wfDebugLog( 'checkUsernames', $out );
                        }
                }
        }
 }
 
-$cun = new checkUsernames();
-$cun->main();
-
+$maintClass = "CheckUsernames";
+require_once( "doMaintenance.php" );
index eb9bd91..b6d8582 100644 (file)
 <?php
 /**
- * @file
+ * Cleanup all spam from a given hostname
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
-require_once( "$IP/includes/LinkFilter.php" );
+require_once( "Maintenance.php" );
 
-function cleanupArticle( $id, $domain ) {
-       $title = Title::newFromID( $id );
-       if ( !$title ) {
-               print "Internal error: no page for ID $id\n";
-               return;
+class CleanupSpam extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Cleanup all spam from a given hostname";
+               $this->addOption( 'all', 'Check all wikis in $wgLocalDatabases' );
+               $this->addArgs( array( 'hostname' ) );
        }
 
-       print $title->getPrefixedDBkey() . " ...";
-       $rev = Revision::newFromTitle( $title );
-       $revId = $rev->getId();
-       $currentRevId = $revId;
-       
-       while ( $rev && LinkFilter::matchEntry( $rev->getText() , $domain ) ) {
-               # Revision::getPrevious can't be used in this way before MW 1.6 (Revision.php 1.26)
-               #$rev = $rev->getPrevious();
-               $revId = $title->getPreviousRevisionID( $revId );
-               if ( $revId ) {
-                       $rev = Revision::newFromTitle( $title, $revId );
-               } else {
-                       $rev = false;
+       public function execute() {
+               global $wgLocalDatabases;
+
+               $username = wfMsg( 'spambot_username' );
+               $wgUser = User::newFromName( $username );
+               // Create the user if necessary
+               if ( !$wgUser->getId() ) {
+                       $wgUser->addToDatabase();
+               }
+               $spec = $this->getArg();
+               $like = LinkFilter::makeLike( $spec );
+               if ( !$like ) {
+                       $this->error( "Not a valid hostname specification: $spec\n", true );
                }
-       }
-       if ( $revId == $currentRevId ) {
-               // The regex didn't match the current article text
-               // This happens e.g. when a link comes from a template rather than the page itself
-               print "False match\n";
-       } else {
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->immediateBegin();
-               if ( !$rev ) {
-                       // Didn't find a non-spammy revision, blank the page
-                       print "blanking\n";
-                       $article = new Article( $title );
-                       $article->updateArticle( '', wfMsg( 'spam_blanking', $domain ),
-                               false, false );
 
+               $dbr = wfGetDB( DB_SLAVE );
+       
+               if ( $this->hasOption('all') ) {
+                       // Clean up spam on all wikis
+                       $dbr = wfGetDB( DB_SLAVE );
+                       $this->output( "Finding spam on " . count($wgLocalDatabases) . " wikis\n" );
+                       $found = false;
+                       foreach ( $wgLocalDatabases as $db ) {
+                               $count = $dbr->selectField( "`$db`.externallinks", 'COUNT(*)', 
+                                       array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
+                               if ( $count ) {
+                                       $found = true;
+                                       passthru( "php cleanupSpam.php $db $spec | sed s/^/$db:  /" );
+                               }
+                       }
+                       if ( $found ) {
+                               $this->output( "All done\n" );
+                       } else {
+                               $this->output( "None found\n" );
+                       }
                } else {
-                       // Revert to this revision
-                       print "reverting\n";
-                       $article = new Article( $title );
-                       $article->updateArticle( $rev->getText(), wfMsg( 'spam_reverting', $domain ), false, false );
+                       // Clean up spam on this wiki
+                       $res = $dbr->select( 'externallinks', array( 'DISTINCT el_from' ), 
+                               array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
+                       $count = $dbr->numRows( $res );
+                       $this->output( "Found $count articles containing $spec\n" );
+                       while ( $row = $dbr->fetchObject( $res ) ) {
+                               $this->cleanupArticle( $row->el_from, $spec );
+                       }
+                       if ( $count ) {
+                               $this->output( "Done\n" );
+                       }
                }
-               $dbw->immediateCommit();
-               wfDoUpdates();
        }
-}
-//------------------------------------------------------------------------------
-
-
-
-
-$username = wfMsg( 'spambot_username' );
-$fname = $username;
-$wgUser = User::newFromName( $username );
-// Create the user if necessary
-if ( !$wgUser->getId() ) {
-       $wgUser->addToDatabase();
-}
-
-if ( !isset( $args[0] ) ) {
-       print "Usage: php cleanupSpam.php <hostname>\n";
-       exit(1);
-}
-$spec = $args[0];
-$like = LinkFilter::makeLike( $spec );
-if ( !$like ) {
-       print "Not a valid hostname specification: $spec\n";
-       exit(1);
-}
 
-$dbr = wfGetDB( DB_SLAVE );
-
-if ( isset($options['all']) ) {
-       // Clean up spam on all wikis
-       $dbr = wfGetDB( DB_SLAVE );
-       print "Finding spam on " . count($wgLocalDatabases) . " wikis\n";
-       $found = false;
-       foreach ( $wgLocalDatabases as $db ) {
-               $count = $dbr->selectField( "`$db`.externallinks", 'COUNT(*)', 
-                       array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), $fname );
-               if ( $count ) {
-                       $found = true;
-                       passthru( "php cleanupSpam.php $db $spec | sed s/^/$db:  /" );
+       private function cleanupArticle( $id, $domain ) {
+               $title = Title::newFromID( $id );
+               if ( !$title ) {
+                       $this->error( "Internal error: no page for ID $id\n" );
+                       return;
+               }
+       
+               $this->output( $title->getPrefixedDBkey() . " ..." );
+               $rev = Revision::newFromTitle( $title );
+               $revId = $rev->getId();
+               $currentRevId = $revId;
+       
+               while ( $rev && LinkFilter::matchEntry( $rev->getText() , $domain ) ) {
+                       # Revision::getPrevious can't be used in this way before MW 1.6 (Revision.php 1.26)
+                       #$rev = $rev->getPrevious();
+                       $revId = $title->getPreviousRevisionID( $revId );
+                       if ( $revId ) {
+                               $rev = Revision::newFromTitle( $title, $revId );
+                       } else {
+                               $rev = false;
+                       }
+               }
+               if ( $revId == $currentRevId ) {
+                       // The regex didn't match the current article text
+                       // This happens e.g. when a link comes from a template rather than the page itself
+                       $this->output( "False match\n" );
+               } else {
+                       $dbw = wfGetDB( DB_MASTER );
+                       $dbw->immediateBegin();
+                       if ( !$rev ) {
+                               // Didn't find a non-spammy revision, blank the page
+                               $this->output( "blanking\n" );
+                               $article = new Article( $title );
+                               $article->updateArticle( '', wfMsg( 'spam_blanking', $domain ),
+                                       false, false );
+       
+                       } else {
+                               // Revert to this revision
+                               $this->output( "reverting\n" );
+                               $article = new Article( $title );
+                               $article->updateArticle( $rev->getText(), wfMsg( 'spam_reverting', $domain ), false, false );
+                       }
+                       $dbw->immediateCommit();
+                       wfDoUpdates();
                }
-       }
-       if ( $found ) {
-               print "All done\n";
-       } else {
-               print "None found\n";
-       }
-} else {
-       // Clean up spam on this wiki
-       $res = $dbr->select( 'externallinks', array( 'DISTINCT el_from' ), 
-               array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), $fname );
-       $count = $dbr->numRows( $res );
-       print "Found $count articles containing $spec\n";
-       while ( $row = $dbr->fetchObject( $res ) ) {
-               cleanupArticle( $row->el_from, $spec );
-       }
-       if ( $count ) {
-               print "Done\n";
        }
 }
 
-
+$maintClass = "CleanupSpam";
+require_once( DO_MAINTENANCE );
index ce15477..ad0e0d0 100644 (file)
@@ -1,27 +1,53 @@
 <?php
 /**
  * This script is used to clear the interwiki links for ALL languages in
- * memcached.
+ * the cache.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
  * @ingroup Maintenance
  */
 
-/** */
-require_once('commandLine.inc');
+require_once( "Maintenance.php" );
 
-$dbr = wfGetDB( DB_SLAVE );
-$res = $dbr->select( 'interwiki', array( 'iw_prefix' ), false );
-$prefixes = array();
-while ( $row = $dbr->fetchObject( $res ) ) {
-       $prefixes[] = $row->iw_prefix;
-}
+class ClearInterwikiCache extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Clear all interwiki links for all languages from the cache";
+       }
+
+       public function execute() {
+               global $wgLocalDatabases;
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select( 'interwiki', array( 'iw_prefix' ), false );
+               $prefixes = array();
+               while ( $row = $dbr->fetchObject( $res ) ) {
+                       $prefixes[] = $row->iw_prefix;
+               }
 
-foreach ( $wgLocalDatabases as $db ) {
-       print "$db ";
-       foreach ( $prefixes as $prefix ) {
-               $wgMemc->delete("$db:interwiki:$prefix");
+               foreach ( $wgLocalDatabases as $db ) {
+                       $this->output( "$db..." );
+                       foreach ( $prefixes as $prefix ) {
+                               $wgMemc->delete("$db:interwiki:$prefix");
+                       }
+                       $this->output( "done\n" );
+               }
        }
 }
-print "\n";
 
+$maintClass = "ClearInterwikiCache";
+require_once( DO_MAINTENANCE );
index 4cacd74..1c5eaae 100644 (file)
@@ -1,38 +1,53 @@
 <?php
 /**
- * This script remove all statistics tracking from memcached
+ * This script remove all statistics tracking from the cache
  * 
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once('commandLine.inc');
+require_once( 'Maintenance.php' );
 
-foreach ( $wgLocalDatabases as $db ) {
-       noisyDelete("$db:stats:request_with_session");
-       noisyDelete("$db:stats:request_without_session");
-       noisyDelete("$db:stats:pcache_hit");
-       noisyDelete("$db:stats:pcache_miss_invalid");
-       noisyDelete("$db:stats:pcache_miss_expired");
-       noisyDelete("$db:stats:pcache_miss_absent");
-       noisyDelete("$db:stats:pcache_miss_stub");
-       noisyDelete("$db:stats:image_cache_hit");
-       noisyDelete("$db:stats:image_cache_miss");
-       noisyDelete("$db:stats:image_cache_update");
-       noisyDelete("$db:stats:diff_cache_hit");
-       noisyDelete("$db:stats:diff_cache_miss");
-       noisyDelete("$db:stats:diff_uncacheable");
-}
+class clear_stats extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Remove all statistics tracking from the cache";
+       }
 
-function noisyDelete( $key ) {
-       global $wgMemc;
-       /*
-       print "$key ";
-       if ( $wgMemc->delete($key) ) {
-               print "deleted\n";
-       } else {
-               print "FAILED\n";
-       }*/
-       $wgMemc->delete($key);
+       public function execute() {
+               global $wgLocalDatabases, $wgMemc;
+               foreach ( $wgLocalDatabases as $db ) {
+                       $wgMemc->delete("$db:stats:request_with_session");
+                       $wgMemc->delete("$db:stats:request_without_session");
+                       $wgMemc->delete("$db:stats:pcache_hit");
+                       $wgMemc->delete("$db:stats:pcache_miss_invalid");
+                       $wgMemc->delete("$db:stats:pcache_miss_expired");
+                       $wgMemc->delete("$db:stats:pcache_miss_absent");
+                       $wgMemc->delete("$db:stats:pcache_miss_stub");
+                       $wgMemc->delete("$db:stats:image_cache_hit");
+                       $wgMemc->delete("$db:stats:image_cache_miss");
+                       $wgMemc->delete("$db:stats:image_cache_update");
+                       $wgMemc->delete("$db:stats:diff_cache_hit");
+                       $wgMemc->delete("$db:stats:diff_cache_miss");
+                       $wgMemc->delete("$db:stats:diff_uncacheable");
+               }
+       }
 }
 
+$maintClass = "clear_stats";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/convertLinks.inc b/maintenance/convertLinks.inc
deleted file mode 100644 (file)
index 4aff81e..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-/**
- * @file
- * @todo document
- * @ingroup Maintenance
- */
-
-/** */
-function convertLinks() {
-       global $wgDBtype;
-       if( $wgDBtype == 'postgres' ) {
-               wfOut( "Links table already ok on Postgres.\n" );
-               return;
-       }
-
-       wfOut( "Converting links table to ID-ID...\n" );
-
-       global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
-       global $noKeys, $logPerformance, $fh;
-
-       $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc
-       $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
-
-       $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table
-       $curReadReportInterval = 1000; #number of rows between progress reports
-
-       $reportLinksConvProgress = true; #whether or not to give progress reports during conversion
-       $linksConvInsertInterval = 1000; #number of rows per INSERT
-
-       $initialRowOffset = 0;
-       #$finalRowOffset = 0; # not used yet; highest row number from links table to process
-
-       # Overwrite the old links table with the new one.  If this is set to false,
-       # the new table will be left at links_temp.
-       $overwriteLinksTable = true;
-
-       # Don't create keys, and so allow duplicates in the new links table.
-       # This gives a huge speed improvement for very large links tables which are MyISAM. (What about InnoDB?)
-       $noKeys = false;
-
-
-       $logPerformance = false; # output performance data to a file
-       $perfLogFilename = "convLinksPerf.txt";
-       #--------------------------------------------------------------------
-
-       $dbw = wfGetDB( DB_MASTER );
-       list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
-
-       $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
-       if ( $dbw->fieldType( $res, 0 ) == "int" ) {
-               wfOut( "Schema already converted\n" );
-               return;
-       }
-
-       $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
-       $row = $dbw->fetchObject($res);
-       $numRows = $row->count;
-       $dbw->freeResult( $res );
-
-       if ( $numRows == 0 ) {
-               wfOut( "Updating schema (no rows to convert)...\n" );
-               createTempTable();
-       } else {
-               if ( $logPerformance ) { $fh = fopen ( $perfLogFilename, "w" ); }
-               $baseTime = $startTime = getMicroTime();
-               # Create a title -> cur_id map
-               wfOut( "Loading IDs from $cur table...\n" );
-               performanceLog ( "Reading $numRows rows from cur table...\n" );
-               performanceLog ( "rows read vs seconds elapsed:\n" );
-
-               $dbw->bufferResults( false );
-               $res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
-               $ids = array();
-
-               while ( $row = $dbw->fetchObject( $res ) ) {
-                       $title = $row->cur_title;
-                       if ( $row->cur_namespace ) {
-                               $title = $wgLang->getNsText( $row->cur_namespace ) . ":$title";
-                       }
-                       $ids[$title] = $row->cur_id;
-                       $curRowsRead++;
-                       if ($reportCurReadProgress) {
-                               if (($curRowsRead % $curReadReportInterval) == 0) {
-                                       performanceLog( $curRowsRead . " " . (getMicroTime() - $baseTime) . "\n" );
-                                       wfOut( "\t$curRowsRead rows of $cur table read.\n" );
-                               }
-                       }
-               }
-               $dbw->freeResult( $res );
-               $dbw->bufferResults( true );
-               wfOut( "Finished loading IDs.\n\n" );
-               performanceLog( "Took " . (getMicroTime() - $baseTime) . " seconds to load IDs.\n\n" );
-       #--------------------------------------------------------------------
-
-               # Now, step through the links table (in chunks of $linksConvInsertInterval rows),
-               # convert, and write to the new table.
-               createTempTable();
-               performanceLog( "Resetting timer.\n\n" );
-               $baseTime = getMicroTime();
-               wfOut( "Processing $numRows rows from $links table...\n" );
-               performanceLog( "Processing $numRows rows from $links table...\n" );
-               performanceLog( "rows inserted vs seconds elapsed:\n" );
-
-               for ($rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval) {
-                       $sqlRead = "SELECT * FROM $links ";
-                       $sqlRead = $dbw->limitResult($sqlRead, $linksConvInsertInterval,$rowOffset);
-                       $res = $dbw->query($sqlRead);
-                       if ( $noKeys ) {
-                               $sqlWrite = array("INSERT INTO $links_temp (l_from,l_to) VALUES ");
-                       } else {
-                               $sqlWrite = array("INSERT IGNORE INTO $links_temp (l_from,l_to) VALUES ");
-                       }
-
-                       $tuplesAdded = 0; # no tuples added to INSERT yet
-                       while ( $row = $dbw->fetchObject($res) ) {
-                               $fromTitle = $row->l_from;
-                               if ( array_key_exists( $fromTitle, $ids ) ) { # valid title
-                                       $from = $ids[$fromTitle];
-                                       $to = $row->l_to;
-                                       if ( $tuplesAdded != 0 ) {
-                                               $sqlWrite[] = ",";
-                                       }
-                                       $sqlWrite[] = "($from,$to)";
-                                       $tuplesAdded++;
-                               } else { # invalid title
-                                       $numBadLinks++;
-                               }
-                       }
-                       $dbw->freeResult($res);
-                       #wfOut( "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n" );
-                       if ( $tuplesAdded != 0  ) {
-                               if ($reportLinksConvProgress) {
-                                       wfOut( "Inserting $tuplesAdded tuples into $links_temp..." );
-                               }
-                               $dbw->query( implode("",$sqlWrite) );
-                               $totalTuplesInserted += $tuplesAdded;
-                               if ($reportLinksConvProgress)
-                                       wfOut( " done. Total $totalTuplesInserted tuples inserted.\n" );
-                                       performanceLog( $totalTuplesInserted . " " . (getMicroTime() - $baseTime) . "\n"  );
-                       }
-               }
-               wfOut( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" );
-               performanceLog( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
-               performanceLog( "Total execution time: " . (getMicroTime() - $startTime) . " seconds.\n" );
-               if ( $logPerformance ) { fclose ( $fh ); }
-       }
-       #--------------------------------------------------------------------
-
-       if ( $overwriteLinksTable ) {
-               $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
-               if (!($dbConn->isOpen())) {
-                       wfOut( "Opening connection to database failed.\n" );
-                       return;
-               }
-               # Check for existing links_backup, and delete it if it exists.
-               wfOut( "Dropping backup links table if it exists..." );
-               $dbConn->query( "DROP TABLE IF EXISTS $links_backup", DB_MASTER);
-               wfOut( " done.\n" );
-
-               # Swap in the new table, and move old links table to links_backup
-               wfOut( "Swapping tables '$links' to '$links_backup'; '$links_temp' to '$links'..." );
-               $dbConn->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", DB_MASTER );
-               wfOut( " done.\n\n" );
-
-               $dbConn->close();
-               wfOut( "Conversion complete. The old table remains at $links_backup;\n" );
-               wfOut( "delete at your leisure.\n" );
-       } else {
-               wfOut( "Conversion complete.  The converted table is at $links_temp;\n" );
-               wfOut( "the original links table is unchanged.\n" );
-       }
-}
-
-#--------------------------------------------------------------------
-
-function createTempTable() {
-       global $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
-       global $noKeys;
-       $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
-
-       if (!($dbConn->isOpen())) {
-               wfOut( "Opening connection to database failed.\n" );
-               return;
-       }
-       $links_temp = $dbConn->tableName( 'links_temp' );
-
-       wfOut( "Dropping temporary links table if it exists..." );
-       $dbConn->query( "DROP TABLE IF EXISTS $links_temp");
-       wfOut( " done.\n" );
-
-       wfOut( "Creating temporary links table..." );
-       if ( $noKeys ) {
-               $dbConn->query( "CREATE TABLE $links_temp ( " .
-               "l_from int(8) unsigned NOT NULL default '0', " .
-               "l_to int(8) unsigned NOT NULL default '0')");
-       } else {
-               $dbConn->query( "CREATE TABLE $links_temp ( " .
-               "l_from int(8) unsigned NOT NULL default '0', " .
-               "l_to int(8) unsigned NOT NULL default '0', " .
-               "UNIQUE KEY l_from(l_from,l_to), " .
-               "KEY (l_to))");
-       }
-       wfOut( " done.\n\n" );
-}
-
-function performanceLog( $text ) {
-       global $logPerformance, $fh;
-       if ( $logPerformance ) {
-               fwrite( $fh, $text );
-       }
-}
-
-function getMicroTime() { # return time in seconds, with microsecond accuracy
-       list($usec, $sec) = explode(" ", microtime());
-       return ((float)$usec + (float)$sec);
-}
index e86d1e7..32a483e 100644 (file)
  * Convert from the old links schema (string->ID) to the new schema (ID->ID)
  * The wiki should be put into read-only mode while this script executes
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-/** */
-require_once( "commandLine.inc" );
-require_once( "convertLinks.inc" );
+require_once( "Maintenance.php" );
+
+class ConvertLinks extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Convert from the old links schema (string->ID) to the new schema (ID->ID)
+The wiki should be put into read-only mode while this script executes";
+       }
+
+       public function execute() {
+               global $wgDBtype;
+               if( $wgDBtype == 'postgres' ) {
+                       $this->output( "Links table already ok on Postgres.\n" );
+                       return;
+               }
+
+               $this->output( "Converting links table to ID-ID...\n" );
+
+               global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
+               global $noKeys, $logPerformance, $fh;
+       
+               $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc
+               $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
+       
+               $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table
+               $curReadReportInterval = 1000; #number of rows between progress reports
+       
+               $reportLinksConvProgress = true; #whether or not to give progress reports during conversion
+               $linksConvInsertInterval = 1000; #number of rows per INSERT
+       
+               $initialRowOffset = 0;
+               #$finalRowOffset = 0; # not used yet; highest row number from links table to process
+       
+               # Overwrite the old links table with the new one.  If this is set to false,
+               # the new table will be left at links_temp.
+               $overwriteLinksTable = true;
+       
+               # Don't create keys, and so allow duplicates in the new links table.
+               # This gives a huge speed improvement for very large links tables which are MyISAM. (What about InnoDB?)
+               $noKeys = false;
+       
+       
+               $logPerformance = false; # output performance data to a file
+               $perfLogFilename = "convLinksPerf.txt";
+               #--------------------------------------------------------------------
+       
+               $dbw = wfGetDB( DB_MASTER );
+               list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
+       
+               $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
+               if ( $dbw->fieldType( $res, 0 ) == "int" ) {
+                       $this->output( "Schema already converted\n" );
+                       return;
+               }
+       
+               $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
+               $row = $dbw->fetchObject($res);
+               $numRows = $row->count;
+               $dbw->freeResult( $res );
+       
+               if ( $numRows == 0 ) {
+                       $this->output( "Updating schema (no rows to convert)...\n" );
+                       $this->createTempTable();
+               } else {
+                       if ( $logPerformance ) { $fh = fopen ( $perfLogFilename, "w" ); }
+                       $baseTime = $startTime = $this->getMicroTime();
+                       # Create a title -> cur_id map
+                       $this->output( "Loading IDs from $cur table...\n" );
+                       $this->performanceLog ( "Reading $numRows rows from cur table...\n" );
+                       $this->performanceLog ( "rows read vs seconds elapsed:\n" );
+
+                       $dbw->bufferResults( false );
+                       $res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
+                       $ids = array();
+
+                       while ( $row = $dbw->fetchObject( $res ) ) {
+                               $title = $row->cur_title;
+                               if ( $row->cur_namespace ) {
+                                       $title = $wgLang->getNsText( $row->cur_namespace ) . ":$title";
+                               }
+                               $ids[$title] = $row->cur_id;
+                               $curRowsRead++;
+                               if ($reportCurReadProgress) {
+                                       if (($curRowsRead % $curReadReportInterval) == 0) {
+                                               $this->performanceLog( $curRowsRead . " " . ($this->getMicroTime() - $baseTime) . "\n" );
+                                               $this->output( "\t$curRowsRead rows of $cur table read.\n" );
+                                       }
+                               }
+                       }
+                       $dbw->freeResult( $res );
+                       $dbw->bufferResults( true );
+                       $this->output( "Finished loading IDs.\n\n" );
+                       $this->performanceLog( "Took " . ($this->getMicroTime() - $baseTime) . " seconds to load IDs.\n\n" );
+               #--------------------------------------------------------------------
+       
+                       # Now, step through the links table (in chunks of $linksConvInsertInterval rows),
+                       # convert, and write to the new table.
+                       $this->createTempTable();
+                       $this->performanceLog( "Resetting timer.\n\n" );
+                       $baseTime = $this->getMicroTime();
+                       $this->output( "Processing $numRows rows from $links table...\n" );
+                       $this->performanceLog( "Processing $numRows rows from $links table...\n" );
+                       $this->performanceLog( "rows inserted vs seconds elapsed:\n" );
+       
+                       for ($rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval) {
+                               $sqlRead = "SELECT * FROM $links ";
+                               $sqlRead = $dbw->limitResult($sqlRead, $linksConvInsertInterval,$rowOffset);
+                               $res = $dbw->query($sqlRead);
+                               if ( $noKeys ) {
+                                       $sqlWrite = array("INSERT INTO $links_temp (l_from,l_to) VALUES ");
+                               } else {
+                                       $sqlWrite = array("INSERT IGNORE INTO $links_temp (l_from,l_to) VALUES ");
+                               }
+       
+                               $tuplesAdded = 0; # no tuples added to INSERT yet
+                               while ( $row = $dbw->fetchObject($res) ) {
+                                       $fromTitle = $row->l_from;
+                                       if ( array_key_exists( $fromTitle, $ids ) ) { # valid title
+                                               $from = $ids[$fromTitle];
+                                               $to = $row->l_to;
+                                               if ( $tuplesAdded != 0 ) {
+                                                       $sqlWrite[] = ",";
+                                               }
+                                               $sqlWrite[] = "($from,$to)";
+                                               $tuplesAdded++;
+                                       } else { # invalid title
+                                               $numBadLinks++;
+                                       }
+                               }
+                               $dbw->freeResult($res);
+                               #$this->output( "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n" );
+                               if ( $tuplesAdded != 0  ) {
+                                       if ($reportLinksConvProgress) {
+                                               $this->output( "Inserting $tuplesAdded tuples into $links_temp..." );
+                                       }
+                                       $dbw->query( implode("",$sqlWrite) );
+                                       $totalTuplesInserted += $tuplesAdded;
+                                       if ($reportLinksConvProgress)
+                                               $this->output( " done. Total $totalTuplesInserted tuples inserted.\n" );
+                                               $this->performanceLog( $totalTuplesInserted . " " . ($this->getMicroTime() - $baseTime) . "\n"  );
+                               }
+                       }
+                       $this->output( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" );
+                       $this->performanceLog( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
+                       $this->performanceLog( "Total execution time: " . ($this->getMicroTime() - $startTime) . " seconds.\n" );
+                       if ( $logPerformance ) { fclose ( $fh ); }
+               }
+               #--------------------------------------------------------------------
+       
+               if ( $overwriteLinksTable ) {
+                       $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
+                       if (!($dbConn->isOpen())) {
+                               $this->output( "Opening connection to database failed.\n" );
+                               return;
+                       }
+                       # Check for existing links_backup, and delete it if it exists.
+                       $this->output( "Dropping backup links table if it exists..." );
+                       $dbConn->query( "DROP TABLE IF EXISTS $links_backup", DB_MASTER);
+                       $this->output( " done.\n" );
+       
+                       # Swap in the new table, and move old links table to links_backup
+                       $this->output( "Swapping tables '$links' to '$links_backup'; '$links_temp' to '$links'..." );
+                       $dbConn->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", DB_MASTER );
+                       $this->output( " done.\n\n" );
+       
+                       $dbConn->close();
+                       $this->output( "Conversion complete. The old table remains at $links_backup;\n" );
+                       $this->output( "delete at your leisure.\n" );
+               } else {
+                       $this->output( "Conversion complete.  The converted table is at $links_temp;\n" );
+                       $this->output( "the original links table is unchanged.\n" );
+               }
+       }
+
+       private function createTempTable() {
+               global $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
+               global $noKeys;
+               $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
+
+               if (!($dbConn->isOpen())) {
+                       $this->output( "Opening connection to database failed.\n" );
+                       return;
+               }
+               $links_temp = $dbConn->tableName( 'links_temp' );
+
+               $this->output( "Dropping temporary links table if it exists..." );
+               $dbConn->query( "DROP TABLE IF EXISTS $links_temp");
+               $this->output( " done.\n" );
+
+               $this->output( "Creating temporary links table..." );
+               if ( $noKeys ) {
+                       $dbConn->query( "CREATE TABLE $links_temp ( " .
+                       "l_from int(8) unsigned NOT NULL default '0', " .
+                       "l_to int(8) unsigned NOT NULL default '0')");
+               } else {
+                       $dbConn->query( "CREATE TABLE $links_temp ( " .
+                       "l_from int(8) unsigned NOT NULL default '0', " .
+                       "l_to int(8) unsigned NOT NULL default '0', " .
+                       "UNIQUE KEY l_from(l_from,l_to), " .
+                       "KEY (l_to))");
+               }
+               $this->output( " done.\n\n" );
+       }
+
+       private function performanceLog( $text ) {
+               global $logPerformance, $fh;
+               if ( $logPerformance ) {
+                       fwrite( $fh, $text );
+               }
+       }
+
+       private function getMicroTime() { # return time in seconds, with microsecond accuracy
+               list($usec, $sec) = explode(" ", microtime());
+               return ((float)$usec + (float)$sec);
+       }
+}
 
-convertLinks();
+$maintClass = "ConvertLinks";
+require_once( DO_MAINTENANCE );
index 5e9d0ea..0f018b4 100644 (file)
@@ -1,41 +1,72 @@
 <?php
-require( './commandLine.inc' );
+/**
+ * Do each user sequentially, since accounts can't be deleted
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
+ */
 
-// Do each user sequentially, since accounts can't be deleted
+require_once( "Maintenance.php" );
 
-print "Beginning batch conversion of user options.\n";
+class ConvertUserOptions extends Maintenance {
 
-$id = 0;
-$dbw = wfGetDB( DB_MASTER );
-$conversionCount = 0;
+       private $mConversionCount = 0;
 
-while ($id !== null) {
-       $idCond = 'user_id>'.$dbw->addQuotes( $id );
-       $optCond = "user_options!=".$dbw->addQuotes( '' ); // For compatibility
-       $res = $dbw->select( 'user', '*',
-                       array( $optCond, $idCond ), __METHOD__,
-                       array( 'LIMIT' => 50, 'FOR UPDATE' ) );
-       $id = convertOptionBatch( $res, $dbw );
-       $dbw->commit();
-       
-       wfWaitForSlaves( 1 );
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Convert user options from old to new system";
+       }
        
-       if ($id)
-               print "--Converted to ID $id\n";
-}
-print "Conversion done. Converted $conversionCount user records.\n";
+       public function execute() {
+               $this->output( "Beginning batch conversion of user options.\n" );
+               $id = 0;
+               $dbw = wfGetDB( DB_MASTER );
 
-function convertOptionBatch( $res, $dbw ) {
-       $id = null;
-       while ($row = $dbw->fetchObject( $res ) ) {
-               global $conversionCount;
-               $conversionCount++;
-               
-               $u = User::newFromRow( $row );
-               
-               $u->saveSettings();
-               $id = $row->user_id;
+               while ($id !== null) {
+                       $idCond = 'user_id>'.$dbw->addQuotes( $id );
+                       $optCond = "user_options!=".$dbw->addQuotes( '' ); // For compatibility
+                       $res = $dbw->select( 'user', '*',
+                                       array( $optCond, $idCond ), __METHOD__,
+                                       array( 'LIMIT' => 50, 'FOR UPDATE' ) );
+                       $id = $this->convertOptionBatch( $res, $dbw );
+                       $dbw->commit();
+       
+                       wfWaitForSlaves( 1 );
+       
+                       if ($id)
+                               $this->output( "--Converted to ID $id\n" );
+               }
+               $this->output( "Conversion done. Converted " . $this->mConversionCount . " user records.\n" );
        }
+
+       function convertOptionBatch( $res, $dbw ) {
+               $id = null;
+               while ($row = $dbw->fetchObject( $res ) ) {
+                       $this->mConversionCount++;
+       
+                       $u = User::newFromRow( $row );
+       
+                       $u->saveSettings();
+                       $id = $row->user_id;
+               }
        
-       return $id;
+               return $id;
+       }
 }
+
+$maintClass = "ConvertUserOptions";
+require_once( DO_MAINTENANCE );
index b55d920..566885c 100644 (file)
@@ -3,71 +3,72 @@
 /**
  * Maintenance script to create an account and grant it administrator rights
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-$options = array( 'help', 'bureaucrat' );
-require_once( 'commandLine.inc' );
-
-if( isset( $options['help'] ) ) {
-       showHelp();
-       exit( 1 );
-}
-
-if( count( $args ) < 2 ) {
-       echo( "Please provide a username and password for the new account.\n" );
-       die( 1 );
-}
-
-$username = $args[0];
-$password = $args[1];
-
-echo( wfWikiID() . ": Creating and promoting User:{$username}..." );
-
-# Validate username and check it doesn't exist
-$user = User::newFromName( $username );
-if( !is_object( $user ) ) {
-       echo( "invalid username.\n" );
-       die( 1 );
-} elseif( 0 != $user->idForName() ) {
-       echo( "account exists.\n" );
-       die( 1 );
+require_once( "Maintenance.php" );
+
+class CreateAndPromote extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Create a new user account with administrator rights";
+               $this->addOption( "bureaucrat", "Grant the account bureaucrat rights" );
+               $this->addArgs( array( "username", "password" ) );
+       }
+
+       public function execute() {
+               $username = $this->getArg(0);
+               $password = $this->getArg(1);
+               
+               $this->output( wfWikiID() . ": Creating and promoting User:{$username}..." );
+               
+               $user = User::newFromName( $username );
+               if( !is_object( $user ) ) {
+                       $this->error( "invalid username.\n", true );
+               } elseif( 0 != $user->idForName() ) {
+                       $this->error( "account exists.\n", true );
+               }
+
+               # Try to set the password
+               try {
+                       $user->setPassword( $password );
+               } catch( PasswordError $pwe ) {
+                       $this->error( $pwe->getText(), true );
+               }
+
+               # Insert the account into the database
+               $user->addToDatabase();
+               $user->saveSettings();
+       
+               # Promote user
+               $user->addGroup( 'sysop' );
+               if( $this->hasOption( 'bureaucrat' ) )
+                       $user->addGroup( 'bureaucrat' );
+       
+               # Increment site_stats.ss_users
+               $ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
+               $ssu->doUpdate();
+       
+               $this->output( "done.\n" );
+       }
 }
 
-try {
-       $user->setPassword( $password );
-} catch( PasswordError $pwe ) {
-       $this->error( $pwe->getText(), true );
-}
-
-# Insert the account into the database
-$user->addToDatabase();
-$user->saveSettings();
-
-# Promote user
-$user->addGroup( 'sysop' );
-if( isset( $option['bureaucrat'] ) )
-       $user->addGroup( 'bureaucrat' );
-
-# Increment site_stats.ss_users
-$ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
-$ssu->doUpdate();
-
-echo( "done.\n" );
-
-function showHelp() {
-       echo( <<<EOT
-Create a new user account with administrator rights
-
-USAGE: php createAndPromote.php [--bureaucrat|--help] <username> <password>
-
-       --bureaucrat
-               Grant the account bureaucrat rights
-       --help
-               Show this help information
-
-EOT
-       );
-}
\ No newline at end of file
+$maintClass = "CreateAndPromote";
+require_once( DO_MAINTENANCE );
\ No newline at end of file
diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc
deleted file mode 100644 (file)
index a956436..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-/**
- * Support functions for the deleteArchivedFiles script
- *
- * @file
- * @ingroup Maintenance
- * @author Aaron Schulz
- */
-
-require_once( "$IP/includes/filerepo/File.php" );
-
-function DeleteArchivedFiles( $delete = false ) {
-       if( !$delete ) {
-               echo( "Use --delete to actually confirm this script\n" );
-               return;
-       }
-       # Data should come off the master, wrapped in a transaction
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->begin();
-       $tbl_arch = $dbw->tableName( 'filearchive' );
-       $repo = RepoGroup::singleton()->getLocalRepo();
-       # Get "active" revisions from the filearchive table
-       echo( "Searching for and deleting archived files...\n" );
-       $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" );
-       $count = 0;
-       while( $row = $dbw->fetchObject( $res ) ) {
-               $key = $row->fa_storage_key;
-               $group = $row->fa_storage_group;
-               $id = $row->fa_id;
-               $path = $repo->getZonePath( 'deleted' ).'/'.$repo->getDeletedHashPath($key).$key;
-               $sha1 = substr( $key, 0, strcspn( $key, '.' ) );
-               // Check if the file is used anywhere...
-               $inuse = $dbw->selectField( 'oldimage', '1',
-                       array( 'oi_sha1' => $sha1,
-                       'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ),
-                       __METHOD__,
-                       array( 'FOR UPDATE' )
-               );
-               if ( $path && file_exists($path) && !$inuse ) {
-                       unlink($path); // delete
-                       $count++;
-                       $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" );
-               } else {
-                       echo( "Notice - file '$key' not found in group '$group'\n" );
-               }
-       }
-       $dbw->commit();
-       echo( "Done! [$count file(s)]\n" );
-}
index 97dc582..171d5d4 100644 (file)
@@ -3,29 +3,78 @@
 /**
  * Delete archived (non-current) files from the database
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Aaron Schulz
  * Based on deleteOldRevisions.php by Rob Church
  */
 
-$options = array( 'delete', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'deleteArchivedFiles.inc' );
+require_once( "Maintenance.php" );
 
-echo( "Delete Archived Images\n\n" );
-
-if( @$options['help'] ) {
-       ShowUsage();
-} else {
-       DeleteArchivedFiles( @$options['delete'] );
-}
+class DeleteArchivedFiles extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Deletes all archived images.";
+               $this->addOption( 'delete', 'Perform the deletion' );
+       }
 
-function ShowUsage() {
-       echo( "Deletes all archived images.\n\n" );
-       echo( "These images will no longer be restorable.\n\n" );
-       echo( "Usage: php deleteArchivedRevisions.php [--delete|--help]\n\n" );
-       echo( "delete : Performs the deletion\n" );
-       echo( "  help : Show this usage information\n" );
+       /**
+        * @todo @fixme FSTransaction/FileStore crap needs removing. Does
+        * not work on trunk
+        */
+       public function execute() {
+               if( !$this->hasOption('delete') ) {
+                       $this->output( "Use --delete to actually confirm this script\n" );
+                       return;
+               }
+               # Data should come off the master, wrapped in a transaction
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+               $tbl_arch = $dbw->tableName( 'filearchive' );
+               $repo = RepoGroup::singleton()->getLocalRepo();
+               # Get "active" revisions from the filearchive table
+               $this->output( "Searching for and deleting archived files...\n" );
+               $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" );
+               $count = 0;
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $key = $row->fa_storage_key;
+                       $group = $row->fa_storage_group;
+                       $id = $row->fa_id;
+                       $path = $repo->getZonePath( 'deleted' ).'/'.$repo->getDeletedHashPath($key).$key;
+                       $sha1 = substr( $key, 0, strcspn( $key, '.' ) );
+                       // Check if the file is used anywhere...
+                       $inuse = $dbw->selectField( 'oldimage', '1',
+                               array( 'oi_sha1' => $sha1,
+                               'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ),
+                               __METHOD__,
+                               array( 'FOR UPDATE' )
+                       );
+                       if ( $path && file_exists($path) && !$inuse ) {
+                               unlink($path); // delete
+                               $count++;
+                               $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" );
+                       } else {
+                               $this->output( "Notice - file '$key' not found in group '$group'\n" );
+                       }
+               }
+               $dbw->commit();
+               $this->output( "Done! [$count file(s)]\n" );
+       }
 }
 
+$maintClass = "DeleteArchivedFiles";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc
deleted file mode 100644 (file)
index cd90ecd..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/**
- * Support functions for the deleteArchivedRevisions script
- *
- * @file
- * @ingroup Maintenance
- * @author Aaron Schulz
- */
-require_once( 'purgeOldText.inc' );
-
-function DeleteArchivedRevisions( $delete = false ) {
-
-       # Data should come off the master, wrapped in a transaction
-       $dbw = wfGetDB( DB_MASTER );
-
-       if( $delete ) {
-               $dbw->begin();
-       
-               $tbl_arch = $dbw->tableName( 'archive' );
-
-               # Delete as appropriate
-               echo( "Deleting archived revisions... " );
-               $dbw->query( "TRUNCATE TABLE $tbl_arch" );
-       
-               $count = $dbw->affectedRows();
-               $deletedRows = $count != 0;
-
-               echo( "done. $count revisions deleted.\n" );
-
-               # This bit's done
-               # Purge redundant text records
-               $dbw->commit();
-               if( $deletedRows ) {
-                       PurgeRedundantText( true );
-               }
-       } else {
-               $res = $dbw->selectRow( 'archive', 'COUNT(*) as count', array(), __FUNCTION__ );
-               echo( "Found {$res->count} revisions to delete.\n" );
-               echo( "Please run the script again with the --delete option to really delete the revisions.\n" );
-       }
-}
index 87eebfa..98e4aff 100644 (file)
@@ -3,29 +3,66 @@
 /**
  * Delete archived (deleted from public) revisions from the database
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Aaron Schulz
  * Shamelessly stolen from deleteOldRevisions.php by Rob Church :)
  */
 
-$options = array( 'delete', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'deleteArchivedRevisions.inc' );
+require_once( "Maintenance.php" );
 
-echo( "Delete Archived Revisions\n\n" );
-
-if( @$options['help'] ) {
-       ShowUsage();
-} else {
-       DeleteArchivedRevisions( @$options['delete'] );
-}
+class DeleteArchivedRevisions extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Deletes all archived revisions\nThese revisions will no longer be restorable";
+               $this->addOption( 'delete', 'Performs the deletion' );
+       }
 
-function ShowUsage() {
-       echo( "Deletes all archived revisions.\n\n" );
-       echo( "These revisions will no longer be restorable.\n\n" );
-       echo( "Usage: php deleteArchivedRevisions.php [--delete|--help]\n\n" );
-       echo( "delete : Performs the deletion\n" );
-       echo( "  help : Show this usage information\n" );
+       public function execute() {
+               $this->output( "Delete archived revisions\n\n" );
+               # Data should come off the master, wrapped in a transaction
+               $dbw = wfGetDB( DB_MASTER );
+               if( $this->hasOption('delete') ) {
+                       $dbw->begin();
+       
+                       $tbl_arch = $dbw->tableName( 'archive' );
+       
+                       # Delete as appropriate
+                       $this->output( "Deleting archived revisions... " );
+                       $dbw->query( "TRUNCATE TABLE $tbl_arch" );
+       
+                       $count = $dbw->affectedRows();
+                       $deletedRows = $count != 0;
+       
+                       $this->output( "done. $count revisions deleted.\n" );
+       
+                       # This bit's done
+                       # Purge redundant text records
+                       $dbw->commit();
+                       if( $deletedRows ) {
+                               $this->purgeRedundantText( true );
+                       }
+               } else {
+                       $res = $dbw->selectRow( 'archive', 'COUNT(*) as count', array(), __FUNCTION__ );
+                       $this->output( "Found {$res->count} revisions to delete.\n" );
+                       $this->output( "Please run the script again with the --delete option to really delete the revisions.\n" );
+               }
+       }
 }
 
+$maintClass = "DeleteArchivedRevisions";
+require_once( DO_MAINTENANCE );
index 5aeea78..5fc7435 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 /**
  * Deletes a batch of pages
  * Usage: php deleteBatch.php [-u <user>] [-r <reason>] [-i <interval>] [listfile]
  *     <reason> is the delete reason
  *     <interval> is the number of seconds to sleep for after each delete
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
-
-$oldCwd = getcwd();
-$optionsWithArgs = array( 'u', 'r', 'i' );
-require_once( 'commandLine.inc' );
-
-chdir( $oldCwd );
-
-# Options processing
-
-$filename = 'php://stdin';
-$user = 'Delete page script';
-$reason = '';
-$interval = 0;
-
-if ( isset( $args[0] ) ) {
-       $filename = $args[0];
-}
-if ( isset( $options['u'] ) ) {
-       $user = $options['u'];
-}
-if ( isset( $options['r'] ) ) {
-       $reason = $options['r'];
-}
-if ( isset( $options['i'] ) ) {
-       $interval = $options['i'];
-}
-
-$wgUser = User::newFromName( $user );
-
-
-# Setup complete, now start
-
-$file = fopen( $filename, 'r' );
-if ( !$file ) {
-       print "Unable to read file, exiting\n";
-       exit;
-}
-
-$dbw = wfGetDB( DB_MASTER );
-
-for ( $linenum = 1; !feof( $file ); $linenum++ ) {
-       $line = trim( fgets( $file ) );
-       if ( $line == '' ) {
-               continue;
-       }
-       $page = Title::newFromText( $line );
-       if ( is_null( $page ) ) {
-               print "Invalid title '$line' on line $linenum\n";
-               continue;
+require_once( "Maintenance.php" );
+
+class DeleteBatch extends Maintenance {
+       
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Deletes a batch of pages";
+               $this->addOption( 'u', "User to perform deletion", false, true );
+               $this->addOption( 'r', "Reason to delete page", false, true );
+               $this->addOption( 'i', "Interval to sleep between deletions" );
+               $this->addArgs( array( 'listfile' ) );
        }
-       if( !$page->exists() ) {
-               print "Skipping nonexistent page '$line'\n";
-               continue;
-       }
-
-
-       print $page->getPrefixedText();
-       $dbw->begin();
-       if( $page->getNamespace() == NS_FILE ) {
-               $art = new ImagePage( $page );
-               $img = wfFindFile( $art->mTitle );
-               if( !$img || !$img->delete( $reason ) ) {
-                       print "FAILED to delete image file... ";
+       
+       public function execute() {
+               global $wgUser;
+
+               # Change to current working directory
+               $oldCwd = getcwd();
+               chdir( $oldCwd );
+       
+               # Options processing
+               $user = $this->getOption( 'u', 'Delete page script' );
+               $reason = $this->getOption( 'r', '' );
+               $interval = $this->getOption( 'i', 0 );
+               if( $this->hasArg() ) {
+                       $file = fopen( $this->getArg(), 'r' );
+               } else {
+                       $file = $this->getStdin();
                }
-       } else {
-               $art = new Article( $page );
-       }
-       $success = $art->doDeleteArticle( $reason );
-       $dbw->immediateCommit();
-       if ( $success ) {
-               print "\n";
-       } else {
-               print " FAILED to delete image page\n";
-       }
 
-       if ( $interval ) {
-               sleep( $interval );
+               # Setup
+               if( !$file ) {
+                       $this->error( "Unable to read file, exiting\n", true );
+               }
+               $wgUser = User::newFromName( $user );
+               $dbw = wfGetDB( DB_MASTER );
+
+               # Handle each entry
+               for ( $linenum = 1; !feof( $file ); $linenum++ ) {
+                       $line = trim( fgets( $file ) );
+                       if ( $line == '' ) {
+                               continue;
+                       }
+                       $page = Title::newFromText( $line );
+                       if ( is_null( $page ) ) {
+                               $this->output( "Invalid title '$line' on line $linenum\n" );
+                               continue;
+                       }
+                       if( !$page->exists() ) {
+                               $this->output( "Skipping nonexistent page '$line'\n" );
+                               continue;
+                       }
+       
+       
+                       $this->output( $page->getPrefixedText() );
+                       $dbw->begin();
+                       if( $page->getNamespace() == NS_FILE ) {
+                               $art = new ImagePage( $page );
+                               $img = wfFindFile( $art->mTitle );
+                               if( !$img || !$img->delete( $reason ) ) {
+                                       $this->output( "FAILED to delete image file... " );
+                               }
+                       } else {
+                               $art = new Article( $page );
+                       }
+                       $success = $art->doDeleteArticle( $reason );
+                       $dbw->immediateCommit();
+                       if ( $success ) {
+                               $this->output( "\n" );
+                       } else {
+                               $this->output( " FAILED to delete article\n" );
+                       }
+       
+                       if ( $interval ) {
+                               sleep( $interval );
+                       }
+                       wfWaitForSlaves( 5 );
+}
        }
-       wfWaitForSlaves( 5 );
 }
 
-
-
+$maintClass = "DeleteBatch";
+require_once( DO_MAINTENANCE );
index 77e8574..93bd6e8 100644 (file)
@@ -1,48 +1,68 @@
 <?php
-
 /**
  * Deletes all pages in the MediaWiki namespace which were last edited by 
  * "MediaWiki default".
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-if ( !defined( 'MEDIAWIKI' ) ) {
-       require_once( 'commandLine.inc' );
-       deleteDefaultMessages();
-}
+require_once( "Maintenance.php" );
 
-function deleteDefaultMessages() {
-       $user = 'MediaWiki default';
-       $reason = 'No longer required';
+class DeleteDefaultMessages extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Deletes all pages in the MediaWiki namespace" .
+                                                               " which were last edited by \"MediaWiki default\"";
+       }
 
-       global $wgUser;
-       $wgUser = User::newFromName( $user );
-       $wgUser->addGroup( 'bot' );
-       
-       $dbr = wfGetDB( DB_SLAVE );
-       $res = $dbr->select( array( 'page', 'revision' ),
-               array( 'page_namespace', 'page_title' ),
-               array(
-                       'page_namespace' => NS_MEDIAWIKI,
-                       'page_latest=rev_id',
-                       'rev_user_text' => 'MediaWiki default',
-               )
-       );
+       public function execute() {
+               $user = 'MediaWiki default';
+               $reason = 'No longer required';
 
-       $dbw = wfGetDB( DB_MASTER );
+               global $wgUser;
+               $wgUser = User::newFromName( $user );
+               $wgUser->addGroup( 'bot' );
 
-       while ( $row = $dbr->fetchObject( $res ) ) {
-               if ( function_exists( 'wfWaitForSlaves' ) ) {
-                       wfWaitForSlaves( 5 );
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select( array( 'page', 'revision' ),
+                       array( 'page_namespace', 'page_title' ),
+                       array(
+                               'page_namespace' => NS_MEDIAWIKI,
+                               'page_latest=rev_id',
+                               'rev_user_text' => 'MediaWiki default',
+                       )
+               );
+
+               $dbw = wfGetDB( DB_MASTER );
+       
+               while ( $row = $dbr->fetchObject( $res ) ) {
+                       if ( function_exists( 'wfWaitForSlaves' ) ) {
+                               wfWaitForSlaves( 5 );
+                       }
+                       $dbw->ping();
+                       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+                       $article = new Article( $title );
+                       $dbw->begin();
+                       $article->doDeleteArticle( $reason );
+                       $dbw->commit();
                }
-               $dbw->ping();
-               $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-               $article = new Article( $title );
-               $dbw->begin();
-               $article->doDeleteArticle( $reason );
-               $dbw->commit();
        }
 }
 
+$maintClass = "DeleteDefaultMessages";
+require_once( DO_MAINTENANCE );
index 2c3afa8..73712d1 100644 (file)
@@ -1,33 +1,43 @@
 <?php
 /**
- * This script delete image information from memcached.
+ * This script delete image information from the cache.
  *
  * Usage example:
- * php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0 --report 10
+ * php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
  * @ingroup Maintenance
  */
 
-$optionsWithArgs = array( 'until', 'sleep', 'report' );
-
-require_once 'commandLine.inc';
-
-/**
- * @ingroup Maintenance
- */
-class DeleteImageCache {
-       var $until, $sleep, $report;
+require_once( "Maintenance.php" );
 
-       function DeleteImageCache( $until, $sleep, $report ) {
-               $this->until = $until;
-               $this->sleep = $sleep;
-               $this->report = $report;
+class DeleteImageCache extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Delete image information from the cache";
+               $this->addOption( 'sleep', 'How many seconds to sleep between deletions', true, true );
+               $this->addOption( 'until', 'Timestamp to delete all entries prior to', true, true );
        }
 
-       function main() {
+       public function execute() {
                global $wgMemc;
-               $fname = 'DeleteImageCache::main';
+
+               $until = preg_replace( "/[^\d]/", '', $this->getOption('until') );
+               $sleep = (int)$this->getOption('sleep') * 1000; // milliseconds
 
                ini_set( 'display_errors', false );
 
@@ -35,8 +45,8 @@ class DeleteImageCache {
 
                $res = $dbr->select( 'image',
                        array( 'img_name' ),
-                       array( "img_timestamp < {$this->until}" ),
-                       $fname
+                       array( "img_timestamp < {$until}" ),
+                       __METHOD__
                );
 
                $i = 0;
@@ -44,29 +54,22 @@ class DeleteImageCache {
 
                while ( $row = $dbr->fetchObject( $res ) ) {
                        if ($i % $this->report == 0)
-                               printf("%s: %13s done (%s)\n", wfWikiID(), "$i/$total", wfPercent( $i / $total * 100 ));
+                               $this->output( sprintf("%s: %13s done (%s)\n", wfWikiID(), "$i/$total", wfPercent( $i / $total * 100 ) ) );
                        $md5 = md5( $row->img_name );
                        $wgMemc->delete( wfMemcKey( 'Image', $md5 ) );
 
-                       if ($this->sleep != 0)
-                               usleep( $this->sleep );
+                       if ($sleep != 0)
+                               usleep( $sleep );
 
                        ++$i;
                }
        }
 
-       function getImageCount() {
-               $fname = 'DeleteImageCache::getImageCount';
-
+       private function getImageCount() {
                $dbr = wfGetDB( DB_SLAVE );
-               return $dbr->selectField( 'image', 'COUNT(*)', array(), $fname );
+               return $dbr->selectField( 'image', 'COUNT(*)', array(), __METHOD__ );
        }
 }
 
-$until = preg_replace( "/[^\d]/", '', $options['until'] );
-$sleep = (int)$options['sleep'] * 1000; // milliseconds
-$report = (int)$options['report'];
-
-$dic = new DeleteImageCache( $until, $sleep, $report );
-$dic->main();
-
+$maintClass = "DeleteImageCache";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/deleteOldRevisions.inc b/maintenance/deleteOldRevisions.inc
deleted file mode 100644 (file)
index b681b9d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
- * Support functions for the deleteOldRevisions script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-require_once( 'purgeOldText.inc' );
-
-function DeleteOldRevisions( $delete = false, $args = array() ) {
-
-       # Data should come off the master, wrapped in a transaction
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->begin();
-       
-       $tbl_pag = $dbw->tableName( 'page' );
-       $tbl_rev = $dbw->tableName( 'revision' );
-       
-       $pageIdClause = '';
-       $revPageClause = '';
-       
-       # If a list of page_ids was provided, limit results to that set of page_ids
-       if ( sizeof( $args ) > 0 ) {
-               $pageIdList = implode( ',', $args );
-               $pageIdClause = " WHERE page_id IN ({$pageIdList})";
-               $revPageClause = " AND rev_page IN ({$pageIdList})";
-               echo( "Limiting to {$tbl_pag}.page_id IN ({$pageIdList})\n" );
-       }
-       
-       # Get "active" revisions from the page table
-       echo( "Searching for active revisions..." );
-       $res = $dbw->query( "SELECT page_latest FROM $tbl_pag{$pageIdClause}" );
-       while( $row = $dbw->fetchObject( $res ) ) {
-               $cur[] = $row->page_latest;
-       }
-       echo( "done.\n" );
-       
-       # Get all revisions that aren't in this set
-       echo( "Searching for inactive revisions..." );
-       $set = implode( ', ', $cur );
-       $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_id NOT IN ( $set ){$revPageClause}" );
-       while( $row = $dbw->fetchObject( $res ) ) {
-               $old[] = $row->rev_id;
-       }
-       echo( "done.\n" );
-       
-       # Inform the user of what we're going to do
-       $count = count( $old );
-       echo( "$count old revisions found.\n" );
-       
-       # Delete as appropriate
-       if( $delete && $count ) {
-               echo( "Deleting..." );
-               $set = implode( ', ', $old );
-               $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" );
-               echo( "done.\n" );
-       }
-       
-       # This bit's done
-       # Purge redundant text records
-       $dbw->commit();
-       if( $delete ) {
-               PurgeRedundantText( true );
-       }
-
-}
index c283c60..7084751 100644 (file)
 /**
  * Delete old (non-current) revisions from the database
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-$options = array( 'delete', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'deleteOldRevisions.inc' );
+require_once( "Maintenance.php" );
 
-echo( "Delete Old Revisions\n\n" );
+class DeleteOldRevisions extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Delete old (non-current) revisions from the database";
+               $this->addOption( 'delete', 'Actually perform the deletion' );
+       }
+       
+       public function execute() {
+               $this->output( "Delete old revisions\n\n" );
+               if( count( $this->mArgs ) < 1 ) {
+                       $this->error( "Must pass at least 1 page_id", true );
+               }
+               $this->doDelete( $this->hasOption( 'delete' ), $this->mArgs );
+       }
+       
+       function doDelete( $delete = false, $args = array() ) {
 
-if( @$options['help'] ) {
-       ShowUsage();
-} else {
-       DeleteOldRevisions( @$options['delete'], $args );
+               # Data should come off the master, wrapped in a transaction
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+       
+               $tbl_pag = $dbw->tableName( 'page' );
+               $tbl_rev = $dbw->tableName( 'revision' );
+       
+               $pageIdClause = '';
+               $revPageClause = '';
+       
+               # If a list of page_ids was provided, limit results to that set of page_ids
+               if ( sizeof( $args ) > 0 ) {
+                       $pageIdList = implode( ',', $args );
+                       $pageIdClause = " WHERE page_id IN ({$pageIdList})";
+                       $revPageClause = " AND rev_page IN ({$pageIdList})";
+                       $this->output( "Limiting to {$tbl_pag}.page_id IN ({$pageIdList})\n" );
+               }
+       
+               # Get "active" revisions from the page table
+               $this->output( "Searching for active revisions..." );
+               $res = $dbw->query( "SELECT page_latest FROM $tbl_pag{$pageIdClause}" );
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $cur[] = $row->page_latest;
+               }
+               $this->output( "done.\n" );
+       
+               # Get all revisions that aren't in this set
+               $this->output( "Searching for inactive revisions..." );
+               $set = implode( ', ', $cur );
+               $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_id NOT IN ( $set ){$revPageClause}" );
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       $old[] = $row->rev_id;
+               }
+               $this->output( "done.\n" );
+       
+               # Inform the user of what we're going to do
+               $count = count( $old );
+               $this->output( "$count old revisions found.\n" );
+       
+               # Delete as appropriate
+               if( $delete && $count ) {
+                       $this->output( "Deleting..." );
+                       $set = implode( ', ', $old );
+                       $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" );
+                       $this->output( "done.\n" );
+               }
+       
+               # This bit's done
+               # Purge redundant text records
+               $dbw->commit();
+               if( $delete ) {
+                       $this->purgeRedundantText( true );
+               }
+       }
 }
 
-function ShowUsage() {
-       echo( "Deletes non-current revisions from the database.\n\n" );
-       echo( "Usage: php deleteOldRevisions.php [--delete|--help] [<page_id> ...]\n\n" );
-       echo( "delete : Performs the deletion\n" );
-       echo( "  help : Show this usage information\n" );
-}
+$maintClass = "DeleteOldRevisions";
+require_once( DO_MAINTENANCE );
 
diff --git a/maintenance/deleteOrphanedRevisions.inc b/maintenance/deleteOrphanedRevisions.inc
deleted file mode 100644 (file)
index 6678d5b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-/**
- * Support functions for the deleteOrphanedRevisions maintenance script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-/**
- * Delete one or more revisions from the database
- * Do this inside a transaction
- *
- * @param $id Array of revision id values
- * @param $db Database class (needs to be a master)
- */
-function deleteRevisions( $id, &$dbw ) {
-       if( !is_array( $id ) )
-               $id = array( $id );
-       $dbw->delete( 'revision', array( 'rev_id' => $id ), 'deleteRevision' );
-}
-
-/**
- * Spit out script usage information and exit
- */
-function showUsage() {
-       echo( "Finds revisions which refer to nonexisting pages and deletes them from the database\n" );
-       echo( "USAGE: php deleteOrphanedRevisions.php [--report]\n\n" );
-       echo( " --report : Prints out a count of affected revisions but doesn't delete them\n\n" );
-}
-
index 0a22515..1447336 100644 (file)
@@ -4,53 +4,86 @@
  * Maintenance script to delete revisions which refer to a nonexisting page
  * Sometimes manual deletion done in a rush leaves crap in the database
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  * @todo More efficient cleanup of text records
  */
-$options = array( 'report', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'deleteOrphanedRevisions.inc' );
-echo( "Delete Orphaned Revisions\n" );
-
-if( isset( $options['help'] ) ) {
-       showUsage();
-       exit(1);
-}
 
-$report = isset( $options['report'] );
+require_once( "Maintenance.php" );
 
-$dbw = wfGetDB( DB_MASTER );
-$dbw->immediateBegin();
-extract( $dbw->tableNames( 'page', 'revision' ) );
+class DeleteOrphanedRevisions extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Maintenance script to delete revisions which refer to a nonexisting page";
+               $this->addOption( 'report', 'Prints out a count of affected revisions but doesn\'t delete them' );
+       }
 
-# Find all the orphaned revisions
-echo( "Checking for orphaned revisions..." );
-$sql = "SELECT rev_id FROM {$revision} LEFT JOIN {$page} ON rev_page = page_id WHERE page_namespace IS NULL";
-$res = $dbw->query( $sql, 'deleteOrphanedRevisions' );
+       public function execute() {
+               $this->output( "Delete Orphaned Revisions\n" );
 
-# Stash 'em all up for deletion (if needed)
-while( $row = $dbw->fetchObject( $res ) )
-       $revisions[] = $row->rev_id;
-$dbw->freeResult( $res );
-$count = count( $revisions );
-echo( "found {$count}.\n" );
+               $report = $this->hasOption('report');
 
-# Nothing to do?
-if( $report || $count == 0 ) {
-       $dbw->immediateCommit();
-       exit(0);
-}
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->immediateBegin();
+               list( $page, $revision ) = $dbw->tableNames( 'page', 'revision' );
 
-# Delete each revision
-echo( "Deleting..." );
-deleteRevisions( $revisions, $dbw );
-echo( "done.\n" );
+               # Find all the orphaned revisions
+               $this->output( "Checking for orphaned revisions..." );
+               $sql = "SELECT rev_id FROM {$revision} LEFT JOIN {$page} ON rev_page = page_id WHERE page_namespace IS NULL";
+               $res = $dbw->query( $sql, 'deleteOrphanedRevisions' );
+       
+               # Stash 'em all up for deletion (if needed)
+               while( $row = $dbw->fetchObject( $res ) )
+                       $revisions[] = $row->rev_id;
+               $dbw->freeResult( $res );
+               $count = count( $revisions );
+               $this->output( "found {$count}.\n" );
+       
+               # Nothing to do?
+               if( $report || $count == 0 ) {
+                       $dbw->immediateCommit();
+                       exit(0);
+               }
+       
+               # Delete each revision
+               $this->output( "Deleting..." );
+               $this->deleteRevs( $revisions, $dbw );
+               $this->output( "done.\n" );
+       
+               # Close the transaction and call the script to purge unused text records
+               $dbw->immediateCommit();
+               $this->purgeRedundantText( true );
+       }
+       
+       /**
+        * Delete one or more revisions from the database
+        * Do this inside a transaction
+        *
+        * @param $id Array of revision id values
+        * @param $db Database class (needs to be a master)
+        */
+       private function deleteRevs( $id, &$dbw ) {
+               if( !is_array( $id ) )
+                       $id = array( $id );
+               $dbw->delete( 'revision', array( 'rev_id' => $id ), __METHOD__ );
+       }
+}
 
-# Close the transaction and call the script to purge unused text records
-$dbw->immediateCommit();
-require_once( 'purgeOldText.inc' );
-PurgeRedundantText( true );
+$maintClass = "DeleteOrphanedRevisions";
+require_once( DO_MAINTENANCE );
 
index 49baf60..9be733a 100644 (file)
@@ -2,56 +2,81 @@
 /**
  * Delete one or more revisions by moving them to the archive table.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
  * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
-
-$dbw = wfGetDB( DB_MASTER );
+require_once( "Maintenance.php" );
 
-if ( count( $args ) == 0 ) {
-       echo "Usage: php deleteRevision.php <revid> [<revid> ...]\n";
-       exit(1);
-}
-
-echo "Deleting revision(s) " . implode( ',', $args ) . " from ".wfWikiID()."...\n";
-
-$affected = 0;
-foreach ( $args as $revID ) {
-       $dbw->insertSelect( 'archive', array( 'page', 'revision' ),
-               array(
-                       'ar_namespace'  => 'page_namespace',
-                       'ar_title'      => 'page_title',
-                       'ar_page_id'    => 'page_id',
-                       'ar_comment'    => 'rev_comment',
-                       'ar_user'       => 'rev_user',
-                       'ar_user_text'  => 'rev_user_text',
-                       'ar_timestamp'  => 'rev_timestamp',
-                       'ar_minor_edit' => 'rev_minor_edit',
-                       'ar_rev_id'     => 'rev_id',
-                       'ar_text_id'    => 'rev_text_id',
-                       'ar_deleted'    => 'rev_deleted',
-                       'ar_len'        => 'rev_len',
-               ), array(
-                       'rev_id' => $revID,
-                       'page_id = rev_page'
-               ), $fname
-       );
-       if ( !$dbw->affectedRows() ) {
-               echo "Revision $revID not found\n";
-       } else {
-               $affected += $dbw->affectedRows();
-               $dbw->delete( 'revision', array( 'rev_id' => $revID ) );
+class DeleteRevision extends Maintenance {
+       
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Delete one or more revisions by moving them to the archive table";
+       }
+       
+       public function execute() {
+               if( count( $this->mArgs ) == 0 ) {
+                       $this->error( "No revisions specified", true );
+               }
 
-               // Database integrity
-               $pageID = $dbw->selectField( 'page', 'page_id', array( 'page_latest' => $revID ), __METHOD__ );
-               if ( $pageID ) {
-                       $newLatest = $dbw->selectField( 'revision', 'rev_id', array( 'rev_page' => $pageID ), __METHOD__, array( 'ORDER BY' => 'rev_timestamp DESC' ) );
-                       $dbw->update( 'page', array( 'page_latest' => $newLatest ), array( 'page_id' => $pageID ), __METHOD__ );
+               $this->output( "Deleting revision(s) " . implode( ',', $this->mArgs ) . 
+                                               " from " . wfWikiID() . "...\n" );
+               $dbw = wfGetDB( DB_MASTER );
+               
+               $affected = 0;
+               foreach ( $this->mArgs as $revID ) {
+                       $dbw->insertSelect( 'archive', array( 'page', 'revision' ),
+                               array(
+                                       'ar_namespace'  => 'page_namespace',
+                                       'ar_title'      => 'page_title',
+                                       'ar_page_id'    => 'page_id',
+                                       'ar_comment'    => 'rev_comment',
+                                       'ar_user'       => 'rev_user',
+                                       'ar_user_text'  => 'rev_user_text',
+                                       'ar_timestamp'  => 'rev_timestamp',
+                                       'ar_minor_edit' => 'rev_minor_edit',
+                                       'ar_rev_id'     => 'rev_id',
+                                       'ar_text_id'    => 'rev_text_id',
+                                       'ar_deleted'    => 'rev_deleted',
+                                       'ar_len'        => 'rev_len',
+                               ), array(
+                                       'rev_id' => $revID,
+                                       'page_id = rev_page'
+                               ), __METHOD__
+                       );
+                       if ( !$dbw->affectedRows() ) {
+                               $this->output( "Revision $revID not found\n" );
+                       } else {
+                               $affected += $dbw->affectedRows();
+                               $dbw->delete( 'revision', array( 'rev_id' => $revID ) );
+                               
+                               // Database integrity
+                               $pageID = $dbw->selectField( 'page', 'page_id', array( 'page_latest' => $revID ), __METHOD__ );
+                               if ( $pageID ) {
+                                       $newLatest = $dbw->selectField( 'revision', 'rev_id', array( 'rev_page' => $pageID ), __METHOD__, array( 'ORDER BY' => 'rev_timestamp DESC' ) );
+                                       $dbw->update( 'page', array( 'page_latest' => $newLatest ), array( 'page_id' => $pageID ), __METHOD__ );
+                               }
+                       }
                }
+               $this->output( "Deleted $affected revisions\n" );
        }
 }
 
-print "Deleted $affected revisions\n";
-
+$maintClass = "DeleteRevision";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php
new file mode 100644 (file)
index 0000000..fc816f4
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * We want to make this whole thing as seamless as possible to the
+ * end-user. Unfortunately, we can't do _all_ of the work in the class
+ * because A) included files are not in global scope, but in the scope 
+ * of their caller, and B) MediaWiki has way too many globals. So instead
+ * we'll kinda fake it, and do the requires() inline. <3 PHP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @author Chad Horohoe <chad@anyonecanedit.org>
+ * @file
+ * @ingroup Maintenance
+ */
+
+error_reporting( E_ALL | E_STRICT );
+
+if( !isset( $maintClass ) || !class_exists( $maintClass ) ) {
+       echo "\$maintClass is not set or is set to a non-existent class.";
+       die();
+}
+
+if( defined( 'MW_NO_SETUP' ) ) {
+       return;
+}
+
+// Get an object to start us off
+$maintenance = new $maintClass();
+
+// Basic sanity checks and such
+$maintenance->setup();
+
+// We used to call this variable $self, but it was moved
+// to $maintenance->mSelf. Keep that here for b/c
+$self = $maintenance->getName();
+
+# Setup the profiler
+if ( file_exists( "$IP/StartProfiler.php" ) ) {
+       require_once( "$IP/StartProfiler.php" );
+} else {
+       require_once( "$IP/includes/ProfilerStub.php" );
+}
+
+// Load settings, using wikimedia-mode if needed
+if( file_exists( dirname(__FILE__).'/wikimedia-mode' ) ) {
+       # TODO FIXME! Wikimedia-specific stuff needs to go away to an ext
+       # Maybe a hook?
+       global $cluster;
+       $wgWikiFarm = true;
+       $cluster = 'pmtma';
+       require_once( "$IP/includes/AutoLoader.php" );
+       require_once( "$IP/includes/SiteConfiguration.php" );
+       require( "$IP/wgConf.php" );
+       $maintenance->loadWikimediaSettings();
+       require( $IP.'/includes/Defines.php' );
+       require( $IP.'/CommonSettings.php' );
+} else {
+       require_once( "$IP/includes/AutoLoader.php" );
+       require_once( "$IP/includes/Defines.php" );
+       require_once( $maintenance->loadSettings() );
+}
+// Some last includes
+require_once( "$IP/includes/Setup.php" );
+require_once( "$IP/install-utils.inc" );
+
+// Much much faster startup than creating a title object
+$wgTitle = null; 
+
+// Do the work
+try {
+       $maintenance->execute();
+} catch( MWException $mwe ) {
+       echo( $mwe->getText() );
+}
+
+// Potentially debug globals
+$maintenance->globals();
index 65dfac6..a3e2bd1 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
  * @ingroup Mainatenance
  */
 
-require_once 'commandLine.inc';
+require_once( "Maintenance.php" );
 
-$dbr = wfGetDB( DB_SLAVE );
-$result = $dbr->select( array( 'pagelinks', 'page' ),
-       array(
-               'page_id',
-               'page_namespace',
-               'page_title',
-               'pl_namespace',
-               'pl_title' ),
-       array( 'page_id=pl_from' ),
-       'dumpLinks',
-       array( 'ORDER BY' => 'page_id' ) );
+class DumpLinks extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Quick demo hack to generate a plaintext link dump";
+       }
 
-$lastPage = null;
-while( $row = $dbr->fetchObject( $result ) ) {
-       if( $lastPage != $row->page_id ) {
-               if( isset( $lastPage ) ) {
-                       print "\n";
+       public function execute() {
+               $dbr = wfGetDB( DB_SLAVE );
+               $result = $dbr->select( array( 'pagelinks', 'page' ),
+                       array(
+                               'page_id',
+                               'page_namespace',
+                               'page_title',
+                               'pl_namespace',
+                               'pl_title' ),
+                       array( 'page_id=pl_from' ),
+                       __METHOD__,
+                       array( 'ORDER BY' => 'page_id' ) );
+       
+               $lastPage = null;
+               while( $row = $dbr->fetchObject( $result ) ) {
+                       if( $lastPage != $row->page_id ) {
+                               if( isset( $lastPage ) ) {
+                                       $this->output( "\n" );
+                               }
+                               $page = Title::makeTitle( $row->page_namespace, $row->page_title );
+                               $this->output( $page->getPrefixedUrl() );
+                               $lastPage = $row->page_id;
+                       }
+                       $link = Title::makeTitle( $row->pl_namespace, $row->pl_title );
+                       $this-output( " " . $link->getPrefixedUrl() );
                }
-               $page = Title::makeTitle( $row->page_namespace, $row->page_title );
-               print $page->getPrefixedUrl();
-               $lastPage = $row->page_id;
+               if( isset( $lastPage ) )
+                       $this->output( "\n" );
        }
-       $link = Title::makeTitle( $row->pl_namespace, $row->pl_title );
-       print " " . $link->getPrefixedUrl();
 }
-if( isset( $lastPage ) )
-       print "\n";
 
+$maintClass = "DumpLinks";
+require_once( DO_MAINTENANCE );
 
index 2a7369c..5b397b7 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
- * @ingroup SpecialPage
+ * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-$dbr = wfGetDB( DB_SLAVE );
-$dbr->bufferResults( false );
-$result = $dbr->select( 'page',
-       array( 'page_namespace', 'page_title' ),
-       array(
-               'page_namespace'   => NS_MAIN,
-               'page_is_redirect' => 0,
-       ),
-       'dumpSisterSites' );
+class DumpSisterSites extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Quickie page name dump script for SisterSites usage";
+       }
+       
+       public function execute() {
+               $dbr = wfGetDB( DB_SLAVE );
+               $dbr->bufferResults( false );
+               $result = $dbr->select( 'page',
+                       array( 'page_namespace', 'page_title' ),
+                       array( 'page_namespace'   => NS_MAIN,
+                                  'page_is_redirect' => 0,
+                       ),
+                       __METHOD__ );
 
-while( $row = $dbr->fetchObject( $result ) ) {
-       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-       $url = $title->getFullUrl();
-       $text = $title->getPrefixedText();
-       echo "$url $text\n";
+               while( $row = $dbr->fetchObject( $result ) ) {
+                       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+                       $url = $title->getFullUrl();
+                       $text = $title->getPrefixedText();
+                       $this->output( "$url $text\n" );
+               }
+               $dbr->freeResult( $result );
+       }
 }
 
-$dbr->freeResult( $result );
-
-
+$maintClass = "DumpSisterSites";
+require_once( DO_MAINTENANCE );
index c237fee..ec549e6 100644 (file)
@@ -1,37 +1,55 @@
 <?php
 /**
- * @file
+ * Dump a the list of files uploaded, for feeding to tar or similar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once 'commandLine.inc';
+require_once( "Maintenance.php" );
 
-class UploadDumper {
-       function __construct( $args ) {
+class UploadDumper extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Generates list of uploaded files which can be fed to tar or similar.
+By default, outputs relative paths against the parent directory of \$wgUploadDirectory.";
+               $this->addOption( 'base', 'Set base relative path instead of wiki include root', false, true );
+               $this->addOption( 'local', 'List all local files, used or not. No shared files included' );
+               $this->addOption( 'used', 'Skip local images that are not used' );
+               $this->addOption( 'shared', 'Include images used from shared repository' );
+       }
+
+       public function execute() {
                global $IP, $wgUseSharedUploads;
                $this->mAction = 'fetchLocal';
-               $this->mBasePath = $IP;
+               $this->mBasePath = $this->getOption( 'base', $IP );
                $this->mShared = false;
                $this->mSharedSupplement = false;
-               
-               if( isset( $args['help'] ) ) {
-                       $this->mAction = 'help';
-               }
-               
-               if( isset( $args['base'] ) ) {
-                       $this->mBasePath = $args['base'];
-               }
-               
-               if( isset( $args['local'] ) ) {
+
+               if( $this->hasOption('local') ) {
                        $this->mAction = 'fetchLocal';
                }
                
-               if( isset( $args['used'] ) ) {
+               if( $this->hasOption('used') ) {
                        $this->mAction = 'fetchUsed';
                }
                
-               if( isset( $args['shared'] ) ) {
-                       if( isset( $args['used'] ) ) {
+               if( $this->hasOption('shared') ) {
+                       if( $this->hasOption('used') ) {
                                // Include shared-repo files in the used check
                                $this->mShared = true;
                        } else {
@@ -39,34 +57,12 @@ class UploadDumper {
                                $this->mSharedSupplement = true;
                        }
                }
-       }
-       
-       function run() {
                $this->{$this->mAction}( $this->mShared );
                if( $this->mSharedSupplement ) {
                        $this->fetchUsed( true );
                }
        }
-       
-       function help() {
-               echo <<<END
-Generates list of uploaded files which can be fed to tar or similar.
-By default, outputs relative paths against the parent directory of
-\$wgUploadDirectory.
 
-Usage:
-php dumpUploads.php [options] > list-o-files.txt
-
-Options:
---base=<path>  Set base relative path instead of wiki include root
-
---local        List all local files, used or not. No shared files included.
---used         Skip local images that are not used
---shared       Include images used from shared repository
-
-END;
-       }
-       
        /**
         * Fetch a list of all or used images from a particular image source.
         * @param string $table
@@ -89,7 +85,7 @@ END;
                }
                $dbr->freeResult( $result );
        }
-       
+
        function fetchLocal( $shared ) {
                $dbr = wfGetDB( DB_SLAVE );
                $result = $dbr->select( 'image',
@@ -108,17 +104,16 @@ END;
                if( $file && $this->filterItem( $file, $shared ) ) {
                        $filename = $file->getFullPath();
                        $rel = wfRelativePath( $filename, $this->mBasePath );
-                       echo "$rel\n";
+                       $this->output( "$rel\n" );
                } else {
                        wfDebug( __METHOD__ . ": base file? $name\n" );
                }
        }
-       
+
        function filterItem( $file, $shared ) {
                return $shared || $file->isLocal();
        }
 }
 
-$dumper = new UploadDumper( $options );
-$dumper->run();
-
+$maintClass = "UploadDumper";
+require_once( DO_MAINTENANCE );
index 6417804..9fdce24 100644 (file)
@@ -1,77 +1,89 @@
 <?php
 /**
- * @file
+ * Make an edit
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$optionsWithArgs = array( 'u', 's' );
+require_once( "Maintenance.php" );
 
-require_once( 'commandLine.inc' );
+class EditCLI extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Edit an article from the command line, text is from stdin";
+               $this->addOption( 'u', 'Username', false, true );
+               $this->addOption( 's', 'Edit summary', false, true );
+               $this->addOption( 'm', 'Minor edit' );
+               $this->addOption( 'b', 'Bot edit' );
+               $this->addOption( 'a', 'Enable autosummary' );
+               $this->addOption( 'no-rc', 'Do not show the change in recent changes' );
+               $this->addArgs( array( 'title' ) );
+       }
 
-if ( count( $args ) == 0 || isset( $options['help'] ) ) {
-       print <<<EOT
-Edit an article from the command line
+       public function execute() {
+               global $wgUser, $wgTitle, $wgArticle;
 
-Usage: php edit.php [options...] <title>
-
-Options:
-  -u <user>         Username
-  -s <summary>      Edit summary
-  -m                Minor edit
-  -b                Bot (hidden) edit
-  -a                Enable autosummary
-  --no-rc           Do not show the change in recent changes
-
-If the specified user does not exist, it will be created. 
-The text for the edit will be read from stdin.
-
-EOT;
-       exit( 1 );
-}
-
-$userName = isset( $options['u'] ) ? $options['u'] : 'Maintenance script';
-$summary = isset( $options['s'] ) ? $options['s'] : '';
-$minor = isset( $options['m'] );
-$bot = isset( $options['b'] );
-$autoSummary = isset( $options['a'] );
-$noRC = isset( $options['no-rc'] );
-
-$wgUser = User::newFromName( $userName );
-if ( !$wgUser ) {
-       print "Invalid username\n";
-       exit( 1 );
-}
-if ( $wgUser->isAnon() ) {
-       $wgUser->addToDatabase();
+               $userName = $this->getOption( 'u', 'Maintenance script' );
+               $summary = $this->getOption( 's', '' );
+               $minor = $this->hasOption( 'm' );
+               $bot = $this->hasOption( 'b' );
+               $autoSummary = $this->hasOption( 'a' );
+               $noRC = $this->hasOption( 'no-rc' );
+               
+               $wgUser = User::newFromName( $userName );
+               if ( !$wgUser ) {
+                       $this->error( "Invalid username\n", true );
+               }
+               if ( $wgUser->isAnon() ) {
+                       $wgUser->addToDatabase();
+               }
+       
+               $wgTitle = Title::newFromText( $this->getArg() );
+               if ( !$wgTitle ) {
+                       $this->error( "Invalid title\n", true );
+               }
+       
+               $wgArticle = new Article( $wgTitle );
+       
+               # Read the text
+               $text = $this->getStdin();
+               
+               # Do the edit
+               $this->output( "Saving... " );
+               $status = $wgArticle->doEdit( $text, $summary, 
+                       ( $minor ? EDIT_MINOR : 0 ) |
+                       ( $bot ? EDIT_FORCE_BOT : 0 ) | 
+                       ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) |
+                       ( $noRC ? EDIT_SUPPRESS_RC : 0 ) );
+               if ( $status->isOK() ) {
+                       $this->output( "done\n" );
+                       $exit = 0;
+               } else {
+                       $this->output( "failed\n" );
+                       $exit = 1;
+               }
+               if ( !$status->isGood() ) {
+                       $this->output( $status->getWikiText() . "\n" );
+               }
+               exit( $exit );
+       }
 }
 
-$wgTitle = Title::newFromText( $args[0] );
-if ( !$wgTitle ) {
-       print "Invalid title\n";
-       exit( 1 );
-}
-
-$wgArticle = new Article( $wgTitle );
-
-# Read the text
-$text = file_get_contents( 'php://stdin' );
-
-# Do the edit
-print "Saving... ";
-$status = $wgArticle->doEdit( $text, $summary, 
-       ( $minor ? EDIT_MINOR : 0 ) |
-       ( $bot ? EDIT_FORCE_BOT : 0 ) | 
-       ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) |
-       ( $noRC ? EDIT_SUPPRESS_RC : 0 ) );
-if ( $status->isOK() ) {
-       print "done\n";
-       $exit = 0;
-} else {
-       print "failed\n";
-       $exit = 1;
-}
-if ( !$status->isGood() ) {
-       print $status->getWikiText() . "\n";
-}
-exit( $exit );
+$maintClass = "EditCLI";
+require_once( DO_MAINTENANCE );
 
index a990a4d..b1b1308 100644 (file)
  * To get decent line editing behavior, you should compile PHP with support
  * for GNU readline (pass --with-readline to configure).
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$wgUseNormalUser = (bool)getenv('MW_WIKIUSER');
+require_once( "Maintenance.php" );
 
-$optionsWithArgs = array( 'd' );
+class EvalPrompt extends Maintenance {
 
-/** */
-require_once( "commandLine.inc" );
-
-if ( isset( $options['d'] ) ) {
-       $d = $options['d'];
-       if ( $d > 0 ) {
-               $wgDebugLogFile = '/dev/stdout';
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "This script lets a command-line user start up the wiki engine and then poke\n" .
+                                                               "about by issuing PHP commands directly.";
+               $this->addOption( 'd', "Enable MediaWiki debug output", false, true );
        }
-       if ( $d > 1 ) {
-               $lb = wfGetLB();
-               foreach ( $lb->mServers as $i => $server ) {
-                       $lb->mServers[$i]['flags'] |= DBO_DEBUG;
+       
+       public function execute() {
+               global $wgUseNormalUser, $wgDebugFunctionEntry, $wgDebugLogFile;
+               $wgUseNormalUser = (bool)getenv('MW_WIKIUSER');
+               if ( $this->hasOption('d') ) {
+                       $d = $this->getOption('d');
+                       if ( $d > 0 ) {
+                               $wgDebugLogFile = '/dev/stdout';
+                       }
+                       if ( $d > 1 ) {
+                               $lb = wfGetLB();
+                               foreach ( $lb->mServers as $i => $server ) {
+                                       $lb->mServers[$i]['flags'] |= DBO_DEBUG;
+                               }
+                       }
+                       if ( $d > 2 ) {
+                               $wgDebugFunctionEntry = true;
+                       }
                }
-       }
-       if ( $d > 2 ) {
-               $wgDebugFunctionEntry = true;
-       }
-}
-
-if ( function_exists( 'readline_add_history' ) 
-       && function_exists( 'posix_isatty' ) && posix_isatty( 0 /*STDIN*/ ) ) 
-{
-       $useReadline = true;
-} else {
-       $useReadline = false;
-}
-
-if ( $useReadline ) {
-       $historyFile = "{$_ENV['HOME']}/.mweval_history";
-       readline_read_history( $historyFile );
-}
-
-while ( ( $line = readconsole( '> ' ) ) !== false ) {
-       if ( $useReadline ) {
-               readline_add_history( $line );
-               readline_write_history( $historyFile );
-       }
-       $val = eval( $line . ";" );
-       if( is_null( $val ) ) {
-               echo "\n";
-       } elseif( is_string( $val ) || is_numeric( $val ) ) {
-               echo "$val\n";
-       } else {
-               var_dump( $val );
+       
+               if ( function_exists( 'readline_add_history' ) 
+                       && function_exists( 'posix_isatty' ) && posix_isatty( 0 /*STDIN*/ ) ) 
+               {
+                       $useReadline = true;
+               } else {
+                       $useReadline = false;
+               }
+       
+               if ( $useReadline ) {
+                       $historyFile = "{$_ENV['HOME']}/.mweval_history";
+                       readline_read_history( $historyFile );
+               }
+       
+               while ( ( $line = readconsole( '> ' ) ) !== false ) {
+                       if ( $useReadline ) {
+                               readline_add_history( $line );
+                               readline_write_history( $historyFile );
+                       }
+                       $val = eval( $line . ";" );
+                       if( is_null( $val ) ) {
+                               echo "\n";
+                       } elseif( is_string( $val ) || is_numeric( $val ) ) {
+                               echo "$val\n";
+                       } else {
+                               var_dump( $val );
+                       }
+               }
+               print "\n";
        }
 }
 
-print "\n";
-
-
+$maintClass = "EvalPrompt";
+require_once( DO_MAINTENANCE );
index 91b78be..76e0dd1 100644 (file)
@@ -2,38 +2,66 @@
 /**
  * Communications protocol...
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require "commandLine.inc";
+require_once( "Maintenance.php" );
 
-$db = wfGetDB( DB_SLAVE );
-$stdin = fopen( "php://stdin", "rt" );
-while( !feof( $stdin ) ) {
-       $line = fgets( $stdin );
-       if( $line === false ) {
-               // We appear to have lost contact...
-               break;
+class FetchText extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Fetch the revision text from an old_id";
        }
-       $textId = intval( $line );
-       $text = doGetText( $db, $textId );
-       echo strlen( $text ) . "\n";
-       echo $text;
-}
 
-/**
- * May throw a database error if, say, the server dies during query.
- */
-function doGetText( $db, $id ) {
-       $id = intval( $id );
-       $row = $db->selectRow( 'text',
-               array( 'old_text', 'old_flags' ),
-               array( 'old_id' => $id ),
-               'TextPassDumper::getText' );
-       $text = Revision::getRevisionText( $row );
-       if( $text === false ) {
-               return false;
+       public function execute() {
+               $db = wfGetDB( DB_SLAVE );
+               $stdin = $this->getStdin();
+               while( !feof( $stdin ) ) {
+                       $line = fgets( $stdin );
+                       if( $line === false ) {
+                               // We appear to have lost contact...
+                               break;
+                       }
+                       $textId = intval( $line );
+                       $text = $this->doGetText( $db, $textId );
+                       $this->output( strlen( $text ) . "\n". $text );
+               }
+       }
+       
+       /**
+        * May throw a database error if, say, the server dies during query.
+        * @param $db Database object
+        * @param $id int The old_id
+        * @return String
+        */
+       private function doGetText( $db, $id ) {
+               $id = intval( $id );
+               $row = $db->selectRow( 'text',
+                       array( 'old_text', 'old_flags' ),
+                       array( 'old_id' => $id ),
+                       'TextPassDumper::getText' );
+               $text = Revision::getRevisionText( $row );
+               if( $text === false ) {
+                       return false;
+               }
+               return $text;
        }
-       return $text;
 }
+
+$maintClass = "FetchText";
+require_once( DO_MAINTENANCE );
index 6c34909..c10e113 100644 (file)
  *
  * Any instance of wfRunHooks that doesn't meet these parameters will be noted.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  *
  * @author Ashar Voultoiz <hashar@altern.org>
  * @license http://www.gnu.org/copyleft/gpl.html GNU General Public Licence 2.0 or later
  */
 
-/** This is a command line script*/
-require('commandLine.inc');
-# GLOBALS
+require_once( "Maintenance.php" );
 
-$doc = $IP . '/docs/hooks.txt';
-$pathinc = array(
-       $IP.'/',
-       $IP.'/includes/',
-       $IP.'/includes/api/',
-       $IP.'/includes/db/',
-       $IP.'/includes/diff/',
-       $IP.'/includes/filerepo/',
-       $IP.'/includes/parser/',
-       $IP.'/includes/search/',
-       $IP.'/includes/specials/',
-       $IP.'/includes/upload/',
-       $IP.'/languages/',
-       $IP.'/maintenance/',
-       $IP.'/skins/',
-);
+class FindHooks extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Find hooks that are undocumented, missing, or just plain wrong";
+               $this->addOption( 'online', 'Check against mediawiki.org hook documentation' );
+       }
 
-# FUNCTIONS
+       public function execute() {
+               global $IP;
 
-/**
- * @return array of documented hooks
- */
-function getHooksFromDoc() {
-       global $doc, $options;
-       if( isset( $options['online'] ) ){
-               // All hooks
-               $allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' );
-               $allhookdata = unserialize( $allhookdata );
-               $allhooks = array();
-               foreach( $allhookdata['query']['categorymembers'] as $page ) {
-                       $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
-                       if( $found ) {
-                               $hook = str_replace( ' ', '_', $matches[1] );
-                               $allhooks[] = $hook;
-                       }
+               $documented = $this->getHooksFromDoc( $IP . '/docs/hooks.txt' );
+               $potential = array();
+               $bad = array();
+               $pathinc = array(
+                       $IP.'/',
+                       $IP.'/includes/',
+                       $IP.'/includes/api/',
+                       $IP.'/includes/db/',
+                       $IP.'/includes/diff/',
+                       $IP.'/includes/filerepo/',
+                       $IP.'/includes/parser/',
+                       $IP.'/includes/search/',
+                       $IP.'/includes/specials/',
+                       $IP.'/includes/upload/',
+                       $IP.'/languages/',
+                       $IP.'/maintenance/',
+                       $IP.'/skins/',
+               );
+
+               foreach( $pathinc as $dir ) {
+                       $potential = array_merge( $potential, $this->getHooksFromPath( $dir ) );
+                       $bad = array_merge( $bad, $this->getBadHooksFromPath( $dir ) );
                }
-               // Removed hooks
-               $oldhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Removed_hooks&cmlimit=500&format=php' );
-               $oldhookdata = unserialize( $oldhookdata );
-               $removed = array();
-               foreach( $oldhookdata['query']['categorymembers'] as $page ) {
-                       $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
-                       if( $found ) {
-                               $hook = str_replace( ' ', '_', $matches[1] );
-                               $removed[] = $hook;
+       
+               $potential = array_unique( $potential );
+               $bad = array_unique( $bad );
+               $todo = array_diff( $potential, $documented );
+               $deprecated = array_diff( $documented, $potential );
+       
+               // let's show the results:
+               $this->printArray('Undocumented', $todo );
+               $this->printArray('Documented and not found', $deprecated );
+               $this->printArray('Unclear hook calls', $bad );
+       
+               if ( count( $todo ) == 0 && count( $deprecated ) == 0 && count( $bad ) == 0 ) 
+                       $this->output( "Looks good!\n" );
+       }
+
+       /**
+        * Get the hook documentation, either locally or from mediawiki.org
+        * @return array of documented hooks
+        */
+       private function getHooksFromDoc( $doc ) {
+               if( $this->hasOption( 'online' ) ){
+                       // All hooks
+                       $allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' );
+                       $allhookdata = unserialize( $allhookdata );
+                       $allhooks = array();
+                       foreach( $allhookdata['query']['categorymembers'] as $page ) {
+                               $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
+                               if( $found ) {
+                                       $hook = str_replace( ' ', '_', $matches[1] );
+                                       $allhooks[] = $hook;
+                               }
+                       }
+                       // Removed hooks
+                       $oldhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Removed_hooks&cmlimit=500&format=php' );
+                       $oldhookdata = unserialize( $oldhookdata );
+                       $removed = array();
+                       foreach( $oldhookdata['query']['categorymembers'] as $page ) {
+                               $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
+                               if( $found ) {
+                                       $hook = str_replace( ' ', '_', $matches[1] );
+                                       $removed[] = $hook;
+                               }
                        }
+                       return array_diff( $allhooks, $removed );
+               } else {
+                       $m = array();
+                       $content = file_get_contents( $doc );
+                       preg_match_all( "/\n'(.*?)'/", $content, $m );
+                       return array_unique( $m[1] );
                }
-               return array_diff( $allhooks, $removed );
-       } else {
-               $m = array();
-               $content = file_get_contents( $doc );
-               preg_match_all( "/\n'(.*?)'/", $content, $m );
-               return array_unique( $m[1] );
        }
-}
 
-/**
- * Get hooks from a PHP file
- * @param $file Full filename to the PHP file.
- * @return array of hooks found.
- */
-function getHooksFromFile( $file ) {
-       $content = file_get_contents( $file );
-       $m = array();
-       preg_match_all( '/wfRunHooks\(\s*([\'"])(.*?)\1/', $content, $m);
-       return $m[2];
-}
+       /**
       * Get hooks from a PHP file
       * @param $file Full filename to the PHP file.
       * @return array of hooks found.
       */
+       private function getHooksFromFile( $file ) {
+               $content = file_get_contents( $file );
+               $m = array();
+               preg_match_all( '/wfRunHooks\(\s*([\'"])(.*?)\1/', $content, $m);
+               return $m[2];
+       }
 
-/**
- * Get hooks from the source code.
- * @param $path Directory where the include files can be found
- * @return array of hooks found.
- */
-function getHooksFromPath( $path ) {
-       $hooks = array();
-       if( $dh = opendir($path) ) {
-               while(($file = readdir($dh)) !== false) {
-                       if( filetype($path.$file) == 'file' ) {
-                               $hooks = array_merge( $hooks, getHooksFromFile($path.$file) );
+       /**
+        * Get hooks from the source code.
+        * @param $path Directory where the include files can be found
+        * @return array of hooks found.
+        */
+       private function getHooksFromPath( $path ) {
+               $hooks = array();
+               if( $dh = opendir($path) ) {
+                       while(($file = readdir($dh)) !== false) {
+                               if( filetype($path.$file) == 'file' ) {
+                                       $hooks = array_merge( $hooks, $this->getHooksFromFile($path.$file) );
+                               }
                        }
+                       closedir($dh);
                }
-               closedir($dh);
+               return $hooks;
        }
-       return $hooks;
-}
 
-/**
- * Get bad hooks (where the hook name could not be determined) from a PHP file
- * @param $file Full filename to the PHP file.
- * @return array of bad wfRunHooks() lines
- */
-function getBadHooksFromFile( $file ) {
-       $content = file_get_contents( $file );
-       $m = array();
-       # We want to skip the "function wfRunHooks()" one.  :)
-       preg_match_all( '/(?<!function )wfRunHooks\(\s*[^\s\'"].*/', $content, $m);
-       $list = array();
-       foreach( $m[0] as $match ){
-               $list[] = $match . "(" . $file . ")";
+       /**
+        * Get bad hooks (where the hook name could not be determined) from a PHP file
+        * @param $file Full filename to the PHP file.
+        * @return array of bad wfRunHooks() lines
+        */
+       private function getBadHooksFromFile( $file ) {
+               $content = file_get_contents( $file );
+               $m = array();
+               # We want to skip the "function wfRunHooks()" one.  :)
+               preg_match_all( '/(?<!function )wfRunHooks\(\s*[^\s\'"].*/', $content, $m);
+               $list = array();
+               foreach( $m[0] as $match ){
+                       $list[] = $match . "(" . $file . ")";
+               }
+               return $list;
        }
-       return $list;
-}
 
-/**
- * Get bad hooks from the source code.
- * @param $path Directory where the include files can be found
- * @return array of bad wfRunHooks() lines
- */
-function getBadHooksFromPath( $path ) {
-       $hooks = array();
-       if( $dh = opendir($path) ) {
-               while(($file = readdir($dh)) !== false) {
-                       # We don't want to read this file as it contains bad calls to wfRunHooks()
-                       if( filetype( $path.$file ) == 'file' && !$path.$file == __FILE__ ) {
-                               $hooks = array_merge( $hooks, getBadHooksFromFile($path.$file) );
+       /**
+        * Get bad hooks from the source code.
+        * @param $path Directory where the include files can be found
+        * @return array of bad wfRunHooks() lines
+        */
+       private function getBadHooksFromPath( $path ) {
+               $hooks = array();
+               if( $dh = opendir($path) ) {
+                       while(($file = readdir($dh)) !== false) {
+                               # We don't want to read this file as it contains bad calls to wfRunHooks()
+                               if( filetype( $path.$file ) == 'file' && !$path.$file == __FILE__ ) {
+                                       $hooks = array_merge( $hooks, $this->getBadHooksFromFile($path.$file) );
+                               }
                        }
+                       closedir($dh);
                }
-               closedir($dh);
+               return $hooks;
        }
-       return $hooks;
-}
 
-/**
- * Nicely output the array
- * @param $msg A message to show before the value
- * @param $arr An array
- * @param $sort Boolean : wheter to sort the array (Default: true)
- */
-function printArray( $msg, $arr, $sort = true ) {
-       if($sort) asort($arr); 
-       foreach($arr as $v) echo "$msg: $v\n";
-}
-
-# MAIN
-
-$documented = getHooksFromDoc($doc);
-$potential = array();
-$bad = array();
-foreach( $pathinc as $dir ) {
-       $potential = array_merge( $potential, getHooksFromPath( $dir ) );
-       $bad = array_merge( $bad, getBadHooksFromPath( $dir ) );
+       /**
+        * Nicely output the array
+        * @param $msg A message to show before the value
+        * @param $arr An array
+        * @param $sort Boolean : wheter to sort the array (Default: true)
+        */
+       private function printArray( $msg, $arr, $sort = true ) {
+               if($sort) asort($arr); 
+               foreach($arr as $v) $this->output( "$msg: $v\n" );
+       }
 }
 
-$potential = array_unique( $potential );
-$bad = array_unique( $bad );
-$todo = array_diff( $potential, $documented );
-$deprecated = array_diff( $documented, $potential );
-
-// let's show the results:
-printArray('undocumented', $todo );
-printArray('not found', $deprecated );
-printArray('unclear hook calls', $bad );
-if ( count( $todo ) == 0 && count( $deprecated ) == 0 && count( $bad ) == 0 ) 
-       echo "Looks good!\n";
+$maintClass = "FindHooks";
+require_once( DO_MAINTENANCE );
index 7817bc5..71492eb 100644 (file)
 <?php
 /**
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$wgUseRootUser = true;
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-//$wgDebugLogFile = '/dev/stdout';
-
-$slaveIndexes = array();
-for ( $i = 1; $i < count( $wgDBservers ); $i++ ) {
-       if ( wfGetLB()->isNonZeroLoad( $i ) ) {
-               $slaveIndexes[] = $i;
+class FixSlaveDesync extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "";
+               
        }
-}
-/*
-foreach ( wfGetLB()->mServers as $i => $server ) {
-       wfGetLB()->mServers[$i]['flags'] |= DBO_DEBUG;
-}*/
-$reportingInterval = 1000;
+       
+       public function execute() {
+               global $wgUseRootUser, $wgDBservers;
+               $wgUseRootUser = true;
 
-if ( isset( $args[0] ) ) {
-       desyncFixPage( $args[0] );
-} else {
-       $dbw = wfGetDB( DB_MASTER );
-       $maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, 'fixDesync.php' );
-       $corrupt = findPageLatestCorruption();
-       foreach ( $corrupt as $id => $dummy ) {
-               desyncFixPage( $id );
-       }
-               /*
-       for ( $i=1; $i <= $maxPage; $i++ ) {
-               desyncFixPage( $i );
-               if ( !($i % $reportingInterval) ) {
-                       print "$i\n";
+               $slaveIndexes = array();
+               for ( $i = 1; $i < count( $wgDBservers ); $i++ ) {
+                       if ( wfGetLB()->isNonZeroLoad( $i ) ) {
+                               $slaveIndexes[] = $i;
+                       }
                }
-       }*/
-}
 
-function findPageLatestCorruption() {
-       $desync = array();
-       $n = 0;
-       $dbw = wfGetDB( DB_MASTER );
-       $masterIDs = array();
-       $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
-       print "Number of pages: " . $dbw->numRows( $res ) . "\n";
-       while ( $row = $dbw->fetchObject( $res ) ) {
-               $masterIDs[$row->page_id] = $row->page_latest;
-               if ( !( ++$n % 10000 ) ) {
-                       print "$n\r";
+               if ( $this->hasArg() ) {
+                       $this->desyncFixPage( $this->getArg() );
+               } else {
+                       $dbw = wfGetDB( DB_MASTER );
+                       $maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+                       $corrupt = $this->findPageLatestCorruption();
+                       foreach ( $corrupt as $id => $dummy ) {
+                               $this->desyncFixPage( $id );
+                       }
                }
        }
-       print "\n";
-       $dbw->freeResult( $res );
-       
-       global $slaveIndexes;
-       foreach ( $slaveIndexes as $i ) {
-               $db = wfGetDB( $i );
-               $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
-               while ( $row = $db->fetchObject( $res ) ) {
-                       if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
-                               $desync[$row->page_id] = true;
-                               print $row->page_id . "\t";
+
+       /**
+        * Find all pages that have a corrupted page_latest
+        * @return array
+        */
+       private function findPageLatestCorruption() {
+               $desync = array();
+               $n = 0;
+               $dbw = wfGetDB( DB_MASTER );
+               $masterIDs = array();
+               $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
+               $this->output( "Number of pages: " . $dbw->numRows( $res ) . "\n" );
+               while ( $row = $dbw->fetchObject( $res ) ) {
+                       $masterIDs[$row->page_id] = $row->page_latest;
+                       if ( !( ++$n % 10000 ) ) {
+                               $this->output( "$n\r" );
                        }
                }
-               $db->freeResult( $res );
+               $this->output( "\n" );
+               $dbw->freeResult( $res );
+
+               global $slaveIndexes;
+               foreach ( $slaveIndexes as $i ) {
+                       $db = wfGetDB( $i );
+                       $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
+                       while ( $row = $db->fetchObject( $res ) ) {
+                               if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
+                                       $desync[$row->page_id] = true;
+                                       $this->output( $row->page_id . "\t" );
+                               }
+                       }
+                       $db->freeResult( $res );
+               }
+               $this->output( "\n" );
+               return $desync;
        }
-       print "\n";
-       return $desync;
-}
 
-function desyncFixPage( $pageID ) {
-       global $slaveIndexes;
-       $fname = 'desyncFixPage';
+       /**
+        * Fix a broken page entry
+        * @param $pageID int The page_id to fix
+        */
+       private function desyncFixPage( $pageID ) {
+               global $slaveIndexes;
 
-       # Check for a corrupted page_latest
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->begin();
-       $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), 
-               $fname, 'FOR UPDATE' );
-       #list( $masterFile, $masterPos ) = $dbw->getMasterPos();
-       $found = false;
-       foreach ( $slaveIndexes as $i ) {
-               $db = wfGetDB( $i );
-               /*
-               if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) {
-                      echo "Slave is too lagged, aborting\n";
-                      $dbw->commit();
-                      sleep(10);
-                      return;
-               }*/            
-               $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), $fname );
-               $max = $db->selectField( 'revision', 'MAX(rev_id)', false, $fname );
-               if ( $latest != $realLatest && $realLatest < $max ) {
-                       print "page_latest corrupted in page $pageID, server $i\n";
-                       $found = true;
-                       break;
+               # Check for a corrupted page_latest
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+               $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), 
+                       __METHOD__, 'FOR UPDATE' );
+               #list( $masterFile, $masterPos ) = $dbw->getMasterPos();
+               $found = false;
+               foreach ( $slaveIndexes as $i ) {
+                       $db = wfGetDB( $i );
+                       /*
+                       if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) {
+                                  $this->output( "Slave is too lagged, aborting\n" );
+                                  $dbw->commit();
+                                  sleep(10);
+                                  return;
+                       }*/            
+                       $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), __METHOD__ );
+                       $max = $db->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ );
+                       if ( $latest != $realLatest && $realLatest < $max ) {
+                               $this->output( "page_latest corrupted in page $pageID, server $i\n" );
+                               $found = true;
+                               break;
+                       }
+               }
+               if ( !$found ) {
+                       $this->output( "page_id $pageID seems fine\n" );
+                       $dbw->commit();
+                       return;
                }
-       }
-       if ( !$found ) {
-               print "page_id $pageID seems fine\n";
-               $dbw->commit();
-               return;
-       }
 
-       # Find the missing revisions
-       $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), 
-               $fname, 'FOR UPDATE' );
-       $masterIDs = array();
-       while ( $row = $dbw->fetchObject( $res ) ) {
-               $masterIDs[] = $row->rev_id;
-       }
-       $dbw->freeResult( $res );
+               # Find the missing revisions
+               $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), 
+                       __METHOD__, 'FOR UPDATE' );
+               $masterIDs = array();
+               while ( $row = $dbw->fetchObject( $res ) ) {
+                       $masterIDs[] = $row->rev_id;
+               }
+               $dbw->freeResult( $res );
 
-       $res = $db->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), $fname );
-       $slaveIDs = array();
-       while ( $row = $db->fetchObject( $res ) ) {
-               $slaveIDs[] = $row->rev_id;
-       }
-       $db->freeResult( $res );
-       if ( count( $masterIDs ) < count( $slaveIDs ) ) {
-               $missingIDs = array_diff( $slaveIDs, $masterIDs );
-               if ( count( $missingIDs ) ) {
-                       print "Found " . count( $missingIDs ) . " lost in master, copying from slave... ";
-                       $dbFrom = $db;
-                       $found = true;
-                       $toMaster = true;
-               } else {
-                       $found = false;
+               $res = $db->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), __METHOD__ );
+               $slaveIDs = array();
+               while ( $row = $db->fetchObject( $res ) ) {
+                       $slaveIDs[] = $row->rev_id;
                }
-       } else {
-               $missingIDs = array_diff( $masterIDs, $slaveIDs );
-               if ( count( $missingIDs ) ) {
-                       print "Found " . count( $missingIDs ) . " missing revision(s), copying from master... ";
-                       $dbFrom = $dbw;
-                       $found = true;
-                       $toMaster = false;
+               $db->freeResult( $res );
+               if ( count( $masterIDs ) < count( $slaveIDs ) ) {
+                       $missingIDs = array_diff( $slaveIDs, $masterIDs );
+                       if ( count( $missingIDs ) ) {
+                               $this->output( "Found " . count( $missingIDs ) . " lost in master, copying from slave... " );
+                               $dbFrom = $db;
+                               $found = true;
+                               $toMaster = true;
+                       } else {
+                               $found = false;
+                       }
                } else {
-                       $found = false;
+                       $missingIDs = array_diff( $masterIDs, $slaveIDs );
+                       if ( count( $missingIDs ) ) {
+                               $this->output( "Found " . count( $missingIDs ) . " missing revision(s), copying from master... " );
+                               $dbFrom = $dbw;
+                               $found = true;
+                               $toMaster = false;
+                       } else {
+                               $found = false;
+                       }
                }
-       }
 
-       if ( $found ) {
-               foreach ( $missingIDs as $rid ) {
-                       print "$rid ";
-                       # Revision
-                       $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), $fname );
-                       if ( $toMaster ) {
-                               $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ), 
-                                       $fname, 'FOR UPDATE' );
-                               if ( $id ) {
-                                       echo "Revision already exists\n";
-                                       $found = false;
-                                       break;
+               if ( $found ) {
+                       foreach ( $missingIDs as $rid ) {
+                               $this->output( "$rid " );
+                               # Revision
+                               $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), __METHOD__ );
+                               if ( $toMaster ) {
+                                       $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ), 
+                                               __METHOD__, 'FOR UPDATE' );
+                                       if ( $id ) {
+                                               $this->output( "Revision already exists\n" );
+                                               $found = false;
+                                               break;
+                                       } else {
+                                               $dbw->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' );
+                                       }
                                } else {
-                                       $dbw->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
+                                       foreach ( $slaveIndexes as $i ) {
+                                               $db = wfGetDB( $i );
+                                               $db->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' );
+                                       }
                                }
-                       } else {
-                               foreach ( $slaveIndexes as $i ) {
-                                       $db = wfGetDB( $i );
-                                       $db->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
+
+                               # Text
+                               $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), __METHOD__ );
+                               if ( $toMaster ) {
+                                       $dbw->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' );
+                               } else {
+                                       foreach ( $slaveIndexes as $i ) {
+                                               $db = wfGetDB( $i );
+                                               $db->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' );
+                                       }
                                }
                        }
+                       $this->output( "done\n" );
+               }
 
-                       # Text
-                       $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), $fname );
+               if ( $found ) {
+                       $this->output( "Fixing page_latest... " );
                        if ( $toMaster ) {
-                               $dbw->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
+                               #$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), __METHOD__ );
                        } else {
                                foreach ( $slaveIndexes as $i ) {
                                        $db = wfGetDB( $i );
-                                       $db->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
+                                       $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), __METHOD__ );
                                }
                        }
+                       $this->output( "done\n" );
                }
-               print "done\n";
-       }
-
-       if ( $found ) {
-               print "Fixing page_latest... ";
-               if ( $toMaster ) {
-                       #$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
-               } else {
-                       foreach ( $slaveIndexes as $i ) {
-                               $db = wfGetDB( $i );
-                               $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
-                       }
-               }
-               print "done\n";
+               $dbw->commit();
        }
-       $dbw->commit();
 }
 
-
+$maintClass = "FixSlaveDesync";
+require_once( DO_MAINTENANCE );
index f679414..61bec78 100644 (file)
  * and must bracket the damage. There must be a majority of good timestamps in the 
  * search period.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
-
-require_once( 'commandLine.inc' );
-
-if ( count( $args ) < 3 ) {
-       echo "Usage: php fixTimestamps.php <offset in hours> <start time> <end time>\n";
-       exit(1);
-}
-
-$offset = $args[0] * 3600;
-$start = $args[1];
-$end = $args[2];
-$fname = 'fixTimestamps.php';
-$grace = 60; // maximum normal clock offset
-
-# Find bounding revision IDs
-$dbw = wfGetDB( DB_MASTER );
-$revisionTable = $dbw->tableName( 'revision' );
-$res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " .
-       "WHERE rev_timestamp BETWEEN '{$start}' AND '{$end}'", $fname );
-$row = $dbw->fetchObject( $res );
-
-if ( is_null( $row->minrev ) ) {
-       echo "No revisions in search period.\n";
-       exit(0);
-}
-
-$minRev = $row->minrev;
-$maxRev = $row->maxrev;
-
-# Select all timestamps and IDs
-$sql = "SELECT rev_id, rev_timestamp FROM $revisionTable " .
-       "WHERE rev_id BETWEEN $minRev AND $maxRev";
-if ( $offset > 0 ) {
-       $sql .= " ORDER BY rev_id DESC";
-       $expectedSign = -1;
-} else {
-       $expectedSign = 1;
-}
-
-$res = $dbw->query( $sql, $fname );
-
-$lastNormal = 0;
-$badRevs = array();
-$numGoodRevs = 0;
-
-while ( $row = $dbw->fetchObject( $res ) ) {
-       $timestamp = wfTimestamp( TS_UNIX, $row->rev_timestamp );
-       $delta = $timestamp - $lastNormal;
-       $sign = $delta == 0 ? 0 : $delta / abs( $delta );
-       if ( $sign == 0 || $sign == $expectedSign ) {
-               // Monotonic change
-               $lastNormal = $timestamp;
-               ++ $numGoodRevs;
-               continue;
-       } elseif ( abs( $delta ) <= $grace ) {
-               // Non-monotonic change within grace interval
-               ++ $numGoodRevs;
-               continue;
-       } else {
-               // Non-monotonic change larger than grace interval
-               $badRevs[] = $row->rev_id;
+require_once( "Maintenance.php" );
+
+class FixTimestamps extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "";
+               $this->addArgs( array( 'offset', 'start', 'end' ) );
        }
-}
-$dbw->freeResult( $res );
-
-$numBadRevs = count( $badRevs );
-if ( $numBadRevs > $numGoodRevs ) {
-       echo 
-"The majority of revisions in the search interval are marked as bad.
 
-Are you sure the offset ($offset) has the right sign? Positive means the clock 
-was incorrectly set forward, negative means the clock was incorrectly set back.
-
-If the offset is right, then increase the search interval until there are enough 
-good revisions to provide a majority reference.
-";
-
-       exit(1);
-} elseif ( $numBadRevs == 0 ) {
-       echo "No bad revisions found.\n";
-       exit(0);
+       public function execute() {
+               $offset = $this->getArg(0) * 3600;
+               $start = $this->getArg(1);
+               $end = $this->getArg(2);
+               $grace = 60; // maximum normal clock offset
+       
+               # Find bounding revision IDs
+               $dbw = wfGetDB( DB_MASTER );
+               $revisionTable = $dbw->tableName( 'revision' );
+               $res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " .
+                       "WHERE rev_timestamp BETWEEN '{$start}' AND '{$end}'", __METHOD__ );
+               $row = $dbw->fetchObject( $res );
+       
+               if ( is_null( $row->minrev ) ) {
+                       $this->error( "No revisions in search period.\n", true );
+               }
+       
+               $minRev = $row->minrev;
+               $maxRev = $row->maxrev;
+       
+               # Select all timestamps and IDs
+               $sql = "SELECT rev_id, rev_timestamp FROM $revisionTable " .
+                       "WHERE rev_id BETWEEN $minRev AND $maxRev";
+               if ( $offset > 0 ) {
+                       $sql .= " ORDER BY rev_id DESC";
+                       $expectedSign = -1;
+               } else {
+                       $expectedSign = 1;
+               }
+       
+               $res = $dbw->query( $sql, __METHOD__ );
+       
+               $lastNormal = 0;
+               $badRevs = array();
+               $numGoodRevs = 0;
+       
+               while ( $row = $dbw->fetchObject( $res ) ) {
+                       $timestamp = wfTimestamp( TS_UNIX, $row->rev_timestamp );
+                       $delta = $timestamp - $lastNormal;
+                       $sign = $delta == 0 ? 0 : $delta / abs( $delta );
+                       if ( $sign == 0 || $sign == $expectedSign ) {
+                               // Monotonic change
+                               $lastNormal = $timestamp;
+                               ++ $numGoodRevs;
+                               continue;
+                       } elseif ( abs( $delta ) <= $grace ) {
+                               // Non-monotonic change within grace interval
+                               ++ $numGoodRevs;
+                               continue;
+                       } else {
+                               // Non-monotonic change larger than grace interval
+                               $badRevs[] = $row->rev_id;
+                       }
+               }
+               $dbw->freeResult( $res );
+       
+               $numBadRevs = count( $badRevs );
+               if ( $numBadRevs > $numGoodRevs ) {
+                       $this->error( 
+               "The majority of revisions in the search interval are marked as bad.
+
+               Are you sure the offset ($offset) has the right sign? Positive means the clock 
+               was incorrectly set forward, negative means the clock was incorrectly set back.
+
+               If the offset is right, then increase the search interval until there are enough 
+               good revisions to provide a majority reference.
+               ", true );
+               } elseif ( $numBadRevs == 0 ) {
+                       $this->output( "No bad revisions found.\n" );
+                       exit(0);
+               }
+       
+               $this->output( sprintf( "Fixing %d revisions (%.2f%% of revisions in search interval)\n", 
+                       $numBadRevs, $numBadRevs / ($numGoodRevs + $numBadRevs) * 100 ) );
+       
+               $fixup = -$offset;
+               $sql = "UPDATE $revisionTable " .
+                       "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
+                       "WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';
+               $dbw->query( $sql, __METHOD__ );
+               $this->output( "Done\n" );
+       }
 }
 
-printf( "Fixing %d revisions (%.2f%% of revisions in search interval)\n", 
-       $numBadRevs, $numBadRevs / ($numGoodRevs + $numBadRevs) * 100 );
-
-$fixup = -$offset;
-$sql = "UPDATE $revisionTable " .
-       "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
-       "WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';
-//echo "$sql\n";
-$dbw->query( $sql, $fname );
-echo "Done\n";
-
-
+$maintClass = "FixTimestamps";
+require_once( DO_MAINTENANCE );
index eb5b7f7..15c00b3 100644 (file)
@@ -3,32 +3,53 @@
  * Fix the user_registration field.
  * In particular, for values which are NULL, set them to the date of the first edit
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-$fname = 'fixUserRegistration.php';
-
-$dbr = wfGetDB( DB_SLAVE );
-$dbw = wfGetDB( DB_MASTER );
+class FixUserRegistration extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Fix the user_registration field";
+       }
 
-// Get user IDs which need fixing
-$res = $dbr->select( 'user', 'user_id', 'user_registration IS NULL', $fname );
+       public function execute() {
+               $dbr = wfGetDB( DB_SLAVE );
+               $dbw = wfGetDB( DB_MASTER );
 
-while ( $row = $dbr->fetchObject( $res ) ) {
-       $id = $row->user_id;
-       // Get first edit time
-       $timestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)', array( 'rev_user' => $id ), $fname );
-       // Update
-       if ( !empty( $timestamp ) ) {
-               $dbw->update( 'user', array( 'user_registration' => $timestamp ), array( 'user_id' => $id ), $fname );
-               print "$id $timestamp\n";
-       } else {
-               print "$id NULL\n";
+               // Get user IDs which need fixing
+               $res = $dbr->select( 'user', 'user_id', 'user_registration IS NULL', __METHOD__ );
+               while ( $row = $dbr->fetchObject( $res ) ) {
+                       $id = $row->user_id;
+                       // Get first edit time
+                       $timestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)', array( 'rev_user' => $id ), __METHOD__ );
+                       // Update
+                       if ( !empty( $timestamp ) ) {
+                               $dbw->update( 'user', array( 'user_registration' => $timestamp ), array( 'user_id' => $id ), __METHOD__ );
+                               $this->output( "$id $timestamp\n" );
+                       } else {
+                               $this->output( "$id NULL\n" );
+                       }
+               }
+               $this->output( "\n" );
        }
 }
-print "\n";
-
 
+$maintClass = "FixUserRegistration";
+require_once( DO_MAINTENANCE );
index 737c4eb..7ac197b 100644 (file)
@@ -4,6 +4,21 @@ define( 'GS_TALK', -1 );
 /**
  * Creates a sitemap for the site
  *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  *
  * @copyright Copyright Â© 2005, Ã†var Arnfjörð Bjarmason
@@ -16,7 +31,9 @@ define( 'GS_TALK', -1 );
  * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
  */
 
-class GenerateSitemap {
+require_once( "Maintenance.php" );
+
+class GenerateSitemap extends Maintenance {
        /**
         * The maximum amount of urls in a sitemap file
         *
@@ -129,36 +146,34 @@ class GenerateSitemap {
        var $file;
 
        /**
-        * A resource pointing to php://stderr
-        *
-        * @var resource
+        * Constructor
         */
-       var $stderr;
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Creates a sitemap for the site";
+               $this->addOption( 'fspath', 'The file system path to save to, e.g. /tmp/sitemap' .
+                                                                       "\n\t\tdefaults to current directory", false, true );
+               $this->addOption( 'server', "The protocol and server name to use in URLs, e.g.\n" .
+                                                                       "\t\thttp://en.wikipedia.org. This is sometimes necessary because\n" .
+                                                                       "\t\tserver name detection may fail in command line scripts.", false, true );
+               $this->addOption( 'compress', 'Compress the sitemap files, can take value yes|no, default yes' );
+       }
 
        /**
-        * Constructor
-        *
-        * @param string $fspath The path to prepend to the filenames, used to
-        *                     save them somewhere else than in the root directory
-        * @param string $path The path to append to the domain name
-        * @param bool $compress Whether to compress the sitemap files
+        * Execute
         */
-       function GenerateSitemap( $fspath, $compress ) {
+       public function execute() {
                global $wgScriptPath;
 
                $this->url_limit = 50000;
                $this->size_limit = pow( 2, 20 ) * 10;
-               $this->fspath = self::init_path( $fspath );
-
-               $this->compress = $compress;
-
-               $this->stderr = fopen( 'php://stderr', 'wt' );
+               $this->fspath = self::init_path( $this->getOption( 'fspath', getcwd() ) );
+               $this->compress = $this->getOption( 'compress', 'yes' ) !== 'no';
                $this->dbr = wfGetDB( DB_SLAVE );
                $this->generateNamespaces();
                $this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() );
-
-
                $this->findex = fopen( "{$this->fspath}sitemap-index-" . wfWikiID() . ".xml", 'wb' );
+               $this->main();
        }
 
        /**
@@ -170,7 +185,7 @@ class GenerateSitemap {
                }
                # Create directory if needed
                if( $fspath && !is_dir( $fspath ) ) {
-                       mkdir( $fspath, 0755 ) or die("Can not create directory $fspath.\n");
+                       wfMkdirParents( $fspath ) or die("Can not create directory $fspath.\n");
                }
 
                return realpath( $fspath ). DIRECTORY_SEPARATOR ;
@@ -180,8 +195,6 @@ class GenerateSitemap {
         * Generate a one-dimensional array of existing namespaces
         */
        function generateNamespaces() {
-               $fname = 'GenerateSitemap::generateNamespaces';
-
                // Only generate for specific namespaces if $wgSitemapNamespaces is an array.
                global $wgSitemapNamespaces;
                if( is_array( $wgSitemapNamespaces ) ) {
@@ -192,7 +205,7 @@ class GenerateSitemap {
                $res = $this->dbr->select( 'page',
                        array( 'page_namespace' ),
                        array(),
-                       $fname,
+                       __METHOD__,
                        array(
                                'GROUP BY' => 'page_namespace',
                                'ORDER BY' => 'page_namespace',
@@ -236,8 +249,6 @@ class GenerateSitemap {
         * @return resource
         */
        function getPageRes( $namespace ) {
-               $fname = 'GenerateSitemap::getPageRes';
-
                return $this->dbr->select( 'page',
                        array(
                                'page_namespace',
@@ -245,7 +256,7 @@ class GenerateSitemap {
                                'page_touched',
                        ),
                        array( 'page_namespace' => $namespace ),
-                       $fname
+                       __METHOD__
                );
        }
 
@@ -267,7 +278,7 @@ class GenerateSitemap {
                        $i = $smcount = 0;
 
                        $fns = $wgContLang->getFormattedNsText( $namespace );
-                       $this->debug( "$namespace ($fns)" );
+                       $this->output( "$namespace ($fns)" );
                        while ( $row = $this->dbr->fetchObject( $res ) ) {
                                if ( $i++ === 0 || $i === $this->url_limit + 1 || $length + $this->limit[1] + $this->limit[2] > $this->size_limit ) {
                                        if ( $this->file !== false ) {
@@ -278,7 +289,7 @@ class GenerateSitemap {
                                        $this->file = $this->open( $this->fspath . $filename, 'wb' );
                                        $this->write( $this->file, $this->openFile() );
                                        fwrite( $this->findex, $this->indexEntry( $filename ) );
-                                       $this->debug( "\t$this->fspath$filename" );
+                                       $this->output( "\t$this->fspath$filename" );
                                        $length = $this->limit[0];
                                        $i = 1;
                                }
@@ -449,13 +460,6 @@ class GenerateSitemap {
                return "</urlset>\n";
        }
 
-       /**
-        * Write a string to stderr followed by a UNIX newline
-        */
-       function debug( $str ) {
-               fwrite( $this->stderr, "$str\n" );
-       }
-
        /**
         * Populate $this->limit
         */
@@ -470,31 +474,5 @@ class GenerateSitemap {
        }
 }
 
-if ( in_array( '--help', $argv ) ) {
-       echo <<<EOT
-Usage: php generateSitemap.php [options]
-       --help                  show this message
-
-       --fspath=<path>         The file system path to save to, e.g /tmp/sitemap
-                           Saves to current directory if not given.
-
-       --server=<server>       The protocol and server name to use in URLs, e.g.
-               http://en.wikipedia.org. This is sometimes necessary because
-               server name detection may fail in command line scripts.
-
-       --compress=[yes|no]     compress the sitemap files, default yes
-
-EOT;
-       die( -1 );
-}
-
-$optionsWithArgs = array( 'fspath', 'server', 'compress' );
-require_once( dirname( __FILE__ ) . '/commandLine.inc' );
-
-if ( isset( $options['server'] ) ) {
-       $wgServer = $options['server'];
-}
-
-$gs = new GenerateSitemap( @$options['fspath'], @$options['compress'] !== 'no' );
-$gs->main();
-
+$maintClass = "GenerateSitemap";
+require_once( DO_MAINTENANCE );
index 0f750ca..cdf73e8 100644 (file)
@@ -1,29 +1,54 @@
 <?php
 /**
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require 'commandLine.inc';
+require_once( "Maintenance.php" );
 
-$lb = wfGetLB();
+class GetLagTimes extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Dump replication lag times";
+       }
+
+       public function execute() {
+               $lb = wfGetLB();
 
-if( $lb->getServerCount() == 1 ) {
-       echo "This script dumps replication lag times, but you don't seem to have\n";
-       echo "a multi-host db server configuration.\n";
-} else {
-       $lags = $lb->getLagTimes();
-       foreach( $lags as $n => $lag ) {
-               $host = $lb->getServerName( $n );
-               if( IP::isValid( $host ) ) {
-                       $ip = $host;
-                       $host = gethostbyaddr( $host );
+               if( $lb->getServerCount() == 1 ) {
+                       $this->error( "This script dumps replication lag times, but you don't seem to have\n"
+                                                 . "a multi-host db server configuration.\n" );
                } else {
-                       $ip = gethostbyname( $host );
+                       $lags = $lb->getLagTimes();
+                       foreach( $lags as $n => $lag ) {
+                               $host = $lb->getServerName( $n );
+                               if( IP::isValid( $host ) ) {
+                                       $ip = $host;
+                                       $host = gethostbyaddr( $host );
+                               } else {
+                                       $ip = gethostbyname( $host );
+                               }
+                               $starLen = min( intval( $lag ), 40 );
+                               $stars = str_repeat( '*', $starLen );
+                               $this->output( sprintf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ) );
+                       }
                }
-               $starLen = min( intval( $lag ), 40 );
-               $stars = str_repeat( '*', $starLen );
-               printf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars );
        }
 }
 
+$maintClass = "GetLagTimes";
+require_once( DO_MAINTENANCE );
index 2525826..f164ec3 100644 (file)
@@ -2,27 +2,49 @@
 /**
  * This script reports the hostname of a slave server.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
+require_once( "Maintenance.php" );
 
-require_once( dirname(__FILE__).'/commandLine.inc' );
-
-if ( $wgAllDBsAreLocalhost ) {
-       # Can't fool the backup script
-       print "localhost\n";
-       exit;
+class GetSlaveServer extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( "group", "Query group to check specifically" );
+               $this->mDescription = "Report the hostname of a slave server";
+       }
+       public function execute() {
+               global $wgAllDBsAreLocalhost;
+               if( $wgAllDBsAreLocalhost ) {
+                       $host = 'localhost';
+               } else {
+                       if( $this->hasOption('group') ) {
+                               $db = wfGetDB( DB_SLAVE, $this->getOption('group') );
+                               $host = $db->getServer();
+                       } else {
+                               $lb = wfGetLB();
+                               $i = $lb->getReaderIndex();
+                               $host = $lb->getServerName( $i );
+                       }
+               }
+               $this->output( "$host\n" );
+       }
 }
 
-if( isset( $options['group'] ) ) {
-       $db = wfGetDB( DB_SLAVE, $options['group'] );
-       $host = $db->getServer();
-} else {
-       $lb = wfGetLB();
-       $i = $lb->getReaderIndex();
-       $host = $lb->getServerName( $i );
-}
-
-print "$host\n";
-
-
+$maintClass = "GetSlaveServer";
+require_once( DO_MAINTENANCE );
index d26349b..da60763 100644 (file)
 <?php
 /**
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once "commandLine.inc";
+require_once( "Maintenance.php" );
 
-if( isset( $options['help'] ) ) {
-       die( "Batch-recalculate user_editcount fields from the revision table.
-Options:
-  --quick        Force the update to be done in a single query.
-  --background   Force replication-friendly mode; may be inefficient but
-                 avoids locking tables or lagging slaves with large updates;
-                 calculates counts on a slave if possible.
+class InitEditCount extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( 'quick', 'Force the update to be done in a single query' );
+               $this->addOption( 'background', 'Force replication-friendly mode; may be inefficient but
+               avoids locking tables or lagging slaves with large updates;
+               calculates counts on a slave if possible.
 
 Background mode will be automatically used if the server is MySQL 4.0
 (which does not support subqueries) or if multiple servers are listed
-in \$wgDBservers, usually indicating a replication environment.
+in $wgDBservers, usually indicating a replication environment.' );
+               $this->mDescription = "Batch-recalculate user_editcount fields from the revision table";
+       }
 
-");
-}
-$dbw = wfGetDB( DB_MASTER );
-$user = $dbw->tableName( 'user' );
-$revision = $dbw->tableName( 'revision' );
+       public function execute() {
+               $dbw = wfGetDB( DB_MASTER );
+               $user = $dbw->tableName( 'user' );
+               $revision = $dbw->tableName( 'revision' );
 
-$dbver = $dbw->getServerVersion();
+               $dbver = $dbw->getServerVersion();
 
-// Autodetect mode...
-$backgroundMode = count( $wgDBservers ) > 1 ||
-       ($dbw instanceof DatabaseMySql && version_compare( $dbver, '4.1' ) < 0);
+               // Autodetect mode...
+               $backgroundMode = count( $wgDBservers ) > 1 ||
+                       ($dbw instanceof DatabaseMySql && version_compare( $dbver, '4.1' ) < 0);
+       
+               if( $this->hasOption('background') ) {
+                       $backgroundMode = true;
+               } elseif( $this->hasOption('quick') ) {
+                       $backgroundMode = false;
+               }
 
-if( isset( $options['background'] ) ) {
-       $backgroundMode = true;
-} elseif( isset( $options['quick'] ) ) {
-       $backgroundMode = false;
-}
+               if( $backgroundMode ) {
+                       $this->output( "Using replication-friendly background mode...\n" );
 
-if( $backgroundMode ) {
-       echo "Using replication-friendly background mode...\n";
-       
-       $dbr = wfGetDB( DB_SLAVE );
-       $chunkSize = 100;
-       $lastUser = $dbr->selectField( 'user', 'MAX(user_id)', '', __FUNCTION__ );
-       
-       $start = microtime( true );
-       $migrated = 0;
-       for( $min = 0; $min <= $lastUser; $min += $chunkSize ) {
-               $max = $min + $chunkSize;
-               $result = $dbr->query(
-                       "SELECT
-                               user_id,
-                               COUNT(rev_user) AS user_editcount
-                       FROM $user
-                       LEFT OUTER JOIN $revision ON user_id=rev_user
-                       WHERE user_id > $min AND user_id <= $max
-                       GROUP BY user_id",
-                       __FUNCTION__ );
-               
-               while( $row = $dbr->fetchObject( $result ) ) {
-                       $dbw->update( 'user',
-                               array( 'user_editcount' => $row->user_editcount ),
-                               array( 'user_id' => $row->user_id ),
-                               __FUNCTION__ );
-                       ++$migrated;
+                       $dbr = wfGetDB( DB_SLAVE );
+                       $chunkSize = 100;
+                       $lastUser = $dbr->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
+
+                       $start = microtime( true );
+                       $migrated = 0;
+                       for( $min = 0; $min <= $lastUser; $min += $chunkSize ) {
+                               $max = $min + $chunkSize;
+                               $result = $dbr->query(
+                                       "SELECT
+                                               user_id,
+                                               COUNT(rev_user) AS user_editcount
+                                       FROM $user
+                                       LEFT OUTER JOIN $revision ON user_id=rev_user
+                                       WHERE user_id > $min AND user_id <= $max
+                                       GROUP BY user_id",
+                                       __METHOD__ );
+
+                               while( $row = $dbr->fetchObject( $result ) ) {
+                                       $dbw->update( 'user',
+                                               array( 'user_editcount' => $row->user_editcount ),
+                                               array( 'user_id' => $row->user_id ),
+                                               __METHOD__ );
+                                       ++$migrated;
+                               }
+                               $dbr->freeResult( $result );
+
+                               $delta = microtime( true ) - $start;
+                               $rate = ($delta == 0.0) ? 0.0 : $migrated / $delta;
+                               $this->output( sprintf( "%s %d (%0.1f%%) done in %0.1f secs (%0.3f accounts/sec).\n",
+                                       $wgDBname,
+                                       $migrated,
+                                       min( $max, $lastUser ) / $lastUser * 100.0,
+                                       $delta,
+                                       $rate ) );
+
+                               wfWaitForSlaves( 10 );
+                       }
+               } else {
+                       // Subselect should work on modern MySQLs etc
+                       $this->output( "Using single-query mode...\n" );
+                       $sql = "UPDATE $user SET user_editcount=(SELECT COUNT(*) FROM $revision WHERE rev_user=user_id)";
+                       $dbw->query( $sql );
                }
-               $dbr->freeResult( $result );
-               
-               $delta = microtime( true ) - $start;
-               $rate = ($delta == 0.0) ? 0.0 : $migrated / $delta;
-               printf( "%s %d (%0.1f%%) done in %0.1f secs (%0.3f accounts/sec).\n",
-                       $wgDBname,
-                       $migrated,
-                       min( $max, $lastUser ) / $lastUser * 100.0,
-                       $delta,
-                       $rate );
-               
-               wfWaitForSlaves( 10 );
+
+               $this->output( "Done!\n" );
        }
-} else {
-       // Subselect should work on modern MySQLs etc
-       echo "Using single-query mode...\n";
-       $sql = "UPDATE $user SET user_editcount=(SELECT COUNT(*) FROM $revision WHERE rev_user=user_id)";
-       $dbw->query( $sql );
 }
 
-echo "Done!\n";
-
-
+$maintClass = "InitEditCount";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/initStats.inc b/maintenance/initStats.inc
deleted file mode 100644 (file)
index b1660ce..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * @file
- * @ingroup Maintenance
- */
-
-function wfInitStats( $options=array() ) {
-       $dbr = wfGetDB( DB_SLAVE );
-
-       wfOut( "Counting total edits..." );
-       $edits = $dbr->selectField( 'revision', 'COUNT(*)', '', __METHOD__ );
-       $edits += $dbr->selectField( 'archive', 'COUNT(*)', '', __METHOD__ );
-       wfOut( "{$edits}\nCounting number of articles..." );
-
-       global $wgContentNamespaces;
-       $good  = $dbr->selectField( 'page', 'COUNT(*)', array( 'page_namespace' => $wgContentNamespaces, 'page_is_redirect' => 0, 'page_len > 0' ), __METHOD__ );
-       wfOut( "{$good}\nCounting total pages..." );
-
-       $pages = $dbr->selectField( 'page', 'COUNT(*)', '', __METHOD__ );
-       wfOut( "{$pages}\nCounting number of users..." );
-
-       $users = $dbr->selectField( 'user', 'COUNT(*)', '', __METHOD__ );
-       wfOut( "{$users}\nCounting number of admins..." );
-
-       $admin = $dbr->selectField( 'user_groups', 'COUNT(*)', array( 'ug_group' => 'sysop' ), __METHOD__ );
-       wfOut( "{$admin}\nCounting number of images..." );
-
-       $image = $dbr->selectField( 'image', 'COUNT(*)', '', __METHOD__ );
-       wfOut( "{$image}\n" );
-
-       if( !isset( $options['noviews'] ) ) {
-               wfOut( "Counting total page views..." );
-               $views = $dbr->selectField( 'page', 'SUM(page_counter)', '', __METHOD__ );
-               wfOut( "{$views}\n" );
-       }
-
-       wfOut( "\nUpdating site statistics..." );
-
-       $dbw = wfGetDB( DB_MASTER );
-       $values = array( 'ss_total_edits' => $edits,
-                                       'ss_good_articles' => $good,
-                                       'ss_total_pages' => $pages,
-                                       'ss_users' => $users,
-                                       'ss_admins' => $admin,
-                                       'ss_images' => $image );
-       $conds = array( 'ss_row_id' => 1 );
-       $views = array( 'ss_total_views' => isset( $views ) ? $views : 0 );
-                               
-       if( isset( $options['update'] ) ) {
-               $dbw->update( 'site_stats', $values, $conds, __METHOD__ );
-       } else {
-               $dbw->delete( 'site_stats', $conds, __METHOD__ );
-               $dbw->insert( 'site_stats', array_merge( $values, $conds, $views ), __METHOD__ );
-       }
-
-       wfOut( "done.\n" );
-}
index bb0cf30..ce46284 100644 (file)
@@ -3,29 +3,82 @@
 /**
  * Maintenance script to re-initialise or update the site statistics table
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Brion Vibber
  * @author Rob Church <robchur@gmail.com>
  * @licence GNU General Public Licence 2.0 or later
  */
-$options = array( 'help', 'update', 'noviews' );
-require_once( 'commandLine.inc' );
-echo( "Refresh Site Statistics\n\n" );
-
-if( isset( $options['help'] ) ) {
-       showHelp();
-       exit(1);
-}
 
-require "$IP/maintenance/initStats.inc";
-wfInitStats( $options );
+require_once( "Maintenance.php" );
+
+class InitStats extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Re-initialise the site statistics tables";
+               $this->addOption( 'update', 'Update the existing statistics (preserves the ss_total_views field)' );
+               $this->addOption( 'noviews', "Don't update the page view counter" );
+               $this->addOption( 'active', 'Also update active users count' );
+               $this->addOption( 'use-master', 'Count using the master database' );
+       }
+
+       public function execute() {
+               $this->output( "Refresh Site Statistics\n\n" );
+               $counter = new SiteStatsInit( $this->hasOption( 'use-master' ) );
+
+               $this->output( "Counting total edits..." );
+               $edits = $counter->edits();
+               $this->output( "{$edits}\nCounting number of articles..." );
+
+               $good  = $counter->articles();
+               $this->output( "{$good}\nCounting total pages..." );
+
+               $pages = $counter->pages();
+               $this->output( "{$pages}\nCounting number of users..." );
+
+               $users = $counter->users();
+               $this->output( "{$users}\nCounting number of images..." );
+
+               $image = $counter->files();
+               $this->output( "{$image}\n" );
+
+               if( !$this->hasOption('noviews') ) {
+                       $this->output( "Counting total page views..." );
+                       $views = $counter->views();
+                       $this->output( "{$views}\n" );
+               }
+
+               if( $this->hasOption( 'active' ) ) {
+                       $this->output( "Counting active users..." );
+                       $active = SiteStatsUpdate::cacheUpdate();
+                       $this->output( "{$active}\n" );
+               }
+
+               $this->output( "\nUpdating site statistics..." );
+
+               if( $this->hasOption( 'update' ) ) {
+                       $counter->update();
+               } else {
+                       $counter->refresh();
+               }
 
-function showHelp() {
-       echo( "Re-initialise the site statistics tables.\n\n" );
-       echo( "Usage: php initStats.php [--update|--noviews]\n\n" );
-       echo( " --update : Update the existing statistics (preserves the ss_total_views field)\n" );
-       echo( "--noviews : Don't update the page view counter\n\n" );
+               $this->output( "done.\n" );
+       }
 }
 
+$maintClass = "InitStats";
+require_once( DO_MAINTENANCE );
index 67c870e..21103eb 100644 (file)
@@ -6,11 +6,21 @@
  * Get all the translations messages, as defined in the English language file.
  */
 
-require_once( dirname(__FILE__).'/../commandLine.inc' );
+require_once( dirname(__FILE__) . '/../Maintenance.php' );
 
-$wgEnglishMessages = array_keys( Language::getMessagesFor( 'en' ) );
-foreach( $wgEnglishMessages as $key ) {
-       echo "$key\n";
-}
+class AllTrans extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Get all messages as defined by the English language file";
+       }
 
+       public function execute() {
+               $wgEnglishMessages = array_keys( Language::getMessagesFor( 'en' ) );
+               foreach( $wgEnglishMessages as $key ) {
+                       $this->output( "$key\n" );
+               }
+       }
+}
 
+$maintClass = "AllTrans";
+require_once( DO_MAINTENANCE );
index acb7f58..63bc3dd 100644 (file)
@@ -3,62 +3,81 @@
  * This script makes several 'set', 'incr' and 'get' requests on every
  * memcached server and shows a report.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$optionsWithArgs = array( 'i' );
-
-require_once('commandLine.inc');
+require_once( "Maintenance.php" );
 
-function microtime_float()
-{
-   list($usec, $sec) = explode(" ", microtime());
-   return ((float)$usec + (float)$sec);
-}
-
-
-#$wgDebugLogFile = '/dev/stdout';
+class mcTest extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Makes several 'set', 'incr' and 'get' requests on every"
+                                                         . " memcached server and shows a report";
+               $this->addOption( 'i', 'Number of iterations', false, true );
+               $this->addArgs( array( 'server' ) );
+       }
 
-if ( isset( $args[0] ) ) {
-       $wgMemCachedServers = array( $args[0] );
-}
-if ( isset( $options['i'] ) ) {
-       $iterations = $options['i'];
-} else {
-       $iterations = 100;
-}
+       public function execute() {
+               global $wgMemCachedServers;
 
-foreach ( $wgMemCachedServers as $server ) {
-        print "$server ";
-       $mcc = new MemCachedClientforWiki( array('persistant' => true) );
-       $mcc->set_servers( array( $server ) );
-       $set = 0;
-       $incr = 0;
-       $get = 0;
-        $time_start=microtime_float();
-       for ( $i=1; $i<=$iterations; $i++ ) {
-               if ( !is_null( $mcc->set( "test$i", $i ) ) ) {
-                       $set++;
-               }
-       }
+               $iterations = $this->getOption( 'i', 100 );
+               if( $this->hasArg() )
+                       $wgMemCachedServers = array( $this->getArg() );
 
-       for ( $i=1; $i<=$iterations; $i++ ) {
-               if ( !is_null( $mcc->incr( "test$i", $i ) ) ) {
-                       $incr++;
+               foreach ( $wgMemCachedServers as $server ) {
+                       $this->output( $server . " " );
+                       $mcc = new MemCachedClientforWiki( array('persistant' => true) );
+                       $mcc->set_servers( array( $server ) );
+                       $set = 0;
+                       $incr = 0;
+                       $get = 0;
+                       $time_start = $this->microtime_float();
+                       for ( $i=1; $i<=$iterations; $i++ ) {
+                               if ( !is_null( $mcc->set( "test$i", $i ) ) ) {
+                                       $set++;
+                               }
+                       }
+                       for ( $i=1; $i<=$iterations; $i++ ) {
+                               if ( !is_null( $mcc->incr( "test$i", $i ) ) ) {
+                                       $incr++;
+                               }
+                       }
+                       for ( $i=1; $i<=$iterations; $i++ ) {
+                               $value = $mcc->get( "test$i" );
+                               if ( $value == $i*2 ) {
+                                       $get++;
+                               }
+                       }
+                       $exectime = $this->microtime_float() - $time_start;
+       
+                       $this->output( "set: $set   incr: $incr   get: $get time: $exectime\n" );
                }
        }
 
-       for ( $i=1; $i<=$iterations; $i++ ) {
-               $value = $mcc->get( "test$i" );
-               if ( $value == $i*2 ) {
-                       $get++;
-               }
+       /**
+        * Return microtime() as a float
+        * @return float
+        */
+       private function microtime_float() {
+               list($usec, $sec) = explode(" ", microtime());
+               return ((float)$usec + (float)$sec);
        }
-        $exectime=microtime_float()-$time_start;
-
-       print "set: $set   incr: $incr   get: $get time: $exectime\n";
 }
 
-
-
+$maintClass = "mcTest";
+require_once( DO_MAINTENANCE );
index 427e5d0..0e07c32 100644 (file)
@@ -1,9 +1,22 @@
 <?php
-
 /**
  * Maintenance script to move a batch of pages
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Tim Starling
  *
  * e.g. immobile_namespace for namespaces which can't be moved
  */
 
-$oldCwd = getcwd();
-$optionsWithArgs = array( 'u', 'r', 'i' );
-require_once( 'commandLine.inc' );
-
-chdir( $oldCwd );
-
-# Options processing
-
-$filename = 'php://stdin';
-$user = 'Move page script';
-$reason = '';
-$interval = 0;
-
-if ( isset( $args[0] ) ) {
-       $filename = $args[0];
-}
-if ( isset( $options['u'] ) ) {
-       $user = $options['u'];
-}
-if ( isset( $options['r'] ) ) {
-       $reason = $options['r'];
-}
-if ( isset( $options['i'] ) ) {
-       $interval = $options['i'];
-}
-
-$wgUser = User::newFromName( $user );
+require_once( "Maintenance.php" );
 
-
-# Setup complete, now start
-
-$file = fopen( $filename, 'r' );
-if ( !$file ) {
-       print "Unable to read file, exiting\n";
-       exit;
-}
-
-$dbw = wfGetDB( DB_MASTER );
-
-for ( $linenum = 1; !feof( $file ); $linenum++ ) {
-       $line = fgets( $file );
-       if ( $line === false ) {
-               break;
-       }
-       $parts = array_map( 'trim', explode( '|', $line ) );
-       if ( count( $parts ) != 2 ) {
-               print "Error on line $linenum, no pipe character\n";
-               continue;
+class MoveBatch extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Moves a batch of pages";
+               $this->addOption( 'u', "User to perform move", false, true );
+               $this->addOption( 'r', "Reason to move page", false, true );
+               $this->addOption( 'i', "Interval to sleep between moves" );
+               $this->addArgs( array( 'listfile' ) );
        }
-       $source = Title::newFromText( $parts[0] );
-       $dest = Title::newFromText( $parts[1] );
-       if ( is_null( $source ) || is_null( $dest ) ) {
-               print "Invalid title on line $linenum\n";
-               continue;
+       
+       public function execute() {
+               global $wgUser;
+
+               # Change to current working directory
+               $oldCwd = getcwd();
+               chdir( $oldCwd );
+
+               # Options processing
+               $user = $this->getOption( 'u', 'Move page script' );
+               $reason = $this->getOption( 'r', '' );
+               $interval = $this->getOption( 'i', 0 );
+               if( $this->hasArg() ) {
+                       $file = fopen( $this->getArg(), 'r' );
+               } else {
+                       $file = $this->getStdin();
+               }
+
+               # Setup
+               if( !$file ) {
+                       $this->error( "Unable to read file, exiting\n", true );
+               }
+               $wgUser = User::newFromName( $user );
+               
+               # Setup complete, now start
+               $dbw = wfGetDB( DB_MASTER );
+               for ( $linenum = 1; !feof( $file ); $linenum++ ) {
+                       $line = fgets( $file );
+                       if ( $line === false ) {
+                               break;
+                       }
+                       $parts = array_map( 'trim', explode( '|', $line ) );
+                       if ( count( $parts ) != 2 ) {
+                               $this->error( "Error on line $linenum, no pipe character\n" );
+                               continue;
+                       }
+                       $source = Title::newFromText( $parts[0] );
+                       $dest = Title::newFromText( $parts[1] );
+                       if ( is_null( $source ) || is_null( $dest ) ) {
+                               $this->error( "Invalid title on line $linenum\n" );
+                               continue;
+                       }
+       
+       
+                       $this->output( $source->getPrefixedText() . ' --> ' . $dest->getPrefixedText() );
+                       $dbw->begin();
+                       $err = $source->moveTo( $dest, false, $reason );
+                       if( $err !== true ) {
+                               $this->output( "\nFAILED: $err" );
+                       }
+                       $dbw->immediateCommit();
+                       $this->output( "\n" );
+       
+                       if ( $interval ) {
+                               sleep( $interval );
+                       }
+                       wfWaitForSlaves( 5 );
+               }
        }
-
-
-       print $source->getPrefixedText() . ' --> ' . $dest->getPrefixedText();
-       $dbw->begin();
-       $err = $source->moveTo( $dest, false, $reason );
-       if( $err !== true ) {
-               print "\nFAILED: $err";
-       }
-       $dbw->immediateCommit();
-       print "\n";
-
-       if ( $interval ) {
-               sleep( $interval );
-       }
-       wfWaitForSlaves( 5 );
 }
 
-
-
+$maintClass = "MoveBatch";
+require_once( DO_MAINTENANCE );
index 11623f4..a402efc 100644 (file)
@@ -1,54 +1,72 @@
 <?php
-# Copyright (C) 2005-2007 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
 /**
- * @file
+ * Check for articles to fix after adding/deleting namespaces
+ *
+ * Copyright (C) 2005-2007 Brion Vibber <brion@pobox.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$options = array( 'fix', 'suffix', 'help' );
+require_once( "Maintenance.php" );
 
-/** */
-require_once( 'commandLine.inc' );
+class NamespaceConflictChecker extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "";
+               $this->addOption( 'fix', 'Attempt to automatically fix errors' );
+               $this->addOption( 'suffix', "Dupes will be renamed with correct namespace with\n" .
+                                                                       "\t\t<text> Appended after the article name", false, true );
+               $this->addOption( 'prefix', "Do an explicit check for the given title prefix\n" .
+                                                                       "\t\tappended after the article name", false, true );
+               $this->addOption( 'wiki', 'Enter the wiki database to edit', false, true );
+       }
 
-if(isset( $options['help'] ) ) {
-print <<<ENDS
-usage: namespaceDupes.php [--fix] [--suffix=<text>] [--help]
-    --help          : this help message
-    --fix           : attempt to automatically fix errors
-    --suffix=<text> : dupes will be renamed with correct namespace with <text>
-                      appended after the article name.
-    --prefix=<text> : Do an explicit check for the given title prefix
-                      in place of the standard namespace list.
-    --verbose       : Display output for checked namespaces without conflicts
-    --wiki=<wiki>   : enter the wiki database to edit
-ENDS;
-die;
-}
+       public function execute() {
+               global $wgTitle;
+
+               $this->db = wfGetDB( DB_MASTER );
+               $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' );
+
+               $fix = $this->hasOption( 'fix' );
+               $suffix = $this->getOption( 'suffix', '' );
+               $prefix = $this->getOption( 'prefix', '' );
+               $key = intval( $this->getOption( 'key', 0 ) );
 
-class NamespaceConflictChecker {
-       function NamespaceConflictChecker( $db, $verbose=false ) {
-               $this->db = $db;
-               $this->verbose = $verbose;
+               if( $prefix ) {
+                       $retval = $this->checkPrefix( $key, $prefix, $fix, $suffix );
+               } else {
+                       $retval = $this->checkAll( $fix, $suffix );
+               }
+       
+               if( $retval ) {
+                       $this->output( "\nLooks good!\n" );
+               } else {
+                       $this->output( "\nOh noeees\n" );
+               }
        }
 
-       function checkAll( $fix, $suffix = '' ) {
+       /**
+        * @todo Document
+        * @param $fix bool Whether or not to fix broken entries
+        * @param $suffix String Suffix to append to renamed articles
+        */
+       private function checkAll( $fix, $suffix = '' ) {
                global $wgContLang, $wgNamespaceAliases, $wgCanonicalNamespaceNames;
                global $wgCapitalLinks;
                
@@ -112,7 +130,11 @@ class NamespaceConflictChecker {
                }
                return $ok;
        }
-       
+
+       /**
+        * Get the interwiki list
+        * @return array
+        */
        private function getInterwikiList() {
                $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) );
                $prefixes = array();
@@ -123,7 +145,14 @@ class NamespaceConflictChecker {
                return $prefixes;
        }
 
-       function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
+       /**
+        * @todo Document
+        * @param $ns int A namespace id
+        * @param $name String
+        * @param $fix bool Whether to fix broken entries
+        * @param $suffix String Suffix to append to renamed articles
+        */
+       private function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
                if( $ns == 0 ) {
                        $header = "Checking interwiki prefix: \"$name\"\n";
                } else {
@@ -133,15 +162,11 @@ class NamespaceConflictChecker {
                $conflicts = $this->getConflicts( $ns, $name );
                $count = count( $conflicts );
                if( $count == 0 ) {
-                       if( $this->verbose ) {
-                               echo $header;
-                               echo "... no conflicts detected!\n";
-                       }
+                       $this->output( $header . "... no conflict detected!\n" );
                        return true;
                }
 
-               echo $header;
-               echo "... $count conflicts detected:\n";
+               $this->output( $header . "... $count conflicts detected:\n" );
                $ok = true;
                foreach( $conflicts as $row ) {
                        $resolvable = $this->reportConflict( $row, $suffix );
@@ -156,12 +181,18 @@ class NamespaceConflictChecker {
        /**
         * @todo: do this for reals
         */
-       function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
-               echo "Checking prefix \"$prefix\" vs namespace $key\n";
+       private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
+               $this->output( "Checking prefix \"$prefix\" vs namespace $key\n" );
                return $this->checkNamespace( $key, $prefix, $fix, $suffix );
        }
 
-       function getConflicts( $ns, $name ) {
+       /**
+        * Find pages in mainspace that have a prefix of the new namespace
+        * so we know titles that will need migrating
+        * @param $ns int Namespace id (id for new namespace?)
+        * @param $name String Prefix that is being made a namespace
+        */
+       private function getConflicts( $ns, $name ) {
                $page  = 'page';
                $table = $this->db->tableName( $page );
 
@@ -194,52 +225,61 @@ class NamespaceConflictChecker {
                return $set;
        }
 
-       function reportConflict( $row, $suffix ) {
+       /**
+        * Report any conflicts we find
+        */
+       private function reportConflict( $row, $suffix ) {
                $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
                if( is_null($newTitle) || !$newTitle->canExist() ) {
                        // Title is also an illegal title...
                        // For the moment we'll let these slide to cleanupTitles or whoever.
-                       printf( "... %d (0,\"%s\")\n",
+                       $this->output( sprintf( "... %d (0,\"%s\")\n",
                                $row->id,
-                               $row->oldtitle );
-                       echo "...  *** cannot resolve automatically; illegal title ***\n";
+                               $row->oldtitle ) );
+                       $this->output( "...  *** cannot resolve automatically; illegal title ***\n" );
                        return false;
                }
-               
-               printf( "... %d (0,\"%s\") -> (%d,\"%s\") [[%s]]\n",
+
+               $this->output( sprintf( "... %d (0,\"%s\") -> (%d,\"%s\") [[%s]]\n",
                        $row->id,
                        $row->oldtitle,
                        $newTitle->getNamespace(),
                        $newTitle->getDBkey(),
-                       $newTitle->getPrefixedText() );
+                       $newTitle->getPrefixedText() ) );
 
                $id = $newTitle->getArticleId();
                if( $id ) {
-                       echo "...  *** cannot resolve automatically; page exists with ID $id ***\n";
+                       $this->output( "...  *** cannot resolve automatically; page exists with ID $id ***\n" );
                        return false;
                } else {
                        return true;
                }
        }
 
-       function resolveConflict( $row, $resolvable, $suffix ) {
+       /**
+        * Resolve any conflicts
+        * @param $row Row from the page table to fix
+        * @param $resolveable bool 
+        * @param $suffix String Suffix to append to the fixed page
+        */
+       private function resolveConflict( $row, $resolvable, $suffix ) {
                if( !$resolvable ) {
-                       echo "...  *** old title {$row->title}\n";
+                       $this->output( "...  *** old title {$row->title}\n" );
                        while( true ) {
                                $row->title .= $suffix;
-                               echo "...  *** new title {$row->title}\n";
+                               $this->output( "...  *** new title {$row->title}\n" );
                                $title = Title::makeTitleSafe( $row->namespace, $row->title );
                                if ( ! $title ) {
-                                       echo "... !!! invalid title\n";
+                                       $this->output( "... !!! invalid title\n" );
                                        return false;
                                }
                                if ( $id = $title->getArticleId() ) {
-                                       echo "...  *** page exists with ID $id ***\n";
+                                       $this->output( "...  *** page exists with ID $id ***\n" );
                                } else {        
                                        break;
                                }
                        }
-                       echo "...  *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n";
+                       $this->output( "...  *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" );
                }
                $tables = array( 'page' );
                foreach( $tables as $table ) {
@@ -248,8 +288,13 @@ class NamespaceConflictChecker {
                return true;
        }
 
-       function resolveConflictOn( $row, $table ) {
-               echo "... resolving on $table... ";
+       /**
+        * Resolve a given conflict
+        * @param $row Row from the old broken entry
+        * @param $table String Table to update
+        */
+       private function resolveConflictOn( $row, $table ) {
+               $this->output( "... resolving on $table... " );
                $newTitle = Title::makeTitleSafe( $row->namespace, $row->title );
                $this->db->update( $table,
                        array(
@@ -261,37 +306,10 @@ class NamespaceConflictChecker {
                                "{$table}_title"     => $row->oldtitle,
                        ),
                        __METHOD__ );
-               echo "ok.\n";
+               $this->output( "ok.\n" );
                return true;
        }
 }
 
-
-
-
-$wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' );
-
-$verbose = isset( $options['verbose'] );
-$fix = isset( $options['fix'] );
-$suffix = isset( $options['suffix'] ) ? $options['suffix'] : '';
-$prefix = isset( $options['prefix'] ) ? $options['prefix'] : '';
-$key = isset( $options['key'] ) ? intval( $options['key'] ) : 0;
-
-$dbw = wfGetDB( DB_MASTER );
-$duper = new NamespaceConflictChecker( $dbw, $verbose );
-
-if( $prefix ) {
-       $retval = $duper->checkPrefix( $key, $prefix, $fix, $suffix );
-} else {
-       $retval = $duper->checkAll( $fix, $suffix );
-}
-
-if( $retval ) {
-       echo "\nLooks good!\n";
-       exit( 0 );
-} else {
-       echo "\nOh noeees\n";
-       exit( -1 );
-}
-
-
+$maintClass = "NamespaceConflictChecker";
+require_once( DO_MAINTENANCE );
index 6af5cbe..c0a8b59 100644 (file)
@@ -2,59 +2,90 @@
 /**
  * Pick a database that has pending jobs
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$options = array( 'type'  );
-
-require_once( 'commandLine.inc' );
-
-$type = isset($options['type'])
-               ? $options['type']
-               : false;
+require_once( "Maintenance.php" );
 
-$mckey = $type === false
-            ? "jobqueue:dbs"
-            : "jobqueue:dbs:$type";
-
-$pendingDBs = $wgMemc->get( $mckey );
-if ( !$pendingDBs ) {
-       $pendingDBs = array();
-       # Cross-reference DBs by master DB server
-       $dbsByMaster = array();
-       foreach ( $wgLocalDatabases as $db ) {
-               $lb = wfGetLB( $db );
-               $dbsByMaster[$lb->getServerName(0)][] = $db;
+class nextJobDB extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Pick a database that has pending jobs";
+               $this->addOption( 'type', "The type of job to search for", false, true );
        }
-
-       foreach ( $dbsByMaster as $master => $dbs ) {
-               $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] );
-               $stype = $dbConn->addQuotes($type);
-
-               # Padding row for MySQL bug
-               $sql = "(SELECT '-------------------------------------------')";
-               foreach ( $dbs as $dbName ) {
-                       if ( $sql != '' ) {
-                               $sql .= ' UNION ';
-                       }
-                       if ($type === false)
-                               $sql .= "(SELECT '$dbName' FROM `$dbName`.job LIMIT 1)";
-                       else
-                               $sql .= "(SELECT '$dbName' FROM `$dbName`.job WHERE job_cmd=$stype LIMIT 1)";
+       public function execute() {
+               global $wgMemc;
+               $type = $this->getOption( 'type', false );
+               $mckey = $type === false
+                                       ? "jobqueue:dbs"
+                                       : "jobqueue:dbs:$type";
+               $pendingDBs = $wgMemc->get( $mckey );
+               
+               # If we didn't get it from the cache
+               if( !$pendingDBs ) {
+                       $pendingDBs = $this->getPendingDbs( $type );
+                       $wgMemc->get( $mckey, $pendingDBs, 300 );
                }
-               $res = $dbConn->query( $sql, 'nextJobDB.php' );
-               $row = $dbConn->fetchRow( $res ); // discard padding row
-               while ( $row = $dbConn->fetchRow( $res ) ) {
-                       $pendingDBs[] = $row[0];
+               # If we've got a pending job in a db, display it. 
+               if ( $pendingDBs ) {
+                       $this->output( $pendingDBs[mt_rand(0, count( $pendingDBs ) - 1)] );
+               }
+       }
+       
+       /**
+        * Get all databases that have a pending job
+        * @param $type String Job type
+        * @return array
+        */
+       private function getPendingDbs( $type ) {
+               global $wgLocalDatabases;
+               $pendingDBs = array();
+               # Cross-reference DBs by master DB server
+               $dbsByMaster = array();
+               foreach ( $wgLocalDatabases as $db ) {
+                       $lb = wfGetLB( $db );
+                       $dbsByMaster[$lb->getServerName(0)][] = $db;
+               }
+       
+               foreach ( $dbsByMaster as $master => $dbs ) {
+                       $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] );
+                       $stype = $dbConn->addQuotes($type);
+                       $jobTable = $dbConn->getTable( 'job' );
+       
+                       # Padding row for MySQL bug
+                       $sql = "(SELECT '-------------------------------------------')";
+                       foreach ( $dbs as $dbName ) {
+                               if ( $sql != '' ) {
+                                       $sql .= ' UNION ';
+                               }
+                               if ($type === false)
+                                       $sql .= "(SELECT '$dbName' FROM `$dbName`.$jobTable LIMIT 1)";
+                               else
+                                       $sql .= "(SELECT '$dbName' FROM `$dbName`.$jobTable WHERE job_cmd=$stype LIMIT 1)";
+                       }
+                       $res = $dbConn->query( $sql, __METHOD__ );
+                       $row = $dbConn->fetchRow( $res ); // discard padding row
+                       while ( $row = $dbConn->fetchRow( $res ) ) {
+                               $pendingDBs[] = $row[0];
+                       }
                }
        }
-
-       $wgMemc->set( $mckey, $pendingDBs, 300 );
-}
-
-if ( $pendingDBs ) {
-       echo $pendingDBs[mt_rand(0, count( $pendingDBs ) - 1)];
 }
 
-
+$maintClass = "nextJobDb";
+require_once( DO_MAINTENANCE );
index 4f9fe92..08232d2 100644 (file)
  * back up your DB if there's anything in the MediaWiki that is important to
  * you.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Steve Sanbeg
  * based on nukePage by Rob Church
  */
 
-require_once( 'commandLine.inc' );
-require_once( 'nukePage.inc' );
+require_once( "Maintenance.php" );
 
-$ns = NS_MEDIAWIKI;
-$delete = false;
+class NukeNS extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Remove pages with only 1 revision from any namespace";
+               $this->addOption( 'delete', "Actually delete the page" );
+               $this->addOption( 'ns', 'Namespace to delete from, default NS_MEDIAWIKI', false, true );
+       }
 
-if (isset($options['ns'])) 
-{
-  $ns = $options['ns'];
-}
+       public function execute() {
+               $ns = $this->getOption( 'ns', NS_MEDIAWIKI );
+               $delete = $this->getOption( 'delete', false );
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
 
-if (isset( $options['delete'] ) and $options['delete']) 
-{
-  $delete = true;
-}
+               $tbl_pag = $dbw->tableName( 'page' );
+               $tbl_rev = $dbw->tableName( 'revision' );
+               $res = $dbw->query( "SELECT page_title FROM $tbl_pag WHERE page_namespace = $ns" );
 
+               $n_deleted = 0;
 
-NukeNS( $ns, $delete);
+               while( $row = $dbw->fetchObject( $res ) ) {
+                       //echo "$ns_name:".$row->page_title, "\n";
+                       $title = Title::newFromText($row->page_title, $ns);
+                       $id   = $title->getArticleID();
 
-function NukeNS($ns_no, $delete) {
+                       // Get corresponding revisions
+                       $res2 = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" );
+                       $revs = array();
 
-  $dbw = wfGetDB( DB_MASTER );
-  $dbw->begin();
-  
-  $tbl_pag = $dbw->tableName( 'page' );
-  $tbl_rev = $dbw->tableName( 'revision' );
-  $res = $dbw->query( "SELECT page_title FROM $tbl_pag WHERE page_namespace = $ns_no" );
+                       while( $row2 = $dbw->fetchObject( $res2 ) ) {
+                               $revs[] = $row2->rev_id;
+                       }
+                       $count = count( $revs );
 
-  $n_deleted = 0;
-  
-  while( $row = $dbw->fetchObject( $res ) ) {
-    //echo "$ns_name:".$row->page_title, "\n";
-    $title = Title::newFromText($row->page_title, $ns_no);
-    $id   = $title->getArticleID();
+                       //skip anything that looks modified (i.e. multiple revs)
+                       if (($count == 1)) {
+                               #echo $title->getPrefixedText(), "\t", $count, "\n";
+                               $this->output( "delete: ", $title->getPrefixedText(), "\n" );
 
-    // Get corresponding revisions
-    $res2 = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" );
-    $revs = array();
-    
-    while( $row2 = $dbw->fetchObject( $res2 ) ) {
-      $revs[] = $row2->rev_id;
-    }
-    $count = count( $revs );
+                               //as much as I hate to cut & paste this, it's a little different, and
+                               //I already have the id & revs
+                               if( $delete ) {
+                                       $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
+                                       $dbw->commit();
+                                       // Delete revisions as appropriate
+                                       $child = $this->spawnChild( 'NukePage', 'NukePage.php' );
+                                       $child->deleteRevisions( $revs );
+                                       $this->purgeRedundantText( true );
+                                       $n_deleted ++;
+                               }
+                       } else {
+                         $this->output( "skip: ", $title->getPrefixedText(), "\n" );
+                       }
+               }
+               $dbw->commit();
 
-    //skip anything that looks modified (i.e. multiple revs)
-    if (($count == 1)) {
-      #echo $title->getPrefixedText(), "\t", $count, "\n";
-      echo "delete: ", $title->getPrefixedText(), "\n";
-      
-      //as much as I hate to cut & paste this, it's a little different, and
-      //I already have the id & revs
-      
-      if( $delete ) {
-       $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
-       $dbw->commit();
-       // Delete revisions as appropriate
-       DeleteRevisions( $revs );
-       PurgeRedundantText( true );
-       $n_deleted ++;
-      }
-    } else {
-      echo "skip: ", $title->getPrefixedText(), "\n";
-    }
-    
-    
-  }
-  $dbw->commit();
-  
-  if ($n_deleted > 0) {
-    #update statistics - better to decrement existing count, or just count
-    #the page table?
-    $pages = $dbw->selectField('site_stats', 'ss_total_pages');
-    $pages -= $n_deleted;
-    $dbw->update( 'site_stats', 
-                 array('ss_total_pages' => $pages ), 
-                 array( 'ss_row_id' => 1),
-                 __METHOD__ );
-    
-  }
-  
-  if (!$delete) {
-    echo( "To update the database, run the script with the --delete option.\n" );
-  }
-  
+               if ($n_deleted > 0) {
+               #update statistics - better to decrement existing count, or just count
+               #the page table?
+               $pages = $dbw->selectField('site_stats', 'ss_total_pages');
+               $pages -= $n_deleted;
+               $dbw->update( 'site_stats', 
+                         array('ss_total_pages' => $pages ), 
+                         array( 'ss_row_id' => 1),
+                         __METHOD__ );
+               }
+       
+               if (!$delete) {
+                       $this->output( "To update the database, run the script with the --delete option.\n" );
+               }
+       }
 }
 
-
+$maintClass = "NukeNS";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/nukePage.inc b/maintenance/nukePage.inc
deleted file mode 100644 (file)
index a19c6df..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-/**
- * Support functions for the nukeArticle script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-require_once( 'purgeOldText.inc' );
-
-function NukePage( $name, $delete = false ) {
-
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->begin();
-       
-       $tbl_pag = $dbw->tableName( 'page' );
-       $tbl_rec = $dbw->tableName( 'recentchanges' );
-       $tbl_rev = $dbw->tableName( 'revision' );
-       
-       # Get page ID
-       echo( "Searching for \"$name\"..." );
-       $title = Title::newFromText( $name );
-       if( $title ) {
-               $id   = $title->getArticleID();
-               $real = $title->getPrefixedText();
-               $isGoodArticle = $title->isContentPage();
-               echo( "found \"$real\" with ID $id.\n" );
-               
-               # Get corresponding revisions
-               echo( "Searching for revisions..." );
-               $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" );
-               while( $row = $dbw->fetchObject( $res ) ) {
-                       $revs[] = $row->rev_id;
-               }
-               $count = count( $revs );
-               echo( "found $count.\n" );
-               
-               # Delete the page record and associated recent changes entries
-               if( $delete ) {
-                       echo( "Deleting page record..." );
-                       $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
-                       echo( "done.\n" );
-                       echo( "Cleaning up recent changes..." );
-                       $dbw->query( "DELETE FROM $tbl_rec WHERE rc_cur_id = $id" );
-                       echo( "done.\n" );
-               }
-
-               $dbw->commit();
-               
-               # Delete revisions as appropriate
-               if( $delete && $count ) {
-                       echo( "Deleting revisions..." );
-                       DeleteRevisions( $revs );
-                       echo( "done.\n" );
-                       PurgeRedundantText( true );
-               }
-               
-               # Update stats as appropriate
-               if ( $delete ) {
-                       echo( "Updating site stats..." );
-                       $ga = $isGoodArticle ? -1 : 0; // if it was good, decrement that too
-                       $stats = new SiteStatsUpdate( 0, -$count, $ga, -1 );
-                       $stats->doUpdate();
-                       echo( "done.\n" );
-               }
-               
-               
-       } else {
-               echo( "not found in database.\n" );
-               $dbw->commit();
-       }
-       
-}
-
-function DeleteRevisions( $ids ) {
-
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->begin();
-       
-       $tbl_rev = $dbw->tableName( 'revision' );
-       
-       $set = implode( ', ', $ids );
-       $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" );
-       
-       $dbw->commit(); 
-       
-}
-
-?>
\ No newline at end of file
index b3bfc76..eb8f166 100644 (file)
 <?php
-
 /**
  * Erase a page record from the database
  * Irreversible (can't use standard undelete) and does not update link tables
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-require_once( 'commandLine.inc' );
-require_once( 'nukePage.inc' );
+require_once( "Maintenance.php" );
 
-echo( "Erase Page Record\n\n" );
+class NukePage extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Remove a page record from the database";
+               $this->addOption( 'delete', "Actually delete the page" );
+               $this->addArgs( array( 'title' ) );
+       }
 
-if( isset( $args[0] ) ) {
-       NukePage( $args[0], true );
-} else {
-       ShowUsage();
-}
+       public function execute() {
+
+               $name = $this->getArg();
+               $delete = $this->getOption( 'delete', false );
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+
+               $tbl_pag = $dbw->tableName( 'page' );
+               $tbl_rec = $dbw->tableName( 'recentchanges' );
+               $tbl_rev = $dbw->tableName( 'revision' );
+
+               # Get page ID
+               $this->output( "Searching for \"$name\"..." );
+               $title = Title::newFromText( $name );
+               if( $title ) {
+                       $id   = $title->getArticleID();
+                       $real = $title->getPrefixedText();
+                       $isGoodArticle = $title->isContentPage();
+                       $this->output( "found \"$real\" with ID $id.\n" );
+
+                       # Get corresponding revisions
+                       $this->output( "Searching for revisions..." );
+                       $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" );
+                       while( $row = $dbw->fetchObject( $res ) ) {
+                               $revs[] = $row->rev_id;
+                       }
+                       $count = count( $revs );
+                       $this->output( "found $count.\n" );
+
+                       # Delete the page record and associated recent changes entries
+                       if( $delete ) {
+                               $this->output( "Deleting page record..." );
+                               $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" );
+                               $this->output( "done.\n" );
+                               $this->output( "Cleaning up recent changes..." );
+                               $dbw->query( "DELETE FROM $tbl_rec WHERE rc_cur_id = $id" );
+                               $this->output( "done.\n" );
+                       }
+
+                       $dbw->commit();
+
+                       # Delete revisions as appropriate
+                       if( $delete && $count ) {
+                               $this->output( "Deleting revisions..." );
+                               $this->deleteRevisions( $revs );
+                               $this->output( "done.\n" );
+                               $this->purgeRedundantText( true );
+                       }
+
+                       # Update stats as appropriate
+                       if ( $delete ) {
+                               $this->output( "Updating site stats..." );
+                               $ga = $isGoodArticle ? -1 : 0; // if it was good, decrement that too
+                               $stats = new SiteStatsUpdate( 0, -$count, $ga, -1 );
+                               $stats->doUpdate();
+                               $this->output( "done.\n" );
+                       }
+               } else {
+                       $this->output( "not found in database.\n" );
+                       $dbw->commit();
+               }
+       }
+
+       public function deleteRevisions( $ids ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+
+               $tbl_rev = $dbw->tableName( 'revision' );
+
+               $set = implode( ', ', $ids );
+               $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" );
 
-/** Show script usage information */
-function ShowUsage() {
-       echo( "Remove a page record from the database.\n\n" );
-       echo( "Usage: php nukePage.php <title>\n\n" );
-       echo( " <title> : Page title; spaces escaped with underscores\n\n" );
+               $dbw->commit(); 
+       }
 }
 
+$maintClass = "NukePage";
+require_once( DO_MAINTENANCE );
index 480b722..6e68a82 100644 (file)
 <?php
-# Copyright (C) 2005 Brion Vibber <brion@pobox.com>
-# http://www.mediawiki.org/
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
-
 /**
  * Look for 'orphan' revisions hooked to pages which don't exist
  * And 'childless' pages with no revisions.
  * Then, kill the poor widows and orphans.
  * Man this is depressing.
  *
- * @file
+ * Copyright (C) 2005 Brion Vibber <brion@pobox.com>
+ * http://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @author <brion@pobox.com>
  * @ingroup Maintenance
  */
 
-$options = array( 'fix' );
-
-/** */
-require_once( 'commandLine.inc' );
-$wgTitle = Title::newFromText( 'Orphan revision cleanup script' );
-
-checkOrphans( isset( $options['fix'] ) );
-checkSeparation( isset( $options['fix'] ) );
-#checkWidows( isset( $options['fix'] ) );
+require_once( "Maintenance.php" );
 
-# ------
-
-function checkOrphans( $fix ) {
-       $dbw = wfGetDB( DB_MASTER );
-       $page = $dbw->tableName( 'page' );
-       $revision = $dbw->tableName( 'revision' );
-
-       if( $fix ) {
-               $dbw->query( "LOCK TABLES $page WRITE, $revision WRITE" );
+class Orphans extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Look for 'orphan' revisions hooked to pages which don't exist\n" .
+                                                               "And 'childless' pages with no revisions\n" .
+                                                               "Then, kill the poor widows and orphans\n" .
+                                                               "Man this is depressing";
+               $this->addOption( 'fix', 'Actually fix broken entries' );
        }
 
-       echo "Checking for orphan revision table entries... (this may take a while on a large wiki)\n";
-       $result = $dbw->query( "
-               SELECT *
-               FROM $revision LEFT OUTER JOIN $page ON rev_page=page_id
-               WHERE page_id IS NULL
-       ");
-       $orphans = $dbw->numRows( $result );
-       if( $orphans > 0 ) {
-               global $wgContLang;
-               echo "$orphans orphan revisions...\n";
-               printf( "%10s %10s %14s %20s %s\n", 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text', 'rev_comment' );
-               while( $row = $dbw->fetchObject( $result ) ) {
-                       $comment = ( $row->rev_comment == '' )
-                               ? ''
-                               : '(' . $wgContLang->truncate( $row->rev_comment, 40 ) . ')';
-                       printf( "%10d %10d %14s %20s %s\n",
-                               $row->rev_id,
-                               $row->rev_page,
-                               $row->rev_timestamp,
-                               $wgContLang->truncate( $row->rev_user_text, 17 ),
-                               $comment );
-                       if( $fix ) {
-                               $dbw->delete( 'revision', array( 'rev_id' => $row->rev_id ) );
-                       }
-               }
-               if( !$fix ) {
-                       echo "Run again with --fix to remove these entries automatically.\n";
-               }
-       } else {
-               echo "No orphans! Yay!\n";
+       public function execute() {
+               global $wgTitle;
+               $wgTitle = Title::newFromText( 'Orphan revision cleanup script' );
+               $this->checkOrphans( $this->hasOption( 'fix' ) );
+               $this->checkSeparation( $this->hasOption( 'fix' ) );
+               # Does not work yet, do not use
+               # $this->checkWidows( $this->hasOption( 'fix' ) );
        }
 
-       if( $fix ) {
-               $dbw->query( "UNLOCK TABLES" );
-       }
-}
-
-/**
- * @todo DON'T USE THIS YET! It will remove entries which have children,
- *       but which aren't properly attached (eg if page_latest is bogus
- *       but valid revisions do exist)
- */
-function checkWidows( $fix ) {
-       $dbw = wfGetDB( DB_MASTER );
-       $page = $dbw->tableName( 'page' );
-       $revision = $dbw->tableName( 'revision' );
-
-       if( $fix ) {
-               $dbw->query( "LOCK TABLES $page WRITE, $revision WRITE" );
+       /**
+        * Lock the appropriate tables for the script
+        * @param $db Database object
+        * @param $extraTable String The name of any extra tables to lock (eg: text)
+        */
+       private function lockTables( &$db, $extraTable = null ) {
+               $tbls = array( 'page', 'revision', 'redirect' );
+               if( $extraTable )
+                       $tbls[] = $extraTable;
+               $db->lockTables( array(), $tbls, __METHOD__, false );
        }
 
-       echo "\nChecking for childless page table entries... (this may take a while on a large wiki)\n";
-       $result = $dbw->query( "
-               SELECT *
-               FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
-               WHERE rev_id IS NULL
-       ");
-       $widows = $dbw->numRows( $result );
-       if( $widows > 0 ) {
-               global $wgContLang;
-               echo "$widows childless pages...\n";
-               printf( "%10s %11s %2s %s\n", 'page_id', 'page_latest', 'ns', 'page_title' );
-               while( $row = $dbw->fetchObject( $result ) ) {
-                       printf( "%10d %11d %2d %s\n",
-                               $row->page_id,
-                               $row->page_latest,
-                               $row->page_namespace,
-                               $row->page_title );
-                       if( $fix ) {
-                               $dbw->delete( 'page', array( 'page_id' => $row->page_id ) );
+       /**
+        * Check for orphan revisions
+        * @param $fix bool Whether to fix broken revisions when found
+        */
+       private function checkOrphans( $fix ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $page = $dbw->tableName( 'page' );
+               $revision = $dbw->tableName( 'revision' );
+       
+               if( $fix ) {
+                       $this->lockTables( $dbw );
+               }
+       
+               $this->output( "Checking for orphan revision table entries... (this may take a while on a large wiki)\n" );
+               $result = $dbw->query( "
+                       SELECT *
+                       FROM $revision LEFT OUTER JOIN $page ON rev_page=page_id
+                       WHERE page_id IS NULL
+               ");
+               $orphans = $dbw->numRows( $result );
+               if( $orphans > 0 ) {
+                       global $wgContLang;
+                       $this->output( "$orphans orphan revisions...\n" );
+                       $this->output( sprintf( "%10s %10s %14s %20s %s\n", 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text', 'rev_comment' ) );
+                       while( $row = $dbw->fetchObject( $result ) ) {
+                               $comment = ( $row->rev_comment == '' )
+                                       ? ''
+                                       : '(' . $wgContLang->truncate( $row->rev_comment, 40 ) . ')';
+                               $this->output( sprintf( "%10d %10d %14s %20s %s\n",
+                                       $row->rev_id,
+                                       $row->rev_page,
+                                       $row->rev_timestamp,
+                                       $wgContLang->truncate( $row->rev_user_text, 17 ),
+                                       $comment ) );
+                               if( $fix ) {
+                                       $dbw->delete( 'revision', array( 'rev_id' => $row->rev_id ) );
+                               }
+                       }
+                       if( !$fix ) {
+                               $this->output( "Run again with --fix to remove these entries automatically.\n" );
                        }
+               } else {
+                       $this->output( "No orphans! Yay!\n" );
                }
-               if( !$fix ) {
-                       echo "Run again with --fix to remove these entries automatically.\n";
+       
+               if( $fix ) {
+                       $dbw->unlockTables();
                }
-       } else {
-               echo "No childless pages! Yay!\n";
-       }
-
-       if( $fix ) {
-               $dbw->query( "UNLOCK TABLES" );
        }
-}
-
-
-function checkSeparation( $fix ) {
-       $dbw = wfGetDB( DB_MASTER );
-       $page     = $dbw->tableName( 'page' );
-       $revision = $dbw->tableName( 'revision' );
-       $text     = $dbw->tableName( 'text' );
 
-       if( $fix ) {
-               $dbw->query( "LOCK TABLES $page WRITE, $revision WRITE, $text WRITE" );
-       }
+       /**
+        * @param $fix bool 
+        * @todo DON'T USE THIS YET! It will remove entries which have children,
+        *       but which aren't properly attached (eg if page_latest is bogus
+        *       but valid revisions do exist)
+        */
+       private function checkWidows( $fix ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $page = $dbw->tableName( 'page' );
+               $revision = $dbw->tableName( 'revision' );
+
+               if( $fix ) {
+                       $this->lockTables( $dbw );
+               }
 
-       echo "\nChecking for pages whose page_latest links are incorrect... (this may take a while on a large wiki)\n";
-       $result = $dbw->query( "
-               SELECT *
-               FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
-       ");
-       $found = 0;
-       while( $row = $dbw->fetchObject( $result ) ) {
-               $result2 = $dbw->query( "
-                       SELECT MAX(rev_timestamp) as max_timestamp
-                       FROM $revision
-                       WHERE rev_page=$row->page_id
-               " );
-               $row2 = $dbw->fetchObject( $result2 );
-               $dbw->freeResult( $result2 );
-               if( $row2 ) {
-                       if( $row->rev_timestamp != $row2->max_timestamp ) {
-                               if( $found == 0 ) {
-                                       printf( "%10s %10s %14s %14s\n",
-                                               'page_id', 'rev_id', 'timestamp', 'max timestamp' );
-                               }
-                               ++$found;
-                               printf( "%10d %10d %14s %14s\n",
+               $this->output( "\nChecking for childless page table entries... (this may take a while on a large wiki)\n" );
+               $result = $dbw->query( "
+                       SELECT *
+                       FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
+                       WHERE rev_id IS NULL
+               ");
+               $widows = $dbw->numRows( $result );
+               if( $widows > 0 ) {
+                       global $wgContLang;
+                       $this->output( "$widows childless pages...\n" );
+                       $this->output( sprintf( "%10s %11s %2s %s\n", 'page_id', 'page_latest', 'ns', 'page_title' ) );
+                       while( $row = $dbw->fetchObject( $result ) ) {
+                               printf( "%10d %11d %2d %s\n",
                                        $row->page_id,
                                        $row->page_latest,
-                                       $row->rev_timestamp,
-                                       $row2->max_timestamp );
+                                       $row->page_namespace,
+                                       $row->page_title );
                                if( $fix ) {
-                                       # ...
-                                       $maxId = $dbw->selectField(
-                                               'revision',
-                                               'rev_id',
-                                               array(
-                                                       'rev_page'      => $row->page_id,
-                                                       'rev_timestamp' => $row2->max_timestamp ) );
-                                       echo "... updating to revision $maxId\n";
-                                       $maxRev = Revision::newFromId( $maxId );
-                                       $title = Title::makeTitle( $row->page_namespace, $row->page_title );
-                                       $article = new Article( $title );
-                                       $article->updateRevisionOn( $dbw, $maxRev );
+                                       $dbw->delete( 'page', array( 'page_id' => $row->page_id ) );
                                }
                        }
+                       if( !$fix ) {
+                               $this->output( "Run again with --fix to remove these entries automatically.\n" );
+                       }
                } else {
-                       echo "wtf\n";
+                       $this->output( "No childless pages! Yay!\n" );
+               }
+       
+               if( $fix ) {
+                       $dbw->unlockTables();
                }
        }
 
-       if( $found ) {
-               echo "Found $found pages with incorrect latest revision.\n";
-       } else {
-               echo "No pages with incorrect latest revision. Yay!\n";
-       }
-       if( !$fix && $found > 0 ) {
-               echo "Run again with --fix to remove these entries automatically.\n";
-       }
-
-       if( $fix ) {
-               $dbw->query( "UNLOCK TABLES" );
+       /**
+        * Check for pages where page_latest is wrong
+        * @param $fix bool Whether to fix broken entries
+        */
+       private function checkSeparation( $fix ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $page     = $dbw->tableName( 'page' );
+               $revision = $dbw->tableName( 'revision' );
+               $text     = $dbw->tableName( 'text' );
+       
+               if( $fix ) {
+                       $dbw->lockTables( $dbw, 'text' );
+               }
+       
+               $this->output( "\nChecking for pages whose page_latest links are incorrect... (this may take a while on a large wiki)\n" );
+               $result = $dbw->query( "
+                       SELECT *
+                       FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
+               ");
+               $found = 0;
+               while( $row = $dbw->fetchObject( $result ) ) {
+                       $result2 = $dbw->query( "
+                               SELECT MAX(rev_timestamp) as max_timestamp
+                               FROM $revision
+                               WHERE rev_page=$row->page_id
+                       " );
+                       $row2 = $dbw->fetchObject( $result2 );
+                       $dbw->freeResult( $result2 );
+                       if( $row2 ) {
+                               if( $row->rev_timestamp != $row2->max_timestamp ) {
+                                       if( $found == 0 ) {
+                                               $this->output( sprintf( "%10s %10s %14s %14s\n",
+                                                       'page_id', 'rev_id', 'timestamp', 'max timestamp' ) );
+                                       }
+                                       ++$found;
+                                       $this->output( sprintf( "%10d %10d %14s %14s\n",
+                                               $row->page_id,
+                                               $row->page_latest,
+                                               $row->rev_timestamp,
+                                               $row2->max_timestamp ) );
+                                       if( $fix ) {
+                                               # ...
+                                               $maxId = $dbw->selectField(
+                                                       'revision',
+                                                       'rev_id',
+                                                       array(
+                                                               'rev_page'      => $row->page_id,
+                                                               'rev_timestamp' => $row2->max_timestamp ) );
+                                               $this->output( "... updating to revision $maxId\n" );
+                                               $maxRev = Revision::newFromId( $maxId );
+                                               $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+                                               $article = new Article( $title );
+                                               $article->updateRevisionOn( $dbw, $maxRev );
+                                       }
+                               }
+                       } else {
+                               $this->output( "wtf\n" );
+                       }
+               }
+       
+               if( $found ) {
+                       $this->output( "Found $found pages with incorrect latest revision.\n" );
+               } else {
+                       $this->output( "No pages with incorrect latest revision. Yay!\n" );
+               }
+               if( !$fix && $found > 0 ) {
+                       $this->output( "Run again with --fix to remove these entries automatically.\n" );
+               }
+       
+               if( $fix ) {
+                       $dbw->unlockTables();
+               }
        }
 }
 
+$maintClass = "Orphans";
+require_once( DO_MAINTENANCE );
index 42380ee..0629b33 100644 (file)
@@ -20,7 +20,7 @@ if( $args ) {
                foreach( $files as $file ) {
                        if( file_exists( $file ) ) {
                                echo "$file ...\n";
-                               dbsource( $file );
+                               wfGetDB( DB_MASTER )->fileSource( $file );
                                continue 2;
                        }
                }
index 1dca7b7..af9f219 100644 (file)
@@ -7,11 +7,16 @@
 
 $optionsWithArgs = array( 'begin', 'max-slave-lag', 'throttle' );
 
-require_once "commandLine.inc";
-require_once "populateCategory.inc";
+require_once( "Maintenance.php" );
 
-if( isset( $options['help'] ) ) {
-       echo <<<TEXT
+
+class PopulateCategory extends Maintenance {
+
+       const REPORTING_INTERVAL = 1000;
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = <<<TEXT
 This script will populate the category table, added in MediaWiki 1.13.  It will
 print out progress indicators every 1000 categories it adds to the table.  The
 script is perfectly safe to run on large, live wikis, and running it multiple
@@ -25,29 +30,98 @@ added after the software update and so will be populated anyway.
 
 When the script has finished, it will make a note of this in the database, and
 will not run again without the --force option.
-
-Usage:
-    php populateCategory.php [--max-slave-lag <seconds>] [--begin <name>]
-[--throttle <seconds>] [--force]
-
-    --begin: Only do categories whose names are alphabetically after the pro-
-vided name.  Default: empty (start from beginning).
-    --max-slave-lag: If slave lag exceeds this many seconds, wait until it
-drops before continuing.  Default: 10.
-    --throttle: Wait this many milliseconds after each category.  Default: 0.
-    --force: Run regardless of whether the database says it's been run already.
-
 TEXT;
-       exit( 0 );
-}
+               $this->addOption( 'begin', 'Only do categories whose names are alphabetically after the provided name', false, true );
+               $this->addOption( 'max-slave-lag', 'If slave lag exceeds this many seconds, wait until it drops before continuing.  Default: 10', false, true );
+               $this->addOption( 'throttle', 'Wait this many milliseconds after each category.  Default: 0', false, true );
+               $this->addOption( 'force', 'Run regardless of whether the database says it\'s been run already' );
+       }
+       
+       public function execute() {
+               $begin = $this->getOption( 'begin', '' );
+               $maxSlaveLag = $this->getOption( 'max-slave-lag', 10 );
+               $throttle = $this->getOption( 'throttle', 0 );
+               $force = $this->getOption( 'force', false );
+               $this->doPopulateCategory( $begin, $maxSlaveLag, $throttle, $force );
+       }
 
-$defaults = array(
-       'begin' => '',
-       'max-slave-lag' => 10,
-       'throttle' => 0,
-       'force' => false
-);
-$options = array_merge( $defaults, $options );
+       private function doPopulateCategory( $begin, $maxlag, $throttle, $force ) {
+               $dbw = wfGetDB( DB_MASTER );
+       
+               if( !$force ) {
+                       $row = $dbw->selectRow(
+                               'updatelog',
+                               '1',
+                               array( 'ul_key' => 'populate category' ),
+                               __FUNCTION__
+                       );
+                       if( $row ) {
+                               $this->output( "Category table already populated.  Use php ".
+                               "maintenance/populateCategory.php\n--force from the command line ".
+                               "to override.\n" );
+                               return true;
+                       }
+               }
+       
+               $maxlag = intval( $maxlag );
+               $throttle = intval( $throttle );
+               $force = (bool)$force;
+               if( $begin !== '' ) {
+                       $where = 'cl_to > '.$dbw->addQuotes( $begin );
+               } else {
+                       $where = null;
+               }
+               $i = 0;
+       
+               while( true ) {
+                       # Find which category to update
+                       $row = $dbw->selectRow(
+                               'categorylinks',
+                               'cl_to',
+                               $where,
+                               __FUNCTION__,
+                               array(
+                                       'ORDER BY' => 'cl_to'
+                               )
+                       );
+                       if( !$row ) {
+                               # Done, hopefully.
+                               break;
+                       }
+                       $name = $row->cl_to;
+                       $where = 'cl_to > '.$dbw->addQuotes( $name );
+       
+                       # Use the row to update the category count
+                       $cat = Category::newFromName( $name );
+                       if( !is_object( $cat ) ) {
+                               $this->output( "The category named $name is not valid?!\n" );
+                       } else {
+                               $cat->refreshCounts();
+                       }
+       
+                       ++$i;
+                       if( !($i % self::REPORTING_INTERVAL) ) {
+                               $this->output( "$name\n" );
+                               wfWaitForSlaves( $maxlag );
+                       }
+                       usleep( $throttle*1000 );
+               }
+       
+               if( $dbw->insert(
+                               'updatelog',
+                               array( 'ul_key' => 'populate category' ),
+                               __FUNCTION__,
+                               'IGNORE'
+                       )
+               ) {
+                       wfOut( "Category population complete.\n" );
+                       return true;
+               } else {
+                       wfOut( "Could not insert category population row.\n" );
+                       return false;
+               }
+       }
+}
 
-populateCategory( $options['begin'], $options['max-slave-lag'],
-       $options['throttle'], $options['force'] );
+$maintClass = "PopulateCategory";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/populateLogSearch.inc b/maintenance/populateLogSearch.inc
deleted file mode 100644 (file)
index d678191..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
- * Makes the required database updates for log display in Special:RevisionDelete
- *
- * Run via update.php or directly through populateLogSearch.php
- *
- * @file
- * @ingroup Maintenance
- */
-
-define( 'LOG_SEARCH_BATCH_SIZE', 100 );
-
-function migrate_log_params( $db ) {
-       $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
-       if( !$start ) {
-               echo "Nothing to do.\n";
-               return true;
-       }
-       $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
-       
-       # Do remaining chunk
-       $end += LOG_SEARCH_BATCH_SIZE - 1;
-       $blockStart = $start;
-       $blockEnd = $start + LOG_SEARCH_BATCH_SIZE - 1;
-       while( $blockEnd <= $end ) {
-               echo "...doing log_id from $blockStart to $blockEnd\n";
-               $cond = "log_id BETWEEN $blockStart AND $blockEnd";
-               $res = $db->select( 'logging', '*', $cond, __FUNCTION__ );
-               $batch = array();
-               while( $row = $db->fetchObject( $res ) ) {
-                       // RevisionDelete logs - revisions
-                       if( LogEventsList::typeAction( $row, array('delete','suppress'), 'revision' ) ) {
-                               $params = LogPage::extractParams( $row->log_params );
-                               // Param format: <urlparam> <item CSV> [<ofield> <nfield>]
-                               if( count($params) >= 2 ) {
-                                       $field = RevisionDeleter::getRelationType($params[0]);
-                                       // B/C, the params may start with a title key
-                                       if( $field == null ) {
-                                               array_shift($params);
-                                               $field = RevisionDeleter::getRelationType($params[0]);
-                                       }
-                                       if( $field == null ) {
-                                               echo "Invalid param type for $row->log_id\n";
-                                               continue; // skip this row
-                                       }
-                                       $items = explode(',',$params[1]);
-                                       $log = new LogPage( $row->log_type );
-                                       $log->addRelations( $field, $items, $row->log_id );
-                               }
-                       // RevisionDelete logs - log events
-                       } else if( LogEventsList::typeAction( $row, array('delete','suppress'), 'event' ) ) {
-                               $params = LogPage::extractParams( $row->log_params );
-                               // Param format: <item CSV> [<ofield> <nfield>]
-                               if( count($params) >= 1 ) {
-                                       $items = explode(',',$params[0]);
-                                       $log = new LogPage( $row->log_type );
-                                       $log->addRelations( 'log_id', $items, $row->log_id );
-                               }
-                       }
-               }
-               $blockStart += LOG_SEARCH_BATCH_SIZE;
-               $blockEnd += LOG_SEARCH_BATCH_SIZE;
-               wfWaitForSlaves( 5 );
-       }
-       if( $db->insert(
-                       'updatelog',
-                       array( 'ul_key' => 'populate log_search' ),
-                       __FUNCTION__,
-                       'IGNORE'
-               )
-       ) {
-               wfOut( "log_search population complete.\n" );
-               return true;
-       } else {
-               wfOut( "Could not insert log_search population row.\n" );
-               return false;
-       }
-}
index fe8dc06..b8f28df 100644 (file)
  * Makes the required database updates for populating the
  * log_search table retroactively
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once 'commandLine.inc';
-require_once 'populateLogSearch.inc';
+require_once( "Maintenance.php" );
+
+class PopulateLogSearch extends Maintenance {
+
+       const LOG_SEARCH_BATCH_SIZE = 100;
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Migrate log params to new table and index for searching";
+       }
+
+       public function execute() {
+               $db = wfGetDB( DB_MASTER );
+               if ( !$db->tableExists( 'log_search' ) ) {
+                       $this->error( "log_search does not exist\n", true );
+               }
+               $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
+               if( !$start ) {
+                       $this->output( "Nothing to do.\n" );
+                       return true;
+               }
+               $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
        
-$db =& wfGetDB( DB_MASTER );
-if ( !$db->tableExists( 'log_search' ) ) {
-       echo "log_search does not exist\n";
-       exit( 1 );
+               # Do remaining chunk
+               $end += self::LOG_SEARCH_BATCH_SIZE - 1;
+               $blockStart = $start;
+               $blockEnd = $start + self::LOG_SEARCH_BATCH_SIZE - 1;
+               while( $blockEnd <= $end ) {
+                       $this->output( "...doing log_id from $blockStart to $blockEnd\n" );
+                       $cond = "log_id BETWEEN $blockStart AND $blockEnd";
+                       $res = $db->select( 'logging', '*', $cond, __FUNCTION__ );
+                       $batch = array();
+                       while( $row = $db->fetchObject( $res ) ) {
+                               // RevisionDelete logs - revisions
+                               if( LogEventsList::typeAction( $row, array('delete','suppress'), 'revision' ) ) {
+                                       $params = LogPage::extractParams( $row->log_params );
+                                       // Param format: <urlparam> <item CSV> [<ofield> <nfield>]
+                                       if( count($params) >= 2 ) {
+                                               $field = RevisionDeleter::getRelationType($params[0]);
+                                               // B/C, the params may start with a title key
+                                               if( $field == null ) {
+                                                       array_shift($params);
+                                                       $field = RevisionDeleter::getRelationType($params[0]);
+                                               }
+                                               if( $field == null ) {
+                                                       $this->output( "Invalid param type for $row->log_id\n" );
+                                                       continue; // skip this row
+                                               }
+                                               $items = explode(',',$params[1]);
+                                               $log = new LogPage( $row->log_type );
+                                               $log->addRelations( $field, $items, $row->log_id );
+                                       }
+                               // RevisionDelete logs - log events
+                               } else if( LogEventsList::typeAction( $row, array('delete','suppress'), 'event' ) ) {
+                                       $params = LogPage::extractParams( $row->log_params );
+                                       // Param format: <item CSV> [<ofield> <nfield>]
+                                       if( count($params) >= 1 ) {
+                                               $items = explode(',',$params[0]);
+                                               $log = new LogPage( $row->log_type );
+                                               $log->addRelations( 'log_id', $items, $row->log_id );
+                                       }
+                               }
+                       }
+                       $blockStart += self::LOG_SEARCH_BATCH_SIZE;
+                       $blockEnd += self::LOG_SEARCH_BATCH_SIZE;
+                       wfWaitForSlaves( 5 );
+               }
+               if( $db->insert(
+                               'updatelog',
+                               array( 'ul_key' => 'populate log_search' ),
+                               __FUNCTION__,
+                               'IGNORE'
+                       )
+               ) {
+                       $this->output( "log_search population complete.\n" );
+                       return true;
+               } else {
+                       $this->output( "Could not insert log_search population row.\n" );
+                       return false;
+               }
+       }
 }
 
-migrate_log_params( $db );
+$maintClass = "PopulateLogSearch";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/populateLogUsertext.inc b/maintenance/populateLogUsertext.inc
deleted file mode 100644 (file)
index 9e74ce9..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * Makes the required database updates for the log_user_text column
- *
- * Run via update.php or directly through populateLogUsertext.php
- *
- * @file
- * @ingroup Maintenance
- */
-
-define( 'LOG_USERTEXT_BATCH_SIZE', 100 );
-
-function populate_logusertext( $db ) {
-       $start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
-       if( !$start ) {
-               echo "Nothing to do.\n";
-               return true;
-       }
-       $end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
-       
-       # Do remaining chunk
-       $end += LOG_USERTEXT_BATCH_SIZE - 1;
-       $blockStart = $start;
-       $blockEnd = $start + LOG_USERTEXT_BATCH_SIZE - 1;
-       while( $blockEnd <= $end ) {
-               echo "...doing log_id from $blockStart to $blockEnd\n";
-               $cond = "log_id BETWEEN $blockStart AND $blockEnd AND log_user = user_id";
-               $res = $db->select( array('logging','user'), 
-                       array('log_id','user_name'), $cond, __FUNCTION__ );
-               $batch = array();
-               $db->begin();
-               while( $row = $db->fetchObject( $res ) ) {
-                       $db->update( 'logging', array('log_user_text' => $row->user_name),
-                               array('log_id' => $row->log_id), __FUNCTION__ );
-               }
-               $db->commit();
-               $blockStart += LOG_USERTEXT_BATCH_SIZE;
-               $blockEnd += LOG_USERTEXT_BATCH_SIZE;
-               wfWaitForSlaves( 5 );
-       }
-       if( $db->insert(
-                       'updatelog',
-                       array( 'ul_key' => 'populate log_usertext' ),
-                       __FUNCTION__,
-                       'IGNORE'
-               )
-       ) {
-               wfOut( "log_usertext population complete.\n" );
-               return true;
-       } else {
-               wfOut( "Could not insert log_usertext population row.\n" );
-               return false;
-       }
-}
index c775aa5..359ee95 100644 (file)
@@ -5,13 +5,78 @@
  * schema change. All remaining page_restriction column values are moved
  * to the new table.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once 'commandLine.inc';
-require_once 'populateLogUsertext.inc';
-       
-$db =& wfGetDB( DB_MASTER );
+require_once( "Maintenance.php" );
+
+class PopulateLogUsertext extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Populates the log_user_text";
+               $this->setBatchSize( 100 );
+       }
+
+       public function execute() {
+               $db = wfGetDB( DB_MASTER );
+               $start = $db->selectField( 'logging', 'MIN(log_id)', false, __METHOD__ );
+               if( !$start ) {
+                       $this->output( "Nothing to do.\n" );
+                       return true;
+               }
+               $end = $db->selectField( 'logging', 'MAX(log_id)', false, __METHOD__ );
+
+               # Do remaining chunk
+               $end += $this->mBatchSize - 1;
+               $blockStart = $start;
+               $blockEnd = $start + $this->mBatchSize - 1;
+               while( $blockEnd <= $end ) {
+                       $this->output( "...doing log_id from $blockStart to $blockEnd\n" );
+                       $cond = "log_id BETWEEN $blockStart AND $blockEnd AND log_user = user_id";
+                       $res = $db->select( array('logging','user'), 
+                               array('log_id','user_name'), $cond, __METHOD__ );
+                       $batch = array();
+                       $db->begin();
+                       while( $row = $db->fetchObject( $res ) ) {
+                               $db->update( 'logging', array('log_user_text' => $row->user_name),
+                                       array('log_id' => $row->log_id), __METHOD__ );
+                       }
+                       $db->commit();
+                       $blockStart += $this->mBatchSize;
+                       $blockEnd += $this->mBatchSize;
+                       wfWaitForSlaves( 5 );
+               }
+               if( $db->insert(
+                               'updatelog',
+                               array( 'ul_key' => 'populate log_usertext' ),
+                               __METHOD__,
+                               'IGNORE'
+                       )
+               ) {
+                       $this->output( "log_usertext population complete.\n" );
+                       return true;
+               } else {
+                       $this->output( "Could not insert log_usertext population row.\n" );
+                       return false;
+               }
+       }
+}
+
+$maintClass = "PopulateLogUsertext";
+require_once( DO_MAINTENANCE );
 
-populate_logusertext( $db );
diff --git a/maintenance/populateParentId.inc b/maintenance/populateParentId.inc
deleted file mode 100644 (file)
index 7b1ae3e..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-define( 'BATCH_SIZE', 200 );
-
-function populate_rev_parent_id( $db ) {
-       wfOut( "Populating rev_parent_id column\n" );
-       $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ );
-       $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ );
-       if( is_null( $start ) || is_null( $end ) ){
-               wfOut( "...revision table seems to be empty.\n" );
-               $db->insert( 'updatelog',
-                       array( 'ul_key' => 'populate rev_parent_id' ),
-                       __FUNCTION__,
-                       'IGNORE' );
-               return;
-       }
-       # Do remaining chunk
-       $end += BATCH_SIZE - 1;
-       $blockStart = intval( $start );
-       $blockEnd = intval( $start ) + BATCH_SIZE - 1;
-       $count = 0;
-       $changed = 0;
-       while( $blockEnd <= $end ) {
-               wfOut( "...doing rev_id from $blockStart to $blockEnd\n" );
-               $cond = "rev_id BETWEEN $blockStart AND $blockEnd";
-               $res = $db->select( 'revision', 
-                       array('rev_id','rev_page','rev_timestamp','rev_parent_id'), 
-                       $cond, __FUNCTION__ );
-               # Go through and update rev_parent_id from these rows.
-               # Assume that the previous revision of the title was
-               # the original previous revision of the title when the
-               # edit was made...
-               foreach( $res as $row ) {
-                       # First, check rows with the same timestamp other than this one
-                       # with a smaller rev ID. The highest ID "wins". This avoids loops
-                       # as timestamp can only decrease and never loops with IDs (from parent to parent)
-                       $previousID = $db->selectField( 'revision', 'rev_id', 
-                               array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $row->rev_timestamp,
-                                       "rev_id < " . intval( $row->rev_id ) ), 
-                               __FUNCTION__,
-                               array( 'ORDER BY' => 'rev_id DESC' ) );
-                       # If there are none, check the the highest ID with a lower timestamp
-                       if( !$previousID ) {
-                               # Get the highest older timestamp
-                               $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp', 
-                                       array( 'rev_page' => $row->rev_page, "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp ) ), 
-                                       __FUNCTION__,
-                                       array( 'ORDER BY' => 'rev_timestamp DESC' ) );
-                               # If there is one, let the highest rev ID win
-                               if( $lastTimestamp ) {
-                                       $previousID = $db->selectField( 'revision', 'rev_id', 
-                                               array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $lastTimestamp ), 
-                                               __FUNCTION__,
-                                               array( 'ORDER BY' => 'rev_id DESC' ) );
-                               }
-                       }
-                       $previousID = intval($previousID);
-                       if( $previousID != $row->rev_parent_id )
-                               $changed++;
-                       # Update the row...
-                       $db->update( 'revision',
-                               array( 'rev_parent_id' => $previousID ),
-                               array( 'rev_id' => $row->rev_id ),
-                               __FUNCTION__ );
-                       $count++;
-               }
-               $blockStart += BATCH_SIZE - 1;
-               $blockEnd += BATCH_SIZE - 1;
-               wfWaitForSlaves( 5 );
-       }
-       $logged = $db->insert( 'updatelog',
-               array( 'ul_key' => 'populate rev_parent_id' ),
-               __FUNCTION__,
-               'IGNORE' );
-       if( $logged ) {
-               wfOut( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" );
-               return true;
-       } else {
-               wfOut( "Could not insert rev_parent_id population row.\n" );
-               return false;
-       }
-}
-
index 0173003..854f2e6 100644 (file)
 <?php
-
 /*
  * Makes the required database updates for rev_parent_id
  * to be of any use. It can be used for some simple tracking
  * and to find new page edits by users.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
  */
 
-require_once 'commandLine.inc';
-require_once 'populateParentId.inc';
-       
-$db =& wfGetDB( DB_MASTER );
-if ( !$db->tableExists( 'revision' ) ) {
-       echo "revision table does not exist\n";
-       exit( 1 );
+require_once( "Maintenance.php" );
+
+class PopulateParentId extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Populates rev_parent_id";
+               $this->setBatchSize( 200 );
+       }
+
+       public function execute() {
+               $db = wfGetDB( DB_MASTER );
+               if ( !$db->tableExists( 'revision' ) ) {
+                       $this->error( "revision table does not exist\n", true );
+               }
+               $this->output( "Populating rev_parent_id column\n" );
+               $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ );
+               $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ );
+               if( is_null( $start ) || is_null( $end ) ){
+                       $this->output( "...revision table seems to be empty.\n" );
+                       $db->insert( 'updatelog',
+                               array( 'ul_key' => 'populate rev_parent_id' ),
+                               __METHOD__,
+                               'IGNORE' );
+                       return;
+               }
+               # Do remaining chunk
+               $end += $this->mBatchSize - 1;
+               $blockStart = intval( $start );
+               $blockEnd = intval( $start ) + $this->mBatchSize - 1;
+               $count = 0;
+               $changed = 0;
+               while( $blockEnd <= $end ) {
+                       $this->output( "...doing rev_id from $blockStart to $blockEnd\n" );
+                       $cond = "rev_id BETWEEN $blockStart AND $blockEnd";
+                       $res = $db->select( 'revision', 
+                               array('rev_id','rev_page','rev_timestamp','rev_parent_id'), 
+                               $cond, __METHOD__ );
+                       # Go through and update rev_parent_id from these rows.
+                       # Assume that the previous revision of the title was
+                       # the original previous revision of the title when the
+                       # edit was made...
+                       foreach( $res as $row ) {
+                               # First, check rows with the same timestamp other than this one
+                               # with a smaller rev ID. The highest ID "wins". This avoids loops
+                               # as timestamp can only decrease and never loops with IDs (from parent to parent)
+                               $previousID = $db->selectField( 'revision', 'rev_id', 
+                                       array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $row->rev_timestamp,
+                                               "rev_id < " . intval( $row->rev_id ) ), 
+                                       __METHOD__,
+                                       array( 'ORDER BY' => 'rev_id DESC' ) );
+                               # If there are none, check the the highest ID with a lower timestamp
+                               if( !$previousID ) {
+                                       # Get the highest older timestamp
+                                       $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp', 
+                                               array( 'rev_page' => $row->rev_page, "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp ) ), 
+                                               __METHOD__,
+                                               array( 'ORDER BY' => 'rev_timestamp DESC' ) );
+                                       # If there is one, let the highest rev ID win
+                                       if( $lastTimestamp ) {
+                                               $previousID = $db->selectField( 'revision', 'rev_id', 
+                                                       array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $lastTimestamp ), 
+                                                       __METHOD__,
+                                                       array( 'ORDER BY' => 'rev_id DESC' ) );
+                                       }
+                               }
+                               $previousID = intval($previousID);
+                               if( $previousID != $row->rev_parent_id )
+                                       $changed++;
+                               # Update the row...
+                               $db->update( 'revision',
+                                       array( 'rev_parent_id' => $previousID ),
+                                       array( 'rev_id' => $row->rev_id ),
+                                       __METHOD__ );
+                               $count++;
+                       }
+                       $blockStart += $this->mBatchSize - 1;
+                       $blockEnd += $this->mBatchSize - 1;
+                       wfWaitForSlaves( 5 );
+               }
+               $logged = $db->insert( 'updatelog',
+                       array( 'ul_key' => 'populate rev_parent_id' ),
+                       __METHOD__,
+                       'IGNORE' );
+               if( $logged ) {
+                       $this->output( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" );
+                       return true;
+               } else {
+                       $this->output( "Could not insert rev_parent_id population row.\n" );
+                       return false;
+               }
+       }
 }
 
-populate_rev_parent_id( $db );
+$maintClass = "PopulateParentId";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/protect.php b/maintenance/protect.php
new file mode 100644 (file)
index 0000000..d929211
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
+ */
+
+require_once( "Maintenance.php" );
+
+class Protect extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Protect or unprotect an article from the command line.";
+               $this->addOption( 'unprotect', 'Removes protection' );
+               $this->addOption( 'semiprotect', 'Adds semi-protection' );
+               $this->addOption( 'u', 'Username to protect with', false, true );
+               $this->addOption( 'r', 'Reason for un/protection', false, true );
+       }
+
+       public function execute() {
+               global $wgUser, $wgTitle, $wgArticle;
+
+               $userName = $this->getOption( 'u', 'Maintenance script' );
+               $reason = $this->getOption( 'r', '' );
+
+               $protection = "sysop";
+               if ( $this->hasOption('semiprotect') ) {
+                       $protection = "autoconfirmed";
+               } elseif ( $this->hasOption('unprotect') ) {
+                       $protection = "";
+               }
+
+               $wgUser = User::newFromName( $userName );
+               $restrictions = array( 'edit' => $protection, 'move' => $protection );
+
+               $wgTitle = Title::newFromText( $args[0] );
+               if ( !$wgTitle ) {
+                       $this->error( "Invalid title\n", true );
+               }
+
+               $wgArticle = new Article( $wgTitle );
+
+               # un/protect the article
+               $this->output( "Updating protection status... " );
+               $success = $wgArticle->updateRestrictions($restrictions, $reason);
+               if ( $success ) {
+                       $this->output( "done\n" );
+               } else {
+                       $this->output( "failed\n" );
+               }
+       }
+}
+
+$maintClass = "Protect";
+require_once( DO_MAINTENANCE );
index ab8ff9f..a267171 100644 (file)
@@ -2,38 +2,62 @@
 /**
  * Send purge requests for listed pages to squid
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( "commandLine.inc" );
+require_once( "Maintenance.php" );
+
+class PurgeList extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Send purge requests for listed pages to squid";
+       }
 
-$stdin = fopen( "php://stdin", "rt" );
-$urls = array();
+       public function execute() {
+               $stdin = $this->getStdin();
+               $urls = array();
 
-while( !feof( $stdin ) ) {
-       $page = trim( fgets( $stdin ) );
-       if ( substr( $page, 0, 7 ) == 'http://' ) {
-               $urls[] = $page;
-       } elseif( $page !== '' ) {
-               $title = Title::newFromText( $page );
-               if( $title ) {
-                       $url = $title->getFullUrl();
-                       echo "$url\n";
-                       $urls[] = $url;
-                       if( isset( $options['purge'] ) ) {
-                               $title->invalidateCache();
+               while( !feof( $stdin ) ) {
+                       $page = trim( fgets( $stdin ) );
+                       if ( substr( $page, 0, 7 ) == 'http://' ) {
+                               $urls[] = $page;
+                       } elseif( $page !== '' ) {
+                               $title = Title::newFromText( $page );
+                               if( $title ) {
+                                       $url = $title->getFullUrl();
+                                       $this->output( "$url\n" );
+                                       $urls[] = $url;
+                                       if( isset( $options['purge'] ) ) {
+                                               $title->invalidateCache();
+                                       }
+                               } else {
+                                       $this->output( "(Invalid title '$page')\n" );
+                               }
                        }
-               } else {
-                       echo "(Invalid title '$page')\n";
                }
-       }
-}
-
-echo "Purging " . count( $urls ) . " urls...\n";
-$u = new SquidUpdate( $urls );
-$u->doUpdate();
 
-echo "Done!\n";
+               $this->output( "Purging " . count( $urls ) . " urls...\n" );
+               $u = new SquidUpdate( $urls );
+               $u->doUpdate();
 
+               $this->output( "Done!\n" );
+       }
+}
 
+$maintClass = "PurgeList";
+require_once( DO_MAINTENANCE );
index 4a4be48..9e078b8 100644 (file)
@@ -1,29 +1,39 @@
 <?php
-
 /**
  * Purge old text records from the database
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-$options = array( 'purge', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'purgeOldText.inc' );
-
-echo( "Purge Old Text\n\n" );
-
-if( @$options['help'] ) {
-       ShowUsage();
-} else {
-       PurgeRedundantText( @$options['purge'] );
-}
+require_once( "Maintenance.php" );
 
-function ShowUsage() {
-       echo( "Prunes unused text records from the database.\n\n" );
-       echo( "Usage: php purgeOldText.php [--purge]\n\n" );
-       echo( "purge : Performs the deletion\n" );
-       echo( " help : Show this usage information\n" );
+class PurgeOldText extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Purge old text records from the database";
+               $this->addOption( 'purge', 'Performs the deletion' );
+       }
+       
+       public function execute() {
+               $this->purgeRedundantText( $this->hasOption('purge') );
+       }
 }
 
+$maintClass = "PurgeOldText";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/reassignEdits.inc b/maintenance/reassignEdits.inc
deleted file mode 100644 (file)
index e68b4cf..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-
-/**
- * Support functions for the reassignEdits script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- * @licence GNU General Public Licence 2.0 or later
- */
-
-/**
- * Reassign edits from one user to another
- *
- * @param $from User to take edits from
- * @param $to User to assign edits to
- * @param $rc Update the recent changes table
- * @param $report Don't change things; just echo numbers
- * @return integer Number of entries changed, or that would be changed
- */
-function reassignEdits( &$from, &$to, $rc = false, $report = false ) {
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->immediateBegin();
-       $fname = 'reassignEdits';
-               
-       # Count things
-       out( "Checking current edits..." );
-       $res = $dbw->select( 'revision', 'COUNT(*) AS count', userConditions( $from, 'rev_user', 'rev_user_text' ), $fname );
-       $row = $dbw->fetchObject( $res );
-       $cur = $row->count;
-       out( "found {$cur}.\n" );
-       
-       out( "Checking deleted edits..." );
-       $res = $dbw->select( 'archive', 'COUNT(*) AS count', userConditions( $from, 'ar_user', 'ar_user_text' ), $fname );
-       $row = $dbw->fetchObject( $res );
-       $del = $row->count;
-       out( "found {$del}.\n" );
-       
-       # Don't count recent changes if we're not supposed to
-       if( $rc ) {
-               out( "Checking recent changes..." );
-               $res = $dbw->select( 'recentchanges', 'COUNT(*) AS count', userConditions( $from, 'rc_user', 'rc_user_text' ), $fname );
-               $row = $dbw->fetchObject( $res );
-               $rec = $row->count;
-               out( "found {$rec}.\n" );
-       } else {
-               $rec = 0;
-       }
-       
-       $total = $cur + $del + $rec;
-       out( "\nTotal entries to change: {$total}\n" );
-       
-       if( !$report ) {
-               if( $total ) {
-                       # Reassign edits
-                       out( "\nReassigning current edits..." );
-                       $res = $dbw->update( 'revision', userSpecification( $to, 'rev_user', 'rev_user_text' ), userConditions( $from, 'rev_user', 'rev_user_text' ), $fname );
-                       out( "done.\nReassigning deleted edits..." );
-                       $res = $dbw->update( 'archive', userSpecification( $to, 'ar_user', 'ar_user_text' ), userConditions( $from, 'ar_user', 'ar_user_text' ), $fname );
-                       out( "done.\n" );
-                       # Update recent changes if required
-                       if( $rc ) {
-                               out( "Updating recent changes..." );
-                               $res = $dbw->update( 'recentchanges', userSpecification( $to, 'rc_user', 'rc_user_text' ), userConditions( $from, 'rc_user', 'rc_user_text' ), $fname );
-                               out( "done.\n" );
-                       }
-               }       
-       }
-       
-       $dbw->immediateCommit();
-       return (int)$total;     
-}
-
-/**
- * Return the most efficient set of user conditions
- * i.e. a user => id mapping, or a user_text => text mapping
- *
- * @param $user User for the condition
- * @param $idfield Field name containing the identifier
- * @param $utfield Field name containing the user text
- * @return array
- */
-function userConditions( &$user, $idfield, $utfield ) {
-       return $user->getId() ? array( $idfield => $user->getId() ) : array( $utfield => $user->getName() );
-}
-
-/**
- * Return user specifications
- * i.e. user => id, user_text => text
- *
- * @param $user User for the spec
- * @param $idfield Field name containing the identifier
- * @param $utfield Field name containing the user text
- * @return array
- */
-function userSpecification( &$user, $idfield, $utfield ) {
-       return array( $idfield => $user->getId(), $utfield => $user->getName() );
-}
-
-/**
- * Echo output if $wgSilent is off
- *
- * @param $output Output to echo
- * @return bool True if the output was echoed
- */
-function out( $output ) {
-       global $wgSilent;
-       if( !$wgSilent ) {
-               echo( $output );
-               return true;
-       } else {
-               return false;
-       }
-}
-
-/**
- * Mutator for $wgSilent
- *
- * @param $silent Switch on $wgSilent
- */
-function silent( $silent = true ) {
-       global $wgSilent;
-       $wgSilent = $silent;
-}
-
-/**
- * Initialise the user object
- *
- * @param $username Username or IP address
- * @return User
- */
-function initialiseUser( $username ) {
-       if( User::isIP( $username ) ) {
-               $user = new User();
-               $user->setId( 0 );
-               $user->setName( $username );
-       } else {
-               $user = User::newFromName( $username );
-       }
-       $user->load();
-       return $user;
-}
-
index 5825644..15fef13 100644 (file)
 <?php
-
 /**
  * Reassign edits from a user or IP address to another user
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  * @licence GNU General Public Licence 2.0 or later
  */
 
-$options = array( 'force', 'norc', 'quiet', 'report' );
-require_once( 'commandLine.inc' );
-require_once( 'reassignEdits.inc' );
-
-# Set silent mode; --report overrides --quiet
-if( !@$options['report'] && @$options['quiet'] )
-       setSilent();
-       
-out( "Reassign Edits\n\n" );
-
-if( @$args[0] && @$args[1] ) {
-
-       # Set up the users involved
-       $from =& initialiseUser( $args[0] );
-       $to   =& initialiseUser( $args[1] );
-       
-       # If the target doesn't exist, and --force is not set, stop here
-       if( $to->getId() || @$options['force'] ) {
-               # Reassign the edits
-               $report = @$options['report'];
-               $count = reassignEdits( $from, $to, !@$options['norc'], $report );
-               # If reporting, and there were items, advise the user to run without --report   
-               if( $report )
-                       out( "Run the script again without --report to update.\n" );
-       } else {
-               $ton = $to->getName();
-               echo( "User '{$ton}' not found.\n" );
+require_once( "Maintenance.php" );
+
+class ReassignEdits extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Reassign edits from one user to another";
+               $this->addOption( "force", "Reassign even if the target user doesn't exist" );
+               $this->addOption( "norc", "Don't update the recent changes table" );
+               $this->addOption( "report", "Print out details of what would be changed, but don't update it" );
+               $this->addArgs( array( 'from', 'to' ) );
        }
        
-} else {
-       ShowUsage();
-}
+       public function execute() {
+               if( $this->hasArg(0) && $this->hasArg(1) ) {
+                       # Set up the users involved
+                       $from =& $this->initialiseUser( $this->getArg(0) );
+                       $to   =& $this->initialiseUser( $this->getArg(1) );
+       
+                       # If the target doesn't exist, and --force is not set, stop here
+                       if( $to->getId() || $this->hasOption('force') ) {
+                               # Reassign the edits
+                               $report = $this->hasOption('report');
+                               $count = $this->doReassignEdits( $from, $to, !$this->hasOption('norc'), $report );
+                               # If reporting, and there were items, advise the user to run without --report   
+                               if( $report )
+                                       $this->output( "Run the script again without --report to update.\n" );
+                       } else {
+                               $ton = $to->getName();
+                               $this->error( "User '{$ton}' not found.\n" );
+                       }
+               }
+       }
+
+       /**
+        * Reassign edits from one user to another
+        *
+        * @param $from User to take edits from
+        * @param $to User to assign edits to
+        * @param $rc Update the recent changes table
+        * @param $report Don't change things; just echo numbers
+        * @return integer Number of entries changed, or that would be changed
+        */
+       private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->immediateBegin();
+
+               # Count things
+               $this->output( "Checking current edits..." );
+               $res = $dbw->select( 'revision', 'COUNT(*) AS count', $this->userConditions( $from, 'rev_user', 'rev_user_text' ), __METHOD__ );
+               $row = $dbw->fetchObject( $res );
+               $cur = $row->count;
+               $this->output( "found {$cur}.\n" );
+
+               $this->output( "Checking deleted edits..." );
+               $res = $dbw->select( 'archive', 'COUNT(*) AS count', $this->userConditions( $from, 'ar_user', 'ar_user_text' ), __METHOD__ );
+               $row = $dbw->fetchObject( $res );
+               $del = $row->count;
+               $this->output( "found {$del}.\n" );
+
+               # Don't count recent changes if we're not supposed to
+               if( $rc ) {
+                       $this->output( "Checking recent changes..." );
+                       $res = $dbw->select( 'recentchanges', 'COUNT(*) AS count', $this->userConditions( $from, 'rc_user', 'rc_user_text' ), __METHOD__ );
+                       $row = $dbw->fetchObject( $res );
+                       $rec = $row->count;
+                       $this->output( "found {$rec}.\n" );
+               } else {
+                       $rec = 0;
+               }
+       
+               $total = $cur + $del + $rec;
+               $this->output( "\nTotal entries to change: {$total}\n" );
+       
+               if( !$report ) {
+                       if( $total ) {
+                               # Reassign edits
+                               $this->output( "\nReassigning current edits..." );
+                               $res = $dbw->update( 'revision', userSpecification( $to, 'rev_user', 'rev_user_text' ), $this->userConditions( $from, 'rev_user', 'rev_user_text' ), __METHOD__ );
+                               $this->output( "done.\nReassigning deleted edits..." );
+                               $res = $dbw->update( 'archive', userSpecification( $to, 'ar_user', 'ar_user_text' ), $this->userConditions( $from, 'ar_user', 'ar_user_text' ), __METHOD__ );
+                               $this->output( "done.\n" );
+                               # Update recent changes if required
+                               if( $rc ) {
+                                       $this->output( "Updating recent changes..." );
+                                       $res = $dbw->update( 'recentchanges', $this->userSpecification( $to, 'rc_user', 'rc_user_text' ), $this->userConditions( $from, 'rc_user', 'rc_user_text' ), __METHOD__ );
+                                       $this->output( "done.\n" );
+                               }
+                       }       
+               }
+       
+               $dbw->immediateCommit();
+               return (int)$total;     
+       }
+       
+       /**
+        * Return the most efficient set of user conditions
+        * i.e. a user => id mapping, or a user_text => text mapping
+        *
+        * @param $user User for the condition
+        * @param $idfield Field name containing the identifier
+        * @param $utfield Field name containing the user text
+        * @return array
+        */
+       private function userConditions( &$user, $idfield, $utfield ) {
+               return $user->getId() ? array( $idfield => $user->getId() ) : array( $utfield => $user->getName() );
+       }
+       
+       /**
+        * Return user specifications
+        * i.e. user => id, user_text => text
+        *
+        * @param $user User for the spec
+        * @param $idfield Field name containing the identifier
+        * @param $utfield Field name containing the user text
+        * @return array
+        */
+       private function userSpecification( &$user, $idfield, $utfield ) {
+               return array( $idfield => $user->getId(), $utfield => $user->getName() );
+       }
+       
+       /**
+        * Initialise the user object
+        *
+        * @param $username Username or IP address
+        * @return User
+        */
+       private function initialiseUser( $username ) {
+               if( User::isIP( $username ) ) {
+                       $user = new User();
+                       $user->setId( 0 );
+                       $user->setName( $username );
+               } else {
+                       $user = User::newFromName( $username );
+               }
+               $user->load();
+               return $user;
+       }
+
 
-/** Show script usage information */
-function ShowUsage() {
-       echo( "Reassign edits from one user to another.\n\n" );
-       echo( "Usage: php reassignEdits.php [--force|--quiet|--norc|--report] <from> <to>\n\n" );
-       echo( "    <from> : Name of the user to assign edits from\n" );
-       echo( "      <to> : Name of the user to assign edits to\n" );
-       echo( "   --force : Reassign even if the target user doesn't exist\n" );
-       echo( "   --quiet : Don't print status information (except for errors)\n" );
-       echo( "    --norc : Don't update the recent changes table\n" );
-       echo( "  --report : Print out details of what would be changed, but don't update it\n\n" );
 }
 
+$maintClass = "ReassignEdits";
+require_once( DO_MAINTENANCE );
+
index 8c01b90..0b48f9a 100644 (file)
 /**
  * Build file cache for content pages
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-/** */
-require_once( "commandLine.inc" );
-if( !$wgUseFileCache ) {
-       echo "Nothing to do -- \$wgUseFileCache is disabled.\n";
-       exit(0);
-}
-$wgDisableCounters = false; // no real hits here
+require_once( "Maintenance.php" );
 
-$start = isset($args[0]) ? intval($args[0]) : 0;
-$overwrite = isset( $args[1] ) && $args[1] === 'overwrite';
-echo "Building content page file cache from page {$start}!\n";
-echo "Format: <start> [overwrite]\n";
+class RebuildFileCache extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Build file cache for content pages";
+               $this->addArgs( array( 'start', 'overwrite' ) );
+               $this->setBatchSize( 100 );
+       }
 
-$dbr = wfGetDB( DB_SLAVE );
-$start = $start > 0 ? $start : $dbr->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ );
-$end = $dbr->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ );
-if( !$start ) {
-       die("Nothing to do.\n");
-}
+       public function execute() {
+               global $wgUseFileCache, $wgDisableCounters, $wgTitle, $wgArticle, $wgOut;
+               if( !$wgUseFileCache ) {
+                       $this->error( "Nothing to do -- \$wgUseFileCache is disabled.\n", true );
+               }
+               $wgDisableCounters = false;
+               $start = intval( $this->getArg( 0, 0 ) );
+               $overwrite = $this->hasArg(1) && $this->getArg(1) === 'overwrite';
+               $this->output( "Building content page file cache from page {$start}!\n" );
 
-$_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
-OutputPage::setEncodings(); # Not really used yet
+               $dbr = wfGetDB( DB_SLAVE );
+               $start = $start > 0 ? $start : $dbr->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ );
+               $end = $dbr->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ );
+               if( !$start ) {
+                       $this->error( "Nothing to do.\n", true );
+               }
 
-$BATCH_SIZE = 100;
-# Do remaining chunk
-$end += $BATCH_SIZE - 1;
-$blockStart = $start;
-$blockEnd = $start + $BATCH_SIZE - 1;
+               $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
+               OutputPage::setEncodings(); # Not really used yet
 
-$dbw = wfGetDB( DB_MASTER );
-// Go through each page and save the output
-while( $blockEnd <= $end ) {
-       // Get the pages
-       $res = $dbr->select( 'page', array('page_namespace','page_title','page_id'),
-               array('page_namespace' => $wgContentNamespaces,
-                       "page_id BETWEEN $blockStart AND $blockEnd" ),
-               array('ORDER BY' => 'page_id ASC','USE INDEX' => 'PRIMARY')
-       );
-       while( $row = $dbr->fetchObject( $res ) ) {
-               $rebuilt = false;
-               $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
-               if( null == $wgTitle ) {
-                       echo "Page {$row->page_id} bad title\n";
-                       continue; // broken title?
-               }
-               $wgArticle = new Article( $wgTitle );
-               // If the article is cacheable, then load it
-               if( $wgArticle->isFileCacheable() ) {
-                       $cache = new HTMLFileCache( $wgTitle );
-                       if( $cache->isFileCacheGood() ) {
-                               if( $overwrite ) {
-                                       $rebuilt = true;
+               # Do remaining chunk
+               $end += $this->mBatchSize - 1;
+               $blockStart = $start;
+               $blockEnd = $start + $this->mBatchSize - 1;
+       
+               $dbw = wfGetDB( DB_MASTER );
+               // Go through each page and save the output
+               while( $blockEnd <= $end ) {
+                       // Get the pages
+                       $res = $dbr->select( 'page', array('page_namespace','page_title','page_id'),
+                               array('page_namespace' => $wgContentNamespaces,
+                                       "page_id BETWEEN $blockStart AND $blockEnd" ),
+                               array('ORDER BY' => 'page_id ASC','USE INDEX' => 'PRIMARY')
+                       );
+                       while( $row = $dbr->fetchObject( $res ) ) {
+                               $rebuilt = false;
+                               $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
+                               if( null == $wgTitle ) {
+                                       $this->output( "Page {$row->page_id} bad title\n" );
+                                       continue; // broken title?
+                               }
+                               $wgArticle = new Article( $wgTitle );
+                               // If the article is cacheable, then load it
+                               if( $wgArticle->isFileCacheable() ) {
+                                       $cache = new HTMLFileCache( $wgTitle );
+                                       if( $cache->isFileCacheGood() ) {
+                                               if( $overwrite ) {
+                                                       $rebuilt = true;
+                                               } else {
+                                                       $this->output( "Page {$row->page_id} already cached\n" );
+                                                       continue; // done already!
+                                               }
+                                       }
+                                       ob_start( array(&$cache, 'saveToFileCache' ) ); // save on ob_end_clean()
+                                       $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache
+                                       $wgArticle->view();
+                                       @$wgOut->output(); // header notices
+                                       $wgUseFileCache = true;
+                                       ob_end_clean(); // clear buffer
+                                       $wgOut = new OutputPage(); // empty out any output page garbage
+                                       if( $rebuilt )
+                                               $this->output( "Re-cached page {$row->page_id}\n" );
+                                       else
+                                               $this->output( "Cached page {$row->page_id}\n" );
                                } else {
-                                       echo "Page {$row->page_id} already cached\n";
-                                       continue; // done already!
+                                       $this->output( "Page {$row->page_id} not cacheable\n" );
                                }
+                               $dbw->commit(); // commit any changes
                        }
-                       ob_start( array(&$cache, 'saveToFileCache' ) ); // save on ob_end_clean()
-                       $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache
-                       $wgArticle->view();
-                       @$wgOut->output(); // header notices
-                       $wgUseFileCache = true;
-                       ob_end_clean(); // clear buffer
-                       $wgOut = new OutputPage(); // empty out any output page garbage
-                       if( $rebuilt )
-                               echo "Re-cached page {$row->page_id}\n";
-                       else
-                               echo "Cached page {$row->page_id}\n";
-               } else {
-                       echo "Page {$row->page_id} not cacheable\n";
+                       $blockStart += $this->mBatchSize;
+                       $blockEnd += $this->mBatchSize;
+                       wfWaitForSlaves( 5 );
                }
-               $dbw->commit(); // commit any changes
+               $this->output( "Done!\n" );
+       
+               // Remove these to be safe
+               if( isset($wgTitle) )
+                       unset($wgTitle);
+               if( isset($wgArticle) )
+                       unset($wgArticle);
        }
-       $blockStart += $BATCH_SIZE;
-       $blockEnd += $BATCH_SIZE;
-       wfWaitForSlaves( 5 );
 }
-echo "Done!\n";
 
-// Remove these to be safe
-if( isset($wgTitle) )
-       unset($wgTitle);
-if( isset($wgArticle) )
-       unset($wgArticle);
+$maintClass = "RebuildFileCache";
+require_once( DO_MAINTENANCE );
index bc61eb1..632b9ea 100644 (file)
@@ -9,61 +9,83 @@
  *
  * Use --force to rebuild all files, even the ones that are not out of date.
  * Use --threads=N to fork more threads.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
  */
 
-require( dirname(__FILE__).'/commandLine.inc' );
-ini_set( 'memory_limit', '200M' );
+require_once( "Maintenance.php" );
 
-$force = isset( $options['force'] );
-$threads = intval( isset( $options['threads'] ) ? $options['threads'] : 1 );
+class RebuildLocalisationCache extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Rebuild the localisation cache";
+               $this->addOption( 'force', 'Rebuild all files, even ones not out of date' );
+               $this->addOption( 'threads', 'Fork more than one thread', false, true );
+       }
 
-$conf = $wgLocalisationCacheConf;
-$conf['manualRecache'] = false; // Allow fallbacks to create CDB files
-if ( $force ) {
-       $conf['forceRecache'] = true;
-}
-$lc = new LocalisationCache_BulkLoad( $conf );
+       public function execute() {
+               global $wgLocalisationCacheConf;
 
-$codes = array_keys( Language::getLanguageNames( true ) );
-sort( $codes );
+               ini_set( 'memory_limit', '200M' );
 
-// Initialise and split into chunks
-$numRebuilt = 0;
-$total = count($codes);
-$chunks = array_chunk( $codes, ceil(count($codes)/$threads) );
-$pids = array();
+               $force = $this->hasOption('force');
+               $threads = $this->getOption( 'threads', 1 );
 
-foreach ( $chunks as $codes ) {
-       // Do not fork for only one thread
-       $pid = ( $threads > 1 ) ? pcntl_fork() : -1;
+               $conf = $wgLocalisationCacheConf;
+               $conf['manualRecache'] = false; // Allow fallbacks to create CDB files
+               if ( $force ) {
+                       $conf['forceRecache'] = true;
+               }
+               $lc = new LocalisationCache_BulkLoad( $conf );
 
-       if ( $pid === 0 ) {
-               // Child
-               doRebuild( $codes, $numRebuilt, $lc, $force );
-               exit();
-       } elseif ($pid === -1) {
-               // Fork failed or one thread, do it serialized
-               doRebuild( $codes, $numRebuilt, $lc, $force );
-       } else {
-               // Main thread
-               $pids[] = $pid;
-       }
-}
+               $codes = array_keys( Language::getLanguageNames( true ) );
+               sort( $codes );
 
-// Wait for all children
-foreach ( $pids as $pid ) pcntl_waitpid($pid, $status);
+               // Initialise and split into chunks
+               $numRebuilt = 0;
+               $total = count($codes);
+               $chunks = array_chunk( $codes, ceil(count($codes)/$threads) );
+               $pids = array();
+               foreach ( $chunks as $codes ) {
+                       // Do not fork for only one thread
+                       $pid = ( $threads > 1 ) ? pcntl_fork() : -1;
 
-echo "$numRebuilt languages rebuilt out of $total.\n";
-if ( $numRebuilt == 0 ) {
-       echo "Use --force to rebuild the caches which are still fresh.\n";
-}
+                       if ( $pid === 0 ) {
+                               // Child
+                               doRebuild( $codes, $numRebuilt, $lc, $force );
+                               exit();
+                       } elseif ($pid === -1) {
+                               // Fork failed or one thread, do it serialized
+                               doRebuild( $codes, $numRebuilt, $lc, $force );
+                       } else {
+                               // Main thread
+                               $pids[] = $pid;
+                       }
+               }
+               // Wait for all children
+               foreach ( $pids as $pid ) pcntl_waitpid($pid, $status);
 
-function doRebuild( $codes, &$numRebuilt, $lc, $force ) {
-       foreach ( $codes as $code ) {
-               if ( $force || $lc->isExpired( $code ) ) {
-                       echo "Rebuilding $code...\n";
-                       $lc->recache( $code );
-                       $numRebuilt++;
+               $this->output( "$numRebuilt languages rebuilt out of $total\n" );
+               if ( $numRebuilt == 0 ) {
+                       $this->output( "Use --force to rebuild the caches which are still fresh.\n" );
                }
        }
 }
+
+$maintClass = "RebuildLocalisationCache";
+require_once( DO_MAINTENANCE );
index 536ebd3..4d743e6 100644 (file)
@@ -3,40 +3,54 @@
  * Rebuild link tracking tables from scratch.  This takes several
  * hours, depending on the database size and server configuration.
  *
- * @file
- * @todo document
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-/** */
-require_once( "commandLine.inc" );
-
-#require_once( "rebuildlinks.inc" );
-require_once( "refreshLinks.inc" );
-require_once( "rebuildtextindex.inc" );
-require_once( "rebuildrecentchanges.inc" );
-
-$dbclass = 'Database' . ucfirst( $wgDBtype ) ;
-$database = new $dbclass( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
-
-if ($wgDBtype == 'mysql') {
-       print "** Rebuilding fulltext search index (if you abort this will break searching; run this script again to fix):\n";
-       dropTextIndex( $database );
-       rebuildTextIndex( $database );
-       createTextIndex( $database );
+require_once( "Maintenance.php" );
+
+class RebuildAll extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Rebuild links, text index and recent changes";
+       }
+
+       public function execute() {
+               global $wgDBtype;
+               // Rebuild the text index
+               if ( $wgDBtype == 'mysql' ) {
+                       $this->output( "** Rebuilding fulltext search index (if you abort this will break searching; run this script again to fix):\n" );
+                       $rebuildText = $this->spawnChild( 'RebuildTextIndex', 'rebuildtextindex.php' );
+                       $rebuildText->execute();
+               }
+
+               // Rebuild RC
+               $this->output( "\n\n** Rebuilding recentchanges table:\n" );
+               $rebuildRC = $this->spawnChild( 'RebuildRecentchanges', 'rebuildrecentchanges.php' );
+               $rebuildRC->execute();
+
+               // Rebuild link tables
+               $this->output( "\n\n** Rebuilding links tables -- this can take a long time. It should be safe to abort via ctrl+C if you get bored.\n" );
+               $rebuildLinks = $this->spawnChild( 'RefreshLinks', 'refreshLinks.php' );
+               $rebuildLinks->execute();
+               
+               $this->output( "Done.\n" );
+       }
 }
 
-print "\n\n** Rebuilding recentchanges table:\n";
-rebuildRecentChangesTable();
-
-# Doesn't work anymore
-# rebuildLinkTables();
-
-# Use the slow incomplete one instead. It's designed to work in the background
-print "\n\n** Rebuilding links tables -- this can take a long time. It should be safe to abort via ctrl+C if you get bored.\n";
-refreshLinks( 1 );
-
-print "Done.\n";
-exit(0);
-
-
+$maintClass = "RebuildAll";
+require_once( DO_MAINTENANCE );
index b0adc87..2afbc3f 100644 (file)
@@ -1,22 +1,50 @@
 <?php
 /**
- * This script purges all language messages from memcached
- * @file
+ * This script purges all language messages from the cache
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-if( $wgLocalDatabases ) {
-       $databases = $wgLocalDatabases;
-} else {
-       $databases = array( $wgDBname );
-}
+class RebuildMessages extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Purge all language messages from the cache";
+       }
 
-foreach( $databases as $db ) {
-       echo "Deleting message cache for {$db}... ";
-       $messageMemc->delete( "{$db}:messages" );
-       if( $wgEnableSidebarCache )
-               $messageMemc->delete( "{$db}:sidebar" );
-       echo "Deleted\n";
+       public function execute() {
+               global $wgLocalDatabases, $wgDBname, $wgEnableSidebarCache, $messageMemc;
+               if( $wgLocalDatabases ) {
+                       $databases = $wgLocalDatabases;
+               } else {
+                       $databases = array( $wgDBname );
+               }
+       
+               foreach( $databases as $db ) {
+                       $this->output( "Deleting message cache for {$db}... " );
+                       $messageMemc->delete( "{$db}:messages" );
+                       if( $wgEnableSidebarCache )
+                               $messageMemc->delete( "{$db}:sidebar" );
+                       $this->output( "Deleted\n" );
+               }
+       }
 }
+
+$maintClass = "RebuildMessages";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/rebuildrecentchanges.inc b/maintenance/rebuildrecentchanges.inc
deleted file mode 100644 (file)
index d37915b..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-<?php
-/**
- * Rebuild recent changes table.
- *
- * @file
- * @todo document
- * @ingroup Maintenance
- */
-
-/** Public entry; more passes might come in! :) */
-function rebuildRecentChangesTable() {
-       rebuildRecentChangesTablePass1();
-       rebuildRecentChangesTablePass2();
-       rebuildRecentChangesTablePass3();
-       rebuildRecentChangesTablePass4();
-}
-
-/** */
-function rebuildRecentChangesTablePass1()
-{
-       $dbw = wfGetDB( DB_MASTER );
-
-       $dbw->delete( 'recentchanges', '*' );
-
-       print( "Loading from page and revision tables...\n" );
-
-       global $wgRCMaxAge;
-
-       print( '$wgRCMaxAge=' . $wgRCMaxAge );
-       $days = $wgRCMaxAge / 24 / 3600;
-       if ( intval($days) == $days ) {
-                       print( " (" . $days . " days)\n" );
-       } else {
-                       print( " (approx. " .  intval($days) . " days)\n" );
-       }
-
-       $cutoff = time() - $wgRCMaxAge;
-       $dbw->insertSelect( 'recentchanges', array( 'page', 'revision' ),
-               array(
-                       'rc_timestamp'  => 'rev_timestamp',
-                       'rc_cur_time'   => 'rev_timestamp',
-                       'rc_user'       => 'rev_user',
-                       'rc_user_text'  => 'rev_user_text',
-                       'rc_namespace'  => 'page_namespace',
-                       'rc_title'      => 'page_title',
-                       'rc_comment'    => 'rev_comment',
-                       'rc_minor'      => 'rev_minor_edit',
-                       'rc_bot'        => 0,
-                       'rc_new'        => 'page_is_new',
-                       'rc_cur_id'     => 'page_id',
-                       'rc_this_oldid' => 'rev_id',
-                       'rc_last_oldid' => 0, // is this ok?
-                       'rc_type'       => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ),
-                       'rc_deleted'    => 'rev_deleted'
-               ), array(
-                       'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
-                       'rev_page=page_id'
-               ), __METHOD__,
-               array(), // INSERT options
-               array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
-       );
-}
-
-function rebuildRecentChangesTablePass2()
-{
-       $dbw = wfGetDB( DB_MASTER );
-       list ($recentchanges, $revision) = $dbw->tableNamesN( 'recentchanges', 'revision' );
-
-       print( "Updating links and size differences...\n" );
-
-       # Fill in the rc_last_oldid field, which points to the previous edit
-       $sql = "SELECT rc_cur_id,rc_this_oldid,rc_timestamp FROM $recentchanges " .
-         "ORDER BY rc_cur_id,rc_timestamp";
-       $res = $dbw->query( $sql, DB_MASTER );
-
-       $lastCurId = 0;
-       $lastOldId = 0;
-       while ( $obj = $dbw->fetchObject( $res ) ) {
-               $new = 0;
-               if( $obj->rc_cur_id != $lastCurId ) {
-                       # Switch! Look up the previous last edit, if any
-                       $lastCurId = intval( $obj->rc_cur_id );
-                       $emit = $obj->rc_timestamp;
-                       $sql2 = "SELECT rev_id,rev_len FROM $revision " .
-                               "WHERE rev_page={$lastCurId} ".
-                               "AND rev_timestamp<'{$emit}' ORDER BY rev_timestamp DESC LIMIT 1";
-                       $res2 = $dbw->query( $sql2 );
-                       if( $row = $dbw->fetchObject( $res2 ) ) {
-                               $lastOldId = intval($row->rev_id);
-                               # Grab the last text size if available
-                               $lastSize = !is_null($row->rev_len) ? intval($row->rev_len) : 'NULL';
-                       } else {
-                               # No previous edit
-                               $lastOldId = 0;
-                               $lastSize = 'NULL';
-                               $new = 1; // probably true
-                       }
-                       $dbw->freeResult( $res2 );
-               }
-               if( $lastCurId == 0 ) {
-                       print "Uhhh, something wrong? No curid\n";
-               } else {
-                       # Grab the entry's text size
-                       $size = $dbw->selectField( 'revision', 'rev_len', array('rev_id' => $obj->rc_this_oldid ) );
-                       $size = !is_null($size) ? intval($size) : 'NULL';
-                       
-                       $sql3 = "UPDATE $recentchanges SET rc_last_oldid=$lastOldId,rc_new=$new,rc_type=$new," .
-                               "rc_old_len=$lastSize,rc_new_len=$size " .
-                               "WHERE rc_cur_id={$lastCurId} AND rc_this_oldid={$obj->rc_this_oldid}";
-                       $dbw->query( $sql3 );
-                       
-                       $lastOldId = intval( $obj->rc_this_oldid );
-                       $lastSize = $size;
-               }
-       }
-       $dbw->freeResult( $res );
-}
-
-function rebuildRecentChangesTablePass3()
-{
-       $dbw = wfGetDB( DB_MASTER );
-
-       print( "Loading from user, page, and logging tables...\n" );
-       
-       global $wgRCMaxAge, $wgLogTypes, $wgLogRestrictions;
-       // Some logs don't go in RC. This should check for that
-       $basicRCLogs = array_diff( $wgLogTypes, array_keys( $wgLogRestrictions ) );
-               
-       // Escape...blah blah
-       $selectLogs = array();
-       foreach( $basicRCLogs as $logtype ) {
-               $safetype = $dbw->strencode( $logtype );
-               $selectLogs[] = "'$safetype'";
-       }
-       
-       $cutoff = time() - $wgRCMaxAge;
-       list($logging, $page) = $dbw->tableNamesN( 'logging', 'page' );
-       $dbw->insertSelect( 'recentchanges', array( 'user', "$logging LEFT JOIN $page ON (log_namespace=page_namespace AND log_title=page_title)" ),
-               array(
-                       'rc_timestamp'  => 'log_timestamp',
-                       'rc_cur_time'   => 'log_timestamp',
-                       'rc_user'       => 'log_user',
-                       'rc_user_text'  => 'user_name',
-                       'rc_namespace'  => 'log_namespace',
-                       'rc_title'      => 'log_title',
-                       'rc_comment'    => 'log_comment',
-                       'rc_minor'      => 0,
-                       'rc_bot'        => 0,
-                       'rc_patrolled'  => 1,
-                       'rc_new'        => 0,
-                       'rc_this_oldid' => 0,
-                       'rc_last_oldid' => 0,
-                       'rc_type'       => RC_LOG,
-                       'rc_cur_id'     => 'COALESCE(page_id, 0)',
-                       'rc_log_type'   => 'log_type',
-                       'rc_log_action' => 'log_action',
-                       'rc_logid'      => 'log_id',
-                       'rc_params'     => 'log_params',
-                       'rc_deleted'    => 'log_deleted'
-               ), array(
-                       'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
-                       'log_user=user_id',
-                       'log_type IN(' . implode(',',$selectLogs) . ')'
-               ), __METHOD__,
-               array(), // INSERT options
-               array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
-       );
-}
-
-function rebuildRecentChangesTablePass4()
-{
-       global $wgGroupPermissions, $wgUseRCPatrol;
-                       
-       $dbw = wfGetDB( DB_MASTER );
-       
-       list($recentchanges,$usergroups,$user) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
-
-       $botgroups = $autopatrolgroups = array();
-       foreach( $wgGroupPermissions as $group => $rights ) {
-               if( isset( $rights['bot'] ) && $rights['bot'] == true ) {
-                       $botgroups[] = $dbw->addQuotes( $group );
-               }
-               if( $wgUseRCPatrol && isset( $rights['autopatrol'] ) && $rights['autopatrol'] == true ) {
-                       $autopatrolgroups[] = $dbw->addQuotes( $group );
-               }
-       }
-       # Flag our recent bot edits
-       if( !empty($botgroups) ) {
-               $botwhere = implode(',',$botgroups);
-               $botusers = array();
-
-               print( "Flagging bot account edits...\n" );
-
-               # Find all users that are bots
-               $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
-                       "WHERE ug_group IN($botwhere) AND user_id = ug_user";
-               $res = $dbw->query( $sql, DB_MASTER );
-
-               while( $obj = $dbw->fetchObject( $res ) ) {
-                       $botusers[] = $dbw->addQuotes( $obj->user_name );
-               }
-               # Fill in the rc_bot field
-               if( !empty($botusers) ) {
-                       $botwhere = implode(',',$botusers);
-                       $sql2 = "UPDATE $recentchanges SET rc_bot=1 " .
-                               "WHERE rc_user_text IN($botwhere)";
-                       $dbw->query( $sql2 );
-               }
-       }
-       global $wgMiserMode;
-       # Flag our recent autopatrolled edits
-       if( !$wgMiserMode && !empty($autopatrolgroups) ) {
-               $patrolwhere = implode(',',$autopatrolgroups);
-               $patrolusers = array();
-
-               print( "Flagging auto-patrolled edits...\n" );
-
-               # Find all users in RC with autopatrol rights
-               $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
-                       "WHERE ug_group IN($patrolwhere) AND user_id = ug_user";
-               $res = $dbw->query( $sql, DB_MASTER );
-
-               while( $obj = $dbw->fetchObject( $res ) ) {
-                       $patrolusers[] = $dbw->addQuotes( $obj->user_name );
-               }
-               
-               # Fill in the rc_patrolled field
-               if( !empty($patrolusers) ) {
-                       $patrolwhere = implode(',',$patrolusers);
-                       $sql2 = "UPDATE $recentchanges SET rc_patrolled=1 " .
-                               "WHERE rc_user_text IN($patrolwhere)";
-                       $dbw->query( $sql2 );
-               }
-       }
-       
-       $dbw->freeResult( $res );
-}
index 4231ff7..13e5705 100644 (file)
  * Rebuild link tracking tables from scratch.  This takes several
  * hours, depending on the database size and server configuration.
  *
- * @file
- * @todo document
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
+ * @todo Document
  */
 
-/** */
-require_once( "commandLine.inc" );
-require_once( "rebuildrecentchanges.inc" );
-$wgTitle = Title::newFromText( "Rebuild recent changes script" );
+require_once( "Maintenance.php" );
+
+class RebuildRecentchanges extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Rebuild recent changes";
+       }
+
+       public function execute() {
+               global $wgTitle;
+               $wgTitle = Title::newFromText( "Rebuild recent changes script" );
+               $this->rebuildRecentChangesTablePass1();
+               $this->rebuildRecentChangesTablePass2();
+               $this->rebuildRecentChangesTablePass3();
+               $this->rebuildRecentChangesTablePass4();
+               $this->output( "Done.\n" );
+       }
 
-$wgDBuser                      = $wgDBadminuser;
-$wgDBpassword          = $wgDBadminpassword;
+       /**
+        * Rebuild pass 1
+        * DOCUMENT ME!
+        */
+       function rebuildRecentChangesTablePass1()
+       {
+               $dbw = wfGetDB( DB_MASTER );
+       
+               $dbw->delete( 'recentchanges', '*' );
+       
+               $this->output( "Loading from page and revision tables...\n" );
+       
+               global $wgRCMaxAge;
+       
+               $this->output( '$wgRCMaxAge=' . $wgRCMaxAge );
+               $days = $wgRCMaxAge / 24 / 3600;
+               if ( intval($days) == $days ) {
+                               $this->output( " (" . $days . " days)\n" );
+               } else {
+                               $this->output( " (approx. " .  intval($days) . " days)\n" );
+               }
+       
+               $cutoff = time() - $wgRCMaxAge;
+               $dbw->insertSelect( 'recentchanges', array( 'page', 'revision' ),
+                       array(
+                               'rc_timestamp'  => 'rev_timestamp',
+                               'rc_cur_time'   => 'rev_timestamp',
+                               'rc_user'       => 'rev_user',
+                               'rc_user_text'  => 'rev_user_text',
+                               'rc_namespace'  => 'page_namespace',
+                               'rc_title'      => 'page_title',
+                               'rc_comment'    => 'rev_comment',
+                               'rc_minor'      => 'rev_minor_edit',
+                               'rc_bot'        => 0,
+                               'rc_new'        => 'page_is_new',
+                               'rc_cur_id'     => 'page_id',
+                               'rc_this_oldid' => 'rev_id',
+                               'rc_last_oldid' => 0, // is this ok?
+                               'rc_type'       => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ),
+                               'rc_deleted'    => 'rev_deleted'
+                       ), array(
+                               'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
+                               'rev_page=page_id'
+                       ), __METHOD__,
+                       array(), // INSERT options
+                       array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
+               );
+       }
 
-rebuildRecentChangesTable();
+       /**
+        * Rebuild pass 2
+        * DOCUMENT ME!
+        */
+       private function rebuildRecentChangesTablePass2() {
+               $dbw = wfGetDB( DB_MASTER );
+               list ($recentchanges, $revision) = $dbw->tableNamesN( 'recentchanges', 'revision' );
+       
+               $this->output( "Updating links and size differences...\n" );
+       
+               # Fill in the rc_last_oldid field, which points to the previous edit
+               $sql = "SELECT rc_cur_id,rc_this_oldid,rc_timestamp FROM $recentchanges " .
+                 "ORDER BY rc_cur_id,rc_timestamp";
+               $res = $dbw->query( $sql, DB_MASTER );
+       
+               $lastCurId = 0;
+               $lastOldId = 0;
+               while ( $obj = $dbw->fetchObject( $res ) ) {
+                       $new = 0;
+                       if( $obj->rc_cur_id != $lastCurId ) {
+                               # Switch! Look up the previous last edit, if any
+                               $lastCurId = intval( $obj->rc_cur_id );
+                               $emit = $obj->rc_timestamp;
+                               $sql2 = "SELECT rev_id,rev_len FROM $revision " .
+                                       "WHERE rev_page={$lastCurId} ".
+                                       "AND rev_timestamp<'{$emit}' ORDER BY rev_timestamp DESC LIMIT 1";
+                               $res2 = $dbw->query( $sql2 );
+                               if( $row = $dbw->fetchObject( $res2 ) ) {
+                                       $lastOldId = intval($row->rev_id);
+                                       # Grab the last text size if available
+                                       $lastSize = !is_null($row->rev_len) ? intval($row->rev_len) : 'NULL';
+                               } else {
+                                       # No previous edit
+                                       $lastOldId = 0;
+                                       $lastSize = 'NULL';
+                                       $new = 1; // probably true
+                               }
+                               $dbw->freeResult( $res2 );
+                       }
+                       if( $lastCurId == 0 ) {
+                               $this->output( "Uhhh, something wrong? No curid\n" );
+                       } else {
+                               # Grab the entry's text size
+                               $size = $dbw->selectField( 'revision', 'rev_len', array('rev_id' => $obj->rc_this_oldid ) );
+                               $size = !is_null($size) ? intval($size) : 'NULL';
+       
+                               $sql3 = "UPDATE $recentchanges SET rc_last_oldid=$lastOldId,rc_new=$new,rc_type=$new," .
+                                       "rc_old_len=$lastSize,rc_new_len=$size " .
+                                       "WHERE rc_cur_id={$lastCurId} AND rc_this_oldid={$obj->rc_this_oldid}";
+                               $dbw->query( $sql3 );
+       
+                               $lastOldId = intval( $obj->rc_this_oldid );
+                               $lastSize = $size;
+                       }
+               }
+               $dbw->freeResult( $res );
+       }
 
-print "Done.\n";
-exit(0);
+       /**
+        * Rebuild pass 3
+        * DOCUMENT ME!
+        */
+       private function rebuildRecentChangesTablePass3() {
+               $dbw = wfGetDB( DB_MASTER );
+       
+               $this->output( "Loading from user, page, and logging tables...\n" );
+       
+               global $wgRCMaxAge, $wgLogTypes, $wgLogRestrictions;
+               // Some logs don't go in RC. This should check for that
+               $basicRCLogs = array_diff( $wgLogTypes, array_keys( $wgLogRestrictions ) );
+       
+               // Escape...blah blah
+               $selectLogs = array();
+               foreach( $basicRCLogs as $logtype ) {
+                       $safetype = $dbw->strencode( $logtype );
+                       $selectLogs[] = "'$safetype'";
+               }
+       
+               $cutoff = time() - $wgRCMaxAge;
+               list($logging, $page) = $dbw->tableNamesN( 'logging', 'page' );
+               $dbw->insertSelect( 'recentchanges', array( 'user', "$logging LEFT JOIN $page ON (log_namespace=page_namespace AND log_title=page_title)" ),
+                       array(
+                               'rc_timestamp'  => 'log_timestamp',
+                               'rc_cur_time'   => 'log_timestamp',
+                               'rc_user'       => 'log_user',
+                               'rc_user_text'  => 'user_name',
+                               'rc_namespace'  => 'log_namespace',
+                               'rc_title'      => 'log_title',
+                               'rc_comment'    => 'log_comment',
+                               'rc_minor'      => 0,
+                               'rc_bot'        => 0,
+                               'rc_patrolled'  => 1,
+                               'rc_new'        => 0,
+                               'rc_this_oldid' => 0,
+                               'rc_last_oldid' => 0,
+                               'rc_type'       => RC_LOG,
+                               'rc_cur_id'     => 'COALESCE(page_id, 0)',
+                               'rc_log_type'   => 'log_type',
+                               'rc_log_action' => 'log_action',
+                               'rc_logid'      => 'log_id',
+                               'rc_params'     => 'log_params',
+                               'rc_deleted'    => 'log_deleted'
+                       ), array(
+                               'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
+                               'log_user=user_id',
+                               'log_type IN(' . implode(',',$selectLogs) . ')'
+                       ), __METHOD__,
+                       array(), // INSERT options
+                       array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
+               );
+       }
 
+       /**
+        * Rebuild pass 4
+        * DOCUMENT ME!
+        */
+       private function rebuildRecentChangesTablePass4() {
+               global $wgGroupPermissions, $wgUseRCPatrol;
+       
+               $dbw = wfGetDB( DB_MASTER );
+       
+               list($recentchanges,$usergroups,$user) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
+       
+               $botgroups = $autopatrolgroups = array();
+               foreach( $wgGroupPermissions as $group => $rights ) {
+                       if( isset( $rights['bot'] ) && $rights['bot'] == true ) {
+                               $botgroups[] = $dbw->addQuotes( $group );
+                       }
+                       if( $wgUseRCPatrol && isset( $rights['autopatrol'] ) && $rights['autopatrol'] == true ) {
+                               $autopatrolgroups[] = $dbw->addQuotes( $group );
+                       }
+               }
+               # Flag our recent bot edits
+               if( !empty($botgroups) ) {
+                       $botwhere = implode(',',$botgroups);
+                       $botusers = array();
+       
+                       $this->output( "Flagging bot account edits...\n" );
+       
+                       # Find all users that are bots
+                       $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
+                               "WHERE ug_group IN($botwhere) AND user_id = ug_user";
+                       $res = $dbw->query( $sql, DB_MASTER );
+       
+                       while( $obj = $dbw->fetchObject( $res ) ) {
+                               $botusers[] = $dbw->addQuotes( $obj->user_name );
+                       }
+                       # Fill in the rc_bot field
+                       if( !empty($botusers) ) {
+                               $botwhere = implode(',',$botusers);
+                               $sql2 = "UPDATE $recentchanges SET rc_bot=1 " .
+                                       "WHERE rc_user_text IN($botwhere)";
+                               $dbw->query( $sql2 );
+                       }
+               }
+               global $wgMiserMode;
+               # Flag our recent autopatrolled edits
+               if( !$wgMiserMode && !empty($autopatrolgroups) ) {
+                       $patrolwhere = implode(',',$autopatrolgroups);
+                       $patrolusers = array();
+       
+                       $this->output( "Flagging auto-patrolled edits...\n" );
+       
+                       # Find all users in RC with autopatrol rights
+                       $sql = "SELECT DISTINCT user_name FROM $usergroups, $user " .
+                               "WHERE ug_group IN($patrolwhere) AND user_id = ug_user";
+                       $res = $dbw->query( $sql, DB_MASTER );
+       
+                       while( $obj = $dbw->fetchObject( $res ) ) {
+                               $patrolusers[] = $dbw->addQuotes( $obj->user_name );
+                       }
+       
+                       # Fill in the rc_patrolled field
+                       if( !empty($patrolusers) ) {
+                               $patrolwhere = implode(',',$patrolusers);
+                               $sql2 = "UPDATE $recentchanges SET rc_patrolled=1 " .
+                                       "WHERE rc_user_text IN($patrolwhere)";
+                               $dbw->query( $sql2 );
+                       }
+               }
+       
+               $dbw->freeResult( $res );
+       }
+}
 
+$maintClass = "RebuildRecentchanges";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/rebuildtextindex.inc b/maintenance/rebuildtextindex.inc
deleted file mode 100644 (file)
index fc059f8..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-/**
- * Rebuild the fulltext search indexes. This may take a while
- * depending on the database size and server configuration.
- *
- * Rebuilding is faster if you drop the index and recreate it,
- * but that will prevent searches from working while it runs.
- *
- * @file
- * @todo document
- * @ingroup Maintenance
- */
-
-/** */
-define( "RTI_CHUNK_SIZE", 500 );
-
-function dropTextIndex( &$database )
-{
-       $searchindex = $database->tableName( 'searchindex' );
-       if ( $database->indexExists( "searchindex", "si_title" ) ) {
-               echo "Dropping index...\n";
-               $sql = "ALTER TABLE $searchindex DROP INDEX si_title, DROP INDEX si_text";
-               $database->query($sql, "dropTextIndex" );
-       }
-}
-
-function createTextIndex( &$database )
-{
-       $searchindex = $database->tableName( 'searchindex' );
-       echo "\nRebuild the index...\n";
-       $sql = "ALTER TABLE $searchindex ADD FULLTEXT si_title (si_title), " .
-         "ADD FULLTEXT si_text (si_text)";
-       $database->query($sql, "createTextIndex" );
-}
-
-function rebuildTextIndex( &$database )
-{
-       list ($page, $revision, $text, $searchindex) = $database->tableNamesN( 'page', 'revision', 'text', 'searchindex' );
-
-       $sql = "SELECT MAX(page_id) AS count FROM $page";
-       $res = $database->query($sql, "rebuildTextIndex" );
-       $s = $database->fetchObject($res);
-       $count = $s->count;
-       echo "Rebuilding index fields for {$count} pages...\n";
-       $n = 0;
-
-       while ( $n < $count ) {
-               echo $n . "\n";
-               $end = $n + RTI_CHUNK_SIZE - 1;
-               $sql = "SELECT page_id, page_namespace, page_title, old_flags, old_text
-                         FROM $page, $revision, $text
-                        WHERE page_id BETWEEN $n AND $end
-                          AND page_latest=rev_id
-                          AND rev_text_id=old_id";
-               $res = $database->query($sql, "rebuildTextIndex" );
-
-               while( $s = $database->fetchObject($res) ) {
-                       $revtext = Revision::getRevisionText( $s );
-                       $u = new SearchUpdate( $s->page_id, $s->page_title, $revtext );
-                       $u->doUpdate();
-               }
-               $database->freeResult( $res );
-               $n += RTI_CHUNK_SIZE;
-       }
-}
index b19f78b..a4d7356 100644 (file)
  * This is only for MySQL (see bug 9905).
  * Postgres is trigger-based and should never need rebuilding.
  *
- * @file
- * @todo document
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
+ * @todo document
  */
 
-/** */
-require_once( "commandLine.inc" );
-require_once( "rebuildtextindex.inc" );
+require_once( "Maintenance.php" );
 
-$database = wfGetDB( DB_MASTER );
-if( !$database instanceof DatabaseMysql ) {
-       print "This script is only for MySQL.\n";
-       exit(1);
-}
+class RebuildTextIndex extends Maintenance {
+
+       const RTI_CHUNK_SIZE = 500;
 
-$wgTitle = Title::newFromText( "Rebuild text index script" );
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Rebuild search index table from scratch";
+       }
 
-dropTextIndex( $database );
-rebuildTextIndex( $database );
-createTextIndex( $database );
+       public function execute() {
+               global $wgTitle;
+               
+               // Only do this for MySQL
+               $database = wfGetDB( DB_MASTER );
+               if( !$database instanceof DatabaseMysql ) {
+                       $this->error( "This script is only for MySQL.\n", true );
+               }
 
-print "Done.\n";
-exit(0);
+               $wgTitle = Title::newFromText( "Rebuild text index script" );
+       
+               $this->dropTextIndex( $database );
+               $this->doRebuildTextIndex( $database );
+               $this->createTextIndex( $database );
+       
+               $this->output( "Done.\n" );
+       }
+       
+       private function dropTextIndex( &$database ) {
+               $searchindex = $database->tableName( 'searchindex' );
+               if ( $database->indexExists( "searchindex", "si_title" ) ) {
+                       $this->output( "Dropping index...\n" );
+                       $sql = "ALTER TABLE $searchindex DROP INDEX si_title, DROP INDEX si_text";
+                       $database->query($sql, "dropTextIndex" );
+               }
+       }
 
+       private function createTextIndex( &$database ) {
+               $searchindex = $database->tableName( 'searchindex' );
+               $this->output( "\nRebuild the index...\n" );
+               $sql = "ALTER TABLE $searchindex ADD FULLTEXT si_title (si_title), " .
+                 "ADD FULLTEXT si_text (si_text)";
+               $database->query($sql, "createTextIndex" );
+       }
+       
+       private function doRebuildTextIndex( &$database ) {
+               list ($page, $revision, $text, $searchindex) = $database->tableNamesN( 'page', 'revision', 'text', 'searchindex' );
+
+               $sql = "SELECT MAX(page_id) AS count FROM $page";
+               $res = $database->query($sql, "rebuildTextIndex" );
+               $s = $database->fetchObject($res);
+               $count = $s->count;
+               $this->output( "Rebuilding index fields for {$count} pages...\n" );
+               $n = 0;
+       
+               while ( $n < $count ) {
+                       $this->output( $n . "\n" );
+                       $end = $n + self::RTI_CHUNK_SIZE - 1;
+                       $sql = "SELECT page_id, page_namespace, page_title, old_flags, old_text
+                                         FROM $page, $revision, $text
+                                        WHERE page_id BETWEEN $n AND $end
+                                          AND page_latest=rev_id
+                                          AND rev_text_id=old_id";
+                       $res = $database->query($sql, "rebuildTextIndex" );
+       
+                       while( $s = $database->fetchObject($res) ) {
+                               $revtext = Revision::getRevisionText( $s );
+                               $u = new SearchUpdate( $s->page_id, $s->page_title, $revtext );
+                               $u->doUpdate();
+                       }
+                       $database->freeResult( $res );
+                       $n += self::RTI_CHUNK_SIZE;
+               }
+       }
+}
 
+$maintClass = "RebuildTextIndex";
+require_once( DO_MAINTENANCE );
index 14f842b..f7756e3 100644 (file)
@@ -3,27 +3,52 @@
  * Quickie hack; patch-ss_images.sql uses variables which don't
  * replicate properly.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( "commandLine.inc" );
-
-$dbw = wfGetDB( DB_MASTER );
-
-// Load the current value from the master
-$count = $dbw->selectField( 'site_stats', 'ss_images' );
-
-echo wfWikiID().": forcing ss_images to $count\n";
-
-// First set to NULL so that it changes on the master
-$dbw->update( 'site_stats',
-       array( 'ss_images' => null ),
-       array( 'ss_row_id' => 1 ) );
-
-// Now this update will be forced to go out
-$dbw->update( 'site_stats',
-       array( 'ss_images' => $count ),
-       array( 'ss_row_id' => 1 ) );
-
+require_once( "Maintenance.php" );
+
+class RefreshImageCount extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Resets ss_image count, forcing slaves to pick it up.";
+       }
+       
+       public function execute() {
+               $dbw = wfGetDB( DB_MASTER );
+
+               // Load the current value from the master
+               $count = $dbw->selectField( 'site_stats', 'ss_images' );
+
+               $this->output( wfWikiID() . ": forcing ss_images to $count\n" );
+
+               // First set to NULL so that it changes on the master
+               $dbw->update( 'site_stats',
+                       array( 'ss_images' => null ),
+                       array( 'ss_row_id' => 1 ) );
+       
+               // Now this update will be forced to go out
+               $dbw->update( 'site_stats',
+                       array( 'ss_images' => $count ),
+                       array( 'ss_row_id' => 1 ) );
+                       }
+}
+
+$maintClass = "RefreshImageCount";
+require_once( DO_MAINTENANCE );
 
diff --git a/maintenance/refreshLinks.inc b/maintenance/refreshLinks.inc
deleted file mode 100644 (file)
index b7d531c..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-<?php
-/**
- * @todo document
- * @file
- * @ingroup Maintenance
- */
-
-function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $redirectsOnly = false, $oldRedirectsOnly = false ) {
-       global $wgUser, $wgParser, $wgUseTidy;
-
-       $reportingInterval = 100;
-       $fname = 'refreshLinks';
-       $dbr = wfGetDB( DB_SLAVE );
-       $start = intval( $start );
-
-       # Don't generate TeX PNGs (lack of a sensible current directory causes errors anyway)
-       $wgUser->setOption('math', MW_MATH_SOURCE);
-
-       # Don't generate extension images (e.g. Timeline)
-       if( method_exists( $wgParser, "clearTagHooks" ) ) {
-               $wgParser->clearTagHooks();
-       }
-
-       # Don't use HTML tidy
-       $wgUseTidy = false;
-
-       $what = $redirectsOnly ? "redirects" : "links";
-
-       if( $oldRedirectsOnly ) {
-               # This entire code path is cut-and-pasted from below.  Hurrah.
-               $res = $dbr->query(
-                       "SELECT page_id ".
-                       "FROM page ".
-                       "LEFT JOIN redirect ON page_id=rd_from ".
-                       "WHERE page_is_redirect=1 AND rd_from IS NULL AND ".
-                       ($end == 0 ? "page_id >= $start"
-                                  : "page_id BETWEEN $start AND $end"),
-                       $fname
-               );
-               $num = $dbr->numRows( $res );
-               print "Refreshing $num old redirects from $start...\n";
-
-               while( $row = $dbr->fetchObject( $res ) ) {
-                       if ( !( ++$i % $reportingInterval ) ) {
-                               print "$i\n";
-                               wfWaitForSlaves( $maxLag );
-                       }
-                       fixRedirect( $row->page_id );
-               }
-       } elseif( $newOnly ) {
-               print "Refreshing $what from ";
-               $res = $dbr->select( 'page',
-                       array( 'page_id' ),
-                       array(
-                               'page_is_new' => 1,
-                               "page_id >= $start" ),
-                       $fname
-               );
-               $num = $dbr->numRows( $res );
-               print "$num new articles...\n";
-
-               $i = 0;
-               while ( $row = $dbr->fetchObject( $res ) ) {
-                       if ( !( ++$i % $reportingInterval ) ) {
-                               print "$i\n";
-                               wfWaitForSlaves( $maxLag );
-                       }
-                       if($redirectsOnly)
-                               fixRedirect( $row->page_id );
-                       else
-                               fixLinksFromArticle( $row->page_id );
-               }
-       } else {
-               print "Refreshing $what table.\n";
-               if ( !$end ) {
-                       $end = $dbr->selectField( 'page', 'max(page_id)', false );
-               }
-               print("Starting from page_id $start of $end.\n");
-
-               for ($id = $start; $id <= $end; $id++) {
-
-                       if ( !($id % $reportingInterval) ) {
-                               print "$id\n";
-                               wfWaitForSlaves( $maxLag );
-                       }
-                       if($redirectsOnly)
-                               fixRedirect( $id );
-                       else
-                               fixLinksFromArticle( $id );
-               }
-       }
-}
-
-function fixRedirect( $id ){
-       global $wgTitle, $wgArticle;
-
-       $wgTitle = Title::newFromID( $id );
-       $dbw = wfGetDB( DB_MASTER );
-
-       if ( is_null( $wgTitle ) ) {
-               return;
-       }
-       $wgArticle = new Article($wgTitle);
-
-       $rt = $wgArticle->followRedirect();
-
-       if($rt == false || !is_object($rt))
-               return;
-
-       $wgArticle->updateRedirectOn($dbw,$rt);
-}
-
-function fixLinksFromArticle( $id ) {
-       global $wgTitle, $wgParser;
-
-       $wgTitle = Title::newFromID( $id );
-       $dbw = wfGetDB( DB_MASTER );
-
-       $linkCache =& LinkCache::singleton();
-       $linkCache->clear();
-
-       if ( is_null( $wgTitle ) ) {
-               return;
-       }
-       $dbw->begin();
-
-       $revision = Revision::newFromTitle( $wgTitle );
-       if ( !$revision ) {
-               return;
-       }
-
-       $options = new ParserOptions;
-       $parserOutput = $wgParser->parse( $revision->getText(), $wgTitle, $options, true, true, $revision->getId() );
-       $update = new LinksUpdate( $wgTitle, $parserOutput, false );
-       $update->doUpdate();
-       $dbw->immediateCommit();
-}
-
-/*
- * Removes non-existing links from pages from pagelinks, imagelinks,
- * categorylinks, templatelinks and externallinks tables.
- *
- * @param $maxLag
- * @param $batchSize The size of deletion batches
- *
- * @author Merlijn van Deen <valhallasw@arctus.nl>
- */
-function deleteLinksFromNonexistent( $maxLag = 0, $batchSize = 100 ) {
-       wfWaitForSlaves( $maxLag );
-       
-       $dbw = wfGetDB( DB_MASTER );
-
-       $lb = wfGetLBFactory()->newMainLB();
-       $dbr = $lb->getConnection( DB_SLAVE );
-       $dbr->bufferResults( false );
-       
-       $linksTables = array( // table name => page_id field
-               'pagelinks' => 'pl_from',
-               'imagelinks' => 'il_from',
-               'categorylinks' => 'cl_from',
-               'templatelinks' => 'tl_from',
-               'externallinks' => 'el_from',
-       );
-       
-       foreach ( $linksTables as $table => $field ) {
-               print "Retrieving illegal entries from $table... ";
-               
-               // SELECT DISTINCT( $field ) FROM $table LEFT JOIN page ON $field=page_id WHERE page_id IS NULL;
-               $results = $dbr->select( array( $table, 'page' ),
-                             $field,
-                             array('page_id' => null ),
-                             __METHOD__,
-                             'DISTINCT',
-                             array( 'page' => array( 'LEFT JOIN', "$field=page_id"))
-               );
-               
-               $counter = 0;
-               $list = array();
-               print "0..";
-               
-               foreach( $results as $row ) {
-                       $counter++;
-                       $list[] = $row->$field;
-                       if ( ( $counter % $batchSize ) == 0 ) {
-                               wfWaitForSlaves(5);
-                               $dbw->delete( $table, array( $field => $list ), __METHOD__ );
-                               
-                               print $counter . "..";
-                               $list = array();
-                       }
-               }
-               
-               print $counter;
-               if (count($list) > 0) {
-                       $dbw->delete( $table, array( $field => $list ), __METHOD__ );
-               }
-               
-               print "\n";
-       }
-       
-       $lb->closeAll();
-}
index c766752..74d07be 100644 (file)
 <?php
 /**
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-/** */
-$optionsWithArgs = array('batch-size', 'm', 'e' );
-
-require_once( "commandLine.inc" );
-require_once( "refreshLinks.inc" );
-
-if( isset( $options['help'] ) ) {
-       echo <<<TEXT
-Usage:
-    php refreshLinks.php --help
-    php refreshLinks.php [<start>] [-e <end>] [-m <maxlag>] [--dfn-only]
-                         [--batch-size <size>] [--new-only] [--redirects-only]
-    php refreshLinks.php [<start>] [-e <end>] [-m <maxlag>] --old-redirects-only
-
-    --help                : This help message
-    --dfn-only            : Delete links from nonexistent articles only
-    --batch-size <number> : The delete batch size when removing links from
-                            nonexistent articles (defaults to 100)
-    --new-only            : Only affect articles with just a single edit
-    --redirects-only      : Only fix redirects, not all links
-    --old-redirects-only  : Only fix redirects with no redirect table entry
-    -m <number>           : Maximum replication lag
-    <start>               : First page id to refresh
-    -e <number>           : Last page id to refresh
-
-TEXT;
-       exit(0);
-}
+require_once( "Maintenance.php" );
 
-error_reporting( E_ALL & (~E_NOTICE) );
+class RefreshLinks extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Refresh link tables";
+               $this->addOption( 'dfn-only', 'Delete links from nonexistent articles only' );
+               $this->addOption( 'new-only', 'Only affect articles with just a single edit' );
+               $this->addOption( 'redirects-only', 'Only fix redirects, not all links' );
+               $this->addOption( 'old-redirects-only', 'Only fix redirects with no redirect table entry' );
+               $this->addOption( 'm', 'Maximum replication lag', false, true );
+               $this->addOption( 'e', 'Last page id to refresh', false, true );
+               $this->addArgs( array( 'start' => true ) );
+               $this->setBatchSize( 100 );
+       }
 
-if ( !$options['dfn-only'] ) {
-       if ( isset( $args[0] ) ) {
-               $start = (int)$args[0];
-       } else {
-               $start = 1;
+       public function execute() {
+               if( !$this->hasOption( 'dfn-only' ) ) {
+                       $start = $this->getArg( 0, 1 );
+                       $new = $this->getOption( 'new-only', false );
+                       $max = $this->getOption( 'm', false );
+                       $end = $this->getOption( 'e', 0 );
+                       $redir = $this->getOption( 'redirects-only', false );
+                       $oldRedir = $this->getOption( 'old-redirects-only', false );
+                       $this->doRefreshLinks( $start, $new, $max, $end, $redir, $oldRedir );
+               }
+               $this->deleteLinksFromNonexistent( $max, $this->mBatchSize );
        }
 
-       refreshLinks( $start, $options['new-only'], $options['m'], $options['e'], $options['redirects-only'], $options['old-redirects-only'] );
-}
+       /**
+        * Do the actual link refreshing.
+        * @param $start int Page_id to start from
+        * @param $newOnly bool Only do pages with 1 edit
+        * @param $maxLag int Max DB replication lag
+        * @param $end int Page_id to stop at
+        * @param $redirectsOnly bool Only fix redirects
+        * @param $oldRedirectsOnly bool Only fix redirects without redirect entries
+        */
+       private function doRefreshLinks( $start, $newOnly = false, $maxLag = false, 
+                                               $end = 0, $redirectsOnly = false, $oldRedirectsOnly = false ) {
+               global $wgUser, $wgParser, $wgUseTidy;
 
-if ( !isset( $options['batch-size'] ) ) {
-  $options['batch-size'] = 100;
-}
+               $reportingInterval = 100;
+               $dbr = wfGetDB( DB_SLAVE );
+               $start = intval( $start );
+
+               # Don't generate TeX PNGs (lack of a sensible current directory causes errors anyway)
+               $wgUser->setOption('math', MW_MATH_SOURCE);
+
+               # Don't generate extension images (e.g. Timeline)
+               if( method_exists( $wgParser, "clearTagHooks" ) ) {
+                       $wgParser->clearTagHooks();
+               }
+
+               # Don't use HTML tidy
+               $wgUseTidy = false;
+
+               $what = $redirectsOnly ? "redirects" : "links";
+
+               if( $oldRedirectsOnly ) {
+                       # This entire code path is cut-and-pasted from below.  Hurrah.
+                       $res = $dbr->query(
+                               "SELECT page_id ".
+                               "FROM page ".
+                               "LEFT JOIN redirect ON page_id=rd_from ".
+                               "WHERE page_is_redirect=1 AND rd_from IS NULL AND ".
+                               ($end == 0 ? "page_id >= $start"
+                                                  : "page_id BETWEEN $start AND $end"),
+                               __METHOD__
+                       );
+                       $num = $dbr->numRows( $res );
+                       $this->output( "Refreshing $num old redirects from $start...\n" );
+
+                       while( $row = $dbr->fetchObject( $res ) ) {
+                               if ( !( ++$i % $reportingInterval ) ) {
+                                       $this->output( "$i\n" );
+                                       wfWaitForSlaves( $maxLag );
+                               }
+                               $this->fixRedirect( $row->page_id );
+                       }
+               } elseif( $newOnly ) {
+                       $this->output( "Refreshing $what from " );
+                       $res = $dbr->select( 'page',
+                               array( 'page_id' ),
+                               array(
+                                       'page_is_new' => 1,
+                                       "page_id >= $start" ),
+                               __METHOD__
+                       );
+                       $num = $dbr->numRows( $res );
+                       $this->output( "$num new articles...\n" );
+       
+                       $i = 0;
+                       while ( $row = $dbr->fetchObject( $res ) ) {
+                               if ( !( ++$i % $reportingInterval ) ) {
+                                       $this->output( "$i\n" );
+                                       wfWaitForSlaves( $maxLag );
+                               }
+                               if($redirectsOnly)
+                                       $this->fixRedirect( $row->page_id );
+                               else
+                                       $this->fixLinksFromArticle( $row->page_id );
+                       }
+               } else {
+                       $this->output( "Refreshing $what table.\n" );
+                       if ( !$end ) {
+                               $end = $dbr->selectField( 'page', 'max(page_id)', false );
+                       }
+                       $this->output( "Starting from page_id $start of $end.\n" );
+       
+                       for ($id = $start; $id <= $end; $id++) {
+       
+                               if ( !($id % $reportingInterval) ) {
+                                       $this->output( "$id\n" );
+                                       wfWaitForSlaves( $maxLag );
+                               }
+                               if($redirectsOnly)
+                                       $this->fixRedirect( $id );
+                               else
+                                       $this->fixLinksFromArticle( $id );
+                       }
+               }
+       }
+
+       /**
+        * Update the redirect entry for a given page
+        * @param $id int The page_id of the redirect
+        */
+       private function fixRedirect( $id ){
+               global $wgTitle, $wgArticle;
+       
+               $wgTitle = Title::newFromID( $id );
+               $dbw = wfGetDB( DB_MASTER );
+       
+               if ( is_null( $wgTitle ) ) {
+                       return;
+               }
+               $wgArticle = new Article($wgTitle);
+       
+               $rt = $wgArticle->followRedirect();
+       
+               if($rt == false || !is_object($rt))
+                       return;
+       
+               $wgArticle->updateRedirectOn($dbw,$rt);
+       }
+
+       /**
+        * Run LinksUpdate for all links on a given page_id
+        * @param $id int The page_id
+        */
+       private function fixLinksFromArticle( $id ) {
+               global $wgTitle, $wgParser;
+
+               $wgTitle = Title::newFromID( $id );
+               $dbw = wfGetDB( DB_MASTER );
 
-deleteLinksFromNonexistent($options['m'], $options['batch-size']);
+               $linkCache =& LinkCache::singleton();
+               $linkCache->clear();
 
-if ( $options['globals'] ) {
-       print_r( $GLOBALS );
+               if ( is_null( $wgTitle ) ) {
+                       return;
+               }
+               $dbw->begin();
+
+               $revision = Revision::newFromTitle( $wgTitle );
+               if ( !$revision ) {
+                       return;
+               }
+
+               $options = new ParserOptions;
+               $parserOutput = $wgParser->parse( $revision->getText(), $wgTitle, $options, true, true, $revision->getId() );
+               $update = new LinksUpdate( $wgTitle, $parserOutput, false );
+               $update->doUpdate();
+               $dbw->immediateCommit();
+       }
+
+       /*
+        * Removes non-existing links from pages from pagelinks, imagelinks,
+        * categorylinks, templatelinks and externallinks tables.
+        *
+        * @param $maxLag
+        * @param $batchSize The size of deletion batches
+        *
+        * @author Merlijn van Deen <valhallasw@arctus.nl>
+        */
+       private function deleteLinksFromNonexistent( $maxLag = 0, $batchSize = 100 ) {
+               wfWaitForSlaves( $maxLag );
+
+               $dbw = wfGetDB( DB_MASTER );
+
+               $lb = wfGetLBFactory()->newMainLB();
+               $dbr = $lb->getConnection( DB_SLAVE );
+               $dbr->bufferResults( false );
+
+               $linksTables = array( // table name => page_id field
+                       'pagelinks' => 'pl_from',
+                       'imagelinks' => 'il_from',
+                       'categorylinks' => 'cl_from',
+                       'templatelinks' => 'tl_from',
+                       'externallinks' => 'el_from',
+               );
+
+               foreach ( $linksTables as $table => $field ) {
+                       $this->output( "Retrieving illegal entries from $table... " );
+
+                       // SELECT DISTINCT( $field ) FROM $table LEFT JOIN page ON $field=page_id WHERE page_id IS NULL;
+                       $results = $dbr->select( array( $table, 'page' ),
+                                                 $field,
+                                                 array('page_id' => null ),
+                                                 __METHOD__,
+                                                 'DISTINCT',
+                                                 array( 'page' => array( 'LEFT JOIN', "$field=page_id"))
+                       );
+
+                       $counter = 0;
+                       $list = array();
+                       $this->output( "0.." );
+
+                       foreach( $results as $row ) {
+                               $counter++;
+                               $list[] = $row->$field;
+                               if ( ( $counter % $batchSize ) == 0 ) {
+                                       wfWaitForSlaves(5);
+                                       $dbw->delete( $table, array( $field => $list ), __METHOD__ );
+
+                                       $this->output( $counter . ".." );
+                                       $list = array();
+                               }
+                       }
+                       $this->output( $counter );
+                       if (count($list) > 0) {
+                               $dbw->delete( $table, array( $field => $list ), __METHOD__ );
+                       }
+                       $this->output( "\n" );
+               }
+               $lb->closeAll();
+       }
 }
+
+$maintClass = 'RefreshLinks';
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/removeUnusedAccounts.inc b/maintenance/removeUnusedAccounts.inc
deleted file mode 100644 (file)
index 02c07c1..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/**
- * Support functions for the removeUnusedAccounts maintenance script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-/**
- * Could the specified user account be deemed inactive?
- * (No edits, no deleted edits, no log entries, no current/old uploads)
- *
- * @param $id User's ID
- * @param $master Perform checking on the master
- * @return bool
- */
-function isInactiveAccount( $id, $master = false ) {
-       $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE );
-       $fname = 'isInactiveAccount';
-       $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log',
-                                        'image' => 'img', 'oldimage' => 'oi' );
-       $count = 0;
-
-       $dbo->immediateBegin();
-       foreach( $checks as $table => $fprefix ) {
-               $conds = array( $fprefix . '_user' => $id );
-               $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, $fname );
-       }
-       $dbo->immediateCommit();
-
-       return $count == 0;
-}
-
-/**
- * Show help for the maintenance script
- */
-function showHelp() {
-       echo( "Delete unused user accounts from the database.\n\n" );
-       echo( "USAGE: php removeUnusedAccounts.php [--delete]\n\n" );
-       echo( "  --delete             : Delete accounts which are discovered to be inactive\n" );
-       echo( "  --ignore-touched=x   : Ignore accounts touched within the lasts x days\n" );
-       echo( "  --ignore-groups=x,y  : Ignore accounts within these groups\n" );
-       echo( "\n" );
-}
index 5f74b65..6a36b68 100644 (file)
  * Remove unused user accounts from the database
  * An unused account is one which has made no edits
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-$options = array( 'help', 'delete' );
-require_once( 'commandLine.inc' );
-require_once( 'removeUnusedAccounts.inc' );
-echo( "Remove Unused Accounts\n\n" );
-$fname = 'removeUnusedAccounts';
+require_once( "Maintenance.php" );
 
-if( isset( $options['help'] ) ) {
-       showHelp();
-       exit(1);
-}
+class RemoveUnusedAccounts extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( 'delete', 'Actually delete the account' );
+               $this->addOption( 'ignore-groups', 'List of comma-separated groups to exclude', false, true );
+               $this->addOption( 'ignore-touched', 'Skip accounts touched in last N days', false, true );
+       }
+
+       public function execute() {
 
-# Do an initial scan for inactive accounts and report the result
-echo( "Checking for unused user accounts...\n" );
-$del = array();
-$dbr = wfGetDB( DB_SLAVE );
-$res = $dbr->select( 'user', array( 'user_id', 'user_name', 'user_touched' ), '', $fname );
-if( isset( $options['ignore-groups'] ) ) {
-       $excludedGroups = explode( ',', $options['ignore-groups'] );
-} else { $excludedGroups = array(); }
-$touchedSeconds = 0;
-if( isset( $options['ignore-touched'] ) ) {
-       $touchedParamError = 0;
-       if( ctype_digit( $options['ignore-touched'] ) ) {
-               if( $options['ignore-touched'] <= 0 ) {
-                       $touchedParamError = 1;
+               $this->output( "Remove unused accounts\n\n" );
+               
+               # Do an initial scan for inactive accounts and report the result
+               $this->output( "Checking for unused user accounts...\n" );
+               $del = array();
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select( 'user', array( 'user_id', 'user_name', 'user_touched' ), '', __METHOD__ );
+               if( $this->hasOption('ignore-groups') ) {
+                       $excludedGroups = explode( ',', $this->getOption('ignore-groups') );
+               } else { 
+                       $excludedGroups = array();
                }
-       } else { $touchedParamError = 1; }
-       if( $touchedParamError == 1 ) {
-               die( "Please put a valid positive integer on the --ignore-touched parameter.\n" );
-       } else { $touchedSeconds = 86400 * $options['ignore-touched']; }
-}
-while( $row = $dbr->fetchObject( $res ) ) {
-       # Check the account, but ignore it if it's within a $excludedGroups group or if it's touched within the $touchedSeconds seconds.
-       $instance = User::newFromId( $row->user_id );
-       if( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0
-               && isInactiveAccount( $row->user_id, true )
-               && wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds )
-               ) {
-               # Inactive; print out the name and flag it
-               $del[] = $row->user_id;
-               echo( $row->user_name . "\n" );
+               $touched = $this->getOption( 'ignore-touched', "1" );
+               if( !ctype_digit( $touched ) ) {
+                       $this->error( "Please put a valid positive integer on the --ignore-touched parameter.\n", true );
+               }
+               $touchedSeconds = 86400 * $touched;
+               while( $row = $dbr->fetchObject( $res ) ) {
+                       # Check the account, but ignore it if it's within a $excludedGroups group or if it's touched within the $touchedSeconds seconds.
+                       $instance = User::newFromId( $row->user_id );
+                       if( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0
+                               && $this->isInactiveAccount( $row->user_id, true )
+                               && wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds )
+                               ) {
+                               # Inactive; print out the name and flag it
+                               $del[] = $row->user_id;
+                               $this->output( $row->user_name . "\n" );
+                       }
+               }
+               $count = count( $del );
+               $this->output( "...found {$count}.\n" );
+       
+               # If required, go back and delete each marked account
+               if( $count > 0 && $this->hasOption('delete') ) {
+                       $this->output( "\nDeleting inactive accounts..." );
+                       $dbw = wfGetDB( DB_MASTER );
+                       $dbw->delete( 'user', array( 'user_id' => $del ), __METHOD__ );
+                       $this->output( "done.\n" );
+                       # Update the site_stats.ss_users field
+                       $users = $dbw->selectField( 'user', 'COUNT(*)', array(), __METHOD__ );
+                       $dbw->update( 'site_stats', array( 'ss_users' => $users ), array( 'ss_row_id' => 1 ), __METHOD__ );
+               } elseif( $count > 0 ) {
+                       $this->output( "\nRun the script again with --delete to remove them from the database.\n" );
+               }
+               $this->output( "\n" );
+       }
+       
+       /**
+        * Could the specified user account be deemed inactive?
+        * (No edits, no deleted edits, no log entries, no current/old uploads)
+        *
+        * @param $id User's ID
+        * @param $master Perform checking on the master
+        * @return bool
+        */
+       private function isInactiveAccount( $id, $master = false ) {
+               $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE );
+               $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log',
+                                                'image' => 'img', 'oldimage' => 'oi' );
+               $count = 0;
+       
+               $dbo->immediateBegin();
+               foreach( $checks as $table => $fprefix ) {
+                       $conds = array( $fprefix . '_user' => $id );
+                       $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ );
+               }
+               $dbo->immediateCommit();
+       
+               return $count == 0;
        }
 }
-$count = count( $del );
-echo( "...found {$count}.\n" );
 
-# If required, go back and delete each marked account
-if( $count > 0 && isset( $options['delete'] ) ) {
-       echo( "\nDeleting inactive accounts..." );
-       $dbw = wfGetDB( DB_MASTER );
-       $dbw->delete( 'user', array( 'user_id' => $del ), $fname );
-       echo( "done.\n" );
-       # Update the site_stats.ss_users field
-       $users = $dbw->selectField( 'user', 'COUNT(*)', array(), $fname );
-       $dbw->update( 'site_stats', array( 'ss_users' => $users ), array( 'ss_row_id' => 1 ), $fname );
-} else {
-       if( $count > 0 )
-               echo( "\nRun the script again with --delete to remove them from the database.\n" );
-}
-echo( "\n" );
+$maintClass = "RemoveUnusedAccounts";
+require_once( DO_MAINTENANCE );
index 277f3b9..68e66ed 100644 (file)
@@ -3,65 +3,79 @@
  * Run this script to after changing $wgDBprefix on a wiki.
  * The wiki will have to get downtime to do this correctly.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
-$optionsWithArgs = array( 'old', 'new', 'help' );
-
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-if( @$options['help'] || !isset( $options['old'] ) || !isset( $options['new'] ) ) {
-       print "usage: renameDbPrefix.php [--help] [--old x] [new y]\n";
-       print "  --help      : this help message\n";
-       print "  --old x       : old db prefix x\n";
-       print "  --old 0       : EMPTY old db prefix x\n";
-       print "  --new y       : new db prefix y\n";
-       print "  --new 0       : EMPTY new db prefix\n";
-       wfDie();
-}
-
-// Allow for no old prefix
-if( $options['old'] === '0' ) {
-       $old = '';
-} else {
-       // Use nice safe, sane, prefixes
-       preg_match( '/^[a-zA-Z]+_$/', $options['old'], $m );
-       $old = isset( $m[0] ) ? $m[0] : false;
-}
-// Allow for no new prefix
-if( $options['new'] === '0' ) {
-       $new = '';
-} else {
-       // Use nice safe, sane, prefixes
-       preg_match( '/^[a-zA-Z]+_$/', $options['new'], $m );
-       $new = isset( $m[0] ) ? $m[0] : false;
-}
-
-if( $old === false || $new === false ) {
-       print "Invalid prefix!\n";
-       wfDie();
-}
-if( $old === $new ) {
-       print "Same prefix. Nothing to rename!\n";
-       wfDie();
-}
-
-print "Renaming DB prefix for tables of $wgDBname from '$old' to '$new'\n";
-$count = 0;
-
-$dbw = wfGetDB( DB_MASTER );
-$res = $dbw->query( "SHOW TABLES LIKE '".$dbw->escapeLike( $old )."%'" );
-foreach( $res as $row ) {
-       // XXX: odd syntax. MySQL outputs an oddly cased "Tables of X"
-       // sort of message. Best not to try $row->x stuff...
-       $fields = get_object_vars( $row );
-       // Silly for loop over one field...
-       foreach( $fields as $resName => $table ) {
-               // $old should be regexp safe ([a-zA-Z_])
-               $newTable = preg_replace( '/^'.$old.'/', $new, $table );
-               print "Renaming table $table to $newTable\n";
-               $dbw->query( "RENAME TABLE $table TO $newTable" );
+class RenameDbPrefix extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( "old", "Old db prefix [0 for none]", true, true );
+               $this->addOption( "new", "New db prefix [0 for none]", true, true );
+       }
+       
+       public function execute() {
+               // Allow for no old prefix
+               if( $this->getOption( 'old', 0 ) === '0' ) {
+                       $old = '';
+               } else {
+                       // Use nice safe, sane, prefixes
+                       preg_match( '/^[a-zA-Z]+_$/', $this->getOption('old'), $m );
+                       $old = isset( $m[0] ) ? $m[0] : false;
+               }
+               // Allow for no new prefix
+               if( $this->getOption( 'new', 0 ) === '0' ) {
+                       $new = '';
+               } else {
+                       // Use nice safe, sane, prefixes
+                       preg_match( '/^[a-zA-Z]+_$/', $this->getOption('new'), $m );
+                       $new = isset( $m[0] ) ? $m[0] : false;
+               }
+       
+               if( $old === false || $new === false ) {
+                       $this->error( "Invalid prefix!\n", true );
+               }
+               if( $old === $new ) {
+                       $this->output( "Same prefix. Nothing to rename!\n", true );
+               }
+       
+               $this->output( "Renaming DB prefix for tables of $wgDBname from '$old' to '$new'\n" );
+               $count = 0;
+       
+               $dbw = wfGetDB( DB_MASTER );
+               $res = $dbw->query( "SHOW TABLES LIKE '".$dbw->escapeLike( $old )."%'" );
+               foreach( $res as $row ) {
+                       // XXX: odd syntax. MySQL outputs an oddly cased "Tables of X"
+                       // sort of message. Best not to try $row->x stuff...
+                       $fields = get_object_vars( $row );
+                       // Silly for loop over one field...
+                       foreach( $fields as $resName => $table ) {
+                               // $old should be regexp safe ([a-zA-Z_])
+                               $newTable = preg_replace( '/^'.$old.'/', $new, $table );
+                               $this->output( "Renaming table $table to $newTable\n" );
+                               $dbw->query( "RENAME TABLE $table TO $newTable" );
+                       }
+                       $count++;
+               }
+               $this->output( "Done! [$count tables]\n" );
        }
-       $count++;
 }
-print "Done! [$count tables]\n";
\ No newline at end of file
+
+$maintClass = "RenameDbPrefix";
+require_once( DO_MAINTENANCE );
\ No newline at end of file
index 66de326..bfdca15 100644 (file)
@@ -3,60 +3,80 @@
  * Why yes, this *is* another special-purpose Wikimedia maintenance script!
  * Should be fixed up and generalized.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-require_once( "commandLine.inc" );
+require_once( "Maintenance.php" );
 
-if ( count( $args ) != 2 ) {
-       wfDie( "Rename external storage dbs and leave a new one...\n" .
-                       "Usage: php renamewiki.php <olddb> <newdb>\n" );
-}
+class RenameWiki extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Rename external storage dbs and leave a new one";
+               $this->addArgs( array( 'olddb', 'newdb' ) );
+       }
 
-list( $from, $to ) = $args;
+       public function execute() {
+               global $wgDefaultExternalStore;
 
-echo "Renaming blob tables in ES from $from to $to...\n";
-echo "Sleeping 5 seconds...";
-sleep(5);
-echo "\n";
+               # Setup
+               $from = $this->getArg( 0 );
+               $to = $this->getArg( 1 );
+               $this->output( "Renaming blob tables in ES from $from to $to...\n" );
+               $this->output( "Sleeping 5 seconds...\n" );
+               sleep(5);
 
-$maintenance = "$IP/maintenance";
+               # Initialise external storage
+               if ( is_array( $wgDefaultExternalStore ) ) {
+                       $stores = $wgDefaultExternalStore;
+               } elseif ( $wgDefaultExternalStore ) {
+                       $stores = array( $wgDefaultExternalStore );
+               } else {
+                       $stores = array();
+               }
 
-# Initialise external storage
-if ( is_array( $wgDefaultExternalStore ) ) {
-       $stores = $wgDefaultExternalStore;
-} elseif ( $wgDefaultExternalStore ) {
-       $stores = array( $wgDefaultExternalStore );
-} else {
-       $stores = array();
-}
-if ( count( $stores ) ) {
-       require_once( 'ExternalStoreDB.php' );
-       print "Initialising external storage $store...\n";
-       global $wgDBuser, $wgDBpassword, $wgExternalServers;
-       foreach ( $stores as $storeURL ) {
-               $m = array();
-               if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) {
-                       continue;
+               if ( count( $stores ) ) {
+                       $this->output( "Initialising external storage $store...\n" );
+                       global $wgDBuser, $wgDBpassword, $wgExternalServers;
+                       foreach ( $stores as $storeURL ) {
+                               $m = array();
+                               if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) {
+                                       continue;
+                               }
+       
+                               $cluster = $m[1];
+       
+                               # Hack
+                               $wgExternalServers[$cluster][0]['user'] = $wgDBuser;
+                               $wgExternalServers[$cluster][0]['password'] = $wgDBpassword;
+       
+                               $store = new ExternalStoreDB;
+                               $extdb =& $store->getMaster( $cluster );
+                               $extdb->query( "SET table_type=InnoDB" );
+                               $extdb->query( "CREATE DATABASE {$to}" );
+                               $extdb->query( "ALTER TABLE {$from}.blobs RENAME TO {$to}.blobs" );
+                               $extdb->selectDB( $from );
+                               $extdb->sourceFile( $this->getDir() . '/storage/blobs.sql' );
+                               $extdb->immediateCommit();
+                       }
                }
-               
-               $cluster = $m[1];
-               
-               # Hack
-               $wgExternalServers[$cluster][0]['user'] = $wgDBuser;
-               $wgExternalServers[$cluster][0]['password'] = $wgDBpassword;
-               
-               $store = new ExternalStoreDB;
-               $extdb =& $store->getMaster( $cluster );
-               $extdb->query( "SET table_type=InnoDB" );
-               $extdb->query( "CREATE DATABASE {$to}" );
-               $extdb->query( "ALTER TABLE {$from}.blobs RENAME TO {$to}.blobs" );
-               $extdb->selectDB( $from );
-               dbsource( "$maintenance/storage/blobs.sql", $extdb );
-               $extdb->immediateCommit();
+               $this->output( "done.\n" );
        }
 }
 
-echo "done.\n";
-
+$maintClass = "RenameWiki";
+require_once( DO_MAINTENANCE );
index 9779779..b6758f7 100644 (file)
  * @file
  * @ingroup Maintenance
  */
+require_once( "Maintenance.php" );
 
-$optionsWithArgs = array( 'report' );
+class DumpRenderer extends Maintenance {
 
-require_once( 'commandLine.inc' );
+       private $count = 0;
+       private $outputDirectory, $startTime;
 
-class DumpRenderer {
-       function __construct( $dir ) {
-               $this->stderr = fopen( "php://stderr", "wt" );
-               $this->outputDirectory = $dir;
-               $this->count = 0;
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Take page text out of an XML dump file and render basic HTML out to files";
+               $this->addOption( 'output-dir', 'The directory to output the HTML files to', true, true );
        }
 
-       function handleRevision( $rev ) {
+       public function execute() {
+               $this->outputDirectory = $this->getOption( 'output-dir' );
+               $this->startTime = wfTime();
+
+               $source = new ImportStreamSource( $this->getStdin() );
+               $importer = new WikiImporter( $source );
+
+               $importer->setRevisionCallback(
+                       array( &$this, 'handleRevision' ) );
+
+               return $importer->doImport();
+       }
+       
+       /**
+        * Callback function for each revision, turn into HTML and save
+        * @param $rev Revision
+        */
+       private function handleRevision( $rev ) {
                $title = $rev->getTitle();
                if (!$title) {
-                       fprintf( $this->stderr, "Got bogus revision with null title!" );
+                       $this->error( "Got bogus revision with null title!" );
                        return;
                }
                $display = $title->getPrefixedText();
-               
+
                $this->count++;
-               
+
                $sanitized = rawurlencode( $display );
                $filename = sprintf( "%s/wiki-%07d-%s.html", 
                        $this->outputDirectory,
                        $this->count,
                        $sanitized );
-               fprintf( $this->stderr, "%s\n", $filename, $display );
-               
-               // fixme
+               $this->output( sprintf( $this->stderr, "%s\n", $filename, $display ) );
+
+               // fixme (what?)
                $user = new User();
                $parser = new Parser();
                $options = ParserOptions::newFromUser( $user );
-               
+
                $output = $parser->parse( $rev->getText(), $title, $options );
-               
+
                file_put_contents( $filename,
                        "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " .
                        "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" .
@@ -76,27 +95,7 @@ class DumpRenderer {
                        "</body>\n" .
                        "</html>" );
        }
-
-       function run() {
-               $this->startTime = wfTime();
-
-               $file = fopen( 'php://stdin', 'rt' );
-               $source = new ImportStreamSource( $file );
-               $importer = new WikiImporter( $source );
-
-               $importer->setRevisionCallback(
-                       array( &$this, 'handleRevision' ) );
-
-               return $importer->doImport();
-       }
 }
 
-if( isset( $options['output-dir'] ) ) {
-       $dir = $options['output-dir'];
-} else {
-       wfDie( "Must use --output-dir=/some/dir\n" );
-}
-$render = new DumpRenderer( $dir );
-$render->run();
-
-
+$maintClass = "DumpRenderer";
+require_once( DO_MAINTENANCE );
index 1340a85..956af83 100644 (file)
@@ -6,75 +6,95 @@
  *  --maxjobs <num> (default 10000)
  *  --type <job_cmd>
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-$optionsWithArgs = array( 'maxjobs', 'type', 'procs' );
-$wgUseNormalUser = true;
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-if ( isset( $options['procs'] ) ) {
-       $procs = intval( $options['procs'] );
-       if ( $procs < 1 || $procs > 1000 ) {
-               echo "Invalid argument to --procs\n";
-               exit( 1 );
+class RunJobs extends Maintenance {
+       public function __construct() {
+               global $wgUseNormalUser;
+               parent::__construct();
+               $this->mDescription = "Run pending jobs";
+               $this->addOption( 'maxjobs', 'Maximum number of jobs to run', false, true );
+               $this->addOption( 'type', 'Type of job to run', false, true );
+               $this->addOption( 'procs', 'Number of processes to use', false, true );
+               $wgUseNormalUser = true;
        }
-       $fc = new ForkController( $procs );
-       if ( $fc->start( $procs ) != 'child' ) {
-               exit( 0 );
-       }
-}
-
-if ( isset( $options['maxjobs'] ) ) {
-       $maxJobs = $options['maxjobs'];
-} else {
-       $maxJobs = 10000;
-}
-
-$type = false;
-if ( isset( $options['type'] ) )
-       $type = $options['type'];
-
-$wgTitle = Title::newFromText( 'RunJobs.php' );
 
-$dbw = wfGetDB( DB_MASTER );
-$n = 0;
-$conds = '';
-if ($type !== false)
-       $conds = "job_cmd = " . $dbw->addQuotes($type);
-
-while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) {
-       $offset=0;
-       for (;;) {
-               $job = ($type == false) ?
-                               Job::pop($offset)
-                               : Job::pop_type($type);
-
-               if ($job == false)
-                       break;
-
-               wfWaitForSlaves( 5 );
-               $t = microtime( true );
-               $offset=$job->id;
-               $status = $job->run();
-               $t = microtime( true ) - $t;
-               $timeMs = intval( $t * 1000 );
-               if ( !$status ) {
-                       runJobsLog( $job->toString() . " t=$timeMs error={$job->error}" );
-               } else {
-                       runJobsLog( $job->toString() . " t=$timeMs good" );
+       public function execute() {
+               global $wgTitle;
+               if ( $this->hasOption( 'procs' ) ) {
+                       $procs = intval( $this->getOption('procs') );
+                       if ( $procs < 1 || $procs > 1000 ) {
+                               $this->error( "Invalid argument to --procs\n", true );
+                       }
+                       $fc = new ForkController( $procs );
+                       if ( $fc->start( $procs ) != 'child' ) {
+                               exit( 0 );
+                       }
                }
-               if ( $maxJobs && ++$n > $maxJobs ) {
-                       break 2;
+               $maxJobs = $this->getOption( 'maxjobs', 10000 );
+               $type = $this->getOption( 'type', false );
+               $wgTitle = Title::newFromText( 'RunJobs.php' );
+               $dbw = wfGetDB( DB_MASTER );
+               $n = 0;
+               $conds = '';
+               if ($type !== false)
+                       $conds = "job_cmd = " . $dbw->addQuotes($type);
+
+               while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) {
+                       $offset=0;
+                       for (;;) {
+                               $job = ($type == false) ?
+                                               Job::pop($offset)
+                                               : Job::pop_type($type);
+       
+                               if ($job == false)
+                                       break;
+       
+                               wfWaitForSlaves( 5 );
+                               $t = microtime( true );
+                               $offset=$job->id;
+                               $status = $job->run();
+                               $t = microtime( true ) - $t;
+                               $timeMs = intval( $t * 1000 );
+                               if ( !$status ) {
+                                       $this->runJobsLog( $job->toString() . " t=$timeMs error={$job->error}" );
+                               } else {
+                                       $this->runJobsLog( $job->toString() . " t=$timeMs good" );
+                               }
+                               if ( $maxJobs && ++$n > $maxJobs ) {
+                                       break 2;
+                               }
+                       }
                }
        }
-}
-
 
-function runJobsLog( $msg ) {
-       print wfTimestamp( TS_DB ) . " $msg\n";
-       wfDebugLog( 'runJobs', $msg );
+       /**
+        * Log the job message
+        * @param $msg String The message to log
+        */
+       private function runJobsLog( $msg ) {
+               $this->output( wfTimestamp( TS_DB ) . " $msg\n" );
+               wfDebugLog( 'runJobs', $msg );
+       }
 }
 
-
+$maintClass = "RunJobs";
+require_once( DO_MAINTENANCE );
index 6e38c85..8f068f5 100644 (file)
@@ -4,15 +4,38 @@
  *
  * Report number of jobs currently waiting in master database.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Tim Starling
  * @author Ashar Voultoiz
  */
-require_once( 'commandLine.inc' );
-
-$dbw = wfGetDB( DB_MASTER );
-$count = $dbw->selectField( 'job', 'count(*)', '', 'runJobs.php' );
-print $count."\n";
+require_once( "Maintenance.php" );
 
+class ShowJobs extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Show number of jobs waiting in master database";
+       }
+       public function execute() {
+               $dbw = wfGetDB( DB_MASTER );
+               $this->output( $dbw->selectField( 'job', 'count(*)', '', __METHOD__ ) . "\n" );
+       }
+}
 
+$maintClass = "ShowJobs";
+require_once( DO_MAINTENANCE );
index ef13f65..e42fab6 100644 (file)
@@ -4,7 +4,21 @@
  * Maintenance script to show the cached statistics.
  * Give out the same output as [[Special:Statistics]]
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Ashar Voultoiz <hashar@altern.org>
  * Based on initStats.php by:
  * @license GNU General Public License 2.0 or later
  */
 
-require_once( 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-#
-# Configuration
-#
-$fields = array(
-       'ss_total_views' => 'Total views',
-       'ss_total_edits' => 'Total edits',
-       'ss_good_articles' => 'Number of articles',
-       'ss_total_pages' => 'Total pages',
-       'ss_users' => 'Number of users',
-       'ss_admins' => 'Number of admins',
-       'ss_images' => 'Number of images',
-);
-
-// Get cached stats from slave database
-$dbr = wfGetDB( DB_SLAVE );
-$fname = 'showStats';
-$stats = $dbr->selectRow( 'site_stats', '*', '' );
-
-// Get maximum size for each column
-$max_length_value = $max_length_desc = 0;
-foreach( $fields as $field => $desc ) {
-       $max_length_value = max( $max_length_value, strlen( $stats->$field ) );
-       $max_length_desc  = max( $max_length_desc , strlen( $desc )) ;
+class ShowStats extends Maintenance {
+       public function __construct() {
+               $this->mDescription = "Show the cached statistics";
+       }
+       public function execute() {
+               $fields = array(
+                       'ss_total_views' => 'Total views',
+                       'ss_total_edits' => 'Total edits',
+                       'ss_good_articles' => 'Number of articles',
+                       'ss_total_pages' => 'Total pages',
+                       'ss_users' => 'Number of users',
+                       'ss_admins' => 'Number of admins',
+                       'ss_images' => 'Number of images',
+               );
+       
+               // Get cached stats from slave database
+               $dbr = wfGetDB( DB_SLAVE );
+               $stats = $dbr->selectRow( 'site_stats', '*', '', __METHOD__ );
+       
+               // Get maximum size for each column
+               $max_length_value = $max_length_desc = 0;
+               foreach( $fields as $field => $desc ) {
+                       $max_length_value = max( $max_length_value, strlen( $stats->$field ) );
+                       $max_length_desc  = max( $max_length_desc , strlen( $desc )) ;
+               }
+       
+               // Show them
+               foreach( $fields as $field => $desc ) {
+                       $this->output( sprintf( "%-{$max_length_desc}s: %{$max_length_value}d\n", $desc, $stats->$field ) );
+               }
+       }
 }
 
-// Show them
-foreach( $fields as $field => $desc ) {
-       printf( "%-{$max_length_desc}s: %{$max_length_value}d\n", $desc, $stats->$field );
-}
+$maintClass = "ShowStats";
+require_once( DO_MAINTENANCE );
 
index ab6546b..16175bd 100644 (file)
@@ -3,42 +3,74 @@
  * Send SQL queries from the specified file to the database, performing
  * variable replacement along the way.
  *
- * @file
- * @ingroup Database Maintenance
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @ingroup Maintenance
  */
 
-require_once( dirname(__FILE__) . '/' . 'commandLine.inc' );
+require_once( "Maintenance.php" );
 
-if ( isset( $options['help'] ) ) {
-       echo "Send SQL queries to a MediaWiki database.\nUsage: php sql.php [<file>]\n";
-       exit( 1 );
-}
+class MwSql extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Send SQL queries to a MediaWiki database";
+       }
 
-if ( isset( $args[0] ) ) {
-       $fileName = $args[0];
-       $file = fopen( $fileName, 'r' );
-       $promptCallback = false;
-} else {
-       $file = STDIN;
-       $promptObject = new SqlPromptPrinter( "> " );
-       $promptCallback = $promptObject->cb();
-}
+       public function execute() {
+               if ( $this->hasArg() ) {
+                       $fileName = $this->getArg();
+                       $file = fopen( $fileName, 'r' );
+                       $promptCallback = false;
+               } else {
+                       $file = $this->getStdin();
+                       $promptObject = new SqlPromptPrinter( "> " );
+                       $promptCallback = $promptObject->cb();
+               }
+       
+               if ( !$file )
+                       $this->error( "Unable to open input file\n", true );
 
-if ( !$file  ) {
-       echo "Unable to open input file\n";
-       exit( 1 );
-}
+               $dbw = wfGetDB( DB_MASTER );
+               $error = $dbw->sourceStream( $file, $promptCallback, array( $this, 'sqlPrintResult' ) );
+               if ( $error !== true ) {
+                       $this->error( $error, true );
+               } else {
+                       exit( 0 );
+               }
+       }
 
-$dbw =& wfGetDB( DB_MASTER );
-$error = $dbw->sourceStream( $file, $promptCallback, 'sqlPrintResult' );
-if ( $error !== true ) {
-       echo $error;
-       exit( 1 );
-} else {
-       exit( 0 );
+       /**
+        * Print the results, callback for $db->sourceStream()
+        * @param $res The results object
+        * @param $db Database object
+        */
+       public function sqlPrintResult( $res, $db ) {
+               if ( !$res ) {
+                       // Do nothing
+               } elseif ( is_object( $res ) && $res->numRows() ) {
+                       while ( $row = $res->fetchObject() ) {
+                               $this->output( print_r( $row, true ) );
+                       }
+               } else {
+                       $affected = $db->affectedRows();
+                       $this->output( "Query OK, $affected row(s) affected\n" );
+               }
+       }
 }
 
-//-----------------------------------------------------------------------------
 class SqlPromptPrinter {
        function __construct( $prompt ) {
                $this->prompt = $prompt;
@@ -53,17 +85,5 @@ class SqlPromptPrinter {
        }
 }
 
-function sqlPrintResult( $res, $db ) {
-       if ( !$res ) {
-               // Do nothing
-       } elseif ( is_object( $res ) && $res->numRows() ) {
-               while ( $row = $res->fetchObject() ) {
-                       print_r( $row );
-               }
-       } else {
-               $affected = $db->affectedRows();
-               echo "Query OK, $affected row(s) affected\n";
-       }
-}
-
-
+$maintClass = "MwSql";
+require_once( DO_MAINTENANCE );
index 00f79de..b496f0c 100644 (file)
@@ -1,58 +1,89 @@
 <?php
 /**
- * Show statistics from memcached
+ * Show statistics from the cache
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
  *
- * @file
  * @ingroup Maintenance
  */
 
-require_once('commandLine.inc');
+require_once( "Maintenance.php" );
 
-if( get_class( $wgMemc ) == 'FakeMemCachedClient' ) {
-       die("You are running FakeMemCachedClient, I can not provide any statistics.\n");
-}
-$session = intval($wgMemc->get(wfMemcKey('stats','request_with_session')));
-$noSession = intval($wgMemc->get(wfMemcKey('stats','request_without_session')));
-$total = $session + $noSession;
-if ( $total == 0 ) {
-       die("You either have no stats or memcached isn't running. Aborting.\n");
+class CacheStats extends Maintenance {
+
+       public function __construct() {
+               $this->mDescription = "Show statistics from the cache";
+       }
+
+       public function execute() {
+               global $wgMemc;
+               
+               // Can't do stats if 
+               if( get_class( $wgMemc ) == 'FakeMemCachedClient' ) {
+                       $this->error( "You are running FakeMemCachedClient, I can not provide any statistics.\n", true );
+               }
+               $session = intval($wgMemc->get(wfMemcKey('stats','request_with_session')));
+               $noSession = intval($wgMemc->get(wfMemcKey('stats','request_without_session')));
+               $total = $session + $noSession;
+               if ( $total == 0 ) {
+                       $this->error( "You either have no stats or the cache isn't running. Aborting.\n", true );
+               }
+               $this->output( "Requests\n" );
+               $this->output( sprintf( "with session:      %-10d %6.2f%%\n", $session, $session/$total*100 ) );
+               $this->output( sprintf( "without session:   %-10d %6.2f%%\n", $noSession, $noSession/$total*100 ) );
+               $this->output( sprintf( "total:             %-10d %6.2f%%\n", $total, 100 ) );
+       
+       
+               $this->output( "\nParser cache\n" );
+               $hits = intval($wgMemc->get(wfMemcKey('stats','pcache_hit')));
+               $invalid = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_invalid')));
+               $expired = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_expired')));
+               $absent = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_absent')));
+               $stub = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_stub')));
+               $total = $hits + $invalid + $expired + $absent + $stub;
+               $this->output( sprintf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 ) );
+               $this->output( sprintf( "invalid:           %-10d %6.2f%%\n", $invalid, $invalid/$total*100 ) );
+               $this->output( sprintf( "expired:           %-10d %6.2f%%\n", $expired, $expired/$total*100 ) );
+               $this->output( sprintf( "absent:            %-10d %6.2f%%\n", $absent, $absent/$total*100 ) );
+               $this->output( sprintf( "stub threshold:    %-10d %6.2f%%\n", $stub, $stub/$total*100 ) );
+               $this->output( sprintf( "total:             %-10d %6.2f%%\n", $total, 100 ) );
+       
+               $hits = intval($wgMemc->get(wfMemcKey('stats','image_cache_hit')));
+               $misses = intval($wgMemc->get(wfMemcKey('stats','image_cache_miss')));
+               $updates = intval($wgMemc->get(wfMemcKey('stats','image_cache_update')));
+               $total = $hits + $misses;
+               $this->output("\nImage cache\n");
+               $this->output( sprintf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 ) );
+               $this->output( sprintf( "misses:            %-10d %6.2f%%\n", $misses, $misses/$total*100 ) );
+               $this->output( sprintf( "updates:           %-10d\n", $updates ) );
+       
+               $hits = intval($wgMemc->get(wfMemcKey('stats','diff_cache_hit')));
+               $misses = intval($wgMemc->get(wfMemcKey('stats','diff_cache_miss')));
+               $uncacheable = intval($wgMemc->get(wfMemcKey('stats','diff_uncacheable')));
+               $total = $hits + $misses + $uncacheable;
+               $this->output("\nDiff cache\n");
+               $this->output( sprintf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 ) );
+               $this->output( sprintf( "misses:            %-10d %6.2f%%\n", $misses, $misses/$total*100 ) );
+               $this->output( sprintf( "uncacheable:       %-10d %6.2f%%\n", $uncacheable, $uncacheable/$total*100 ) );
+       }
 }
-print "Requests\n";
-printf( "with session:      %-10d %6.2f%%\n", $session, $session/$total*100 );
-printf( "without session:   %-10d %6.2f%%\n", $noSession, $noSession/$total*100 );
-printf( "total:             %-10d %6.2f%%\n", $total, 100 );
-
-
-print "\nParser cache\n";
-$hits = intval($wgMemc->get(wfMemcKey('stats','pcache_hit')));
-$invalid = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_invalid')));
-$expired = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_expired')));
-$absent = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_absent')));
-$stub = intval($wgMemc->get(wfMemcKey('stats','pcache_miss_stub')));
-$total = $hits + $invalid + $expired + $absent + $stub;
-printf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 );
-printf( "invalid:           %-10d %6.2f%%\n", $invalid, $invalid/$total*100 );
-printf( "expired:           %-10d %6.2f%%\n", $expired, $expired/$total*100 );
-printf( "absent:            %-10d %6.2f%%\n", $absent, $absent/$total*100 );
-printf( "stub threshold:    %-10d %6.2f%%\n", $stub, $stub/$total*100 );
-printf( "total:             %-10d %6.2f%%\n", $total, 100 );
-
-$hits = intval($wgMemc->get(wfMemcKey('stats','image_cache_hit')));
-$misses = intval($wgMemc->get(wfMemcKey('stats','image_cache_miss')));
-$updates = intval($wgMemc->get(wfMemcKey('stats','image_cache_update')));
-$total = $hits + $misses;
-print("\nImage cache\n");
-printf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 );
-printf( "misses:            %-10d %6.2f%%\n", $misses, $misses/$total*100 );
-printf( "updates:           %-10d\n", $updates );
-
-$hits = intval($wgMemc->get(wfMemcKey('stats','diff_cache_hit')));
-$misses = intval($wgMemc->get(wfMemcKey('stats','diff_cache_miss')));
-$uncacheable = intval($wgMemc->get(wfMemcKey('stats','diff_uncacheable')));
-$total = $hits + $misses + $uncacheable;
-print("\nDiff cache\n");
-printf( "hits:              %-10d %6.2f%%\n", $hits, $hits/$total*100 );
-printf( "misses:            %-10d %6.2f%%\n", $misses, $misses/$total*100 );
-printf( "uncacheable:       %-10d %6.2f%%\n", $uncacheable, $uncacheable/$total*100 );
+
+$maintClass = "CacheStats";
+require_once( DO_MAINTENANCE );
+
+
 
 
index b7b7df9..35fa640 100644 (file)
@@ -6,34 +6,35 @@
  * @ingroup Maintenance
  */
 
-$usage = <<<EOT
-Undelete a page
-Usage: php undelete.php [-u <user>] [-r <reason>] <pagename>
+require_once( "Maintenance.php" );
 
-EOT;
+class Undelete extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Undelete a page";
+               $this->addOption( 'u', 'The user to perform the undeletion', false, true );
+               $this->addOption( 'r', 'The reason to undelete', false, true );
+               $this->addArgs( array( 'pagename' ) );
+       }
 
-$optionsWithArgs = array( 'u', 'r' );
-require_once( 'commandLine.inc' );
+       public function execute() {
+               global $wgUser;
 
-$user = 'Command line script';
-$reason = '';
+               $user = $this->getOption( 'u', 'Command line script' );
+               $reason = $this->getOption( 'r', '' );
+               $pageName = $this->getArg();
 
-if ( isset( $options['u'] ) ) {
-       $user = $options['u'];
+               $title = Title::newFromText( $pageName );
+               if ( !$title ) {
+                       $this->error( "Invalid title", true );
+               }
+               $wgUser = User::newFromName( $user );
+               $archive = new PageArchive( $title );
+               $this->output( "Undeleting " . $title->getPrefixedDBkey() . '...' );
+               $archive->undelete( array(), $reason );
+               $this->output( "done\n" );
+       }
 }
-if ( isset( $options['r'] ) ) {
-       $reason = $options['r'];
-}
-$pageName = @$args[0];
-$title = Title::newFromText( $pageName );
-if ( !$title ) {
-       echo $usage;
-       exit( 1 );
-}
-$wgUser = User::newFromName( $user );
-$archive = new PageArchive( $title );
-echo "Undeleting " . $title->getPrefixedDBkey() . '...';
-$archive->undelete( array(), $reason );
-echo "done\n";
-
 
+$maintClass = "Undelete";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/updateArticleCount.inc b/maintenance/updateArticleCount.inc
deleted file mode 100644 (file)
index a847a2e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-/**
- * Support class for the updateArticleCount.php maintenance script
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-class ArticleCounter {
-
-       var $dbr;
-       var $namespaces;
-       
-       function ArticleCounter() {
-               global $wgContentNamespaces;
-               $this->namespaces = $wgContentNamespaces;
-               $this->dbr = wfGetDB( DB_SLAVE );
-       }
-       
-       /**
-        * Produce a comma-delimited set of namespaces
-        * Includes paranoia
-        *
-        * @return string
-        */
-       function makeNsSet() {
-               foreach( $this->namespaces as $namespace )
-                       $namespaces[] = intval( $namespace );
-               return implode( ', ', $namespaces );
-       }
-       
-       /**
-        * Produce SQL for the query
-        *
-        * @return string
-        */
-       function makeSql() {
-               list( $page, $pagelinks ) = $this->dbr->tableNamesN( 'page', 'pagelinks' );
-               $nsset = $this->makeNsSet();
-               return "SELECT COUNT(DISTINCT page_namespace, page_title) AS pagecount " .
-                       "FROM $page, $pagelinks " .
-                       "WHERE pl_from=page_id and page_namespace IN ( $nsset ) " .
-                       "AND page_is_redirect = 0 AND page_len > 0";
-       }
-       
-       /**
-        * Count the number of valid content pages in the wiki
-        *
-        * @return mixed Integer, or false if there's a problem
-        */
-       function count() {
-               $res = $this->dbr->query( $this->makeSql(), __METHOD__ );
-               $row = $this->dbr->fetchObject( $res );
-               $this->dbr->freeResult( $res );
-               return $row->pagecount;
-       }
-
-}
-
-
index 15033ad..3b348b5 100644 (file)
@@ -3,38 +3,99 @@
  * Maintenance script to provide a better count of the number of articles
  * and update the site statistics table, if desired
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  * @author Rob Church <robchur@gmail.com>
  */
 
-$options = array( 'update', 'help' );
-require_once( 'commandLine.inc' );
-require_once( 'updateArticleCount.inc' );
-echo( "Update Article Count\n\n" );
+require_once( "Maintenance.php" );
 
-if( isset( $options['help'] ) && $options['help'] ) {
-       echo( "Usage: php updateArticleCount.php [--update]\n\n" );
-       echo( "--update : Update site statistics table\n" );
-       exit( 0 );
-}
+class UpdateArticleCount extends Maintenance {
+
+       // Content namespaces
+       private $namespaces;
+
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Count of the number of articles and update the site statistics table";
+               $this->addOption( 'update', 'Update the site_stats table with the new count' );
+       }
+
+       public function execute() {
+               global $wgContentNamespaces;
+               $this->namespaces = $wgContentNamespaces;
+               $this->output( "Counting articles..." );
+               $result = $this->count();
+       
+               if( $result !== false ) {
+                       $this->output( "found {$result}.\n" );
+                       if( isset( $options['update'] ) && $options['update'] ) {
+                               $this->output( "Updating site statistics table... " );
+                               $dbw = wfGetDB( DB_MASTER );
+                               $dbw->update( 'site_stats', array( 'ss_good_articles' => $result ), array( 'ss_row_id' => 1 ), __METHOD__ );
+                               $this->output( "done.\n" );
+                       } else {
+                               $this->output( "To update the site statistics table, run the script with the --update option.\n" );
+                       }
+               } else {
+                       $this->output( "failed.\n" );
+               }
+       }
+
+       /**
+        * Produce a comma-delimited set of namespaces
+        * Includes paranoia
+        *
+        * @return string
+        */
+       private function makeNsSet() {
+               foreach( $this->namespaces as $namespace )
+                       $namespaces[] = intval( $namespace );
+               return implode( ', ', $namespaces );
+       }
+
+       /**
+        * Produce SQL for the query
+        *
+        * @param $dbr Database handle
+        * @return string
+        */
+       private function makeSql( $dbr ) {
+               list( $page, $pagelinks ) = $dbr->tableNamesN( 'page', 'pagelinks' );
+               $nsset = $this->makeNsSet();
+               return "SELECT COUNT(DISTINCT page_namespace, page_title) AS pagecount " .
+                       "FROM $page, $pagelinks " .
+                       "WHERE pl_from=page_id and page_namespace IN ( $nsset ) " .
+                       "AND page_is_redirect = 0 AND page_len > 0";
+       }
 
-echo( "Counting articles..." );
-$counter = new ArticleCounter();
-$result = $counter->count();
-
-if( $result !== false ) {
-       echo( "found {$result}.\n" );
-       if( isset( $options['update'] ) && $options['update'] ) {
-               echo( "Updating site statistics table... " );
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update( 'site_stats', array( 'ss_good_articles' => $result ), array( 'ss_row_id' => 1 ), __METHOD__ );
-               echo( "done.\n" );
-       } else {
-               echo( "To update the site statistics table, run the script with the --update option.\n" );
+       /**
+        * Count the number of valid content pages in the wiki
+        *
+        * @return mixed Integer, or false if there's a problem
+        */
+       private function count() {
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->query( $this->makeSql( $dbr ), __METHOD__ );
+               $row = $dbr->fetchObject( $res );
+               $dbr->freeResult( $res );
+               return $row->pagecount;
        }
-} else {
-       echo( "failed.\n" );
 }
-echo( "\n" );
 
+$maintClass = "UpdateArticleCount";
+require_once( DO_MAINTENANCE );
index 59879ea..52af600 100644 (file)
  * schema change. All remaining page_restriction column values are moved
  * to the new table.
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
 
-define( 'BATCH_SIZE', 100 );
+require_once( "Maintenance.php" );
 
-require_once 'commandLine.inc';
-       
-$db =& wfGetDB( DB_MASTER );
-if ( !$db->tableExists( 'page_restrictions' ) ) {
-       echo "page_restrictions does not exist\n";
-       exit( 1 );
-}
+class UpdateRestrictions extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Updates page_restrictions table from old page_restriction column";
+               $this->setBatchSize( 100 );
+       }
 
-migrate_page_restrictions( $db );
+       public function execute() {
+               $db = wfGetDB( DB_MASTER );
+               if( !$db->tableExists( 'page_restrictions' ) ) {
+                       $this->error( "page_restrictions table does not exist\n", true );
+               }
 
-function migrate_page_restrictions( $db ) {
-       $start = $db->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ );
-       if( !$start ) {
-               die("Nothing to do.\n");
-       }
-       $end = $db->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ );
+               $start = $db->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+               if( !$start ) {
+                       $this->error( "Nothing to do.\n", true );
+               }
+               $end = $db->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
        
-       # Do remaining chunk
-       $end += BATCH_SIZE - 1;
-       $blockStart = $start;
-       $blockEnd = $start + BATCH_SIZE - 1;
-       $encodedExpiry = 'infinity';
-       while( $blockEnd <= $end ) {
-               echo "...doing page_id from $blockStart to $blockEnd\n";
-               $cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !=''";
-               $res = $db->select( 'page', array('page_id','page_namespace','page_restrictions'), $cond, __FUNCTION__ );
-               $batch = array();
-               while( $row = $db->fetchObject( $res ) ) {
-                       $oldRestrictions = array();
-                       foreach( explode( ':', trim( $row->page_restrictions ) ) as $restrict ) {
-                               $temp = explode( '=', trim( $restrict ) );
-                               // Make sure we are not settings restrictions to ""
-                               if( count($temp) == 1 && $temp[0] ) {
-                                       // old old format should be treated as edit/move restriction
-                                       $oldRestrictions["edit"] = trim( $temp[0] );
-                                       $oldRestrictions["move"] = trim( $temp[0] );
-                               } else if( $temp[1] ) {
-                                       $oldRestrictions[$temp[0]] = trim( $temp[1] );
+               # Do remaining chunk
+               $end += $this->mBatchSize - 1;
+               $blockStart = $start;
+               $blockEnd = $start + $this->mBatchSize - 1;
+               $encodedExpiry = 'infinity';
+               while( $blockEnd <= $end ) {
+                       $this->output( "...doing page_id from $blockStart to $blockEnd\n" );
+                       $cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !=''";
+                       $res = $db->select( 'page', array('page_id','page_namespace','page_restrictions'), $cond, __METHOD__ );
+                       $batch = array();
+                       while( $row = $db->fetchObject( $res ) ) {
+                               $oldRestrictions = array();
+                               foreach( explode( ':', trim( $row->page_restrictions ) ) as $restrict ) {
+                                       $temp = explode( '=', trim( $restrict ) );
+                                       // Make sure we are not settings restrictions to ""
+                                       if( count($temp) == 1 && $temp[0] ) {
+                                               // old old format should be treated as edit/move restriction
+                                               $oldRestrictions["edit"] = trim( $temp[0] );
+                                               $oldRestrictions["move"] = trim( $temp[0] );
+                                       } else if( $temp[1] ) {
+                                               $oldRestrictions[$temp[0]] = trim( $temp[1] );
+                                       }
+                               }
+                               # Clear invalid columns
+                               if( $row->page_namespace == NS_MEDIAWIKI ) {
+                                       $db->update( 'page', array( 'page_restrictions' => '' ),
+                                               array( 'page_id' => $row->page_id ), __FUNCTION__ );
+                                       $this->output( "...removed dead page_restrictions column for page {$row->page_id}\n" );
+                               }
+                               # Update restrictions table
+                               foreach( $oldRestrictions as $action => $restrictions ) {
+                                       $batch[] = array( 
+                                               'pr_page' => $row->page_id,
+                                               'pr_type' => $action,
+                                               'pr_level' => $restrictions,
+                                               'pr_cascade' => 0,
+                                               'pr_expiry' => $encodedExpiry
+                                       );
                                }
                        }
-                       # Clear invalid columns
-                       if( $row->page_namespace == NS_MEDIAWIKI ) {
-                               $db->update( 'page', array( 'page_restrictions' => '' ),
-                                       array( 'page_id' => $row->page_id ), __FUNCTION__ );
-                               echo "...removed dead page_restrictions column for page {$row->page_id}\n";
-                       }
-                       # Update restrictions table
-                       foreach( $oldRestrictions as $action => $restrictions ) {
-                               $batch[] = array( 
-                                       'pr_page' => $row->page_id,
-                                       'pr_type' => $action,
-                                       'pr_level' => $restrictions,
-                                       'pr_cascade' => 0,
-                                       'pr_expiry' => $encodedExpiry
-                               );
-                       }
-               }
-               # We use insert() and not replace() as Article.php replaces
-               # page_restrictions with '' when protected in the restrictions table
-               if ( count( $batch ) ) {
-                       $ok = $db->deadlockLoop( array( $db, 'insert' ), 'page_restrictions', 
-                               $batch, __FUNCTION__, array( 'IGNORE' ) );
-                       if( !$ok ) {
-                               throw new MWException( "Deadlock loop failed wtf :(" );
+                       # We use insert() and not replace() as Article.php replaces
+                       # page_restrictions with '' when protected in the restrictions table
+                       if ( count( $batch ) ) {
+                               $ok = $db->deadlockLoop( array( $db, 'insert' ), 'page_restrictions', 
+                                       $batch, __FUNCTION__, array( 'IGNORE' ) );
+                               if( !$ok ) {
+                                       throw new MWException( "Deadlock loop failed wtf :(" );
+                               }
                        }
+                       $blockStart += $this->mBatchSize - 1;
+                       $blockEnd += $this->mBatchSize - 1;
+                       wfWaitForSlaves( 5 );
                }
-               $blockStart += BATCH_SIZE - 1;
-               $blockEnd += BATCH_SIZE - 1;
-               wfWaitForSlaves( 5 );
+               $this->output( "...removing dead rows from page_restrictions\n" );
+               // Kill any broken rows from previous imports
+               $db->delete( 'page_restrictions', array( 'pr_level' => '' ) );
+               // Kill other invalid rows
+               $db->deleteJoin( 'page_restrictions', 'page', 'pr_page', 'page_id', array('page_namespace' => NS_MEDIAWIKI) );
+               $this->output( "...Done!\n" );
        }
-       echo "...removing dead rows from page_restrictions\n";
-       // Kill any broken rows from previous imports
-       $db->delete( 'page_restrictions', array( 'pr_level' => '' ) );
-       // Kill other invalid rows
-       $db->deleteJoin( 'page_restrictions', 'page', 'pr_page', 'page_id', array('page_namespace' => NS_MEDIAWIKI) );
-       echo "...Done!\n";
 }
 
-
+$maintClass = "UpdateRestrictions";
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/updateSearchIndex.inc b/maintenance/updateSearchIndex.inc
deleted file mode 100644 (file)
index ed7e46a..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-/**
- * @file
- * @ingroup Maintenance
- */
-
-/** */
-function updateSearchIndex( $start, $end, $maxLockTime, $quiet ) {
-       global $wgQuiet;
-       global $wgDisableSearchUpdate;
-
-       $fname = "updateSearchIndex";
-
-       $wgQuiet = $quiet;
-       $wgDisableSearchUpdate = false;
-
-       $dbw = wfGetDB( DB_MASTER );
-       $recentchanges = $dbw->tableName( 'recentchanges' );
-
-       output( "Updating searchindex between $start and $end\n" );
-
-       # Select entries from recentchanges which are on top and between the specified times
-       $start = $dbw->strencode( $dbw->timestamp( $start ) );
-       $end = $dbw->strencode( $dbw->timestamp( $end ) );
-
-       $page = $dbw->tableName( 'page' );
-       $sql = "SELECT rc_cur_id,rc_type,rc_moved_to_ns,rc_moved_to_title FROM $recentchanges
-         JOIN $page ON rc_cur_id=page_id AND rc_this_oldid=page_latest
-         WHERE rc_timestamp BETWEEN '$start' AND '$end'
-         ";
-       $res = $dbw->query( $sql, $fname );
-       
-
-       # Lock searchindex
-       if ( $maxLockTime ) {
-               output( "   --- Waiting for lock ---" );
-               lockSearchindex( $dbw );
-               $lockTime = time();
-               output( "\n" );
-       }
-
-       # Loop through the results and do a search update
-       while ( $row = $dbw->fetchObject( $res ) ) {
-               # Allow reads to be processed
-               if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
-                       output( "    --- Relocking ---" );
-                       relockSearchindex( $dbw );
-                       $lockTime = time();
-                       output( "\n" );
-               }
-               if ( $row->rc_type == RC_LOG ) {
-                       continue;
-               } elseif ( $row->rc_type == RC_MOVE || $row->rc_type == RC_MOVE_OVER_REDIRECT ) {
-                       # Rename searchindex entry
-                       $titleObj = Title::makeTitle( $row->rc_moved_to_ns, $row->rc_moved_to_title );
-                       $title = $titleObj->getPrefixedDBkey();
-                       output( "$title..." );
-                       $u = new SearchUpdate( $row->rc_cur_id, $title, false );
-                       output( "\n" );
-               } else {
-                       // Get current revision
-                       $rev = Revision::loadFromPageId( $dbw, $row->rc_cur_id );
-                       if( $rev ) {
-                               $titleObj = $rev->getTitle();
-                               $title = $titleObj->getPrefixedDBkey();
-                               output( $title );
-                               # Update searchindex
-                               $u = new SearchUpdate( $row->rc_cur_id, $titleObj->getText(), $rev->getText() );
-                               $u->doUpdate();
-                               output( "\n" );
-                       }
-               }
-       }
-
-       # Unlock searchindex
-       if ( $maxLockTime ) {
-               output( "    --- Unlocking --" );
-               $dbw->unlockTables( 'updateSearchIndex.inc ' . __METHOD__ );
-               output( "\n" );
-       }
-       output( "Done\n" );
-}
-
-function lockSearchindex( &$db ) {
-       $write = array( 'searchindex' );
-       $read = array( 'page', 'revision', 'text', 'interwiki' );
-       $db->lockTables( $read, $write, 'updateSearchIndex.inc ' . __METHOD__ );
-}
-
-# Unlock and lock again
-# Since the lock is low-priority, queued reads will be able to complete
-function relockSearchindex( &$db ) {
-       $db->unlockTables( 'updateSearchIndex.inc ' . __METHOD__ );
-       lockSearchindex( $db );
-}
-
-function output( $text ) {
-       global $wgQuiet;
-       if ( !$wgQuiet ) {
-               print $text;
-       }
-}
index 5fa24ad..4750015 100644 (file)
  * Usage: php updateSearchIndex.php [-s START] [-e END] [-p POSFILE] [-l LOCKTIME] [-q]
  * Where START is the starting timestamp
  * END is the ending timestamp
- * POSFILE is a file to load timestamps from and save them to, searchUpdate.pos by default
- * LOCKTIME is how long the searchindex and cur tables will be locked for
+ * POSFILE is a file to load timestamps from and save them to, searchUpdate.WIKI_ID.pos by default
+ * LOCKTIME is how long the searchindex and revision tables will be locked for
  * -q means quiet
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
+require_once( "Maintenance.php" );
 
-/** */
-$optionsWithArgs = array( 's', 'e', 'p' );
+class UpdateSearchIndex extends Maintenance {
 
-require_once( 'commandLine.inc' );
-require_once( 'updateSearchIndex.inc' );
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Script for periodic off-peak updating of the search index";
+               $this->addOption( 's', 'starting timestamp', false, true );
+               $this->addOption( 'e', 'Ending timestamp', false, true );
+               $this->addOption( 'p', 'File for saving/loading timestamps, searchUpdate.WIKI_ID.pos by default', false, true );
+               $this->addOption( 'l', 'How long the searchindex and revision tables will be locked for', false, true );
+       }
 
-if ( isset( $options['p'] ) ) {
-       $posFile = $options['p'];
-} else {
-       $posFile = 'searchUpdate.' . wfWikiId() . '.pos';
-}
+       public function execute() {
+               $posFile = $this->getOption( 'p', 'searchUpdate.' . wfWikiId() . '.pos' );
+               $end = $this->getOption( 'e', wfTimestampNow() );
+               if ( $this->hasOption( 's' ) ) {
+                       $start = $this->getOption('s');
+               } elseif( is_readable( 'searchUpdate.pos' ) ) {
+                       # B/c to the old position file name which was hardcoded
+                       # We can safely delete the file when we're done though.
+                       $start = file_get_contents( 'searchUpdate.pos' );
+                       unlink( 'searchUpdate.pos' );
+               } else {
+                       $start = @file_get_contents( $posFile );
+                       if ( !$start ) {
+                               $start = wfTimestamp( TS_MW, time() - 86400 );
+                       }
+               }
+               $lockTime = $this->getOption( 'l', 20 );
+               
+               $this->doUpdateSearchIndex( $start, $end, $lockTime );
+               $file = fopen( $posFile, 'w' );
+               fwrite( $file, $end );
+               fclose( $file );
+       }
+       
+       private function doUpdateSearchIndex( $start, $end, $maxLockTime ) {
+               global $wgDisableSearchUpdate;
 
-if ( isset( $options['e'] ) ) {
-       $end = $options['e'];
-} else {
-       $end = wfTimestampNow();
-}
+               $wgDisableSearchUpdate = false;
 
-if ( isset( $options['s'] ) ) {
-       $start = $options['s'];
-} elseif( is_readable( 'searchUpdate.pos' ) ) {
-       # B/c to the old position file name which was hardcoded
-       # We can safely delete the file when we're done though.
-       $start = file_get_contents( 'searchUpdate.pos' );
-       unlink( 'searchUpdate.pos' );
-} else {
-       $start = @file_get_contents( $posFile );
-       if ( !$start ) {
-               $start = wfTimestamp( TS_MW, time() - 86400 );
-       }
-}
+               $dbw = wfGetDB( DB_MASTER );
+               $recentchanges = $dbw->tableName( 'recentchanges' );
 
-if ( isset( $options['l'] ) ) {
-       $lockTime = $options['l'];
-} else {
-       $lockTime = 20;
-}
+               $this->output( "Updating searchindex between $start and $end\n" );
 
-$quiet = (bool)(@$options['q']);
+               # Select entries from recentchanges which are on top and between the specified times
+               $start = $dbw->strencode( $start );
+               $end = $dbw->strencode( $end );
 
-updateSearchIndex( $start, $end, $lockTime, $quiet );
+               $page = $dbw->tableName( 'page' );
+               $sql = "SELECT rc_cur_id,rc_type,rc_moved_to_ns,rc_moved_to_title FROM $recentchanges
+                 JOIN $page ON rc_cur_id=page_id AND rc_this_oldid=page_latest
+                 WHERE rc_timestamp BETWEEN '$start' AND '$end'
+                 ";
+               $res = $dbw->query( $sql, __METHOD__ );
 
-$file = fopen( $posFile, 'w' );
-fwrite( $file, $end );
-fclose( $file );
 
+               # Lock searchindex
+               if ( $maxLockTime ) {
+                       $this->output( "   --- Waiting for lock ---" );
+                       $this->lockSearchindex( $dbw );
+                       $lockTime = time();
+                       $this->output( "\n" );
+               }
+
+               # Loop through the results and do a search update
+               while ( $row = $dbw->fetchObject( $res ) ) {
+                       # Allow reads to be processed
+                       if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
+                               $this->output( "    --- Relocking ---" );
+                               $this->relockSearchindex( $dbw );
+                               $lockTime = time();
+                               $this->output( "\n" );
+                       }
+                       if ( $row->rc_type == RC_LOG ) {
+                               continue;
+                       } elseif ( $row->rc_type == RC_MOVE || $row->rc_type == RC_MOVE_OVER_REDIRECT ) {
+                               # Rename searchindex entry
+                               $titleObj = Title::makeTitle( $row->rc_moved_to_ns, $row->rc_moved_to_title );
+                               $title = $titleObj->getPrefixedDBkey();
+                               $this->output( "$title..." );
+                               $u = new SearchUpdate( $row->rc_cur_id, $title, false );
+                               $this->output( "\n" );
+                       } else {
+                               // Get current revision
+                               $rev = Revision::loadFromPageId( $dbw, $row->rc_cur_id );
+                               if( $rev ) {
+                                       $titleObj = $rev->getTitle();
+                                       $title = $titleObj->getPrefixedDBkey();
+                                       $this->output( $title );
+                                       # Update searchindex
+                                       $u = new SearchUpdate( $row->rc_cur_id, $titleObj->getText(), $rev->getText() );
+                                       $u->doUpdate();
+                                       $this->output( "\n" );
+                               }
+                       }
+               }
+
+               # Unlock searchindex
+               if ( $maxLockTime ) {
+                       $this->output( "    --- Unlocking --" );
+                       $this->unlockSearchindex( $dbw );
+                       $this->output( "\n" );
+               }
+               $this->output( "Done\n" );
+       }
+
+       /**
+        * Lock the search index
+        * @param &$db Database object
+        */
+       private function lockSearchindex( &$db ) {
+               $write = array( 'searchindex' );
+               $read = array( 'page', 'revision', 'text', 'interwiki' );
+               $items = array();
+       
+               foreach( $write as $table ) {
+                       $items[] = $db->tableName( $table ) . ' LOW_PRIORITY WRITE';
+               }
+               foreach( $read as $table ) {
+                       $items[] = $db->tableName( $table ) . ' READ';
+               }
+               $sql = "LOCK TABLES " . implode( ',', $items );
+               $db->query( $sql, 'updateSearchIndex.php ' . __METHOD__ );
+       }
+
+       /**
+        * Unlock the tables
+        * @param &$db Database object
+        */
+       private function unlockSearchindex( &$db ) {
+               $db->query( "UNLOCK TABLES", 'updateSearchIndex.php ' . __METHOD__ );
+       }
+       
+       /**
+        * Unlock and lock again
+        * Since the lock is low-priority, queued reads will be able to complete
+        * @param &$db Database object
+        */
+       private function relockSearchindex( &$db ) {
+               $this->unlockSearchindex( $db );
+               $this->lockSearchindex( $db );
+       }
+}
 
+$maintClass = "UpdateSearchIndex";
+require_once( DO_MAINTENANCE );
index 3eaa620..5bd18c3 100644 (file)
  * Run this script periodically if you have miser mode enabled, to refresh the
  * caches
  *
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
  */
-$options = array('only','help');
-
-require_once( 'commandLine.inc' );
-
-require_once( "$IP/includes/SpecialPage.php" );
-require_once( "$IP/includes/QueryPage.php" );
-
-if(@$options['help']) {
-       print "usage:updateSpecialPages.php [--help] [--only=page]\n";
-       print "  --help      : this help message\n";
-       print "  --list      : list special pages names\n";
-       print "  --only=page : only update 'page'. Ex: --only=BrokenRedirects\n";
-       print "  --override  : update even pages which have had updates disabled\n";
-       wfDie();
-}
-
-$wgOut->disable();
-$dbw = wfGetDB( DB_MASTER );
-
-foreach( $wgSpecialPageCacheUpdates as $special => $call ) {
-       if( !is_callable($call) ) {
-               print "Uncallable function $call!\n";
-               continue;
-       }
-       $t1 = explode( ' ', microtime() );
-       call_user_func( $call, $dbw );
-       $t2 = explode( ' ', microtime() );
-       printf( '%-30s ', $special );
-       $elapsed = ($t2[0] - $t1[0]) + ($t2[1] - $t1[1]);
-       $hours = intval( $elapsed / 3600 );
-       $minutes = intval( $elapsed % 3600 / 60 );
-       $seconds = $elapsed - $hours * 3600 - $minutes * 60;
-       if ( $hours ) {
-               print $hours . 'h ';
-       }
-       if ( $minutes ) {
-               print $minutes . 'm ';
-       }
-       printf( "completed in %.2fs\n", $seconds );
-       # Wait for the slave to catch up
-       wfWaitForSlaves( 5 );
-}
-
-foreach( $wgQueryPages as $page ) {
-       @list( $class, $special, $limit ) = $page;
-
-       # --list : just show the name of pages
-       if( @$options['list'] ) {
-               print "$special\n";
-               continue;
-       }
+require_once( "Maintenance.php" );
 
-       if ( !isset( $options['override'] ) && $wgDisableQueryPageUpdate && in_array( $special, $wgDisableQueryPageUpdate ) ) {
-               printf("%-30s disabled\n", $special);
-               continue;
+class UpdateSpecialPages extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->addOption( 'list', 'List special page names' );
+               $this->addOption( 'only', 'Only update "page". Ex: --only=BrokenRedirects', false, true );
+               $this->addOption( 'override', 'Also update pages that have updates disabled' );
        }
 
-       $specialObj = SpecialPage::getPage( $special );
-       if ( !$specialObj ) {
-               print "No such special page: $special\n";
-               exit;
-       }
-       if ( !class_exists( $class ) ) {
-               $file = $specialObj->getFile();
-               require_once( $file );
-       }
-       $queryPage = new $class;
+       public function execute() {
+               global $wgOut;
+               $wgOut->disable();
+               $dbw = wfGetDB( DB_MASTER );
 
-       if( !isset($options['only']) or $options['only'] == $queryPage->getName() ) {
-               printf( '%-30s ',  $special );
-               if ( $queryPage->isExpensive() ) {
+               foreach( $wgSpecialPageCacheUpdates as $special => $call ) {
+                       if( !is_callable($call) ) {
+                               $this->error( "Uncallable function $call!\n" );
+                               continue;
+                       }
                        $t1 = explode( ' ', microtime() );
-                       # Do the query
-                       $num = $queryPage->recache( $limit === null ? $wgQueryCacheLimit : $limit );
+                       call_user_func( $call, $dbw );
                        $t2 = explode( ' ', microtime() );
-                       if ( $num === false ) {
-                               print "FAILED: database error\n";
-                       } else {
-                               print "got $num rows in ";
-
-                               $elapsed = ($t2[0] - $t1[0]) + ($t2[1] - $t1[1]);
-                               $hours = intval( $elapsed / 3600 );
-                               $minutes = intval( $elapsed % 3600 / 60 );
-                               $seconds = $elapsed - $hours * 3600 - $minutes * 60;
-                               if ( $hours ) {
-                                       print $hours . 'h ';
+                       $this->output( sprintf( '%-30s ', $special ) );
+                       $elapsed = ($t2[0] - $t1[0]) + ($t2[1] - $t1[1]);
+                       $hours = intval( $elapsed / 3600 );
+                       $minutes = intval( $elapsed % 3600 / 60 );
+                       $seconds = $elapsed - $hours * 3600 - $minutes * 60;
+                       if ( $hours ) {
+                               $this->output( $hours . 'h ' );
+                       }
+                       if ( $minutes ) {
+                               $this->output( $minutes . 'm ' );
+                       }
+                       $this->output( sprintf( "completed in %.2fs\n", $seconds ) );
+                       # Wait for the slave to catch up
+                       wfWaitForSlaves( 5 );
+               }
+       
+               foreach( $wgQueryPages as $page ) {
+                       @list( $class, $special, $limit ) = $page;
+       
+                       # --list : just show the name of pages
+                       if( $this->hasOption('list') ) {
+                               $this->output( "$special\n" );
+                               continue;
+                       }
+       
+                       if ( $this->hasOption('override') && $wgDisableQueryPageUpdate && in_array( $special, $wgDisableQueryPageUpdate ) ) {
+                               $this->output( sprintf( "%-30s disabled\n", $special ) );
+                               continue;
+                       }
+       
+                       $specialObj = SpecialPage::getPage( $special );
+                       if ( !$specialObj ) {
+                               $this->output( "No such special page: $special\n" );
+                               exit;
+                       }
+                       if ( !class_exists( $class ) ) {
+                               $file = $specialObj->getFile();
+                               require_once( $file );
+                       }
+                       $queryPage = new $class;
+       
+                       if( !$this->hasOption('only') || $this->getOption('only') == $queryPage->getName() ) {
+                               $this->output( sprintf( '%-30s ',  $special ) );
+                               if ( $queryPage->isExpensive() ) {
+                                       $t1 = explode( ' ', microtime() );
+                                       # Do the query
+                                       $num = $queryPage->recache( $limit === null ? $wgQueryCacheLimit : $limit );
+                                       $t2 = explode( ' ', microtime() );
+                                       if ( $num === false ) {
+                                               $this->output( "FAILED: database error\n" );
+                                       } else {
+                                               $this->output( "got $num rows in " );
+       
+                                               $elapsed = ($t2[0] - $t1[0]) + ($t2[1] - $t1[1]);
+                                               $hours = intval( $elapsed / 3600 );
+                                               $minutes = intval( $elapsed % 3600 / 60 );
+                                               $seconds = $elapsed - $hours * 3600 - $minutes * 60;
+                                               if ( $hours ) {
+                                                       $this->output( $hours . 'h ' );
+                                               }
+                                               if ( $minutes ) {
+                                                       $this->output( $minutes . 'm ' );
+                                               }
+                                               $this->output( sprintf( "%.2fs\n", $seconds ) );
                                }
-                               if ( $minutes ) {
-                                       print $minutes . 'm ';
+                               # Reopen any connections that have closed
+                               if ( !wfGetLB()->pingAll())  {
+                                       $this->output( "\n" );
+                                       do {
+                                               $this->error( "Connection failed, reconnecting in 10 seconds...\n" );
+                                               sleep(10);
+                                       } while ( !wfGetLB()->pingAll() );
+                                       $this->output( "Reconnected\n\n" );
+                               } else {
+                                       # Commit the results
+                                       $dbw->immediateCommit();
                                }
-                               printf( "%.2fs\n", $seconds );
-               }
-               # Reopen any connections that have closed
-               if ( !wfGetLB()->pingAll())  {
-                       print "\n";
-                       do {
-                               print "Connection failed, reconnecting in 10 seconds...\n";
-                               sleep(10);
-                       } while ( !wfGetLB()->pingAll() );
-                       print "Reconnected\n\n";
-               } else {
-                       # Commit the results
-                       $dbw->immediateCommit();
-               }
-               # Wait for the slave to catch up
-               wfWaitForSlaves( 5 );
-               } else {
-                       print "cheap, skipped\n";
+                               # Wait for the slave to catch up
+                               wfWaitForSlaves( 5 );
+                               } else {
+                                       $this->output( "cheap, skipped\n" );
+                               }
+                       }
                }
        }
 }
+
+$maintClass = "UpdateSpecialPages";
+require_once( DO_MAINTENANCE );
index 8304b25..0d5975a 100644 (file)
@@ -216,7 +216,7 @@ function rename_table( $from, $to, $patch ) {
                        wfOut( "...can't move table $from to $to, $to already exists.\n" );
                } else {
                        wfOut( "Moving table $from to $to..." );
-                       dbsource( archive($patch), $wgDatabase );
+                       $wgDatabase->sourceFile( archive($patch) );
                        wfOut( "ok\n" );
                }
        } else {
@@ -233,9 +233,9 @@ function add_table( $name, $patch, $fullpath=false ) {
        } else {
                wfOut( "Creating $name table..." );
                if( $fullpath ) {
-                       dbsource( $patch, $wgDatabase );
+                       $wgDatabase->sourceFile( $patch );
                } else {
-                       dbsource( archive($patch), $wgDatabase );
+                       $wgDatabase->sourceFile( archive($patch) );
                }
                wfOut( "ok\n" );
        }
@@ -250,9 +250,9 @@ function add_field( $table, $field, $patch, $fullpath=false ) {
        } else {
                wfOut( "Adding $field field to table $table..." );
                if( $fullpath ) {
-                       dbsource( $patch, $wgDatabase );
+                       $wgDatabase->sourceFile( $patch );
                } else {
-                       dbsource( archive($patch), $wgDatabase );
+                       $wgDatabase->sourceFile( archive($patch) );
                }
                wfOut( "ok\n" );
        }
@@ -265,9 +265,9 @@ function add_index( $table, $index, $patch, $fullpath=false ) {
        } else {
                wfOut( "Adding $index key to table $table... " );
                if( $fullpath ) {
-                       dbsource( $patch, $wgDatabase );
+                       $wgDatabase->sourceFile( $patch );
                } else {
-                       dbsource( archive($patch), $wgDatabase );
+                       $wgDatabase->sourceFile( archive($patch) );
                }
                wfOut( "ok\n" );
        }
@@ -281,10 +281,10 @@ function do_interwiki_update() {
                return true;
        }
        wfOut( "Creating interwiki table: " );
-       dbsource( archive("patch-interwiki.sql") );
+       $wgDatabase->sourceFile( archive("patch-interwiki.sql") );
        wfOut( "ok\n" );
        wfOut( "Adding default interwiki definitions: " );
-       dbsource( "$IP/maintenance/interwiki.sql" );
+       $wgDatabase->sourceFile( "$IP/maintenance/interwiki.sql" );
        wfOut( "ok\n" );
 }
 
@@ -294,7 +294,7 @@ function do_index_update() {
        $meta = $wgDatabase->fieldInfo( "recentchanges", "rc_timestamp" );
        if( !$meta->isMultipleKey() ) {
                wfOut( "Updating indexes to 20031107: " );
-               dbsource( archive("patch-indexes.sql") );
+               $wgDatabase->sourceFile( archive("patch-indexes.sql") );
                wfOut( "ok\n" );
                return true;
        }
@@ -308,7 +308,7 @@ function do_image_index_update() {
        $meta = $wgDatabase->fieldInfo( "image", "img_major_mime" );
        if( !$meta->isMultipleKey() ) {
                wfOut( "Updating indexes to 20050912: " );
-               dbsource( archive("patch-mimesearch-indexes.sql") );
+               $wgDatabase->sourceFile( archive("patch-mimesearch-indexes.sql") );
                wfOut( "ok\n" );
                return true;
        }
@@ -322,7 +322,7 @@ function do_image_name_unique_update() {
                wfOut( "...image primary key already set.\n" );
        } else {
                wfOut( "Making img_name the primary key... " );
-               dbsource( archive("patch-image_name_primary.sql"), $wgDatabase );
+               $wgDatabase->sourceFile( archive("patch-image_name_primary.sql") );
                wfOut( "ok\n" );
        }
 }
@@ -333,7 +333,7 @@ function do_logging_timestamp_index() {
                wfOut( "...timestamp key on logging already exists.\n" );
        } else {
                wfOut( "Adding timestamp key on logging table... " );
-               dbsource( archive("patch-logging-times-index.sql"), $wgDatabase );
+               $wgDatabase->sourceFile( archive("patch-logging-times-index.sql") );
                wfOut( "ok\n" );
        }
 }
@@ -344,7 +344,7 @@ function do_archive_user_index() {
                wfOut( "...usertext,timestamp key on archive already exists.\n" );
        } else {
                wfOut( "Adding usertext,timestamp key on archive table... " );
-               dbsource( archive("patch-archive-user-index.sql"), $wgDatabase );
+               $wgDatabase->sourceFile( archive("patch-archive-user-index.sql") );
                wfOut( "ok\n" );
        }
 }
@@ -355,7 +355,7 @@ function do_image_user_index() {
                wfOut( "...usertext,timestamp key on image already exists.\n" );
        } else {
                wfOut( "Adding usertext,timestamp key on image table... " );
-               dbsource( archive("patch-image-user-index.sql"), $wgDatabase );
+               $wgDatabase->sourceFile( archive("patch-image-user-index.sql") );
                wfOut( "ok\n" );
        }
 }
@@ -366,7 +366,7 @@ function do_oldimage_user_index() {
                wfOut( "...usertext,timestamp key on oldimage already exists.\n" );
        } else {
                wfOut( "Adding usertext,timestamp key on oldimage table... " );
-               dbsource( archive("patch-oldimage-user-index.sql"), $wgDatabase );
+               $wgDatabase->sourceFile( archive("patch-oldimage-user-index.sql") );
                wfOut( "ok\n" );
        }
 }
@@ -379,7 +379,7 @@ function do_watchlist_update() {
        } else {
                wfOut( "Adding wl_notificationtimestamp field for email notification management." );
                /* ALTER TABLE watchlist ADD (wl_notificationtimestamp varchar(14) binary NOT NULL default '0'); */
-               dbsource( archive( 'patch-email-notification.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-email-notification.sql' ) );
                wfOut( "ok\n" );
        }
        # Check if we need to add talk page rows to the watchlist
@@ -445,7 +445,7 @@ function do_user_update() {
        global $wgDatabase;
        if( $wgDatabase->fieldExists( 'user', 'user_emailauthenticationtimestamp' ) ) {
                wfOut( "User table contains old email authentication field. Dropping... " );
-               dbsource( archive( 'patch-email-authentication.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-email-authentication.sql' ) );
                wfOut( "ok\n" );
        } else {
                wfOut( "...user table does not contain old email authentication field.\n" );
@@ -469,7 +469,7 @@ function check_bin( $table, $field, $patchFile ) {
                wfOut( "$table table has correct $field encoding.\n" );
        } else {
                wfOut( "Fixing $field encoding on $table table... " );
-               dbsource( archive( $patchFile ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( $patchFile ) );
                wfOut( "ok\n" );
        }
 }
@@ -644,7 +644,7 @@ function do_inverse_timestamp() {
        global $wgDatabase;
        if( $wgDatabase->fieldExists( 'revision', 'inverse_timestamp' ) ) {
                wfOut( "Removing revision.inverse_timestamp and fixing indexes... " );
-               dbsource( archive( 'patch-inverse_timestamp.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-inverse_timestamp.sql' ) );
                wfOut( "ok\n" );
        } else {
                wfOut( "revision timestamp indexes already up to 2005-03-13\n" );
@@ -657,7 +657,7 @@ function do_text_id() {
                wfOut( "...rev_text_id already in place.\n" );
        } else {
                wfOut( "Adding rev_text_id field... " );
-               dbsource( archive( 'patch-rev_text_id.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-rev_text_id.sql' ) );
                wfOut( "ok\n" );
        }
 }
@@ -706,7 +706,7 @@ function do_pagelinks_update() {
                wfOut( "...already have pagelinks table.\n" );
        } else {
                wfOut( "Converting links and brokenlinks tables to pagelinks... " );
-               dbsource( archive( 'patch-pagelinks.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-pagelinks.sql' ) );
                wfOut( "ok\n" );
                flush();
 
@@ -745,7 +745,7 @@ function do_drop_img_type() {
 
        if( $wgDatabase->fieldExists( 'image', 'img_type' ) ) {
                wfOut( "Dropping unused img_type field in image table... " );
-               dbsource( archive( 'patch-drop_img_type.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-drop_img_type.sql' ) );
                wfOut( "ok\n" );
        } else {
                wfOut( "No img_type field in image table; Good.\n" );
@@ -767,7 +767,7 @@ function fix_ancient_imagelinks() {
        if ( $info && $info->type() === 'string' ) {
                wfOut( "Fixing ancient broken imagelinks table.\n" );
                wfOut( "NOTE: you will have to run maintenance/refreshLinks.php after this.\n" );
-               dbsource( archive( 'patch-fix-il_from.sql' ) );
+               $wgDatabase->sourceFile( archive( 'patch-fix-il_from.sql' ) );
                wfOut( "ok\n" );
        } else {
                wfOut( "...il_from OK\n" );
@@ -784,7 +784,7 @@ function do_user_unique_update() {
                        wfOut( "WARNING: This next step will probably fail due to unfixed duplicates...\n" );
                }
                wfOut( "Adding unique index on user_name... " );
-               dbsource( archive( 'patch-user_nameindex.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-user_nameindex.sql' ) );
                wfOut( "ok\n" );
        }
 }
@@ -799,13 +799,13 @@ function do_user_groups_update() {
        }
 
        wfOut( "Adding user_groups table... " );
-       dbsource( archive( 'patch-user_groups.sql' ), $wgDatabase );
+       $wgDatabase->sourceFile( archive( 'patch-user_groups.sql' ) );
        wfOut( "ok\n" );
 
        if( !$wgDatabase->tableExists( 'user_rights' ) ) {
                if( $wgDatabase->fieldExists( 'user', 'user_rights' ) ) {
                        wfOut( "Upgrading from a 1.3 or older database? Breaking out user_rights for conversion..." );
-                       dbsource( archive( 'patch-user_rights.sql' ), $wgDatabase );
+                       $wgDatabase->sourceFile( archive( 'patch-user_rights.sql' ) );
                        wfOut( "ok\n" );
                } else {
                        wfOut( "*** WARNING: couldn't locate user_rights table or field for upgrade.\n" );
@@ -851,7 +851,7 @@ function do_user_groups_reformat() {
                wfOut( "ok\n" );
 
                wfOut( "Re-adding fresh user_groups table... " );
-               dbsource( archive( 'patch-user_groups.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-user_groups.sql' ) );
                wfOut( "ok\n" );
 
                wfOut( "***\n" );
@@ -872,7 +872,7 @@ function do_watchlist_null() {
 
        if( !$info->nullable() ) {
                wfOut( "Making wl_notificationtimestamp nullable... " );
-               dbsource( archive( 'patch-watchlist-null.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-watchlist-null.sql' ) );
                wfOut( "ok\n" );
        } else {
                wfOut( "...wl_notificationtimestamp is already nullable.\n" );
@@ -904,7 +904,7 @@ function do_templatelinks_update() {
                return;
        }
        wfOut( "Creating templatelinks table...\n" );
-       dbsource( archive('patch-templatelinks.sql'), $wgDatabase );
+       $wgDatabase->sourceFile( archive('patch-templatelinks.sql') );
        wfOut( "Populating...\n" );
        if ( isset( $wgLoadBalancer ) && $wgLoadBalancer->getServerCount() > 1 ) {
                // Slow, replication-friendly update
@@ -960,7 +960,7 @@ function do_rc_indices_update() {
                $info = $wgDatabase->indexInfo( 'recentchanges', $index, __METHOD__ );
                if( !$info ) {
                        wfOut( "...index `{$index}` not found; adding..." );
-                       dbsource( archive( $patch ) );
+                       $wgDatabase->sourceFile( archive( $patch ) );
                        wfOut( "done.\n" );
                } else {
                        wfOut( "...index `{$index}` seems ok.\n" );
@@ -990,7 +990,7 @@ function do_backlinking_indices_update() {
                !index_has_field('templatelinks', 'tl_namespace', 'tl_from') ||
                !index_has_field('imagelinks', 'il_to', 'il_from'))
        {       
-               dbsource( archive( 'patch-backlinkindexes.sql' ) );
+               $wgDatabase->sourceFile( archive( 'patch-backlinkindexes.sql' ) );
                wfOut( "...backlinking indices updated\n" );
        }
 }
@@ -999,7 +999,7 @@ function do_categorylinks_indices_update() {
        wfOut( "Checking for categorylinks indices...\n" );
        if (!index_has_field('categorylinks', 'cl_sortkey', 'cl_from'))
        {       
-               dbsource( archive( 'patch-categorylinksindex.sql' ) );
+               $wgDatabase->sourceFile( archive( 'patch-categorylinksindex.sql' ) );
                wfOut( "...categorylinks indices updated\n" );
        }
 }
@@ -1010,7 +1010,7 @@ function do_filearchive_indices_update() {
        $info = $wgDatabase->indexInfo( 'filearchive', 'fa_user_timestamp', __METHOD__ );
        if ( !$info )
        {       
-               dbsource( archive( 'patch-filearchive-user-index.sql' ) );
+               $wgDatabase->sourceFile( archive( 'patch-filearchive-user-index.sql' ) );
                wfOut( "...filearchive indices updated\n" );
        }
 }
@@ -1023,7 +1023,7 @@ function maybe_do_profiling_memory_update() {
                wfOut( "profiling table has pf_memory field.\n" );
        } else {
                wfOut( "Adding pf_memory field to table profiling..." );
-               dbsource( archive( 'patch-profiling-memory.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-profiling-memory.sql' ) );
                wfOut( "ok\n" );
        }
 }
@@ -1041,10 +1041,7 @@ function do_stats_init() {
                wfOut( "ok.\n" );
                return;
        }
-
-       global $IP;
-       require_once "$IP/maintenance/initStats.inc";
-       wfInitStats();
+       SiteStatsInit::doAllAndUpdate( false );
 }
 
 function do_active_users_init() {
@@ -1150,8 +1147,8 @@ function do_restrictions_update() {
                wfOut( "...$name table already exists.\n" );
        } else {
                wfOut( "Creating $name table..." );
-               dbsource( archive($patch), $wgDatabase );
-               dbsource( archive($patch2), $wgDatabase );
+               $wgDatabase->sourceFile( archive($patch) );
+               $wgDatabase->sourceFile( archive($patch2) );
                wfOut( "ok\n" );
 
                wfOut( "Migrating old restrictions to new table..." );
@@ -1253,7 +1250,7 @@ function do_unique_pl_tl_il() {
                wfOut( "...pl_namespace, tl_namespace, il_to indices are already UNIQUE.\n" );
        } else {
                wfOut( "Making pl_namespace, tl_namespace and il_to indices UNIQUE... " );
-               dbsource( archive( 'patch-pl-tl-il-unique.sql' ), $wgDatabase );
+               $wgDatabase->sourceFile( archive( 'patch-pl-tl-il-unique.sql' ) );
                wfOut( "ok\n" );
        }
 }
@@ -1627,7 +1624,7 @@ function do_postgres_updates() {
                }
 
                wfOut( "Creating table \"$nt[0]\"\n" );
-               dbsource(archive($nt[1]));
+               $wgDatabase->sourceFile(archive($nt[1]));
        }
 
        ## Needed before newcols
@@ -1641,7 +1638,7 @@ function do_postgres_updates() {
                        wfOut( "Dropping rule \"archive_delete\"\n" );
                        $wgDatabase->query("DROP RULE archive_delete ON archive");
                }
-               dbsource(archive("patch-remove-archive2.sql"));
+               $wgDatabase->sourceFile(archive("patch-remove-archive2.sql"));
        }
        else
                wfOut( "... obsolete table \"archive2\" does not exist\n" );
@@ -1736,7 +1733,7 @@ function do_postgres_updates() {
                        continue;
                }
                wfOut( "Adding rule \"$nr[1]\" to table \"$nr[0]\"\n" );
-               dbsource(archive($nr[2]));
+               $wgDatabase->sourceFile(archive($nr[2]));
        }
 
        if ($wgDatabase->hasConstraint("oldimage_oi_name_fkey_cascaded")) {
@@ -1756,7 +1753,7 @@ function do_postgres_updates() {
 
        if (!$wgDatabase->triggerExists("page", "page_deleted")) {
                wfOut( "Adding function and trigger \"page_deleted\" to table \"page\"\n" );
-               dbsource(archive('patch-page_deleted.sql'));
+               $wgDatabase->sourceFile(archive('patch-page_deleted.sql'));
        }
        else
                wfOut( "... table \"page\" has \"page_deleted\" trigger\n" );
@@ -1764,7 +1761,7 @@ function do_postgres_updates() {
        $fi = $wgDatabase->fieldInfo("recentchanges", "rc_cur_id");
        if (!$fi->nullable()) {
                wfOut( "Removing NOT NULL constraint from \"recentchanges.rc_cur_id\"\n" );
-               dbsource(archive('patch-rc_cur_id-not-null.sql'));
+               $wgDatabase->sourceFile(archive('patch-rc_cur_id-not-null.sql'));
        }
        else
                wfOut( "... column \"recentchanges.rc_cur_id\" has a NOT NULL constraint\n" );
@@ -1790,7 +1787,7 @@ function do_postgres_updates() {
        }
        else {
                wfOut( "Changing constraint \"revision_rev_user_fkey\" to ON DELETE RESTRICT\n" );
-               dbsource(archive('patch-revision_rev_user_fkey.sql'));
+               $wgDatabase->sourceFile(archive('patch-revision_rev_user_fkey.sql'));
        }
 
        # Fix ipb_address index
@@ -1803,7 +1800,7 @@ function do_postgres_updates() {
        }
        else {
                wfOut( "Adding ipb_address_unique index\n" );
-               dbsource(archive('patch-ipb_address_unique.sql'));
+               $wgDatabase->sourceFile(archive('patch-ipb_address_unique.sql'));
        }
 
        global $wgExtNewTables, $wgExtPGNewFields, $wgExtPGAlteredFields, $wgExtNewIndexes;
@@ -1814,7 +1811,7 @@ function do_postgres_updates() {
                        continue;
                }
                wfOut( "Creating table \"$nt[0]\"\n" );
-               dbsource($nt[1]);
+               $wgDatabase->sourceFile($nt[1]);
        }
        # Add missing extension fields
        foreach ( $wgExtPGNewFields as $nc ) {
@@ -1857,18 +1854,18 @@ function do_postgres_updates() {
                        $wgDatabase->query( "CREATE INDEX $ni[1] ON $ni[0] $ni[2]" );
                }
                else {
-                       dbsource($ni[2]);
+                       $wgDatabase->sourceFile($ni[2]);
                }
        }
 
        # Tweak the page_title tsearch2 trigger to filter out slashes
        # This is create or replace, so harmless to call if not needed
-       dbsource(archive('patch-ts2pagetitle.sql'));
+       $wgDatabase->sourceFile(archive('patch-ts2pagetitle.sql'));
 
        ## If the server is 8.3 or higher, rewrite the tsearch2 triggers
        ## in case they have the old 'default' versions
        if ( $numver >= 8.3 )
-               dbsource(archive('patch-tsearch2funcs.sql'));
+               $wgDatabase->sourceFile(archive('patch-tsearch2funcs.sql'));
 
        ## Put a new row in the mediawiki_version table
        $wgDatabase->insert( 'mediawiki_version',
index 309d0e7..e8c1034 100644 (file)
@@ -1,15 +1,34 @@
 <?php
 /**
- * @see wfWaitForSlaves()
- * @file
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @ingroup Maintenance
+ * @see wfWaitForSlaves()
  */
 
-require_once( "commandLine.inc" );
-if ( isset( $args[0] ) ) {
-       wfWaitForSlaves($args[0]);
-} else {
-       wfWaitForSlaves(10);
-}
+require_once( "Maintenance.php" );
 
+class WaitForSlave extends Maintenance {
+       public function __construct() {
+               $this->addArgs( array( 'maxlag' ) );
+       }
+       public function execute() {
+               wfWaitForSlaves( $this->getArg( 0, 10 ) );
+       }
+}
 
+$maintClass = "WaitForSlave";
+require_once( DO_MAINTENANCE );