Fixing bug 20524: Hideuser: Nicer error when trying to block hidden user without...
[lhc/web/wiklou.git] / maintenance / Maintenance.php
index 1d2d115..bcd2913 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 // Define this so scripts can easily find doMaintenance.php
 define( 'DO_MAINTENANCE', dirname( __FILE__ ) . '/doMaintenance.php' );
+$maintClass = false;
 
 // Make sure we're on PHP5 or better
 if( version_compare( PHP_VERSION, '5.0.0' ) < 0 ) {
@@ -50,13 +51,13 @@ abstract class Maintenance {
        const STDIN_ALL = 'all';
 
        // This is the desired params
-       private $mParams = array();
+       protected $mParams = array();
 
        // Array of desired args
-       private $mArgList = array();
+       protected $mArgList = array();
 
        // This is the list of options that were actually passed
-       private $mOptions = array();
+       protected $mOptions = array();
 
        // This is the list of arguments that were actually passed
        protected $mArgs = array();
@@ -65,14 +66,14 @@ abstract class Maintenance {
        protected $mSelf;
 
        // Special vars for params that are always used
-       private $mQuiet = false;
-       private $mDbUser, $mDbPass;
+       protected $mQuiet = false;
+       protected $mDbUser, $mDbPass;
 
        // A description of the script, children should change this
        protected $mDescription = '';
 
        // Have we already loaded our user input?
-       private $mInputLoaded = false;
+       protected $mInputLoaded = false;
 
        // Batch size. If a script supports this, they should set
        // a default with setBatchSize()
@@ -137,10 +138,17 @@ abstract class Maintenance {
        }
 
        /**
-        * Add some args that are needed. Used in formatting help
+        * Add some args that are needed
+        * @param $arg String Name of the arg, like 'start'
+        * @param $description String Short description of the arg
+        * @param $required Boolean Is this required?
         */
-       protected function addArgs( $args ) {
-               $this->mArgList = array_merge( $this->mArgList, $args );
+       protected function addArg( $arg, $description, $required = true ) {
+               $this->mArgList[] = array( 
+                       'name' => $arg,
+                       'desc' => $description, 
+                       'require' => $required 
+               );
        }
 
        /**
@@ -217,9 +225,13 @@ abstract class Maintenance {
         * @param $die boolean If true, go ahead and die out.
         */
        protected function error( $err, $die = false ) {
-               $f = fopen( 'php://stderr', 'w' ); 
-               fwrite( $f, $err . "\n" );
-               fclose( $f );
+               if ( php_sapi_name() == 'cli' ) {
+                       fwrite( STDERR, $err . "\n" );
+               } else {
+                       $f = fopen( 'php://stderr', 'w' ); 
+                       fwrite( $f, $err . "\n" );
+                       fclose( $f );
+               }
                if( $die ) die();
        }
 
@@ -240,7 +252,7 @@ abstract class Maintenance {
        /**
         * Add the default parameters to the scripts
         */
-       private function addDefaultParams() {
+       protected 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 );
@@ -259,13 +271,13 @@ abstract class Maintenance {
        }
 
        /**
-        * Spawn a child maintenance script. Pass all of the current arguments
+        * Run 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 ) {
+       protected function runChild( $maintClass, $classFile = null ) {
                // If we haven't already specified, kill setup procedures
                // for child scripts, we've already got a sane environment
                self::disableSetup();
@@ -325,7 +337,8 @@ abstract class Maintenance {
                }
 
                # Set the memory limit
-               ini_set( 'memory_limit', -1 );
+               # Note we need to set it again later in cache LocalSettings changed it
+               ini_set( 'memory_limit', $this->memoryLimit() );
 
                # Set max execution time to 0 (no limit). PHP.net says that
                # "When running PHP from the command line the default setting is 0."
@@ -354,6 +367,15 @@ abstract class Maintenance {
                $this->maybeHelp();
                $this->validateParamsAndArgs();
        }
+       
+       /**
+        * Normally we disable the memory_limit when running admin scripts.
+        * Some scripts may wish to actually set a limit, however, to avoid
+        * blowing up unexpectedly.
+        */
+       public function memoryLimit() {
+               return -1;
+       }
 
        /**
         * Clear all params and arguments.
@@ -436,7 +458,7 @@ abstract class Maintenance {
                                # Short options
                                for ( $p=1; $p<strlen( $arg ); $p++ ) {
                                        $option = $arg{$p};
-                                       if ( $this->mParams[$option]['withArg'] ) {
+                                       if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) {
                                                $param = next( $argv );
                                                if ( $param === false ) {
                                                        $this->error( "\nERROR: $option needs a value after it\n" );
@@ -461,24 +483,30 @@ abstract class Maintenance {
        /**
         * Run some validation checks on the params, etc
         */
-       private function validateParamsAndArgs() {
-               # Check to make sure we've got all the required ones
+       protected function validateParamsAndArgs() {
+               $die = false;
+               # Check to make sure we've got all the required options
                foreach( $this->mParams as $opt => $info ) {
                        if( $info['require'] && !$this->hasOption( $opt ) ) {
-                               $this->error( "Param $opt required.", true );
+                               $this->error( "Param $opt required!" );
+                               $die = true;
                        }
                }
-
-               # Also make sure we've got enough arguments
-               if ( count( $this->mArgs ) < count( $this->mArgList ) ) {
-                       $this->error( "Not enough arguments passed", true );
+               # Check arg list too
+               foreach( $this->mArgList as $k => $info ) {
+                       if( $info['require'] && !$this->hasArg($k) ) {
+                               $this->error( "Argument <" . $info['name'] . "> required!" );
+                               $die = true;
+                       }
                }
+               
+               if( $die ) $this->maybeHelp( true );
        }
 
        /**
         * Handle the special variables that are global to all scripts
         */
-       private function loadSpecialVars() {
+       protected function loadSpecialVars() {
                if( $this->hasOption( 'dbuser' ) )
                        $this->mDbUser = $this->getOption( 'dbuser' );
                if( $this->hasOption( 'dbpass' ) )
@@ -493,9 +521,9 @@ abstract class Maintenance {
         * Maybe show the help.
         * @param $force boolean Whether to force the help to show, default false
         */
-       private function maybeHelp( $force = false ) {
+       protected function maybeHelp( $force = false ) {
                ksort( $this->mParams );
-               if( $this->hasOption( 'help' ) || in_array( 'help', $this->mArgs ) || $force ) {
+               if( $this->hasOption( 'help' ) || $force ) {
                        $this->mQuiet = false;
                        if( $this->mDescription ) {
                                $this->output( "\n" . $this->mDescription . "\n" );
@@ -505,12 +533,20 @@ abstract class Maintenance {
                                $this->output( " [--" . implode( array_keys( $this->mParams ), "|--" ) . "]" );
                        }
                        if( $this->mArgList ) {
-                               $this->output( " <" . implode( $this->mArgList, "> <" ) . ">" );
+                               $this->output( " <" );
+                               foreach( $this->mArgList as $k => $arg ) {
+                                       $this->output( $arg['name'] . ">" );
+                                       if( $k < count( $this->mArgList ) - 1 )
+                                               $this->output( " <" );
+                               }
                        }
                        $this->output( "\n" );
                        foreach( $this->mParams as $par => $info ) {
                                $this->output( "\t$par : " . $info['desc'] . "\n" );
                        }
+                       foreach( $this->mArgList as $info ) {
+                               $this->output( "\t<" . $info['name'] . "> : " . $info['desc'] . "\n" );
+                       }
                        die( 1 );
                }
        }
@@ -559,6 +595,7 @@ abstract class Maintenance {
 
                $wgShowSQLErrors = true;
                @set_time_limit( 0 );
+               ini_set( 'memory_limit', $this->memoryLimit() );
 
                $wgProfiling = false; // only for Profiler.php mode; avoids OOM errors
        }
@@ -671,7 +708,7 @@ abstract class Maintenance {
                # 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 ) ) {
+               foreach( $res as $row ) {
                        $cur[] = $row->rev_text_id;
                }
                $this->output( "done.\n" );
@@ -679,7 +716,7 @@ abstract class Maintenance {
                # 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 ) ) {
+               foreach( $res as $row ) {
                        $cur[] = $row->ar_text_id;
                }
                $this->output( "done.\n" );
@@ -689,7 +726,7 @@ abstract class Maintenance {
                $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 ) ) {
+               foreach( $res as $row ) {
                        $old[] = $row->old_id;
                }
                $this->output( "done.\n" );
@@ -732,7 +769,7 @@ abstract class Maintenance {
         * Return all of the core maintenance scripts
         * @return array
         */
-       private static function getCoreScripts() {
+       protected static function getCoreScripts() {
                if( !self::$mCoreScripts ) {
                        self::disableSetup();
                        $paths = array(