Differential D14463 Diff 35378 src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php
| Show All 15 Lines | $this | ||||
| 'help' => pht( | 'help' => pht( | ||||
| 'Apply __patch__ explicitly. This is an advanced feature for '. | 'Apply __patch__ explicitly. This is an advanced feature for '. | ||||
| 'development and debugging; you should not normally use this '. | 'development and debugging; you should not normally use this '. | ||||
| 'flag. This skips adjustment.'), | 'flag. This skips adjustment.'), | ||||
| ), | ), | ||||
| array( | array( | ||||
| 'name' => 'no-quickstart', | 'name' => 'no-quickstart', | ||||
| 'help' => pht( | 'help' => pht( | ||||
| 'Build storage patch-by-patch from scatch, even if it could '. | 'Build storage patch-by-patch from scratch, even if it could '. | ||||
| 'be loaded from the quickstart template.'), | 'be loaded from the quickstart template.'), | ||||
| ), | ), | ||||
| array( | array( | ||||
| 'name' => 'init-only', | 'name' => 'init-only', | ||||
| 'help' => pht( | 'help' => pht( | ||||
| 'Initialize storage only; do not apply patches or adjustments.'), | 'Initialize storage only; do not apply patches or adjustments.'), | ||||
| ), | ), | ||||
| array( | array( | ||||
| 'name' => 'no-adjust', | 'name' => 'no-adjust', | ||||
| 'help' => pht( | 'help' => pht( | ||||
| 'Do not apply storage adjustments after storage upgrades.'), | 'Do not apply storage adjustments after storage upgrades.'), | ||||
| ), | ), | ||||
| )); | )); | ||||
| } | } | ||||
| public function execute(PhutilArgumentParser $args) { | public function didExecute(PhutilArgumentParser $args) { | ||||
| $is_dry = $args->getArg('dryrun'); | $console = PhutilConsole::getConsole(); | ||||
| $is_force = $args->getArg('force'); | |||||
| $api = $this->getAPI(); | |||||
| $patches = $this->getPatches(); | $patches = $this->getPatches(); | ||||
| if (!$is_dry && !$is_force) { | if (!$this->isDryRun() && !$this->isForce()) { | ||||
| echo phutil_console_wrap( | $console->writeOut( | ||||
| phutil_console_wrap( | |||||
| pht( | pht( | ||||
| 'Before running storage upgrades, you should take down the '. | 'Before running storage upgrades, you should take down the '. | ||||
| 'Phabricator web interface and stop any running Phabricator '. | 'Phabricator web interface and stop any running Phabricator '. | ||||
| 'daemons (you can disable this warning with %s).', | 'daemons (you can disable this warning with %s).', | ||||
| '--force')); | '--force'))); | ||||
| if (!phutil_console_confirm(pht('Are you ready to continue?'))) { | if (!phutil_console_confirm(pht('Are you ready to continue?'))) { | ||||
| echo pht('Cancelled.')."\n"; | $console->writeOut("%s\n", pht('Cancelled.')); | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| } | } | ||||
| $apply_only = $args->getArg('apply'); | $apply_only = $args->getArg('apply'); | ||||
| if ($apply_only) { | if ($apply_only) { | ||||
| if (empty($patches[$apply_only])) { | if (empty($patches[$apply_only])) { | ||||
| throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
| pht( | pht( | ||||
| "%s argument '%s' is not a valid patch. ". | "%s argument '%s' is not a valid patch. ". | ||||
| "Use '%s' to show patch status.", | "Use '%s' to show patch status.", | ||||
| '--apply', | '--apply', | ||||
| $apply_only, | $apply_only, | ||||
| 'storage status')); | './bin/storage status')); | ||||
| } | } | ||||
| } | } | ||||
| $no_quickstart = $args->getArg('no-quickstart'); | $no_quickstart = $args->getArg('no-quickstart'); | ||||
| $init_only = $args->getArg('init-only'); | $init_only = $args->getArg('init-only'); | ||||
| $no_adjust = $args->getArg('no-adjust'); | $no_adjust = $args->getArg('no-adjust'); | ||||
| $applied = $api->getAppliedPatches(); | $this->upgradeSchemata($apply_only, $no_quickstart, $init_only); | ||||
| if ($applied === null) { | |||||
| if ($is_dry) { | |||||
| echo pht( | |||||
| "DRYRUN: Patch metadata storage doesn't exist yet, ". | |||||
| "it would be created.\n"); | |||||
| return 0; | |||||
| } | |||||
| if ($apply_only) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Storage has not been initialized yet, you must initialize '. | |||||
| 'storage before selectively applying patches.')); | |||||
| return 1; | |||||
| } | |||||
| $legacy = $api->getLegacyPatches($patches); | |||||
| if ($legacy || $no_quickstart || $init_only) { | |||||
| // If we have legacy patches, we can't quickstart. | |||||
| $api->createDatabase('meta_data'); | |||||
| $api->createTable( | |||||
| 'meta_data', | |||||
| 'patch_status', | |||||
| array( | |||||
| 'patch VARCHAR(255) NOT NULL PRIMARY KEY COLLATE utf8_general_ci', | |||||
| 'applied INT UNSIGNED NOT NULL', | |||||
| )); | |||||
| foreach ($legacy as $patch) { | |||||
| $api->markPatchApplied($patch); | |||||
| } | |||||
| } else { | |||||
| echo pht('Loading quickstart template...')."\n"; | |||||
| $root = dirname(phutil_get_library_root('phabricator')); | |||||
| $sql = $root.'/resources/sql/quickstart.sql'; | |||||
| $api->applyPatchSQL($sql); | |||||
| } | |||||
| } | |||||
| if ($init_only) { | |||||
| echo pht('Storage initialized.')."\n"; | |||||
| return 0; | |||||
| } | |||||
| $applied = $api->getAppliedPatches(); | |||||
| $applied = array_fuse($applied); | |||||
| $skip_mark = false; | |||||
| if ($apply_only) { | |||||
| if (isset($applied[$apply_only])) { | |||||
| unset($applied[$apply_only]); | |||||
| $skip_mark = true; | |||||
| if (!$is_force && !$is_dry) { | |||||
| echo phutil_console_wrap( | |||||
| pht( | |||||
| "Patch '%s' has already been applied. Are you sure you want ". | |||||
| "to apply it again? This may put your storage in a state ". | |||||
| "that the upgrade scripts can not automatically manage.", | |||||
| $apply_only)); | |||||
| if (!phutil_console_confirm(pht('Apply patch again?'))) { | |||||
| echo pht('Cancelled.')."\n"; | |||||
| return 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| while (true) { | |||||
| $applied_something = false; | |||||
| foreach ($patches as $key => $patch) { | |||||
| if (isset($applied[$key])) { | |||||
| unset($patches[$key]); | |||||
| continue; | |||||
| } | |||||
| if ($apply_only && $apply_only != $key) { | |||||
| unset($patches[$key]); | |||||
| continue; | |||||
| } | |||||
| $can_apply = true; | |||||
| foreach ($patch->getAfter() as $after) { | |||||
| if (empty($applied[$after])) { | |||||
| if ($apply_only) { | |||||
| echo pht( | |||||
| "Unable to apply patch '%s' because it depends ". | |||||
| "on patch '%s', which has not been applied.\n", | |||||
| $apply_only, | |||||
| $after); | |||||
| return 1; | |||||
| } | |||||
| $can_apply = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!$can_apply) { | |||||
| continue; | |||||
| } | |||||
| $applied_something = true; | |||||
| if ($is_dry) { | |||||
| echo pht("DRYRUN: Would apply patch '%s'.", $key)."\n"; | |||||
| } else { | |||||
| echo pht("Applying patch '%s'...", $key)."\n"; | |||||
| $t_begin = microtime(true); | |||||
| $api->applyPatch($patch); | |||||
| $t_end = microtime(true); | |||||
| if (!$skip_mark) { | |||||
| $api->markPatchApplied($key, ($t_end - $t_begin)); | |||||
| } | |||||
| } | |||||
| unset($patches[$key]); | |||||
| $applied[$key] = true; | |||||
| } | |||||
| if (!$applied_something) { | |||||
| if (count($patches)) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Some patches could not be applied: %s', | |||||
| implode(', ', array_keys($patches)))); | |||||
| } else if (!$is_dry && !$apply_only) { | |||||
| echo pht( | |||||
| "Storage is up to date. Use '%s' for details.", | |||||
| 'storage status')."\n"; | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| $console = PhutilConsole::getConsole(); | |||||
| if ($no_adjust || $init_only || $apply_only) { | if ($no_adjust || $init_only || $apply_only) { | ||||
| $console->writeOut( | $console->writeOut( | ||||
| "%s\n", | "%s\n", | ||||
| pht('Declining to apply storage adjustments.')); | pht('Declining to apply storage adjustments.')); | ||||
| return 0; | return 0; | ||||
| } else { | } else { | ||||
| return $this->adjustSchemata($is_force, $unsafe = false, $is_dry); | return $this->adjustSchemata(false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||