r76390 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r76389‎ | r76390 | r76391 >
Date:15:58, 9 November 2010
Author:demon
Status:resolved (Comments)
Tags:
Comment:
Rewrite install step callbacks to use the array model Ævar said I should use like 6 months ago. Still no way for extensions to hook into this, but it's a lot cleaner now for them to maybe do it. Also rids of the useless one-line wrappers around install steps in other objects.
Modified paths:
  • /trunk/phase3/includes/installer/CoreInstaller.php (modified) (history)
  • /trunk/phase3/includes/installer/Installer.php (modified) (history)
  • /trunk/phase3/includes/installer/MysqlInstaller.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/installer/MysqlInstaller.php
@@ -396,10 +396,8 @@
397397 public function preInstall() {
398398 # Add our user callback to installSteps, right before the tables are created.
399399 $callback = array(
400 - array(
401 - 'name' => 'user',
402 - 'callback' => array( $this, 'setupUser' ),
403 - )
 400+ 'name' => 'user',
 401+ 'callback' => array( $this, 'setupUser' ),
404402 );
405403 $this->parent->addInstallStepFollowing( "tables", $callback );
406404 }
Index: trunk/phase3/includes/installer/Installer.php
@@ -337,24 +337,6 @@
338338 *
339339 * @return Status
340340 */
341 - public function installDatabase( DatabaseInstaller &$installer ) {
342 - if( !$installer ) {
343 - $type = $this->getVar( 'wgDBtype' );
344 - $status = Status::newFatal( "config-no-db", $type );
345 - } else {
346 - $status = $installer->setupDatabase();
347 - }
348 -
349 - return $status;
350 - }
351 -
352 - /**
353 - * TODO: document
354 - *
355 - * @param $installer DatabaseInstaller
356 - *
357 - * @return Status
358 - */
359341 public function installTables( DatabaseInstaller &$installer ) {
360342 $status = $installer->createTables();
361343
@@ -366,17 +348,6 @@
367349 }
368350
369351 /**
370 - * TODO: document
371 - *
372 - * @param $installer DatabaseInstaller
373 - *
374 - * @return Status
375 - */
376 - public function installInterwiki( DatabaseInstaller &$installer ) {
377 - return $installer->populateInterwikiTable();
378 - }
379 -
380 - /**
381352 * Exports all wg* variables stored by the installer into global scope.
382353 */
383354 public function exportVars() {
Index: trunk/phase3/includes/installer/CoreInstaller.php
@@ -88,18 +88,11 @@
8989 );
9090
9191 /**
92 - * Steps for installation.
 92+ * Extra steps for installation, for things like DatabaseInstallers to modify
9393 *
9494 * @var array
9595 */
96 - protected $installSteps = array(
97 - 'database',
98 - 'tables',
99 - 'interwiki',
100 - 'secretkey',
101 - 'sysop',
102 - 'mainpage',
103 - );
 96+ protected $extraInstallSteps = array();
