Make maintenance scripts fail on unknown parameters
authorBill Pirkle <bpirkle@wikimedia.org>
Thu, 2 Aug 2018 20:10:31 +0000 (15:10 -0500)
committerBill Pirkle <bpirkle@wikimedia.org>
Mon, 6 Aug 2018 19:37:49 +0000 (14:37 -0500)
Passing parameters not registered via standard mechanisms
(addOption/$optionsWithArgs/$optionsWihtoutArgs) will now
cause an error, unless, the script opts out via the new
setAllowUnregisteredOptions/$allowUnregisteredOptions.

Bug: T110209
Change-Id: I21957837f10852169ca3e1eeca9bf1f4052f8c0b

maintenance/Maintenance.php
maintenance/commandLine.inc
tests/phpunit/phpunit.php

index d919249..286bd8f 100644 (file)
@@ -85,6 +85,9 @@ abstract class Maintenance {
        // This is the list of arguments that were actually passed
        protected $mArgs = [];
 
+       // Allow arbitrary options to be passed, or only specified ones?
+       protected $mAllowUnregisteredOptions = false;
+
        // Name of the script currently running
        protected $mSelf;
 
@@ -210,6 +213,16 @@ abstract class Maintenance {
         */
        abstract public function execute();
 
+       /**
+        * Checks to see if a particular option in supported.  Normally this means it
+        * has been registered by the script via addOption.
+        * @param string $name The name of the option
+        * @return bool true if the option exists, false otherwise
+        */
+       protected function supportsOption( $name ) {
+               return isset( $this->mParams[$name] );
+       }
+
        /**
         * Add a parameter to the script. Will be displayed on --help
         * with the associated description
@@ -238,8 +251,8 @@ abstract class Maintenance {
        }
 
        /**
-        * Checks to see if a particular param exists.
-        * @param string $name The name of the param
+        * Checks to see if a particular option exists.
+        * @param string $name The name of the option
         * @return bool
         */
        protected function hasOption( $name ) {
@@ -289,6 +302,15 @@ abstract class Maintenance {
                unset( $this->mParams[$name] );
        }
 
+       /**
+        * Sets whether to allow unregistered options, which are options passed to
+        * a script that do not match an expected parameter.
+        * @param bool $allow Should we allow?
+        */
+       protected function setAllowUnregisteredOptions( $allow ) {
+               $this->mAllowUnregisteredOptions = $allow;
+       }
+
        /**
         * Set the description text.
         * @param string $text The text of the description
@@ -974,6 +996,15 @@ abstract class Maintenance {
                                $die = true;
                        }
                }
+               if ( !$this->mAllowUnregisteredOptions ) {
+                       # Check for unexpected options
+                       foreach ( $this->mOptions as $opt => $val ) {
+                               if ( !$this->supportsOption( $opt ) ) {
+                                       $this->error( "Unexpected option $opt!" );
+                                       $die = true;
+                               }
+                       }
+               }
 
                if ( $die ) {
                        $this->maybeHelp( true );
index 8232d52..bb1443f 100644 (file)
@@ -24,7 +24,7 @@
 require_once __DIR__ . '/Maintenance.php';
 
 // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
-global $optionsWithArgs, $optionsWithoutArgs;
+global $optionsWithArgs, $optionsWithoutArgs, $allowUnregisteredOptions;
 
 if ( !isset( $optionsWithArgs ) ) {
        $optionsWithArgs = [];
@@ -32,19 +32,25 @@ if ( !isset( $optionsWithArgs ) ) {
 if ( !isset( $optionsWithoutArgs ) ) {
        $optionsWithoutArgs = [];
 }
+if ( !isset( $allowUnregisteredOptions ) ) {
+       $allowUnregisteredOptions = false;
+}
 
 class CommandLineInc extends Maintenance {
        public function __construct() {
                // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
-               global $optionsWithArgs, $optionsWithoutArgs;
+               global $optionsWithArgs, $optionsWithoutArgs, $allowUnregisteredOptions;
 
                parent::__construct();
+
                foreach ( $optionsWithArgs as $name ) {
                        $this->addOption( $name, '', false, true );
                }
                foreach ( $optionsWithoutArgs as $name ) {
                        $this->addOption( $name, '', false, false );
                }
+
+               $this->setAllowUnregisteredOptions( $allowUnregisteredOptions );
        }
 
        /**
index 7cf042d..d83dedb 100755 (executable)
@@ -29,6 +29,7 @@ class PHPUnitMaintClass extends Maintenance {
 
        public function __construct() {
                parent::__construct();
+               $this->setAllowUnregisteredOptions( true );
                $this->addOption(
                        'with-phpunitclass',
                        'Class name of the PHPUnit entry point to use',