From: Andrew H Date: Tue, 29 Dec 2015 22:15:12 +0000 (+0000) Subject: Add support for specifying options multiple times in Maintenance scripts. X-Git-Tag: 1.31.0-rc.0~8518 X-Git-Url: http://git.cyclocoop.org/%24self?a=commitdiff_plain;h=0a0b02b56c2c9f03918eab099d1e196ac513fa10;p=lhc%2Fweb%2Fwiklou.git Add support for specifying options multiple times in Maintenance scripts. Bug: T122588 Change-Id: I847d45684ccd4054f4a159394266dc3e5506bbdb --- diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 7825ce950d..185a1f4028 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -122,6 +122,18 @@ abstract class Maintenance { */ private $config; + /** + * Used to read the options in the order + * they were passed. Useful for option + * chaining. (Ex. dumpBackup.php) + * + * This is an array of arrays where + * 0 => the option and 1 => parameter value + * + * @var array + */ + public $orderedOptions = array(); + /** * Default constructor. Children should call this *first* if implementing * their own constructors @@ -184,15 +196,17 @@ abstract class Maintenance { * @param bool $required Is the param required? * @param bool $withArg Is an argument required with this option? * @param string $shortName Character to use as short name + * @param bool $multiOccurrence Can this option be passed multiple times? */ protected function addOption( $name, $description, $required = false, - $withArg = false, $shortName = false + $withArg = false, $shortName = false, $multiOccurrence = false ) { $this->mParams[$name] = array( 'desc' => $description, 'require' => $required, 'withArg' => $withArg, - 'shortName' => $shortName + 'shortName' => $shortName, + 'multiOccurrence' => $multiOccurrence ); if ( $shortName !== false ) { @@ -210,7 +224,11 @@ abstract class Maintenance { } /** - * Get an option, or return the default + * Get an option, or return the default. + * + * If the option was added to support multiple occurrences, + * this will return an array. + * * @param string $name The name of the param * @param mixed $default Anything you want, default null * @return mixed @@ -673,6 +691,7 @@ abstract class Maintenance { $options = array(); $args = array(); + $this->orderedOptions = array(); # Parse arguments for ( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) { @@ -687,17 +706,14 @@ abstract class Maintenance { } elseif ( substr( $arg, 0, 2 ) == '--' ) { # Long options $option = substr( $arg, 2 ); - if ( array_key_exists( $option, $options ) ) { - $this->error( "\nERROR: $option parameter given twice\n" ); - $this->maybeHelp( true ); - } if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) { $param = next( $argv ); if ( $param === false ) { $this->error( "\nERROR: $option parameter needs a value after it\n" ); $this->maybeHelp( true ); } - $options[$option] = $param; + + $this->setParam( $options, $option, $param ); } else { $bits = explode( '=', $option, 2 ); if ( count( $bits ) > 1 ) { @@ -706,7 +722,8 @@ abstract class Maintenance { } else { $param = 1; } - $options[$option] = $param; + + $this->setParam( $options, $option, $param ); } } elseif ( $arg == '-' ) { # Lonely "-", often used to indicate stdin or stdout. @@ -719,19 +736,16 @@ abstract class Maintenance { if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) { $option = $this->mShortParamsMap[$option]; } - if ( array_key_exists( $option, $options ) ) { - $this->error( "\nERROR: $option parameter given twice\n" ); - $this->maybeHelp( true ); - } + if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) { $param = next( $argv ); if ( $param === false ) { $this->error( "\nERROR: $option parameter needs a value after it\n" ); $this->maybeHelp( true ); } - $options[$option] = $param; + $this->setParam( $options, $option, $param ); } else { - $options[$option] = 1; + $this->setParam( $options, $option, 1 ); } } } else { @@ -745,6 +759,37 @@ abstract class Maintenance { $this->mInputLoaded = true; } + /** + * Helper function used solely by loadParamsAndArgs + * to prevent code duplication + * + * This sets the param in the options array based on + * whether or not it can be specified multiple times. + * + * @since 1.27 + * @param array $options + * @param string $option + * @param mixed $value + */ + private function setParam( &$options, $option, $value ) { + $this->orderedOptions[] = array( $option, $value ); + + if ( isset( $this->mParams[$option] ) ) { + $multi = $this->mParams[$option]['multiOccurrence']; + $exists = array_key_exists( $option, $options ); + if ( $multi && $exists ) { + $options[$option][] = $value; + } elseif ( $multi ) { + $options[$option] = array( $value ); + } elseif ( !$exists ) { + $options[$option] = $value; + } else { + $this->error( "\nERROR: $option parameter given twice\n" ); + $this->maybeHelp( true ); + } + } + } + /** * Run some validation checks on the params, etc */ diff --git a/tests/phpunit/maintenance/MaintenanceTest.php b/tests/phpunit/maintenance/MaintenanceTest.php index 5c6a6cde85..7b84dfa84e 100644 --- a/tests/phpunit/maintenance/MaintenanceTest.php +++ b/tests/phpunit/maintenance/MaintenanceTest.php @@ -120,6 +120,16 @@ class MaintenanceFixup extends Maintenance { return call_user_func_array( array( "parent", __FUNCTION__ ), func_get_args() ); } + public function addOption( $name, $description, $required = false, + $withArg = false, $shortName = false, $multiOccurance = false + ) { + return call_user_func_array( array( "parent", __FUNCTION__ ), func_get_args() ); + } + + public function getOption( $name, $default = null ) { + return call_user_func_array( array( "parent", __FUNCTION__ ), func_get_args() ); + } + // --- Requirements for getting instance of abstract class public function execute() { @@ -829,4 +839,45 @@ class MaintenanceTest extends MediaWikiTestCase { $this->m->setConfig( $conf ); $this->assertSame( $conf, $this->m->getConfig() ); } + + function testParseArgs() { + global $argv; + $oldArgv = $argv; + + $argv = array( '', '--multi', 'this1', '--multi', 'this2' ); + $m2 = new MaintenanceFixup( $this ); + // Create an option with an argument allowed to be specified multiple times + $m2->addOption( 'multi', 'This option does stuff', false, true, false, true ); + $m2->loadParamsAndArgs(); + + $this->assertEquals( array( 'this1', 'this2' ), $m2->getOption( 'multi' ) ); + $this->assertEquals( array( array( 'multi', 'this1' ), array( 'multi', 'this2' ) ), + $m2->orderedOptions ); + + $m2->simulateShutdown(); + + $argv = array( '', '--multi', '--multi' ); + $m2 = new MaintenanceFixup( $this ); + + $m2->addOption( 'multi', 'This option does stuff', false, false, false, true ); + $m2->loadParamsAndArgs(); + + $this->assertEquals( array( 1, 1 ), $m2->getOption( 'multi' ) ); + $this->assertEquals( array( array( 'multi', 1 ), array( 'multi', 1 ) ), $m2->orderedOptions ); + + $m2->simulateShutdown(); + + $argv = array( '', '--multi=yo' ); + $m2 = new MaintenanceFixup( $this ); + // Create an option with an argument allowed to be specified multiple times + $m2->addOption( 'multi', 'This option doesn\'t actually support multiple occurrences' ); + $m2->loadParamsAndArgs(); + + $this->assertEquals( 'yo', $m2->getOption( 'multi' ) ); + $this->assertEquals( array( array( 'multi', 'yo' ) ), $m2->orderedOptions ); + + $m2->simulateShutdown(); + + $argv = $oldArgv; + } }