10497
10598 /**
10699 * Known object cache types and the functions used to test for their existence.
@@ -288,12 +281,9 @@
289282 /**
290283 * Installs the auto-detected extensions.
291284 *
292 - * @TODO: this only requires them? That's all it's supposed to do. Poorly
293 - * named step.
294 - *
295285 * @return Status
296286 */
297 - protected function installExtensions() {
 287+ protected function includeExtensions() {
298288 $exts = $this->getVar( '_Extensions' );
299289 $path = $this->getVar( 'IP' ) . '/extensions';
300290
@@ -308,13 +298,31 @@
309299 * Get an array of install steps. These could be a plain key like the defaults
310300 * in $installSteps, or could be an array with a name and a specific callback
311301 *
 302+ * @param $installer DatabaseInstaller so we can make callbacks
312303 * @return array
313304 */
314 - protected function getInstallSteps() {
 305+ protected function getInstallSteps( DatabaseInstaller &$installer ) {
 306+ $installSteps = array(
 307+ array( 'name' => 'database', 'callback' => array( $installer, 'setupDatabase' ) ),
 308+ array( 'name' => 'tables', 'callback' => array( $this, 'installTables' ) ),
 309+ array( 'name' => 'interwiki', 'callback' => array( $installer, 'populateInterwikiTable' ) ),
 310+ array( 'name' => 'secretkey', 'callback' => array( $this, 'generateSecretKey' ) ),
 311+ array( 'name' => 'sysop', 'callback' => array( $this, 'createSysop' ) ),
 312+ array( 'name' => 'mainpage', 'callback' => array( $this, 'createMainpage' ) ),
 313+ );
315314 if( count( $this->getVar( '_Extensions' ) ) ) {
316 - array_unshift( $this->installSteps, 'extensions' );
 315+ array_unshift( $installSteps,
 316+ array( 'extensions', array( $this, 'includeExtensions' ) )
 317+ );
317318 }
318 - return $this->installSteps;
 319+ foreach( $installSteps as $idx => $stepObj ) {
 320+ if( isset( $this->extraInstallSteps[ $stepObj['name'] ] ) ) {
 321+ $tmp = array_slice( $installSteps, 0, $idx );
 322+ $tmp[] = $this->extraInstallSteps[ $stepObj['name'] ];
 323+ $installSteps = array_merge( $tmp, array_slice( $installSteps, $idx ) );
 324+ }
 325+ }
 326+ return $installSteps;
319327 }
320328
321329 /**
@@ -329,37 +337,27 @@
330338 $installResults = array();
331339 $installer = $this->getDBInstaller();
332340 $installer->preInstall();
 341+ $steps = $this->getInstallSteps( $installer );
 342+ foreach( $steps as $stepObj ) {
 343+ $name = $stepObj['name'];
 344+ call_user_func_array( $startCB, array( $name ) );
333345
334 - foreach( $this->getInstallSteps() as $stepObj ) {
335 - $step = is_array( $stepObj ) ? $stepObj['name'] : $stepObj;
336 - call_user_func_array( $startCB, array( $step ) );
 346+ // Perform the callback step
 347+ $status = call_user_func_array( $stepObj['callback'], array( &$installer ) );
337348
338 - # Call our working function
339 - if ( is_array( $stepObj ) ) {
340 - # A custom callaback
341 - $callback = $stepObj['callback'];
342 - $status = call_user_func_array( $callback, array( $installer ) );
343 - } else {
344 - # Boring implicitly named callback
345 - $func = 'install' . ucfirst( $step );
346 - $status = $this->{$func}( $installer );
347 - }
 349+ // Output and save the results
 350+ call_user_func_array( $endCB, array( $name, $status ) );
 351+ $installResults[$name] = $status;
348352
349 - call_user_func_array( $endCB, array( $step, $status ) );
350 - $installResults[$step] = $status;
351 -
352353 // If we've hit some sort of fatal, we need to bail.
353354 // Callback already had a chance to do output above.
354355 if( !$status->isOk() ) {
355356 break;
356357 }
357 -
358358 }
359 -
360359 if( $status->isOk() ) {
361360 $this->setVar( '_InstallDone', true );
362361 }
363 -
364362 return $installResults;
365363 }
366364
@@ -369,7 +367,7 @@
370368 *
371369 * @return Status
372370 */
373 - protected function installSecretKey() {
 371+ protected function generateSecretKey() {
374372 if ( wfIsWindows() ) {
375373 $file = null;
376374 } else {
@@ -403,7 +401,7 @@
404402 *
405403 * @return Status
406404 */
407 - protected function installSysop() {
 405+ protected function createSysop() {
408406 $name = $this->getVar( '_AdminName' );
409407 $user = User::newFromName( $name );
410408
@@ -434,7 +432,7 @@
435433 *
436434 * @return Status
437435 */
438 - public function installMainpage( DatabaseInstaller &$installer ) {
 436+ protected function createMainpage( DatabaseInstaller &$installer ) {
439437 $status = Status::newGood();
440438 try {
441439 $article = new Article( Title::newMainPage() );
@@ -480,16 +478,9 @@
481479 * Add an installation step following the given step.
482480 *
483481 * @param $findStep String the step to find. Use NULL to put the step at the beginning.
484 - * @param $callback array
 482+ * @param $callback array A valid callback array, with name and callback given
485483 */
486484 public function addInstallStepFollowing( $findStep, $callback ) {
487 - $where = 0;
488 -
489 - if( $findStep !== null ) {
490 - $where = array_search( $findStep, $this->installSteps );
491 - }
492 -
493 - array_splice( $this->installSteps, $where, 0, $callback );
 485+ $this->extraInstallSteps[$findStep] = $callback;
494486 }
495 -
496487 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r78774Rewrite install steps again (cleanup r76390)...demon05:21, 22 December 2010

Comments

#Comment by Catrope (talk | contribs)   13:50, 13 December 2010
+	protected function getInstallSteps( DatabaseInstaller &$installer ) {

I thought we stopped passing objects by reference a few years ago?

+		foreach( $installSteps as $idx => $stepObj ) {
+			if( isset( $this->extraInstallSteps[ $stepObj['name'] ] ) ) {
+				$tmp = array_slice( $installSteps, 0, $idx );
+				$tmp[] = $this->extraInstallSteps[ $stepObj['name'] ];
+				$installSteps = array_merge( $tmp, array_slice( $installSteps, $idx ) );
+			}
+		}

This loop is completely broken. First, it modifies the array it iterates over, which almost always makes for bugs or confusing code (or both). In this case, you're forgetting that foreach runs on a copy of the array, which is good for you because it means the elements you add don't get iterated over and bad because $idx corresponds to the index of $stepObj before anything was added in, not after. I suggest rewriting this loop to read from $installSteps and write to another, initially empty array. Second, it appends $this->extraInstallSteps[ $stepObj['name'] ] to $tmp as if the former were a single element, but it seems to be an array of elements. It's not completely clear to me what the desired behavior is because neither this code nor $extraInstallSteps have any documentation at all; both implementing this properly and reading the result will be much easier if there's a comment explaining what the format of $extraInstallSteps is and just how the loop is supposed to multiplex it into $installSteps.

#Comment by Catrope (talk | contribs)   13:52, 13 December 2010

Addendum: I've just realized $this->extraInstallSteps[ $stepObj['name'] ] is indeed a single element, but that's even worse: it means the design of the $extraInstallSteps is seriously broken because it only allows one extension to attach itself to a given install step. In practice, some version of the 80-20 rule applies to these things: there's gonna be a few popular install steps multiple extensions will want to attach themselves to.

#Comment by 😂 (talk | contribs)   14:09, 13 December 2010

Whee will fix :)

Status & tagging log