Differential D20467 Diff 48843 src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php
<?php | <?php | ||||
final class PhabricatorRepositoryManagementReparseWorkflow | final class PhabricatorRepositoryManagementReparseWorkflow | ||||
extends PhabricatorRepositoryManagementWorkflow { | extends PhabricatorRepositoryManagementWorkflow { | ||||
protected function didConstruct() { | protected function didConstruct() { | ||||
$this | $this | ||||
->setName('reparse') | ->setName('reparse') | ||||
->setExamples('**reparse** [options] __commit__') | ->setExamples('**reparse** [options] __commit__') | ||||
->setSynopsis( | ->setSynopsis( | ||||
pht( | pht( | ||||
'**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n". | '**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n". | ||||
'Rerun the Diffusion parser on specific commits and repositories. '. | 'Rerun the Diffusion parser on specific commits and repositories. '. | ||||
'Mostly useful for debugging changes to Diffusion.'."\n\n". | 'Mostly useful for debugging changes to Diffusion.'."\n\n". | ||||
'e.g. enqueue reparse owners in the TEST repo for all commits:'."\n". | |||||
'repository reparse --all TEST --owners'."\n\n". | |||||
'e.g. do same but exclude before yesterday (local time):'."\n". | 'e.g. do same but exclude before yesterday (local time):'."\n". | ||||
'repository reparse --all TEST --owners --min-date yesterday'."\n". | 'repository reparse --all TEST --change --min-date yesterday'."\n". | ||||
'repository reparse --all TEST --owners --min-date "today -1 day".'. | 'repository reparse --all TEST --change --min-date "today -1 day".'. | ||||
"\n\n". | "\n\n". | ||||
'e.g. do same but exclude before 03/31/2013 (local time):'."\n". | 'e.g. do same but exclude before 03/31/2013 (local time):'."\n". | ||||
'repository reparse --all TEST --owners --min-date "03/31/2013"')) | 'repository reparse --all TEST --change --min-date "03/31/2013"')) | ||||
->setArguments( | ->setArguments( | ||||
array( | array( | ||||
array( | array( | ||||
'name' => 'revision', | 'name' => 'revision', | ||||
'wildcard' => true, | 'wildcard' => true, | ||||
), | ), | ||||
array( | array( | ||||
'name' => 'all', | 'name' => 'all', | ||||
'param' => 'repository', | 'param' => 'repository', | ||||
'help' => pht( | 'help' => pht( | ||||
'Reparse all commits in the specified repository. This mode '. | 'Reparse all commits in the specified repository.'), | ||||
'queues parsers into the task queue; you must run taskmasters '. | |||||
'to actually do the parses. Use with __%s__ to run '. | |||||
'the tasks locally instead of with taskmasters.', | |||||
'--force-local'), | |||||
), | ), | ||||
array( | array( | ||||
'name' => 'min-date', | 'name' => 'min-date', | ||||
'param' => 'date', | 'param' => 'date', | ||||
'help' => pht( | 'help' => pht( | ||||
"Must be used with __%s__, this will exclude commits which ". | "Must be used with __%s__, this will exclude commits which ". | ||||
"are earlier than __date__.\n". | "are earlier than __date__.\n". | ||||
"Valid examples:\n". | "Valid examples:\n". | ||||
" 'today', 'today 2pm', '-1 hour', '-2 hours', '-24 hours',\n". | " 'today', 'today 2pm', '-1 hour', '-2 hours', '-24 hours',\n". | ||||
" 'yesterday', 'today -1 day', 'yesterday 2pm', '2pm -1 day',\n". | " 'yesterday', 'today -1 day', 'yesterday 2pm', '2pm -1 day',\n". | ||||
" 'last Monday', 'last Monday 14:00', 'last Monday 2pm',\n". | " 'last Monday', 'last Monday 14:00', 'last Monday 2pm',\n". | ||||
" '31 March 2013', '31 Mar', '03/31', '03/31/2013',\n". | " '31 March 2013', '31 Mar', '03/31', '03/31/2013',\n". | ||||
"See __%s__ for more.", | "See __%s__ for more.", | ||||
'--all', | '--all', | ||||
'http://www.php.net/manual/en/datetime.formats.php'), | 'http://www.php.net/manual/en/datetime.formats.php'), | ||||
), | ), | ||||
array( | array( | ||||
'name' => 'message', | 'name' => 'message', | ||||
'help' => pht('Reparse commit messages.'), | 'help' => pht('Reparse commit messages.'), | ||||
), | ), | ||||
array( | array( | ||||
'name' => 'change', | 'name' => 'change', | ||||
'help' => pht('Reparse changes.'), | 'help' => pht('Reparse source changes.'), | ||||
), | ), | ||||
array( | array( | ||||
'name' => 'herald', | 'name' => 'publish', | ||||
'help' => pht( | 'help' => pht( | ||||
'Reevaluate Herald rules (may send huge amounts of email!)'), | 'Publish changes: send email, publish Feed stories, run '. | ||||
), | 'Herald rules, etc.'), | ||||
amckinley: 'Publish changes. Includes evaluating Owners packages and Herald rules.'? | |||||
array( | |||||
'name' => 'owners', | |||||
'help' => pht( | |||||
'Reevaluate related commits for owners packages (may delete '. | |||||
'existing relationship entries between your package and some '. | |||||
'old commits!)'), | |||||
), | ), | ||||
array( | array( | ||||
'name' => 'force', | 'name' => 'force', | ||||
'short' => 'f', | 'short' => 'f', | ||||
'help' => pht('Act noninteractively, without prompting.'), | 'help' => pht('Act noninteractively, without prompting.'), | ||||
), | ), | ||||
array( | array( | ||||
'name' => 'force-local', | 'name' => 'background', | ||||
'help' => pht( | 'help' => pht( | ||||
'Only used with __%s__, use this to run the tasks locally '. | 'Queue tasks for the daemons instead of running them in the '. | ||||
'instead of deferring them to taskmaster daemons.', | 'foreground.'), | ||||
'--all'), | |||||
), | ), | ||||
array( | array( | ||||
'name' => 'importing', | 'name' => 'importing', | ||||
'help' => pht( | 'help' => pht('Reparse all steps which have not yet completed.'), | ||||
'Reparse all steps which have not yet completed.'), | |||||
), | ), | ||||
)); | )); | ||||
} | } | ||||
public function execute(PhutilArgumentParser $args) { | public function execute(PhutilArgumentParser $args) { | ||||
$console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
$all_from_repo = $args->getArg('all'); | $all_from_repo = $args->getArg('all'); | ||||
$reparse_message = $args->getArg('message'); | $reparse_message = $args->getArg('message'); | ||||
$reparse_change = $args->getArg('change'); | $reparse_change = $args->getArg('change'); | ||||
$reparse_herald = $args->getArg('herald'); | $reparse_publish = $args->getArg('publish'); | ||||
$reparse_owners = $args->getArg('owners'); | |||||
$reparse_what = $args->getArg('revision'); | $reparse_what = $args->getArg('revision'); | ||||
$force = $args->getArg('force'); | $force = $args->getArg('force'); | ||||
$force_local = $args->getArg('force-local'); | $background = $args->getArg('background'); | ||||
$min_date = $args->getArg('min-date'); | $min_date = $args->getArg('min-date'); | ||||
$importing = $args->getArg('importing'); | $importing = $args->getArg('importing'); | ||||
if (!$all_from_repo && !$reparse_what) { | if (!$all_from_repo && !$reparse_what) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht('Specify a commit or repository to reparse.')); | pht('Specify a commit or repository to reparse.')); | ||||
} | } | ||||
if ($all_from_repo && $reparse_what) { | if ($all_from_repo && $reparse_what) { | ||||
$commits = implode(', ', $reparse_what); | $commits = implode(', ', $reparse_what); | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
"Specify a commit or repository to reparse, not both:\n". | "Specify a commit or repository to reparse, not both:\n". | ||||
"All from repo: %s\n". | "All from repo: %s\n". | ||||
"Commit(s) to reparse: %s", | "Commit(s) to reparse: %s", | ||||
$all_from_repo, | $all_from_repo, | ||||
$commits)); | $commits)); | ||||
} | } | ||||
$any_step = ($reparse_message || | $any_step = ($reparse_message || $reparse_change || $reparse_publish); | ||||
$reparse_change || | |||||
$reparse_herald || | |||||
$reparse_owners); | |||||
if ($any_step && $importing) { | if ($any_step && $importing) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'Choosing steps with %s conflicts with flags which select '. | 'Choosing steps with "--importing" conflicts with flags which '. | ||||
'specific steps.', | 'select specific steps.')); | ||||
'--importing')); | |||||
} else if ($any_step) { | } else if ($any_step) { | ||||
// OK. | // OK. | ||||
} else if ($importing) { | } else if ($importing) { | ||||
// OK. | // OK. | ||||
} else if (!$any_step && !$importing) { | } else if (!$any_step && !$importing) { | ||||
Not Done Inline ActionsNever saw control flow like this before. Makes sense, but it took me a second. amckinley: Never saw control flow like this before. Makes sense, but it took me a second. | |||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'Specify which steps to reparse with %s, or %s, %s, %s, or %s.', | 'Specify which steps to reparse with "--message", "--change", '. | ||||
'--importing', | 'and/or "--publish"; or "--importing" to run all missing steps.')); | ||||
Not Done Inline ActionsExtra "or" amckinley: Extra "or" | |||||
Not Done Inline Actions"; or --importing for all uncompleted steps" amckinley: "; or --importing for all uncompleted steps" | |||||
'--message', | |||||
'--change', | |||||
'--herald', | |||||
'--owners')); | |||||
} | } | ||||
$min_timestamp = false; | $min_timestamp = false; | ||||
if ($min_date) { | if ($min_date) { | ||||
$min_timestamp = strtotime($min_date); | $min_timestamp = strtotime($min_date); | ||||
if (!$all_from_repo) { | if (!$all_from_repo) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
"You must use --all if you specify --min-date\n". | 'You must use "--all" if you specify "--min-date".')); | ||||
"e.g.\n". | |||||
" repository reparse --all TEST --owners --min-date yesterday")); | |||||
} | } | ||||
// previous to PHP 5.1.0 you would compare with -1, instead of false | // previous to PHP 5.1.0 you would compare with -1, instead of false | ||||
if (false === $min_timestamp) { | if (false === $min_timestamp) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
"Supplied --min-date is not valid. See help for valid examples.\n". | "Supplied --min-date is not valid. See help for valid examples.\n". | ||||
"Supplied value: '%s'\n", | "Supplied value: '%s'\n", | ||||
$min_date)); | $min_date)); | ||||
} | } | ||||
} | } | ||||
if ($reparse_owners && !$force) { | |||||
$console->writeOut( | |||||
"%s\n", | |||||
pht( | |||||
'You are about to recreate the relationship entries between the '. | |||||
'commits and the packages they touch. This might delete some '. | |||||
'existing relationship entries for some old commits.')); | |||||
if (!phutil_console_confirm(pht('Are you ready to continue?'))) { | |||||
throw new PhutilArgumentUsageException(pht('Cancelled.')); | |||||
} | |||||
} | |||||
$commits = array(); | $commits = array(); | ||||
if ($all_from_repo) { | if ($all_from_repo) { | ||||
$repository = id(new PhabricatorRepositoryQuery()) | $repository = id(new PhabricatorRepositoryQuery()) | ||||
->setViewer(PhabricatorUser::getOmnipotentUser()) | ->setViewer(PhabricatorUser::getOmnipotentUser()) | ||||
->withIdentifiers(array($all_from_repo)) | ->withIdentifiers(array($all_from_repo)) | ||||
->executeOne(); | ->executeOne(); | ||||
if (!$repository) { | if (!$repository) { | ||||
Show All 20 Lines | if ($all_from_repo) { | ||||
pht( | pht( | ||||
'No commits have been discovered in the "%s" repository!', | 'No commits have been discovered in the "%s" repository!', | ||||
$repository->getDisplayName())); | $repository->getDisplayName())); | ||||
} | } | ||||
} else { | } else { | ||||
$commits = $this->loadNamedCommits($reparse_what); | $commits = $this->loadNamedCommits($reparse_what); | ||||
} | } | ||||
if ($all_from_repo && !$force_local) { | if (!$background) { | ||||
$console->writeOut("%s\n", pht( | PhabricatorWorker::setRunAllTasksInProcess(true); | ||||
"**NOTE**: This script will queue tasks to reparse the data. Once the ". | |||||
"tasks have been queued, you need to run Taskmaster daemons to ". | |||||
"execute them.\n\n%s", | |||||
pht( | |||||
'QUEUEING TASKS (%s Commit(s)):', | |||||
phutil_count($commits)))); | |||||
Not Done Inline ActionsI think it's a little unfair to remove this and the similar warning back on line 22. amckinley: I think it's a little unfair to remove this //and// the similar warning back on line 22. | |||||
} | } | ||||
$progress = new PhutilConsoleProgressBar(); | $progress = new PhutilConsoleProgressBar(); | ||||
$progress->setTotal(count($commits)); | $progress->setTotal(count($commits)); | ||||
$tasks = array(); | $tasks = array(); | ||||
foreach ($commits as $commit) { | foreach ($commits as $commit) { | ||||
$repository = $commit->getRepository(); | $repository = $commit->getRepository(); | ||||
if ($importing) { | if ($importing) { | ||||
$status = $commit->getImportStatus(); | $status = $commit->getImportStatus(); | ||||
// Find the first missing import step and queue that up. | // Find the first missing import step and queue that up. | ||||
$reparse_message = false; | $reparse_message = false; | ||||
$reparse_change = false; | $reparse_change = false; | ||||
$reparse_owners = false; | $reparse_publish = false; | ||||
$reparse_herald = false; | |||||
if (!($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE)) { | if (!($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE)) { | ||||
$reparse_message = true; | $reparse_message = true; | ||||
} else if (!($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE)) { | } else if (!($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE)) { | ||||
$reparse_change = true; | $reparse_change = true; | ||||
} else if (!($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS)) { | } else if (!($status & PhabricatorRepositoryCommit::IMPORTED_PUBLISH)) { | ||||
$reparse_owners = true; | $reparse_publish = true; | ||||
} else if (!($status & PhabricatorRepositoryCommit::IMPORTED_HERALD)) { | |||||
$reparse_herald = true; | |||||
} else { | } else { | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
$classes = array(); | $classes = array(); | ||||
switch ($repository->getVersionControlSystem()) { | switch ($repository->getVersionControlSystem()) { | ||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | ||||
Show All 18 Lines | foreach ($commits as $commit) { | ||||
$classes[] = 'PhabricatorRepositorySvnCommitMessageParserWorker'; | $classes[] = 'PhabricatorRepositorySvnCommitMessageParserWorker'; | ||||
} | } | ||||
if ($reparse_change) { | if ($reparse_change) { | ||||
$classes[] = 'PhabricatorRepositorySvnCommitChangeParserWorker'; | $classes[] = 'PhabricatorRepositorySvnCommitChangeParserWorker'; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if ($reparse_herald) { | if ($reparse_publish) { | ||||
$classes[] = 'PhabricatorRepositoryCommitHeraldWorker'; | $classes[] = 'PhabricatorRepositoryCommitPublishWorker'; | ||||
} | |||||
if ($reparse_owners) { | |||||
$classes[] = 'PhabricatorRepositoryCommitOwnersWorker'; | |||||
} | } | ||||
// NOTE: With "--importing", we queue the first unparsed step and let | // NOTE: With "--importing", we queue the first unparsed step and let | ||||
// it queue the other ones normally. Without "--importing", we queue | // it queue the other ones normally. Without "--importing", we queue | ||||
// all the requested steps explicitly. | // all the requested steps explicitly. | ||||
$spec = array( | $spec = array( | ||||
'commitID' => $commit->getID(), | 'commitID' => $commit->getID(), | ||||
'only' => !$importing, | 'only' => !$importing, | ||||
); | ); | ||||
if ($all_from_repo && !$force_local) { | |||||
$background = true; | |||||
} else { | |||||
$background = false; | |||||
} | |||||
if (!$background) { | |||||
PhabricatorWorker::setRunAllTasksInProcess(true); | |||||
} | |||||
foreach ($classes as $class) { | foreach ($classes as $class) { | ||||
PhabricatorWorker::scheduleTask( | PhabricatorWorker::scheduleTask( | ||||
$class, | $class, | ||||
$spec, | $spec, | ||||
array( | array( | ||||
'priority' => PhabricatorWorker::PRIORITY_IMPORT, | 'priority' => PhabricatorWorker::PRIORITY_IMPORT, | ||||
)); | )); | ||||
} | } | ||||
Show All 10 Lines |
'Publish changes. Includes evaluating Owners packages and Herald rules.'?