/** * Run migration * * @museDescription Runs pending migrations according to options provided * * @return void **/ public function run() { // Direction, up or down $direction = 'up'; if ($this->arguments->getOpt('d')) { if ($this->arguments->getOpt('d') == 'up' || $this->arguments->getOpt('d') == 'down') { $direction = $this->arguments->getOpt('d'); } else { $this->output->error('Error: Direction must be one of "up" or "down"'); } } // Overriding default document root? $directory = null; if ($this->arguments->getOpt('r')) { if (is_dir($this->arguments->getOpt('r')) && is_readable($this->arguments->getOpt('r'))) { $directory = rtrim($this->arguments->getOpt('r'), DS); } else { $this->output->error('Error: Provided directory is not valid'); } } // Migrating a super group $alternativeDatabase = null; if ($this->arguments->getOpt('group')) { $cname = $this->arguments->getOpt('group'); $group = \Hubzero\User\Group::getInstance($cname); if ($group && $group->isSuperGroup()) { // Get group config $groupsConfig = \Component::params('com_groups'); // Path to group folder $directory = PATH_APP . DS . trim($groupsConfig->get('uploadpath', '/site/groups'), DS); $directory .= DS . $group->get('gidNumber'); // make sure we have migrations dir if (!is_dir($directory . DS . 'migrations') || !is_readable($directory . DS . 'migrations')) { $this->output->error('Error: Migrations directory does not exist.'); } // Get group database $alternativeDatabase = \Hubzero\User\Group\Helper::getDBO(array(), $group->get('cn')); // make sure we have a group db if ($alternativeDatabase->getErrorNum() > 0) { $this->output->error('Error: Could not connect to Group Database.'); } } else { $this->output->error('Error: Provided group is not valid'); } } // Forcing update $force = false; if ($this->arguments->getOpt('force')) { if (!$this->arguments->getOpt('e') && !$this->arguments->getOpt('file')) { $this->output->error('Error: You cannot specify the "force" option without specifying a specific extention or file'); } else { $force = true; } } // Logging only - record migration $logOnly = false; if ($this->arguments->getOpt('m')) { if (!$this->arguments->getOpt('e') && !$this->arguments->getOpt('file')) { $this->output->error('Error: You cannot specify the "Log only (-m)" option without specifying a specific extention or file'); } else { $logOnly = true; } } // Ignore dates $ignoreDates = false; if ($this->arguments->getOpt('i')) { $ignoreDates = true; } // Specific extension $extension = null; if ($this->arguments->getOpt('e')) { if (!preg_match('/^com_[[:alnum:]]+$|^mod_[[:alnum:]]+$|^plg_[[:alnum:]]+_[[:alnum:]]+$|^core$/i', $this->arguments->getOpt('e'))) { $this->output->error('Error: extension should match the pattern of com_*, mod_*, plg_*_*, or core'); } else { $extension = $this->arguments->getOpt('e'); } } // Specific file $file = null; if ($this->arguments->getOpt('file')) { if (!preg_match('/^Migration[0-9]{14}[[:alnum:]]+\\.php$/', $this->arguments->getOpt('file'))) { $this->output->error('Error: Provided filename does not appear to be valid'); } else { $file = $this->arguments->getOpt('file'); // Also force "ignore dates mode", as that's somewhat implied by giving a specific filename $ignoreDates = true; } } // Dryrun $dryrun = true; if ($this->arguments->getOpt('f')) { $dryrun = false; } // Email results $email = false; if ($this->arguments->getOpt('email')) { if (!preg_match('/^[a-zA-Z0-9\\.\\_\\-]+@[a-zA-Z0-9\\.]+\\.[a-zA-Z]{2,4}$/', $this->arguments->getOpt('email'))) { $this->output->error('Error: ' . $this->arguments->getOpt('email') . ' does not appear to be a valid email address'); } else { $email = $this->arguments->getOpt('email'); } } // Create migration object $migration = new \Hubzero\Content\Migration($directory, $alternativeDatabase); // Make sure we got a migration object if ($migration === false) { $this->output->error('Error: failed to instantiate new migration object.'); } if ($this->output->isInteractive()) { // Register callback function for adding lines interactively $output = $this->output; $callback = function ($message, $type = null) use($output) { $output->addLine($message, $type); }; $migration->registerCallback('message', $callback); // Add progress callback as well $progress = $this->output->getProgressOutput(); $migration->registerCallback('progress', $progress); } // Find migration files if ($migration->find($extension, $file) === false) { // Find failed, do nothing $this->output->error('Migration find failed! See log messages for details.'); } else { // Run migration itself if (!($result = $migration->migrate($direction, $force, $dryrun, $ignoreDates, $logOnly))) { $this->output->error('Migration failed! See log messages for details.'); } else { if (!$this->output->isInteractive()) { if ($this->output->getMode() == 'minimal') { if (count($migration->get('log')) > 0) { $missed = array(); $pending = array(); $complete = array(); foreach ($migration->get('log') as $log) { if (preg_match('/would run up\\(\\) (Migration[0-9]{14}[[:alnum:]_]*\\.php)/i', $log['message'], $matches)) { $pending[] = $matches[1]; } if (preg_match('/completed up\\(\\) in (Migration[0-9]{14}[[:alnum:]_]*\\.php)/i', $log['message'], $matches) || preg_match('/would ignore up\\(\\) (Migration[0-9]{14}[[:alnum:]_]*\\.php)/i', $log['message'], $matches)) { $complete[] = $matches[1]; } if (preg_match('/migration up\\(\\) in (Migration[0-9]{14}[[:alnum:]_]*\\.php) has not been run/i', $log['message'], $matches)) { $missed[] = $matches[1]; } } if (count($pending) > 0) { $this->output->addLine(array('pending' => $pending)); } if (count($missed) > 0) { $this->output->addLine(array('missed' => $missed)); } if (count($complete) > 0) { $this->output->addLine(array('complete' => $complete)); } } } else { $this->output->addLinesFromArray($migration->get('log')); } } // Final success message if ($this->output->getMode() != 'minimal') { $this->output->addLine('Success: ' . ucfirst($direction) . ' migration complete!', 'success'); } } } // Email results if requested (only do so if there's something to report) if ($email && count($migration->get('affectedFiles')) > 0) { $this->output->addLine("Emailing results to: {$email}"); $headers = "From: Migrations <automator@" . php_uname("n") . ">"; $subject = "Migration output - " . php_uname("n") . " [" . date("d-M-Y H:i:s") . "]"; $message = ""; foreach ($migration->get('log') as $line) { $message .= $line['message'] . "\n"; } // Send the message if (!mail($email, $subject, $message, $headers)) { $this->output->addLine("Error: failed to send message!", 'warning'); } } elseif ($email) { $this->output->addLine('Ignoring email as no files were affected in this run.', 'info'); } }